Upload
seiki-okude
View
119
Download
0
Embed Size (px)
Citation preview
Unity&UnrealEngine作って比べるハンズオン勉強会
Unity編
2015/06/20 奥出 成希@sokude
ハンズオン概要● UnityとUnrealEngineでの制作方法や考え方の違いを、実際の制作を通して体感する● 理想的には両方を作って比べたいのだが、PCの性能その他諸々の理由でどちらかを選んで作ってもOK● 宇宙モノSF映画によくある、隕石群を突破する宇宙船をテーマにミニゲームを作成する● 視覚効果的なところは取り上げない
登場オブジェクトの概要● 宇宙船
○ プレイヤー操作可能○ 前方へ向かって自動的に移動○ キー操作で上下左右に移動
● 隕石○ 回転している。移動はしない。(宇宙船が移動するため)○ 宇宙船進行方向に対して一定間隔で30個ほど配置○ 前方方向へは一定間隔だが、上下左右はランダムで配置○ カメラより後方になった場合前方へ位置を変える
● 壁○ 宇宙船上下左右の移動を制限するための壁○ 見えないけど当たり判定だけある○ 宇宙船についてくるようにする
● カメラ○ カメラは宇宙船後方から一定距離で撮影○ これも宇宙船についてくるようにする
制作手順 1● Unityの起動とプロジェクトの作成
○ 新しいプロジェクト作成○ プロジェクトフォルダとプロジェクト名は適切に設定する。
● エディタの設定○
● 各ビューの説明○ Hierarchy : UE4ではワールドアウトライナーに相当○ Inspector : UE4では詳細に相当○ Project: UE4ではコンテンツブラウザに相当○ Scene/Gameビュー: UE4ではビューポートに相当
● 不要なオブジェクトの削除○
● この時点で一旦セーブ○ シーンは「scene」と呼ばれるアセットに保存される○ 適当に名前をつけて保存する(例えばscene01など)
制作手順 1● 環境光の設定
○ Window → Lightingメニュー○ SkyboxをNoneに変更
● 背景の設定○ MainCameraを選択○ InspectorでClearFlagをSolidColorに
変更○ Backgroudを黒(0,0,0)に変更
制作手順 2● 制作開始前に確認
○ Unityでの座標系■ X:左右■ Y:上下■ Z:前後
● 宇宙船の作成、配置○ Cubeを組み合わせて宇宙船っぽいもの
を作る○ Sceneビューでの作業
制作手順 2● 宇宙船の作成
○ Cubeを図のように配置○ starShipは宇宙船全体をまとめるための空
オブジェクト■ CreateEmptyで作成
○ starShipの子オブジェクトとして4つのキューブの変形を置く
● 各部品のTransformのpositionとScale○ starShip [0, 0, 0] [1, 1, 1]○ base [0, 0, 0] [1, 0.1, 1]○ body [0, -0.2, -0.6] [0.2, 0.2, 0.8]○ wingL [-0.3, 0.05, -1.2] [0.1, 0.15, 1]○ wingR[0.3, 0.05, -1.2] [0.1, 0.15, 1]
● マテリアルの作成○ マテリアルとは、表示物の材質のこと。
ここでは単純に色を設定するだけのマテリアルを作る。
○ 名前は「starshipMat」○ projectビュー上で選択しているとInspectorで
編集できる
StandardShaderを使うAlbedoとEmissionだけ設定する
● マテリアルの適用○ プロジェクト上にあるマテリアルを宇宙
船の各部品にドラッグ&ドロップして部品にマテリアルを適用する
制作手順 3● 隕石の作成
○ 基本部品のキューブをそのまま使う
○ 名前はCubeからMeteorに変更しておく
● 隕石のマテリアル○ 名前は「meteorMat」○ 宇宙船と同じような作りにな
る○ 色だけ違うものにしておく
隕石をprefab化しておく● prefabとは、同じ物体がゲーム上に多
数出現する場合、その物体のひな形になるもの
● とりあえず1つ作って、prefab化しておく● 後からプログラムでこのprefabを大量
発生させたりすることができる● 名前は「meteorPrefab」
● ProjectビューからMeteorのオリジナルをMeteorPrefabにドラッグアンドドロップする
● prefab化したら一旦Hierarchyビューからは取り除いておく
制作手順 4● 移動範囲制限壁セット
○ キューブを拡大して上下左右を壁床天井として配置する
○ 宇宙船の上下方向の移動を制限するための「壁」を設置する
○ 宇宙船の動きに追従して動く○ Cubeオブジェクトを使うが、後で表
示だけ消すことで当たり判定のみ残す
○ 上下左右の壁はそれぞれwallU,wallD,wallL,wallRとする
○ wallSetという名前で空オブジェクトを作り壁4つはその下の階層に配置する
各物体の位置とスケールwallSet[0,0,0][1,1,1]
wallU[0,3,0][10,1,3]wallD[0,-3,0][10,1,3]wallL[-5,0,0][1,10,3]wallR[5,0,0][1,10,3]
制作手順 5● カメラの設定
○ wallSetの子オブジェクトとして配置○ 座標は[0,0,-4]とする
● ゲーム登場物の階層構造と配置確認
制作手順 6● スクリプトの作成
○ starShipのスクリプト■ 前方へ向かって自動的に移動する■ プレイヤーの入力で上下左右に移動する
○ Meteorのスクリプト■ ランダムな回転■ 移動はしない■ カメラの位置より後方になったら前方へ移動する
○ 全体コントロールのスクリプト■ 隕石をたくさん生成する■ 壁セットを宇宙船に追従させる
宇宙船のスクリプト● 宇宙船の移動に関して
○ 物理エンジンを用いて移動させる(AddForce命令)○ 定期的に前方に向かって一定の力をかけ続ける○ ユーザーの入力に従って上下左右にも力をかける○ 重力下での物理挙動は重力の影響を受けて落下するが今回は重力を使わない(宇宙だから)○ しかし空気抵抗まで消してしまうと操作が難しくなるのでこれはいれる(ゲーム的嘘)
● 当たり判定に関して○ meteorと衝突する設定だが、完全にぶつかって通り抜けできない状態だとゲームが進行しない可能性があ
る○ これを回避するためにmeteorはすり抜けられる物体として、宇宙船と接触した場合プログラムで宇宙船にか
かっている物理的な力を0にすることで停止させる
● スクリプトを書く前にstarShipが物理的な力を受け取れるようにしておく
● starShipのインスペクタ下部のAddComponentからPhysics→Rigidbodyを追加する
○ 左の図のようになる● Mass(質量) : 0.1● Drag(摩擦) : 1● Use Gravityのチェックを外す● Constraint(移動と回転の制限) : 回転の制限をかける
宇宙船にスクリプトを追加するAdd Component→New Scriptnameには「starShipScript」Languageは「C Sharp」Create and Addで追加する追加したらprojectビューのstarShipScriptをダブルクリックで開く→mono develop起動
→
キー操作で動かしてみる
Update関数の中に追加
// Update is called once per framevoid Update () {
float xaxis = Input.GetAxis ("Horizontal") * Time.deltaTime * 60;float yaxis = Input.GetAxis ("Vertical") * Time.deltaTime * 60;transform.GetComponent<Rigidbody> ().AddForce (new Vector3 (xaxis, -yaxis, 0));
}
打ち込んだら保存してUnityに戻り、画面上部の三角ボタンで実行する。入力ミス、設定ミスがなければ宇宙船が上下左右に動き、壁にあたって止まるようになっている。
Input.GetAxis ("Horizontal")の軸名はEdit→ProjectSettings→Inputで確認Time.deltaTime * 60の意味
● 可変フレームレート実装のため● 前フレームからの経過時間(Time.deltaTime)を取得して掛け算を行う● フレーム更新レートが低い時には大きな動きを回数少なく実行● フレーム更新レートが高い時には小さい動きを回数多く実行
隕石の設定● projectビュー上のMeteorPrefabをSceneビューに置く● 座標0,0,10にする● 前述の当たり判定関連でBoxColliderのisTriggerのチェックを入れる● 宇宙船と同様、Add ComponentでC#スクリプトを追加● 名前はMeteorScript● projectビュー上のMeteorScriptをダブルクリックでMonoDevelopを起動
隕石を回転させる
public class MeteorScript : MonoBehaviour {Vector3 rotSpd;// Use this for initializationvoid Start () {
rotSpd = new Vector3 (Random.Range (-1.0f, 1.0f),Random.Range (-1.0f, 1.0f),Random.Range (-1.0f, 1.0f));
}// Update is called once per framevoid Update () {
transform.Rotate (rotSpd * Time.deltaTime * 60);}
}
隕石の位置をランダムにする再利用することを考えて関数にしておく奥行方向は引数で指定、上下左右をランダムにする
追加
public void resetPos(float _zpos){Vector3 pos = new Vector3 (
Random.Range (-4.0f, 4.0f),Random.Range (-2.0f, 2.0f),_zpos);
transform.position = pos;}
Scene上で編集したMeteorはprefabとして更新しておく必要があるApplyボタンを押すとScene上の変更点がprefabにも適用される
出来上がったprefabをたくさんScene上に配置すれば隕石群の完成だが、30個ほどもいちいち手動で配置するのは手間がかかりすぎる
そこでスクリプトを使って自動生成させることにする
座標(0,0,0)に空オブジェクトを作成、名前はGameCtrlとする。Add Componentを使って新しいスクリプトgameCtrlScriptを作る。
gameCtrlScriptの内容
public class gameCtrlScript : MonoBehaviour {public Transform meteorPrefab;// Use this for initializationvoid Start () {
for (int i = 0; i < 30; ++i) {Transform tmp = Instantiate (meteorPrefab) as Transform;tmp.GetComponent<MeteorScript>().resetPos(i * 3 + 10);
}}// Update is called once per framevoid Update () {}
}
GameCtrlにmeteorPrefabを割り当てる
public Transform meteorPrefab;
この部分はgameCtrlScriptのなかで使う隕石のPrefabを変数として表現したもの。ただしこの段階ではmeteorPrefabという変数名を宣言しただけで、実際にProjectビュー上に存在しているMeteoPrefabと関連づいているわけではない。この関連付けを行う。
Hierarchy上のgameCtrlを選択して、InspectorにGameCtrlの情報が出ている状態にする。その後、Project上のMeteorPrefabをGameCtrlのInspectorのMeteor Prefabの項目へドラッグアンドドロップする。前項の変数とPrefabが関連づく。
実行結果
宇宙船を前に進ませるstarShipScriptを編集する
Update関数の中を修正
// Update is called once per framevoid Update () {
float xaxis = Input.GetAxis ("Horizontal") * Time.deltaTime * 60;float yaxis = Input.GetAxis ("Vertical") * Time.deltaTime * 60;transform.GetComponent<Rigidbody> ().AddForce (
new Vector3 (xaxis, -yaxis, 120 * Time.deltaTime));}
このまま実行すると、カメラと移動制限壁を置き去りにして、宇宙船は前方へ加速していきます。これは意図している動きではありません。
カメラと移動制限壁を宇宙船の位置に追従させます。
壁セット+カメラを宇宙船に追従させる登場物のどれかがその制御を担当することになります。この選定もゲームによったり、プログラマの判断によったり適宜選択することになります。今回はGameCtrlに担当させます。
隕石の初期配置を行った時と同様にgameCtrlScriptに書くオブジェクトを変数として把握させます。
gameCtrlScriptに
public class gameCtrlScript : MonoBehaviour {public Transform meteorPrefab;public Transform starship;public Transform wallSet;
この2行を追加する。
GameCtrlを選択状態してInspectorのStarshipとWallSetのところにHierarchyからそれぞれのオブジェクトをドラッグアンドドロップして割り当てを行う
座標を連動させるだけなら
// Update is called once per framevoid Update () {
wallSet.position = starship.transform.position;}
これだと宇宙船の前後だけではなく上下左右も連動してしまう。宇宙船の上下とともに壁も上下に動いてしまうので永久に壁には当たらない。そこで、位置情報のうちZの値だけ宇宙船のものを採用し、XとYは0にしてしまうことにする。
// Update is called once per framevoid Update () {
wallSet.position = Vector3.Scale(starship.position,new Vector3(0,0,1));}
いよいよ完成に近づいてきました。残る問題は以下の3つです。
● 隕石が後ろに飛び去ったあとの処理○ meteorScriptで宇宙船との位置関係を調べて後ろに飛び去ったと判定したら前方へ位置を変える
● 隕石との当たり判定○ starshipScriptで他の物体とあたった時の処理を記述する
● 壁セットとの当たり判定○ 動かしてみるとわかるのだが、壁との摩擦抵抗で宇宙船の動きが止まる。これはこれでゲームとして成り立
つのだが、今回は壁が見えないこともあるので摩擦は無しにしたい。○ PhysicalMaterialの設定を行う
隕石が後ろに飛び去ったあとの処理(MeteorScript)宇宙船の位置を把握する必要があるのでgameCtrlScriptでやったように変数として把握させる。ただし、隕石はprefabのためドラッグアンドドロップでは割り当てられない。transform.Findを使ってプログラム実行時にHierarchy上にあるものを探す。
public class MeteorScript : MonoBehaviour {Vector3 rotSpd;Transform starship;// Use this for initializationvoid Start () {
rotSpd = new Vector3 (Random.Range (-1.0f, 1.0f),Random.Range (-1.0f, 1.0f),Random.Range (-1.0f, 1.0f));
starship = transform.Find ("/starShip");}// Update is called once per framevoid Update () {
transform.Rotate (rotSpd * Time.deltaTime * 60);if (transform.position.z < starship.position.z - 3) {
resetPos(transform.position.z + 90);}
}
隕石との当たり判定(starShipScript)
隕石Prefab作成時にisTriggerのチェックを入れたためstarShipとの当たりはOnTriggerEnterを用いて判定する。当たるとOnTriggerEnter関数が呼ばれる。
starShipScriptのUpdate()の後に付け加える
void OnTriggerEnter(Collider _othre ){GetComponent<Rigidbody> ().velocity = Vector3.zero;
}
壁セットとの当たり判定
物理マテリアルの作成名前はwallMaterialとする
インスペクタでDynamic Frictionを0Static Frictionを0に
材質を適用するため壁をすべて選択しておく
wallMaterialをBoxColliderのMaterialにドラッグアンドドロップする。MeshRendererのチェックボックスを外して非表示にする。
完成
改造項目● よりゲームらしく
○ 1分間でどれだけの距離を進んだか計測する
○ 3回ダメージでゲームオーバー
○ 途中で金色の隕石が現れて当たると無敵になる
etc.
まだゲームになっていない状態なので、ここからは自らの手で改造してゲームに仕立てていってください。