Unity エディターからインスペクター上のコンポーネントのプロパティーを変更できます。例えば、Transform コンポーネントの位置の値の変更は、ゲームオブジェクトの位置に反映されます。同様にレンダラーのマテリアルの色を変更したり、リジッドボディの重さを変更してゲームオブジェクトの動きを変えられます。スクリプトの多くは、ゲームオブジェクトを操作するためにコンポーネントのプロパティーを変更します。違いがあるのは、スクリプトは時間の経過とともにプロパティーの値を徐々に増やしたり、ユーザー入力の反応を介して変更させることができるところです。適切なタイミングでオブジェクト作成や破棄を行なうことで、ゲームプレイの実装ができます。
同じゲームオブジェクトにある、他のコンポーネントへのアクセスを必要とする場合がよくあります。イントロダクションなどですでに述べている通り、コンポーネントはクラスのインスタンスであるため、まずはコンポーネントインスタンスの参照を取得します。これには GetComponent 関数を使います。通常、コンポーネントオブジェクトをなんらかの変数に割り当てたい場合 C#で は次の構文を使います。
void Start () {
Rigidbody rb = GetComponent<Rigidbody>();
}
UnityScript では、構文がわずかに異なります。
function Start () {
var rb = GetComponent.<Rigidbody>();
}
コンポーネントインスタンスへの参照が取得できた後は、インスペクター上でセットするのと同様にプロパティーの値を設定できます。
void Start () {
Rigidbody rb = GetComponent<Rigidbody>();
// オブジェクトの Rigidbody の Mass を変更
rb.mass = 10f;
}
インスペクター上では利用できない機能はコンポーネントのインスタンス化を行う関数を呼ぶことです。
void Start () {
Rigidbody rb = GetComponent<Rigidbody>();
// Rigidbody に力を加えます
rb.AddForce(Vector3.up * 10f);
}
同じオブジェクトに一つ以上のカスタムのスクリプトをアタッチできることに注意してください。もし一つのスクリプトから別のものへアクセスが必要である場合、通常どおり GetComponent 関数を使用したうえでコンポーネントの型を指定するためにスクリプトクラス名(あるいはファイル名)を使用します。
もしゲームオブジェクトに追加されてないコンポーネントを取得しようと試みた場合、GetComponent は null を返します。実行時に null オブジェクトの値を変更しようとすると、null 参照エラーとなります。
オブジェクトが独立して動作するとはいえ、スクリプトが他のオブジェクトを管理することが良くあります。例えば、追いかけてくる敵がプレイヤーの位置を知る必要があるとしましょう。Unity でオブジェクトを取得する方法は複数あり、状況に応じて使い分けます。
ゲームオブジェクトを関連付けるもっとも分かりやすい方法は public であるゲームオブジェクト変数をスクリプトに追加することです:
public class Enemy : MonoBehaviour {
public GameObject player;
// 他の変数と関数...
}
この変数は他と同様にインスペクター上で表示されます:
シーンまたは階層パネルからオブジェクトをこの変数の上にドラッグして割り当てることができます。このオブジェクトは他と同様に GetComponent 関数およびコンポーネントにアクセスできる変数が利用可能となります。そのため、次のようなコードが使用できます:
public class Enemy : MonoBehaviour {
public GameObject player;
void Start() {
// プレイヤーキャラクターから 10 ユニット遅れてエネミーを開始
transform.position = player.transform.position - Vector3.forward * 10f;
}
}
さらに、もしスクリプトの中でコンポーネント型の public である変数を宣言すると、コンポーネントがアタッチされている任意のゲームオブジェクトをその上にドラッグできます。これはゲームオブジェクト自身ではなくコンポーネントを直接アクセスします。
public Transform gunEnd;
変数にオブジェクトをリンクさせることは永続的にそのオブジェクトを使い続ける上でもっとも実用的な方法です。同じタイプのオブジェクトを配列で保持することができますが、それはランタイムで行うよりもむしろ Unity エディター上で行う必要があります。これは多くの場合、ランタイムでオブジェクトの位置を突き止めるのに便利であり、これを行う方法として 2 つの方法を提供しています。
ゲームシーンにおいて同じ型のオブジェクトを複数使用する場合があり、敵、巡回点、障害物などに使われます。この場合に別のスクリプトによりそれらへの反応をまとめて管理することが必要となるかもしれません(例.すべての巡回地点を経路探索のスクリプトで利用可能とする)。変数を使用してこれらのオブジェクトを紐付けるのは一つの方法ですが、新しい巡回地点をスクリプト上の変数にドラッグするのは設計上も面倒です。同様に、もし巡回点を削除したときに削除オブジェクトだけ変数の参照を取り除くのも面倒でしょう。このような場合、一つの親オブジェクトの子オブジェクトとすることで、すべてを管理するのがよい解決策です。子オブジェクトは親オブジェクトの Transform コンポーネントを通して取得できます(すべてのオブジェクトには明示的に Transform があるため)。
using UnityEngine;
public class WaypointManager : MonoBehaviour {
public Transform[] waypoints;
void Start() {
waypoints = new Transform[transform.childCount];
int i = 0;
foreach (Transform t in transform) {
waypoints[i++] = t;
}
}
}
名前を指定して特定の子オブジェクトを見つけるには Transform.Find 関数を使用します。
transform.Find("Gun");
これはオブジェクトがゲームの途中で追加、削除する子オブジェクトがある場合に便利です。拾ったり捨てたりできる武器が分かりやすい例です。
識別できる情報があるかぎり、シーン階層上のどこでもゲームオブジェクトを見つけることができます。名前を指定して個別オブジェクトを取得するには GameObject.Find 関数を使用します:
GameObject player;
void Start() {
player = GameObject.Find("MainHeroCharacter");
}
オブジェクトまたはその集合をタグを使用して見つけるには GameObject.FindWithTag、GameObject.FindGameObjectsWithTag 関数を使用します:
GameObject player;
GameObject[] enemies;
void Start() {
player = GameObject.FindWithTag("Player");
enemies = GameObject.FindGameObjectsWithTag("Enemy");
}