Unityでシューティングゲームでよく使われるデザインパターン
Unityでシューティングゲームを作る際によく使われるデザインパターンには、以下のようなものがあります。
Object Poolパターン
Object Poolパターンは、頻繁に生成と破棄が行われるオブジェクトを事前に生成し、再利用することで、パフォーマンスを向上させるためのパターンです。シューティングゲームでは、敵や弾など、頻繁に生成されるオブジェクトをObject Poolで管理することで、メモリの消費や処理負荷を減らすことができます。
以下は、Object Poolパターンの例です。
public class ObjectPool : MonoBehaviour
{
public GameObject objectPrefab;
public int poolSize;
private List<GameObject> pool = new List<GameObject>();
private void Start()
{
for (int i = 0; i < poolSize; i++)
{
GameObject obj = Instantiate(objectPrefab, Vector3.zero, Quaternion.identity);
obj.SetActive(false);
pool.Add(obj);
}
}
public GameObject GetObject()
{
foreach (GameObject obj in pool)
{
if (!obj.activeInHierarchy)
{
obj.SetActive(true);
return obj;
}
}
GameObject newObj = Instantiate(objectPrefab, Vector3.zero, Quaternion.identity);
newObj.SetActive(true);
pool.Add(newObj);
return newObj;
}
public void ReleaseObject(GameObject obj)
{
obj.SetActive(false);
}
}
この例では、ObjectPool
クラスがObject Pool、objectPrefab
が再利用するオブジェクトのプレハブ、poolSize
がプールするオブジェクトの数です。Start()
メソッドで、指定された数のオブジェクトを生成し、非アクティブにします。GetObject()
メソッドでは、再利用可能なオブジェクトを検索し、アクティブにして返します。再利用可能なオブジェクトがない場合は、新しいオブジェクトを生成してプールに追加します。ReleaseObject()
メソッドでは、オブジェクトを非アクティブにします。
Singletonパターン
Singletonパターンは、アプリケーション内で唯一のインスタンスを保証するためのパターンです。シューティングゲームでは、GameManagerやInputManagerなどのシステム管理クラスに使用されます。
以下は、Singletonパターンの例です。
public class GameManager : MonoBehaviour
{
private static GameManager instance;
public static GameManager Instance
{
get
{
if (instance == null)
{
instance = FindObjectOfType<GameManager>();
}
return instance;
}
}
private void Awake()
{
if (instance != null && instance != this)
{
Destroy(gameObject);
}
else
{
instance = this;
}
DontDestroyOnLoad(gameObject);
}
public void GameOver()
{
// ゲームオーバー時の処理
}
}
この例では、GameManager
クラスがシングルトンで、instance
変数が唯一のインスタンスを保持します。Instance
プロパティで、instance
変数がnullの場合に、シーン内からGameManager
を検索して取得し、返します。Awakeメソッドで、instance
変数がnullの場合に、自身をinstance
に代入します。既にインスタンスが存在する場合は、自身を破棄します。DontDestroyOnLoad()
メソッドで、シーンを切り替えた際にGameManager
が破棄されないように設定します。
Commandパターン
Commandパターンは、操作をオブジェクトとしてカプセル化することで、実行履歴の保存ややり直し、アンドゥの実現などを容易にするパターンです。シューティングゲームでは、プレイヤーの攻撃やアイテム使用などの操作をCommandパターンで実装することができます。
以下は、Commandパターンの例です。
public interface ICommand
{
void Execute();
void Undo();
}
public class AttackCommand : ICommand
{
private GameObject player;
private GameObject enemy;
public AttackCommand(GameObject player, GameObject enemy)
{
this.player = player;
this.enemy = enemy;
}
public void Execute()
{
// プレイヤーの攻撃処理
}
public void Undo()
{
// プレイヤーの攻撃を取り消す処理
}
}
public class InputHandler : MonoBehaviour
{
public GameObject player;
public GameObject enemy;
private Stack<ICommand> commandStack = new Stack<ICommand>();
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
ICommand command = new AttackCommand(player, enemy);
command.Execute();
commandStack.Push(command);
}
else if (Input.GetKeyDown(KeyCode.Z))
{
if (commandStack.Count > 0)
{
ICommand command = commandStack.Pop();
command.Undo();
}
}
}
}
この例では、ICommand
インターフェースがCommandパターンを表し、Execute()
メソッドとUndo()
メソッドが定義されています。AttackCommand
クラスは、プレイヤーの攻撃操作をカプセル化したコマンドで、player
とenemy
を受け取っています。InputHandler
クラスは、プレイヤーの入力を処理し、スペースキーで攻撃コマンドを実行し、Zキーで直前の操作を取り消すコマンドを実行します。実行されたコマンドは、commandStack
に追加されます。
Observerパターン
Observerパターンは、オブジェクトの状態変化を他のオブジェクトに通知することで、オブジェクト間の依存関係を疎にするパターンです。シューティングゲームでは、敵の出現や撃破、プレイヤーの残り体力など、様々な状態の変化をObserverパターンで管理することができます。
以下は、Observerパターンの例です。
public interface IObserver
{
void UpdateObserver();
}
public class EnemySpawner : MonoBehaviour
{
public GameObject enemyPrefab;
private List<IObserver> observers = new List<IObserver>();
private void Start()
{
SpawnEnemy();
}
private void SpawnEnemy()
{
Instantiate(enemyPrefab, transform.position, transform.rotation);
NotifyObservers();
}
public void AddObserver(IObserver observer)
{
observers.Add(observer);
}
public void RemoveObserver(IObserver observer)
{
observers.Remove(observer);
}
private void NotifyObservers()
{
foreach (IObserver observer in observers)
{
observer.UpdateObserver();
}
}
}
public class UIManager : MonoBehaviour, IObserver
{
public Text healthText;
private int health = 100;
private void Start()
{
GameObject spawner = GameObject.Find("EnemySpawner");
if (spawner != null)
{
EnemySpawner enemySpawner = spawner.GetComponent<EnemySpawner>();
enemySpawner.AddObserver(this);
}
}
public void UpdateObserver()
{
health -= 10;
healthText.text = "Health: " + health;
}
}
この例では、IObserver
インターフェースがObserverパターンを表し、UpdateObserver()
メソッドが定義されています。EnemySpawner
クラスは、敵の出現を管理し、AddObserver()
メソッドでObserverを追加し、RemoveObserver()
メソッドでObserverを削除します。敵を出現させると、NotifyObservers()
メソッドでObserverに通知します。
UIManager
クラスは、プレイヤーの体力を表示するUIを管理し、UpdateObserver()
メソッドで体力を減らします。Start()
メソッドで、EnemySpawner
を検索して、自身をObserverとして追加します。
以上が、シューティングゲームでよく使われるデザインパターンの一部です。他にも、Template MethodパターンやStateパターンなど、様々なパターンがあります。適切なパターンを選択することで、シューティングゲームの開発を効率化することができます。例えば、AIの行動パターンを管理するStateパターンを使うことで、複雑な状態遷移を簡単に扱うことができます。
Factory Methodパターン
Factory Methodパターンは、インスタンスの生成をサブクラスに任せることで、オブジェクトの生成を簡単にするパターンです。シューティングゲームでは、敵やアイテムの生成などでFactory Methodパターンを使うことができます。
以下は、Factory Methodパターンの例です。
public abstract class EnemyFactory
{
public abstract GameObject CreateEnemy();
}
public class EasyEnemyFactory : EnemyFactory
{
public override GameObject CreateEnemy()
{
return Resources.Load<GameObject>("EasyEnemy");
}
}
public class MediumEnemyFactory : EnemyFactory
{
public override GameObject CreateEnemy()
{
return Resources.Load<GameObject>("MediumEnemy");
}
}
public class HardEnemyFactory : EnemyFactory
{
public override GameObject CreateEnemy()
{
return Resources.Load<GameObject>("HardEnemy");
}
}
public class EnemySpawner : MonoBehaviour
{
public EnemyFactory enemyFactory;
private void Start()
{
SpawnEnemy();
}
private void SpawnEnemy()
{
GameObject enemyPrefab = enemyFactory.CreateEnemy();
Instantiate(enemyPrefab, transform.position, transform.rotation);
}
}
この例では、EnemyFactory
クラスがFactory Methodパターンを表し、CreateEnemy()
メソッドが定義されています。EasyEnemyFactory
、MediumEnemyFactory
、HardEnemyFactory
クラスは、CreateEnemy()
メソッドをオーバーライドして、それぞれ異なる敵のPrefabを返します。
EnemySpawner
クラスは、敵の出現を管理し、SpawnEnemy()
メソッドでEnemyFactory
から敵のPrefabを生成して、インスタンスを作成します。EnemyFactory
の具体的な実装は、EnemySpawner
から注入されます。
以上が、シューティングゲームでよく使われるデザインパターンの一部です。デザインパターンは、様々なシーンで使われる汎用的な解決策を提供してくれます。適切なパターンを選択することで、より効率的に、より品質の高いシューティングゲームを開発することができます。
ディスカッション
コメント一覧
まだ、コメントがありません