Unity と C# を使用した初めてのゲーム開発 (第 3 部)
Unity シリーズの第 3 回です。第 1 回は Unity の基本をいくつか取り上げました (msdn.microsoft.com/magazine/dn759441)。第 2 回は Unity の 2D に注目しました (msdn.microsoft.com/magazine/dn781360)。今回は、私のお気に入りの 3D ゲーム開発について考えます。3D の世界は、夢中になれる環境、豊かなサウンド効果、美しいビジュアルから構成される幻想的な空間です。単純なパズルゲームに現実世界の物理現象を追加するだけでも、プレイヤーは時間を忘れて熱中できるようになるでしょう。
3D ゲームは 2D の上に層を重ねて複雑になっていることは確かですが、1 つ 1 つ取り組んでいけばすばらしい 3D ゲームを構築できます。Unity の 2D と 3D の新しいプロジェクト設定はどちらも 3D をサポートしており、3D オブジェクトを 2D ゲームで使用してもかまいません (逆も同様です)。
3D シーンの構成要素
3D シーンは、光、メッシュ レンダラー、シェーダーという 3 つのメイン ビジュアル コンポーネントを中心に構成されます。光とは光源のことで、Unity では 4 種類の光がサポートされます。これらはすべて、[GameObject] メニューにあります。さまざまな種類の光を追加して、そのプロパティを変更してみましょう。シーンを照らす最も簡単な光は、Directional Light (指向性光) です。これは、空にある太陽のような光源です。
メッシュ (モデル) は、オブジェクトを構成する多角形の基になる頂点の集合です。シェーダーは、オブジェクトに対する光の表示や処理の方法を制御するコードを保持するコンパイル済みのルーチンです。単純に光を受けて鏡のように反射するシェーダーもあれば、テクスチャ (メッシュに適用される画像) を受け取って影や深さを表現できるシェーダーも、モデルの表示にフェンスのような穴を開けられるシェーダーもあります。
モデルは、一般に FBX ファイルまたは OBJ ファイルで、別のモデル作成ソフトウェア パッケージからエクスポートされます。FBX ファイルは、アニメーション データも保持できるため、1 つの FBX ファイルでモデルとそれに含まれる複数のアニメーションを表現できます。また、Autodesk Maya の .ma 形式や Blender ファイルなど、複数のサードパーティ ファイル形式もサポートされます。それらのファイルを Unity にインポートするには、通常、同じシステム上にそのサードパーティ製プログラムがインストールされている必要があります。インストールされていれば、他のファイル形式と同様、ファイルを Unity プロジェクトにドラッグ アンド ドロップするだけです。(インポート時またはファイル変更の検出時に) Unity はバックグラウンドで他のファイル形式を FBX ファイル形式に変換します。
Asset Store
初回のコラムで Asset Store に触れましたが、3D ゲームではこれが真価を発揮します。私は芸術家ではありませんし、技術者向けの雑誌なので、読者の中にも芸術家は少ないでしょう (もしも芸術家の方がいたら、貴重な読者を得たことに感謝するしかありません)。とは言え、緑生い茂る環境や、古くて壊れた建物が出てくるゲームを作成したいものです。でも、問題ありません。必要なものは Asset Store から購入できます。15 体の異なるゾンビが欲しければ、Asset Store の Mixamo からパックを調達します。考えられる組み合わせは無限に近いので、他人のゲームと見た目が似てしまう恐れはありません。何よりすばらしいのは、Asset Store が Unity に統合されている点です。[Window] (ウィンドウ)、[Asset Store] の順にクリックし、箱のアイコンをクリックしてパッケージをアップグレードできます。レビューやコメントを確認して、特定のアイテムがプロジェクトにふさわしいかどうか (たとえば、モバイルに最適化されているかどうか) を簡単に判断することも可能です。新しいチップがいくつか登場したことによって、現状モバイル デバイスも Xbox 360 に近くなっていますが、一般的に、デスクトップ ゲームの方が、モバイル ゲームよりも多くのオブジェクト/頂点/テクスチャ/メモリを処理できます。
代表的な 3D ゲームには、2D ゲームと同じ多くの概念 (コライダー、トリガー、剛体、ゲーム オブジェクト/変換、コンポーネントなど) が当てはまります。通常は、どのような 3D ゲームの場合でも、入力、動き、キャラクターを制御し、アニメーションやパーティクル効果を使って、ファンタジックかつリアルな創意に富んだ世界を構築することを考えます。ここからは、3D 環境構築に役立つ Unity での作業方法について説明します。
入力、動き、キャラクターのコントローラー
動きの入力の読み取りは、2D では XY 平面での単純な動きだったものが 3D では X、Y、Z の 3 次元に動くようになるため、複雑さが増します。3D の動きのシナリオには、キャラクターが水平および垂直のみに動くトップダウンの動きのほか、多くのファーストパーソン シューティング ゲーム (FPS) に実装されているように、マウス入力を読み取ってカメラやキャラクターが回転する、水平方向の入力を読み取って機銃掃射する、水平方向の入力を読み取って方向転換する、後ろ向きに歩くなどのシナリオがあります (もちろん、これだけではありません)。かなりの数の動きのオプションから選択できます。
オブジェクトを動かす場合、ご想像のとおり、オブジェクトに移動先の位置は渡しません。コードはフレームごとに実行されるため、オブジェクトは少しずつ動かさなければなりません。RigidBody に加えた力を物理エンジンに処理させて動かすことも、オブジェクトをトゥイーン (tween) することもできます。トゥイーンとは、中間値 (between) の遷移、つまり、点 A から点 B への動きを意味します。Unity で値をトゥイーンする方法は、iTween などの無料のサード パーティ ライブラリを使用するなど、さまざまです。図 1 に、Unity 内のオブジェクトを手動で動かす方法をいくつか示しています。わかりやすいように、各方法は最適化していません (transform への参照を変数に保持し、マネージ コードがネイティブ コードにならないようにしています)。
図 1 オブジェクトを動かすさまざまな方法
// Method 1
void Update()
{
// Move from point a to point b by .2 each frame - assuming called in Update.
// Will not overshoot the destination, so .2 is the max amount moved.
transform.position =
Vector3.MoveTowards(transform.position, new Vector3(10, 1, 100), .2f);
}
// Method 2
void Update()
{
// Interpolate from point a to point b by a percentage each frame,
// in this case 10 percent (.1 float).
var targetPosition = new Vector3(10,0,15);
transform.position = Vector3.Lerp(parentRig.position, targetPosition, .1f);
}
// Method 3
void Update()
{
// Teleport the object forward in the direction it is rotated.
// If you rotate the object 90 degrees, it will now move forward in the direction
// it is now facing. This essentially translates local coordinates to
// world coordinates to move object in direction and distance
// specified by vector. See the Unity Coordinate Systems section in the
// main article.
transform.Translate(Vector3.forward * Time.deltaTime);
}
// Method 4
void FixedUpdate()
{
// Cause the object to act like it's being pushed to the
// right (positive x axis). You can also use (Vector.right * someForce)
// instead of new Vector().
rigidbody.AddForce( new Vector3(7, 0, 0), ForceMode.Force);
}
// Method 5
void FixedUpdate()
{
// Cause the object to act like it's being pushed to the positive
// x axis (world coordinates) at a speed of approx 7 meters per second.
// The object will slow down due to friction.
rigidbody.velocity = new Vector3(7,0,0);
}
// Method 6
// Move the rigidbody's position (note this is not via the transform).
// This method will push other objects out of the way and move to the right in
// world space ~three units per second.
private Vector3 speed = new Vector3(3, 0, 0);
void FixedUpdate()
{
rigidbody.MovePosition(rigidbody.position + speed * Time.deltaTime);
}
// Method 7
void FixedUpdate()
{
// Vector3.forward is 0,0,1. You could move a character toward 0,0,1, but you
// actually want to move the object forward no matter its rotation.
// This is used when you want a character to move in the direction it's
// facing, no matter its rotation. You need to convert the meaning of
// this vector from local space (0,0,1) to world space,
// and for that you can use TransformDirection and assign that vector
// to its velocity.
rigidbody.velocity = transform.TransformDirection(Vector3.forward * speed);
}
どの方法にもメリットとデメリットがあります。方法 1 と 2 は、非常に簡単な動きですが、transform を動かすパフォーマンスが低下する可能性があります。Unity は、オブジェクトに RigidBody コンポーネントが設定されていない場合、そのオブジェクトは動かないと考えます。その場合、オブジェクトの場所を把握するために静的衝突行列を内部に構築して、パフォーマンスを向上します。transform を移動してオブジェクトを動かすときは、この行列を再計算する必要があるため、パフォーマンスが低下します。シンプルなゲームであればパフォーマンスの低下に気付かないのでこの方法が最も簡単です。ただし、ゲームが複雑になるほど、方法 4 ~ 6 のように RigidBodey そのものを動かすことが重要になります。
オブジェクトの回転
オブジェクトの回転は、オブジェクトの移動と同様、かなり簡単です。ただし、回転の場合、ベクトルは位置や正規化ベクトルではなく角度を表します。正規化ベクトルとは、任意の値を取る、最大値が 1 のベクトルです。ベクトルによって単純に方向を参照する場合に使用します。Vector3.right、back、forward、down、up、left、right、zero、one など、役立つベクトル キーワードがいくつかあります。正の水平方向に移動または回転させる場合は Vector.right を使用します。これは、(1,0,0)、つまり、右方向 1 単位動かすショートカットです。回転の場合には 1 度を表します。図 2 は、各フレームで少しずつオブジェクトを回転させています。
図 2 オブジェクトを回転させる方法
// Any code below that uses _player assumes you
// have this code prior to it to cache a reference to it.
private GameObject _player;
void Start()
{
_player = GameObject.FindGameObjectWithTag("Player");
}
// Method 1
void Update () {
// Every frame rotate around the X axis by 1 degree a
// second (Vector3.right = (1,0,0)).
transform.Rotate(Vector3.right * Time.deltaTime);
}
// Method 2
void Update () {
// No matter where the player goes, rotate toward him, like a gun
// turret following a target.
transform.LookAt(_player.transform);
}
// Method 3
void Update()
{
Vector3 relativePos = _player.transform.position - transform.position;
// If you set rotation directly, you need to do it via a Quaternion.
transform.rotation = Quaternion.LookRotation(relativePos);
}
各方法は、微妙に異なります。どの方法を使用すればよいでしょう。私の場合、可能であれば、RigidBody に力を加えます。おそらく、この方法には少し困惑するでしょう。この方法の良いところは、こうした処理のすべてを事実上実行できる既存のコードが存在することです。
方法 3 の Quaternion (クオータニオン、四元数) に気付きましたか。Unity は、内部でクオータニオンを使用してすべての回転を表現しています。クオータニオンは、ジンバル ロックと呼ばれる効果を防ぐのに効果的な構造です。ジンバル ロックは、回転に標準オイラー角を使用すると発生することがあり、2 つの軸が同じ平面上に揃い、分離できない状態を指します (bit.ly/1mKgdFI (英語) のビデオ説明が参考になります)。この問題を避けるために、Unity はオイラー角ではなくクオータニオンを使用します。ただし、Unity エディターでオイラー角を指定し、バックエンドでクオータニオンに変換することもできます。多くの人はジンバル ロックを経験することはないでしょうが、コードで回転を直接設定する場合には、クオータニオンで指定する必要があります。その回転は Quaternion.Euler を使用してオイラー角から変換できます。
さまざまなオプションを紹介しましたが、最も簡単なのは RigidBody を使用して、キャラクターに .AddForce を単純に適用する方法です。できればコードを再利用します。さいわい、Unity には多数のプレハブが用意されています。
無駄な労力を使わない
Unity では、Asset Store に Sample Assets パッケージが用意されています (www.assetstore.unity3d.com/jp/#!/content/14474)。このサンプルには、モバイル ジョイスティック コントロールを利用するクロスプラットフォーム入力マネージャー、アニメーションとパーティクルのほか、特に重要な、いくつかの構築済みキャラクター コントローラーが含まれています。
以前 Unity に含まれていたアセットもいくつかあります (本稿執筆時点ではバージョン 4.6)。こうしたアセットは、Unity から個別に更新できる個別パッケージとして配布されるようになりました。ゲーム内の一人称視点キャラクター、三人称視点キャラクター、自動運転の車などを作成するのに、すべてのコードを記述しなくても、サンプル アセットのプレハブを使用するだけで作成できます。シーンにドラッグ アンド ドロップすると、複数のアニメーションを備えた三人称視点キャラクターがすぐに使用できるようになり、すべてのソース コードにアクセスできます (図 3 参照)。
図 3 三人称視点キャラクターのプレハブ
アニメーション
Unity の Mecanim アニメーション システムを説明すると、書籍を 1 冊執筆できます (それぐらいの内容があります)。一般的に、3D アニメーションは 2D アニメーションよりも複雑です。2D では通常、アニメーション ファイルを使用して、キー フレームごとにスプライト レンダラーを変化させて、アニメーションのように見せます。3D では、アニメーションのデータがはるかに複雑になります。第 2 回のコラムで、アニメーション ファイルには複数のキー フレームが含まれていることを説明しました。3D の場合、このキー フレームが多数になり、各キー フレームには、指を変える、腕や脚を動かす、さまざまな種類の動作を行うといった多数のデータ ポイントが含まれることになります。メッシュでも、キー フレームのボーンを定義し、スキン メッシュ レンダラーと呼ばれるコンポーネントを使用できます。このコンポーネントは、ボーンの動きに基づいて、メッシュを変形させます。
アニメーション ファイルは、Unity でも作成できますが、通常、サード パーティ製のモデル作成/アニメーション システムで作成します。
3D アニメーション システムのキャラクターの基本ポーズは T ポーズといい、その名のとおり、直立し、両腕を左右に広げたポーズです。これは、どの人型モデルにも当てはまります。これに、Mecanim を使用してキャラクターに事実上すべてのアニメーション ファイルを割り当てることで、基本キャラクターを動かすことができます。ゾンビ、妖精、人間など、何でも同じように躍らせることができます。2D と同じように、適切だと思われるアニメーション ファイルを組み合わせ、ステートを通じて割り当てます。これを行うには、図 4 に示すようなアニメーション コントローラーを使用します。
図 4 キャラクターのアニメーション ステートを制御するアニメーション コントローラー
キャラクターやアニメーションは、Unity Asset Store から入手することも、モデル作成ツールで作成することもできます。また、独自にカスタマイズしたキャラクターを簡単に生成できる Mixamo Fuse のようなサード パーティ製品も提供されています。Unity におけるアニメーションの概要は、Channel 9 ビデオをご覧ください。
世界を作る
Unity には、世界を生み出すための地形システムが組み込まれています。地形を作成したら、組み込みの地形ツールを使用して、地形の調整、山の作成、木や草の配置、テクスチャの描画などが可能です。世界に空を追加するには、スカイボックス パッケージ をインポート ([Assets] (アセット)、[Import Package] (パッケージのインポート)、[Skyboxes] (スカイボックス) の順に移動) して、[Edit] (編集)、[Render Settings] (レンダリング設定)、[Skybox Material] (スカイボックス素材) の順に移動して割り当てます。図 5 に示す、動きがあり、光を反射する水、木、砂、山、草などのある地形を作成するのにかかった時間は数分でした。
図 5 短時間で作成した地形
Unity の座標系
Unity には、ゲームまたは画面内の点を表現する方法が 4 つあります (図 6 参照)。1 つ目は画面領域 (Screen Space) です。これは、0 ~ ピクセル数の範囲で表し、通常、ユーザーがタッチまたはクリックした画面上の位置の取得に使用します。2 つ目のビューポート領域 (Viewport Spsce) は、単純に 0 ~ 1 の範囲の値で表します。そのため、たとえば中間の場所はピクセル数を 2 で割らなくても、0.5 と簡単に表現できます。そのため、位置として (.5, .5) を使用して、画面の中央にオブジェクトを簡単に配置できます。3つ目のワールド空間 (World Space) は、3 つの座標 (0, 0, 0) に基づいて、ゲーム内のオブジェクトの絶対位置を表現します。シーン内のすべてのトップレベル ゲーム オブジェクトは、ワールド空間で座標が一覧されます。最後の、ローカル空間は、親ゲーム オブジェクトに対して常に相対的に表現されます。トップレベル ゲーム オブジェクトであれば、ローカル空間とワールド空間は同じです。エディターでは、すべての子オブジェクトは、親に対する相対座標で表示されます。そのため、たとえば、アプリケーション内にある家屋のモデルが、ワールド座標では (200, 0, 35) だとしても、その正面ドア (家屋の子ゲーム オブジェクトと想定) の座標は親に対する相対座標として (1.5, 0, 0) と表現されます。コード内で、transform.position を参照するときは、子オブジェクトであっても、その座標は常にワールド座標です。今の例で、ドアの座標は (201.5, 0, 35) ですが、transform.localPosition を参照すると、(1.5, 0, 0) が返されます。Unity には、さまざまな座標系の変換を行う関数が用意されています。
図 6 Unity での座標
先ほどの動きの例では、主としてワールド空間を使用して移動しましたが、ローカル空間を使用する場合もあります。図 1 の方法 7 をもう一度見てください。この例では、ローカル正規化 (単位) ベクトルであり、(0,0,1) を意味する Vector.forward を使用しています。このベクトル自体にはあまり意味がありませんが、何かを Z 軸 (前方) 方向に動かす意図を表します。(0,0,0) からオブジェクトを 90 度回転する場合はどうすればよいでしょう。前方には 2 つの意味があります。1 つは元の絶対 Z 軸 (ワールド座標) で、もう 1 つは回転したオブジェクトに対する相対 Z 軸 (オブジェクトに対して常に前方方向を指す) です。回転に関係なくオブジェクトを常に前方に動かす場合、例に示すように、transform.TransformDirection(Vector3.forward * speed) を使用してローカルの前方をワールドの前方ベクトルに変換します。
スレッドとコルーチン
Unity はコルーチン システムを使用してスレッドを管理します。別のスレッドで何かを発生させる場合には、新しいスレッドを作成するのではなくコルーチンを起動します。Unity では、スレッドが自動管理されます。コルーチンでの処理は、処理が yield メソッドに到達すると停止します。図 7 の例では、攻撃アニメーションが再生され、ランダムな時間一時停止した後、再び攻撃が再生されます。
図 7 コルーチンを使用したアクションの一時停止
void Start()
{
// Kick off a separate routine that acts like a separate thread.
StartCoroutine(Attack());
}
IEnumerator Attack()
{
// Trigger an attack animation.
_animator.SetTrigger("Attack");
// Wait for .5 to 4 seconds before playing attacking animation, repeat.
float randomTime = Random.Range(.5f, 4f);
yield return new WaitForSeconds(randomTime);
}
物理学と衝突検出
3D の物理作用と衝突検出は、コライダーの形状が異なる点と、RigidBody コンポーネントが X、Y、Z 軸に自由に回転/移動できるなど、プロパティが少し異なる点を除けば 2D とほぼ同じです。3D には、モデル全体の形に沿って衝突検出ゾーンが設定される Mesh Collider (メッシュ コライダー) があります。このコライダーはすばらしそうに思え、衝突検出には便利ですが、パフォーマンスは良くありません。コライダーの形をシンプルにして、コライダーを使用する処理能力を抑えるのが理想的です。ゾンビがいる場合は Capsule Collider (カプセル コライダー) を使用し、複雑なオブジェクトの場合は複数のコライダーを使用するようにして、できる限り Mesh Collider コライダーの使用を避けます。
Unity には、衝突の発生やトリガーの起動を把握するための多数の方法が用意されています。基本的な例を以下に示します。
void OnCollisionEnter(Collision collision)
{
// Called when you have a physical collision.
Debug.Log("Collided with " + collision.gameObject.name);
}
void OnTriggerEnter(Collider collider)
{
// Called when another object comes within the trigger zone.
Debug.Log("Triggered by " + collider.gameObject.name);
}
ここに記載した以外にも、OnTriggerExit や OnCollisionExit など、多数の方法があります。それらは、2D 用の方法とほぼ同じです。
オブジェクトの作成
実行時に新しい GameObject ベースのアイテムを作成する場合、コンストラクターは使用しません。代わりに、Instantiate を使用します。もちろん、スクリプトで直接 MonoBehavior から継承しないだけで、コンストラクターのあるクラスを使用することはできます。これは、任意の GameObject に割り当てられたすべてのトップレベル スクリプトに当てはまります。ただし、これらのスクリプトを使用して、すべての必要な他のオブジェクトのコンストラクターを呼び出すことができます。
// Assume this reference has been assigned in the editor.
[SerializeField]
private GameObject _zombie;
void Start()
{
// Create a new instance of that game object. This can be
// a prefab from your project or object already in scene.
Instantiate(zombie, transform.position, Quaternion.identity);
}
パーティクル効果
星の瞬き、埃、雪、爆発、火、滝の霧、血しぶきなどを表現する場合は、パーティクル効果を使用します。Unity には、従来のパーティクル システムと、新しく最適化された Shuriken というパーティクル システムがあります。Unity の Shuriken では、落下するパーティクルで衝突がサポートされるなど、さまざまなすばらしい機能があります。bit.ly/1pZ71it (英語) など、さまざまなチュートリアルが用意されています。また、そのようなチュートリアルでは通常、デザイナーのエディターを使用しています。そのため、ここでは単純に、キャラクターがコインを集めるためのトリガー領域に侵入した場合にパーティクルのインスタンスを作成する方法を紹介します。
パーティクルを使用するには、[GameObject]、[Particle System] (パーティクル システム) メニューの順にクリックすると、すぐに、シーンにパーティクルが追加されます (図 8 参照)。
図 8 パーティクル効果
パーティクル システムからプレハブ (第 2 回のコラムで説明) を作成して、簡単に再利用できるようにします。プレハブは、まずゲーム オブジェクト (他のゲーム オブジェクト スクリプト コンポーネントと同様、MonoBehavior から派生したクラス内にあることを想定) にスクリプトを割り当てた後、エディターでシーンまたはプロジェクトのプレハブから (たとえば) 公開されている SmokeEffect プロパティにパーティクル効果をドラッグすることで、コードから簡単にインスタンスを作成できます (図 9 参照)。
図 9 公開されている SmokeEffect プロパティ
[SerializeField]
private ParticleSystem _smokeEffect;
void OnTriggerEnter(Collider collider)
{
// Ensure you only show particles if the player comes within your zone.
if (collider.gameObject.tag == "Player")
{
GameController.Score++;
// Create particle system at the game objects position
// with no rotation.
Instantiate(_smokeEffect, transform.position, Quaternion.identity);
// Don’t do: Destroy(this) because "this"
// is a script component on a game object, so use
// this.gameObject, that is, just gameObject.
Destroy(gameObject);
}
}
UI の作成
Unity 4.6 には、ゲームのヘッドアップ ディスプレイ要素をテキスト、パネル、ウィジェットなどを使用して作成するまったく新しい UI システムが追加されました。ゲームのディスプレイにテキストを追加するには、[GameObject]、[UI]、[Text] (テキスト) の順にクリックして、フォントとテキストを設定するだけです。スコアの更新などで、後からフォントやテキストをコードから設定する場合は、次のようにします。
// Gets the UnityEngine.UI.Text component.
var score = GetComponent<Text>();
score.text = "Score:0";
UI に画像を表示する場合は、[GameObject]、[UI]、[Image] (画像) の順にクリックして、この新しいコンポーネントに 2D スプライト画像を割り当てます。これらの値は、他のゲーム オブジェクトと同じように設定できます。そろそろパターンがつかめたでしょうか。単純な GUI を作成するには、[GameObject]、[UI] メニューの順にクリックして UI オブジェクトを作成し、エディターで初期値を設定した後、それらの UI コンポーネントへの参照を取得して値を設定するか、値をアニメーションにして、オブジェクトを制御します。今回は、新しい Canvas コンポーネントの下に要素を作成して基本的な GUI を作成しました (図 10 参照)。新しい Unity 4.6 UI システムには、Panel、Button、Text、Image、Slider、Scrollbar、Toggle など、多数の基本オブジェクト型が用意されており、それらのオブジェクトを固定、拡大/縮小、ドラッグ アンド ドロップして、非常に簡単に UI を作成できます。
図 10 画像とヘッドアップ テキストを設定した UI
ゲームの AI
ここでは AI の作成には触れませんでしたが (ただし、AI に該当するビルディング ブロックは先ほどの検出/移動/回転のコード サンプルにあります)、AI について説明しないのは公平ではないので、実行可能ないくつかのオプションを紹介しましょう。ゲームの AI は単に基本アクションを実行するだけであまり知能的ではないため、それを AI と呼ぶには抵抗があります。別のオブジェクトに向けて回転変換を行う方法やそのオブジェクトを動かす方法を説明しましたが、これが、多くのゲームにおける基本 AI です。Unity には、NavMesh サポートを使用したいくつかの経路探索機能が用意されています。NavMesh では事前にオブジェクトの周囲の経路がすべて計算されます。NavMesh の機能はすばらしく、現在は Unity の無料バージョンに含まれるようになりました。しかし、多くの開発者は、自分で実装したり、アセット パッケージを購入することで時間を短縮したりできるアルゴリズムである A* Pathfinding Project (arongranberg.com/astar、英語) を使用しています。本稿執筆時点で Unity に組み込みの経路探索サポートは 3D のみで、2D はサポートされていません。一方、A* には 2D 経路探索機能も用意されています。AngryAnt の Behave 2.0 は、いくつかの強力な機能を備えた Unity 用の人気のある AI プラグインです。また、rivaltheory.com (英語) の RAIN は、追跡、探索、Mecanim 統合などの組み込み動作を備えた優れた無料 AI ツールキットです。
まとめ
3D の世界では、1 つ多い次元をフル メッシュで処理するために、2D の上に層が重ねられ、複雑さを増しています。Asset Store は初心者と経験者のどちらにとっても非常に重要です。事前に作成されたアセットを使用すると、幸先の良いスタートを切ることができます。
私がゲーム開発を始めたとき、インターネット上にさまざまなモデルやテクスチャが公開されているのを見つけてわくわくしました。すばらしいアセット マーケットプレースはいくつかありますが、それらすべてがゲーム向きではないことにすぐにわかります。小さな岩をダウンロードしたところ、そのモデルに 100,000 個近い頂点が設定されていたことがあります。ゲームで適切に機能するアセットを見つけるには、モバイルに最適化されたアセットを探すか、頂点の数やポリゴンの数を確認します。これを怠ると、アセットによってパフォーマンスが大幅に低下することになります。モデルを最適化できるツールも存在します (Unity 用には Cruncher というツールなどがあります)。次回は、Unity のゲームやアプリケーションを Windows プラットフォームに移行する方法について説明します。私の Channel 9 ブログ (aka.ms/AdamChannel9、英語) にはビデオやダウンロード コンテンツへのリンクがあるので、そちらも参照してください。
Adam Tuliper は、南カリフォルニア在住のマイクロソフトのシニア テクニカル エバンジェリストです。彼は、インディーズ ゲーム開発者であり、Orange County Unity Meetup の共同管理者であり、Pluralsight.com (英語) の著者でもあります。Tuliper 夫妻には間もなく第 3 子が生まれます。連絡がある場合は、彼に時間の余裕がある間に、adamt@microsoft.com (英語のみ) または Twitter (twitter.com/AdamTuliper、英語) に連絡してください。
この記事のレビューに協力してくれた技術スタッフの Matt Newman (Subscience Studios) と Tautvydas Žilys (Unity) に心より感謝いたします。