IDamageable
CoddyのUnityジャーニー「Unityのゲームアーキテクチャ」セクションの一部。レッスン 7/64。
インターフェースとは、クラスが実装することを約束するメソッドの一覧で、その中にコードはありません。ほかに共通点のないクラス同士でも、同じ約束をできます。通常の C# では次のようになります。
interface IGreeter
{
string Greet();
}
class Robot : IGreeter
{
public string Greet() { return "Beep"; }
}
class Cat : IGreeter
{
public string Greet() { return "Meow"; }
}IGreeter型の変数にはRobotまたはCatを入れることができ、greeter.Greet()を実行すると、その変数に入っている方のメソッドが呼び出されます。IGreeterを宣言しているクラスに、publicなGreet()がない場合、コンパイルできません。
ゲームでは、ダメージを受けるものがたくさんありますが、それ以外の共通点はほとんどありません。プレイヤーにはヒットポイントがあり、木箱は最初の攻撃で壊れます。共通の基底クラスを使うと、これらを1つの系統に押し込むことになります。インターフェースは共通する1つの性質に名前を付け、それぞれのスクリプトが独自の方法で実装できます。
public interface IDamageable
{
void TakeDamage(int amount);
}public class PlayerHealth : MonoBehaviour, IDamageable
{
public int hp = 10;
public void TakeDamage(int amount)
{
hp -= amount;
Debug.Log("Ouch! hp: " + hp);
}
}public class Crate : MonoBehaviour, IDamageable
{
public void TakeDamage(int amount)
{
Destroy(gameObject);
}
}スクリプトが持てる基底クラスは引き続き1つで、インターフェースはその後に列挙します。インターフェースは専用のファイルIDamageable.csに置き、MonoBehaviourを継承しません。コンポーネントではないため、それ自体をオブジェクトに追加することはありません。インターフェースを宣言したクラスには、publicなTakeDamage(int)が必要です。そうでなければコンパイルできません。
ダメージを与える側は、クラスではなくインターフェースを要求します。
// Fireball.cs
void OnCollisionEnter(Collision collision)
{
IDamageable target = collision.gameObject.GetComponent<IDamageable>();
if (target != null)
{
target.TakeDamage(3);
}
Destroy(gameObject);
}この同じコードで、火の玉はプレイヤーにダメージを与え、木箱を壊せます。後から別の種類の対象を追加しても、ここを変更する必要はありません。Unityでは、インターフェース型のフィールドはInspectorに表示されません。そのため、火の玉の例のように、スクリプトはGameObjectまたはコンポーネントを保持し、それにインターフェースを問い合わせます。
チャレンジ
簡単雪だるま、ベル、かかしを IDamageable にして、ハンマーが攻撃できるようにしましょう。
Snowman:TakeDamageを受けるたびに、すべての軸で0.25f * amountだけ縮小します。0.5 以下になったら破壊します。Bell: 1ポイントごとにDongをログに記録し、amountをringsに加算します。Scarecrow: 最初の攻撃時にのみtransform.Rotate(0f, 0f, 90f);を実行します。Slamで、各コライダーにIDamageableがあれば、そのTakeDamage(power)を呼び出します。
「プレイ」を押して、それぞれを攻撃しましょう。その後、「確認」を押します。
自分で試してみよう
using UnityEngine;
public class Snowman : MonoBehaviour
{
}
Unityのゲームアーキテクチャのすべてのレッスン
自分で練習してみよう: Unityプレイグラウンド