まずは簡単なおさらいから。床と球を作成して、球に Rigidbody を与えて物理挙動させてみる。単に平らな床の上に落とすだけでなく、床を傾けるなどしてみよう。
Rigidbody とは「剛体」の意。変形することのない物体のことを表す。このコンポーネントをゲームオブジェクトに与えると、そのゲームオブジェクトは剛体として物理挙動をとるようになる。
Rigidbody にはいくつかのパラメータがある。
Physic material を使えば更に詳しい属性を与えることができる。
Physic material は Project ビューの Create メニューから作成する。ゲームオブジェクトにドラッグ&ドロップすることで割り当てる。実際に physic material を作成し、色々と設定を変えて挙動を確認してみよう。
Rigidbody をスクリプトから操作する方法は色々ある。今回は速度ベクトルを直接設定する方法を試してみよう。
適当な JavaScript を作成し、次のような内容にする。
function Start() {
rigidbody.velocity = Vector3(20, 0, 0);
}
Start
は処理を開始するときに呼ばれる関数。スクリプトから Rigidbody へアクセスするには rigidbody
プロパティを使えばいい。 rigidbody
の中には更に多種のプロパティがあるが、ここでアクセスしているのは velocity
という速度ベクトルを保持するプロパティ。これにX軸方向20の大きさのベクトルを与えている。
これを実行すると、このスクリプトを与えたゲームオブジェクトは右方向へと飛んでいく。
Rigidbody のパラメータの中に Constraints という項目がある。これは rigidbody の動きを特定の軸に限定するというもの。チェックを入れた軸が動かなくなる。
例えば Freeze Position の Z にチェックを入れるとZ軸方向には動かなくなり、XY軸だけの平面的な動きになる。 Freeze Rotation の X, Z にチェックを入れるとY軸だけの回転になり、 rigidbody は横転しなくなる。
階層構造とは、ゲームオブジェクトの間に主従(親子)の関係を与えるもの。子のゲームオブジェクトは親のゲームオブジェクトの位置や回転に追従して動くようになる。子のゲームオブジェクトの動きは、親のゲームオブジェクトからの相対的なものになる。
Unity で階層構造を作るには、親となるゲームオブジェクトに対して子となるゲームオブジェクトをドラッグ&ドロップするだけでよい。
棒と球を作成し、球を棒の子の構造にしてみよう。球と棒のそれぞれを動かしたり回転させてみて、両者の動きがどのように関係しているかを確認しよう。
このような親子構造は、物体を特定の軸で回転させたり、複数の物体をまとめて動かしたりするのに便利。空のゲームオブジェクトを使うことで、そのような構造を気軽に増やせるようになる。
メインメニューの Game Object から Create Empty を選択すると、中身の無い空っぽのゲームオブジェクトを作成できる。
階層構造を構築し、そのトップ(ルート)のゲームオブジェクトに Rigidbody を与えると、その子の構造にある形状をすべて合成したものとして剛体が作られる。これを使って比較的複雑な形状の剛体を作り出すことができる。
試しに鉄アレイとか机とか作ってみよう。
Unity にはプレハブという仕組みがある。シーン中のゲームオブジェクトを使い回しのきくデータとして保存するもの。
プレハブを作成するには、 Hierarchy ビュー上にあるゲームオブジェクトを Project ビューの空白エリアにドラッグ&ドロップするだけでよい。あるいは、 Project ビューの Create メニューから Prefab を選択して作成することもできる。
こうして作成したプレハブは、 Hierarchy ビュー上にドラッグ&ドロップするだけで簡単に複製できる。このようにプレハブからゲームオブジェクトを作成することをインスタンス化と呼ぶ。また、プレハブから作られた複製物のゲームオブジェクトのことを、プレハブのインスタンスと呼ぶ。
インスタンスは元となったプレハブと関連付けられている。プレハブ側で設定を変更すると、それがインスタンス側にも一斉に反映される。あとから設定を調整する可能性のあるゲームオブジェクトを大量に配置する場合はプレハブを使うと良い。
プレハブを使うと便利なのは、スクリプトからインスタンス化が行えるということ。例えばシューティングゲームを作るなら、あらかじめ弾をプレハブ化しておき、ボタンが押される度にその弾プレハブをインスタンス化すればよい。
プレハブのインスタンス化は次のようなスクリプトによって行われる。
var prefab : GameObject;
function Update() {
if (Input.GetButtonDown("Fire1")) {
Instantiate(prefab);
}
}
プレハブは GameObject 型の変数で受け取ることができる。プレハブをインスタンス化するには Instantiate
関数を使う。
これで Cannon を回転させることにより Cylinder が根元から回転するようになる。
弾を出す位置に空のゲームオブジェクトを置くようにしよう。名前は Launcher とする。これは Cannon の子の構造とすると都合良い。こんな感じの構成にする。
次に JavaScript を作成する。名前は Launcher とする。スクリプトの内容は次のようにする。
var shellPrefab : GameObject;
function Update() {
if (Input.GetButtonDown("Fire1")) {
Instantiate(shellPrefab, transform.position, Quaternion.identity);
}
}
このスクリプトを空のゲームオブジェクト Launcher に与える。 Inspector 上から変数 shellPrefab が見えるようになるので、これに Shell プレハブをドラッグ&ドロップする。
実行確認。マウスクリックでボロボロと弾が出現すれば成功。
弾をインスタンス化した直後に初速を与えるようにする。 Launcher スクリプトの内容を次のようにすればよい。
var shellPrefab : GameObject;
var initialVelocity : float;
function Update() {
if (Input.GetButtonDown("Fire1")) {
var shell : GameObject =
Instantiate(shellPrefab, transform.position, Quaternion.identity);
shell.rigidbody.velocity = transform.up * initialVelocity;
}
}
Inspector 上で initialVelocity を設定してから弾を出すと、設定した初速で弾が飛び出すようになる。
適当に箱などを積み上げて目標とするとよい。目標には Rigidbody を入れたうえでプレハブ化し配置する。プレハブ化しておくことによって、後からの調整がしやすくなる。
とりあえず大砲ゲームっぽくなった。
弾に使っている Rigidbody と目標に使っている Rigidbody とで Constraints を入れることによって 2D 的な動きに拘束する。
動きがなんとなく Angry Birds っぽくなっていることを確認する。
砲身の角度がマウスの縦座標位置によって変化するようにしてみよう。新しいスクリプト Cannon を作成し、 Cannon ゲームオブジェクトに与える。中身はこんな感じ。
function Update() {
var angle = 90.0 * (Input.mousePosition.y / Screen.height - 1.0);
transform.rotation = Quaternion.AngleAxis(angle, Vector3(0, 0, 1));
}
弾の初速もマウスで操作できるようにしよう。こちらはマウスの横座標位置を使う。 Launcher スクリプトの中身を次のようにする。
var shellPrefab : GameObject;
function Update() {
if (Input.GetButtonDown("Fire1")) {
var shell : GameObject =
kInstantiate(shellPrefab, transform.position, Quaternion.identity);
var velocity = 30.0 * Input.mousePosition.x / Screen.width;
shell.rigidbody.velocity = transform.up * velocity;
}
}
きりの良い所でシーンをセーブしておく。このプロジェクトは次回の授業でも使いまわすので、消さないようにしておくこと。