🐡

Unity C#で実践!デザインパターン5選で作る堅牢かつ拡張性の高いゲームシステム

に公開

閲覧いただきありがとうございます。はじめまして、ゲーム開発所RYURYUの「りゅうや」と申します。

❏ ゲーム開発ランキング【 1位 】実績多数 (ココナラ)
❏ ココナラ総販売【 220件超 】
❏ GC甲子園2022・東京ゲームショウ2023など出展経験あり

Unity初心者へ。週末3日でゲーム開発人生を始めよう👈

  1. 3日間の内容を、好きな時間に好きな場所で学べるオンライン講座
  2. わからないところはDiscordで質問OK!💬 仲間と一緒に進めよう!
  3. 完全無料でUnityの基礎が身につく、初心者向けオンライン講座です!

https://unity.super.site/

Unity C#で実践!デザインパターン5選で作る堅牢かつ拡張性の高いゲームシステム

ゲーム開発において、システムの堅牢性と拡張性はプロジェクトの成否を左右します。複雑な処理や多数の要素が絡み合うUnity C#プロジェクトでは、洗練された設計手法が求められます。本記事では、代表的なデザインパターン5選を通じ、ゲームシステムの品質向上に直結する実践的なテクニックを解説します。ここで紹介するパターンは、実際の開発現場でも活用され、拡張性と保守性を高めるための強力な武器となります。

1. ステートパターン

ステートパターンは、オブジェクトが状態に応じた振る舞いをするための設計手法です。特に、敵キャラクターの行動管理やプレイヤーの状態変化など、複数の状態が存在するシーンで有効です。
メリット: 状態ごとの処理が独立し、状態遷移が明確になるため、コードの可読性と保守性が向上します。

実装例

以下は、敵キャラクターの行動管理をステートパターンで実装する際の簡単な例です。

public interface IEnemyState {
    void Execute(Enemy enemy);
}

public class IdleState : IEnemyState {
    public void Execute(Enemy enemy) {
        // 待機状態の処理
        enemy.SetAnimation("Idle");
    }
}

public class AttackState : IEnemyState {
    public void Execute(Enemy enemy) {
        // 攻撃状態の処理
        enemy.SetAnimation("Attack");
        enemy.PerformAttack();
    }
}

public class Enemy {
    private IEnemyState currentState;

    public void SetState(IEnemyState newState) {
        currentState = newState;
    }

    public void UpdateState() {
        currentState?.Execute(this);
    }

    public void SetAnimation(string animName) {
        // アニメーション設定処理
    }

    public void PerformAttack() {
        // 攻撃処理
    }
}

実際の状態遷移のフローやクラス図は、以下の画像で視覚的に確認できます。

Unity初心者へ。週末3日でゲーム開発人生を始めよう👈

  1. 3日間の内容を、好きな時間に好きな場所で学べるオンライン講座
  2. わからないところはDiscordで質問OK!💬 仲間と一緒に進めよう!
  3. 完全無料でUnityの基礎が身につく、初心者向けオンライン講座です!

https://unity.super.site/

2. コマンドパターン

コマンドパターンは、操作をオブジェクトとしてカプセル化する手法です。ユーザーの入力や操作履歴の管理、Undo/Redo機能の実装に非常に適しています。
メリット: 各操作が独立したコマンドオブジェクトとして管理されるため、機能の追加や修正が容易になり、システム全体の柔軟性が向上します。

実装例

以下は、簡単なコマンドパターンの実装例です。

public interface ICommand {
    void Execute();
    void Undo();
}

public class MoveCommand : ICommand {
    private readonly Player player;
    private readonly Vector3 direction;

    public MoveCommand(Player player, Vector3 direction) {
        this.player = player;
        this.direction = direction;
    }

    public void Execute() {
        player.Move(direction);
    }

    public void Undo() {
        player.Move(-direction);
    }
}

public class Player {
    public void Move(Vector3 dir) {
        // 移動処理
    }
}

この手法を用いることで、入力の履歴を管理し、操作の取り消し機能をシンプルに実装できます。詳細な解説は、Qiitaの記事も参考にしてください。
https://qiita.com/automation2025/items/ffc14b85ad134457d215

3. オブザーバーパターン

オブザーバーパターンは、あるオブジェクトの状態変化を複数のオブザーバーに通知する仕組みです。ゲーム内では、キャラクターのHP変化やスコア更新など、複数の要素が連動する処理に適しています。
メリット: イベント通知を中心に設計することで、モジュール間の依存関係を低減し、柔軟なシステム構築が可能となります。

実装例

以下は、簡単なオブザーバーパターンの実装例です。

public interface IObserver {
    void OnNotify(string eventType);
}

public class Subject {
    private List<IObserver> observers = new List<IObserver>();

    public void RegisterObserver(IObserver observer) {
        observers.Add(observer);
    }

    public void UnregisterObserver(IObserver observer) {
        observers.Remove(observer);
    }

    public void Notify(string eventType) {
        foreach (var observer in observers) {
            observer.OnNotify(eventType);
        }
    }
}

public class UIObserver : IObserver {
    public void OnNotify(string eventType) {
        if (eventType == "HPChanged") {
            // HP変更に応じたUI更新処理
        }
    }
}

Unity初心者へ。週末3日でゲーム開発人生を始めよう👈

  1. 3日間の内容を、好きな時間に好きな場所で学べるオンライン講座
  2. わからないところはDiscordで質問OK!💬 仲間と一緒に進めよう!
  3. 完全無料でUnityの基礎が身につく、初心者向けオンライン講座です!

https://unity.super.site/

4. シングルトンパターン

シングルトンパターンは、クラスのインスタンスを1つだけ生成し、どこからでもアクセスできるようにする設計手法です。ゲーム内の各種マネージャ(サウンド、入力、データ管理など)に多用されます。
メリット: グローバルに一貫した状態を保持でき、システム全体の調和を保ちやすくなります。

実装例

以下は、シンプルトンパターンの基本的な実装例です。

public class GameManager {
    private static GameManager instance;
    public static GameManager Instance {
        get {
            if (instance == null) {
                instance = new GameManager();
            }
            return instance;
        }
    }

    private GameManager() {
        // 初期化処理
    }

    public void StartGame() {
        // ゲーム開始処理
    }
}

シングルトンパターンは、システム全体で一貫性のある管理が求められる部分において、その利点を最大限に発揮します。より詳しい解説は、Zennの記事も参考にしてください。
https://zenn.dev/twugo/books/21cb3a6515e7b8/viewer/24c429

Unity初心者へ。週末3日でゲーム開発人生を始めよう👈

  1. 3日間の内容を、好きな時間に好きな場所で学べるオンライン講座
  2. わからないところはDiscordで質問OK!💬 仲間と一緒に進めよう!
  3. 完全無料でUnityの基礎が身につく、初心者向けオンライン講座です!

https://unity.super.site/

5. ファサードパターン

ファサードパターンは、複雑なサブシステムへのアクセスを簡略化するための設計手法です。複数のクラスや処理が絡み合う場合でも、シンプルなインターフェースを提供することで、開発者や利用者の負担を軽減します。
メリット: 複雑な内部処理を隠蔽し、シンプルな呼び出しで機能を実現できるため、コード全体の可読性と保守性が向上します。

実装例

下記は、ゲーム内の複数のサブシステムを統合するためのファサードクラスの例です。

public class GameFacade {
    private AudioManager audioManager;
    private UIManager uiManager;
    private SceneController sceneController;

    public GameFacade() {
        audioManager = new AudioManager();
        uiManager = new UIManager();
        sceneController = new SceneController();
    }

    public void StartNewGame() {
        sceneController.LoadScene("GameScene");
        uiManager.InitializeUI();
        audioManager.PlayBackgroundMusic();
    }
}

public class AudioManager {
    public void PlayBackgroundMusic() {
        // BGM再生処理
    }
}

public class UIManager {
    public void InitializeUI() {
        // UI初期化処理
    }
}

public class SceneController {
    public void LoadScene(string sceneName) {
        // シーン読み込み処理
    }
}

ファサードパターンは、複数のコンポーネントを統合する際に、呼び出し側の負担を大幅に軽減できるため、特に大規模なプロジェクトで効果を発揮します。詳細な解説については、Unity DOTSとオブジェクト指向設計を解説した記事も参考にしてください。
https://zenn.dev/ken_okabe/articles/2024-06-03-unity-oo

Unity初心者へ。週末3日でゲーム開発人生を始めよう👈

  1. 3日間の内容を、好きな時間に好きな場所で学べるオンライン講座
  2. わからないところはDiscordで質問OK!💬 仲間と一緒に進めよう!
  3. 完全無料でUnityの基礎が身につく、初心者向けオンライン講座です!

https://unity.super.site/

Unity C#におけるデザインパターンのメリット

デザインパターンを適切に取り入れることで、以下のようなメリットが得られます。

  • 各処理の責務が明確になり、メンテナンスが容易になる
  • 再利用性が高まり、新たな機能追加時にも柔軟に対応可能
  • チーム全体での共通認識が形成され、開発効率が向上する
  • 複雑なシステムをシンプルなインターフェースで制御できる

これらのメリットは、堅牢かつ拡張性の高いゲームシステムを実現するための基盤となります。

実践Tipsと注意点

デザインパターンを導入する際は、以下のポイントに注意しましょう。

  • 適用タイミングの見極め: すべてのケースでデザインパターンが有効というわけではありません。システムの複雑性や将来的な拡張性を考慮し、適切なパターンを選択することが重要です。
  • 過剰な抽象化は避け、シンプルな設計を心がける
  • 各パターンの利点と欠点を把握し、実装前に十分な検討を行う
Tips

各パターンの実装例を試行する際は、小規模なプロトタイプで動作確認を行い、問題点や改善点を洗い出すとよいでしょう。実際のプロジェクトに適用する前に、チーム内で設計のレビューを実施することも効果的です。

また、設計図やクラス図などのビジュアル資料を活用することで、複雑な関係性を整理しやすくなります。Qiitaや夜中にUnityの提供する図解は、その一助となるでしょう。
https://qiita.com/automation2025/items/ffc14b85ad134457d215
https://www.midnightunity.net/design-pattern-observer/

まとめ

本記事では、Unity C#において堅牢かつ拡張性の高いゲームシステムを実現するためのデザインパターン5選(ステート、コマンド、オブザーバー、シングルトン、ファサード)について解説しました。各パターンの実装例とそのメリット、そして実践する際の注意点を具体的に示すことで、開発現場で直面する課題の解決策を提示しています。
ぜひ、これらのパターンをあなたのプロジェクトに取り入れ、効率的でメンテナンス性に優れたシステム構築に挑戦してみてください。

Unity初心者へ。週末3日でゲーム開発人生を始めよう👈

  1. 3日間の内容を、好きな時間に好きな場所で学べるオンライン講座
  2. わからないところはDiscordで質問OK!💬 仲間と一緒に進めよう!
  3. 完全無料でUnityの基礎が身につく、初心者向けオンライン講座です!

https://unity.super.site/

Discussion