敵の基底スクリプト
CoddyのUnityジャーニー「Unityのゲームアーキテクチャ」セクションの一部。レッスン 2/64。
C#では、クラスは別のクラスを継承できます。class Ghost : EnemyはEnemyのすべてのフィールドとメソッドを受け継ぎ、独自のものを追加します。基底クラスでvirtualと指定されたメソッドは、サブクラスでoverrideを使って置き換えられます。また、base.Describe()を呼び出すと、新しいメソッドの中から基底クラスのバージョンを実行できます。通常のC#では、次のようになります。
class Enemy
{
protected int hp = 3;
public virtual string Describe()
{
return "Enemy with " + hp + " hp";
}
}
class Ghost : Enemy
{
public override string Describe()
{
return base.Describe() + ", see-through";
}
}GhostのDescribe()はEnemy with 3 hp, see-throughを返します。protectedは、Enemyとそのサブクラスがhpを使える一方、ほかのクラスは使えないことを意味します。
Unityでは、敵のコードの大部分を共有できます。ヒットポイント、速度、移動方法などです。このコードはMonoBehaviourを継承する基底クラスに置き、それぞれの種類の敵がそのクラスを継承します。このEnemyはStartでヒットポイントを設定し、Updateで向いている方向へ歩きます。Ghostは開始時の処理を変更し、速度を2倍にします。
public class Enemy : MonoBehaviour
{
public int maxHp = 3;
public float speed = 2f;
protected int hp;
protected virtual void Start()
{
hp = maxHp;
}
protected virtual void Update()
{
transform.Translate(Vector3.forward * speed * Time.deltaTime);
}
}public class Ghost : Enemy
{
protected override void Start()
{
base.Start();
speed *= 2f;
}
}Ghostはフィールドを継承するため、GhostのInspectorにはmaxHpとspeedが表示されます。また、Updateも継承するので、独自のUpdateがなくても歩きます。hpはprotectedです。Enemyとそのサブクラスは使えますが、ほかのスクリプトは使えません。
Unityはアクセス修飾子にかかわらず、名前でStartとUpdateを見つけ、最も派生したクラスにあるものを呼び出します。EnemyのStartがprivateなvoid Start()で、Ghostが独自のものを宣言した場合、Unityが呼び出すのはGhostのものだけです。EnemyのStartは実行されず、エラーも起きないままhpは0のままになります。基底クラスのメッセージをprotected virtualと宣言すれば、これが通常のC#の仕組みになります。サブクラスではoverrideを書き、base.Start()を呼び出すと、その位置で基底クラスの処理が実行されます。この呼び出しを省略すると、基底クラスの処理はスキップされます。これは、サブクラスが処理を追加するのではなく、ある手順を置き換える方法です。
チャレンジ
簡単Golem と Wasp が、それぞれの処理の前に Enemy の処理を実行するようにしましょう。
Enemyで、void Start()とvoid Update()の前にprotected virtualを記述します。Golemで、protected override void Start()にし、最初の行にbase.Start();を記述します。Waspで、protected override void Update()にし、最初の行にbase.Update();を記述します。
「プレイ」を押します。ゴーレムは hp が満タンの状態で進み、スズメバチは進みながらジグザグに動きます。その後、「確認」を押します。
自分で試してみよう
using UnityEngine;
// すべてのモンスターに共通するもの。
public class Enemy : MonoBehaviour
{
public int maxHp = 4;
public float speed = 1.5f;
protected int hp;
protected Vector3 spawnPoint;
void Start()
{
hp = maxHp;
spawnPoint = transform.position;
}
void Update()
{
// z軸に沿って城へ進軍する
transform.position += Vector3.back * speed * Time.deltaTime;
}
}
Unityのゲームアーキテクチャのすべてのレッスン
自分で練習してみよう: Unityプレイグラウンド