ジェネリックヘルパー
CoddyのUnityジャーニー「Unityにおけるゲームアーキテクチャ」セクションの一部。レッスン 35/50。
いくつかのヘルパーは、どの型でも同じです。コンポーネントを取得するか追加する、配列からランダムな要素を選ぶ、といった処理です。ジェネリックメソッドを使えば、型をパラメーターとして一度だけ記述でき、呼び出しごとにその型が T に当てはめられます。
public static class Helpers
{
public static T GetOrAdd<T>(this GameObject go) where T : Component
{
if (!go.TryGetComponent(out T found)) found = go.AddComponent<T>();
return found;
}
public static T RandomItem<T>(T[] items)
{
return items[Random.Range(0, items.Length)];
}
}Rigidbody body = crate.GetOrAdd<Rigidbody>();
Color paint = Helpers.RandomItem(colors);
GameObject enemy = Helpers.RandomItem(enemyPrefabs);where T : Component は T に関する制約で、メソッドが T に対して何をできるかを決めます。AddComponent が受け取れるのはコンポーネントだけなので、この制約がなければコンパイラーは go.AddComponent<T>() を拒否します。制約があれば、Unity の Rigidbody でも独自のスクリプトでも、どのコンポーネントでも使えます。また、この制約により、.transform や .gameObject など、Component のすべてのメンバーを T に対して使えるようになります。すでに Rigidbody が付いている crate なら、その Rigidbody が返され、新たに追加されることはありません。
RandomItem には制約がありません。T に触れることがないからです。そのため、色、文字列、プレハブのいずれにも使えます。呼び出し時に型を明示することはほとんどありません。Color[] 型の colors から、コンパイラーは T が Color だと判断します。T[] の代わりに IEnumerable<T> を受け取るメソッドなら、配列と List の両方を受け取れます。これには FindObjectsByType<T> が返す配列も含まれます。
チャレンジ
中級庭に衝撃タワーが立っています。Spaceを押すとパルスを放ち、タワーから4以内にある木箱は上に吹き飛ばされ、4以内にあるランプが点灯します。Lamp.csは準備済みで、TurnOn()があります。両方を検索するヘルパーを1つ書いてください。
Helpers.csに、ジェネリックメソッドInRange<T>(IEnumerable<T> items, Vector3 center, float range)を持つ静的クラスHelpersを作成し、任意のコンポーネント型に対応させてください。このメソッドは、位置がcenterからrange以内にある項目のList<T>を返します。Pulse.csでは、Spaceが押されたとき、シーン内でタワーからrange以内にあるすべてのRigidbodyに上向きのliftインパルスを加え、range以内にあるすべてのLampを点灯させてください。FindObjectsByTypeが返す配列の両方に、InRangeを使ってください。
Playを押し、Spaceを押してから、Checkを押してください。
自分で試してみよう
using System.Collections.Generic;
using UnityEngine;
// Helpers.InRange<T>: ある点の範囲内にあるアイテム
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。