抽象コンポーネント
CoddyのUnityジャーニー「Unityにおけるゲームアーキテクチャ」セクションの一部。レッスン 3/50。
一部の基底クラスは、それ自体では決して存在しない種類のものを表します。すべての武器は発射しますが、ピストルでもショットガンでもない武器には発射する方法がありません。そのようなクラスには abstract を付け、サブクラスが実装しなければならない各処理を、本文のない抽象メソッドとして宣言します。
public abstract class Weapon : MonoBehaviour
{
public int shots;
public void Pull()
{
shots++;
Fire();
}
protected abstract void Fire();
}public class Shotgun : Weapon
{
public GameObject pelletPrefab;
protected override void Fire()
{
for (int i = -1; i <= 1; i++)
{
Instantiate(pelletPrefab, transform.position + transform.right * i * 0.3f, transform.rotation);
}
}
}Fire を実装しないサブクラスはコンパイルできません。エラーは CS0534、'Pistol' does not implement inherited abstract member 'Weapon.Fire()' です。Unity も、抽象スクリプトをオブジェクトに追加することを拒否します。Weapon をオブジェクトにドラッグすると、Can't add script behaviour 'Weapon'. The script class can't be abstract! と表示されます。Fire のない Weapon を Unity が作成できないためです。
ほかのスクリプトは引き続き基底型を使えます。GetComponent<Weapon>() はオブジェクトに付いているサブクラスを返し、Pull() はそのサブクラスの Fire を実行します。
// Player.cs
private Weapon weapon;
void Start()
{
weapon = GetComponent<Weapon>();
}
void Update()
{
if (Mouse.current.leftButton.wasPressedThisFrame)
{
weapon.Pull();
}
}Shotgun コンポーネントを Pistol に置き換えても、Player スクリプトはそのままです。
チャレンジ
簡単魔法使いの塔がフィールドのモンスターに電撃を放ちます。Monster.cs には、すべてのモンスターに共通するもの、つまり hp(3)と Zap() が含まれています。Zap() は hp を1減らし、0になったらモンスターを破壊し、そうでなければ React() を呼び出します。Slime.cs は縮んで反応します。Imp.cs には反応がなく、Monster が空の React を与えているため、反応がないことに気づけません。
- Monster を抽象クラスにし、React を抽象メソッドにして、反応の仕方を定義していないモンスターはコンパイルできないようにします。すると、コンパイラーは Imp を指摘します。
- Imp の React を書きます。塔から離れる方向(+z 方向)に2ユニット後ろへ跳びます。
- Tower.cs では、Space キーが押されたとき、種類にかかわらず、Monster タグが付いた各オブジェクトの Monster コンポーネントを取得し、
Zap()を呼び出します。
Play を押してモンスターに電撃を放ち、それから Check を押します。
自分で試してみよう
using UnityEngine;
// すべてのモンスターに共通するもの。
public class Monster : MonoBehaviour
{
public int hp = 3;
public void Zap()
{
hp--;
if (hp <= 0)
{
Destroy(gameObject);
}
else
{
React();
}
}
// この種類のモンスターが、耐えた攻撃にどう反応するか。
protected virtual void React()
{
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。