IkinokoBattle で学ぶ Unity OOP 設計パターン:目次
このシリーズは、技術評論社刊『作って学べる Unity本格入門[Unity 6対応版]』(賀好 昭仁 著)の題材プロジェクト IkinokoBattle のソースコードを題材に、オブジェクト指向設計(OOP)のパターンを読み解きます。
本サイトは出版社・著者の公式サイトではありません。 コード掲載は学習上必要な範囲にとどめます。
実装編(Chapter 5〜9) | 機能別解説編
書籍・著作について
- 出典: 技術評論社刊『作って学べる Unity本格入門[Unity 6対応版]』(賀好 昭仁 著)
- 本ブログの位置づけ: 題材プロジェクトのコードを読み解く学習補助の解説です。書籍の代替提供を目的とせず、**コード掲載は学習上必要な範囲(必要最小限)**にとどめます。
- 著作権・サンプルの利用: 書籍に関する権利は出版社・著者に帰属します。サンプル等の利用条件は書籍記載(P.4〜5)および出版社サポート情報に従ってください。
このシリーズについて
- 対象読者: C# と Unity の基礎を習得し、「なぜこう書くのか」を深く理解したい方
- 記事の構成: OOP 設計パターンを 1 パターン(または関連する 2 パターン)ずつ取り上げ、IkinokoBattle の実装コードと照らし合わせながら解説します
- シリーズの目的: デザインパターンの「名前と定義を知る」だけでなく、Unity の MonoBehaviour や ScriptableObject、UnityEvent といった仕組みの中でどう活かすかを体感することにあります
記事一覧
第1回|シングルトンパターン
記事ファイル: 01-OOP_シングルトンパターン.md
アプリケーション全体で「唯一のインスタンス」を保証する Singleton パターンを、IkinokoBattle の 3 つのバリエーションで読み解きます。
登場クラス
| クラス | 種別 | シングルトンの方式 |
|---|---|---|
OwnedItemsData |
純粋 C# | Lazy<T> による遅延初期化、private コンストラクタ |
AudioManager |
MonoBehaviour | DontDestroyOnLoad + 重複時 Destroy |
LifeGaugeContainer |
MonoBehaviour | 重複時に Exception をスロー(厳格版) |
学習ポイント
| # | 学習ポイント |
|---|---|
| ① | private コンストラクタで外部からの new を禁止する |
| ② | Lazy<T> で初回アクセス時のみインスタンスを生成する |
| ③ | MonoBehaviour では DontDestroyOnLoad でシーンをまたいで存続させる |
| ④ | Awake で重複チェックし、既存インスタンスがあれば Destroy(gameObject) する |
| ⑤ | 3 種のバリエーション(純 C#・MonoBehaviour 寛容版・MonoBehaviour 厳格版)を使い分ける |
第2回|テンプレートメソッドパターンと抽象クラス
記事ファイル: 02-OOP_テンプレートメソッド.md
「処理の骨格を親クラスが定め、詳細を子クラスが埋める」Template Method パターンを、MobStatus → PlayerStatus / EnemyStatus の継承ツリーで解説します。
登場クラス
| クラス | 役割 |
|---|---|
MobStatus(abstract) |
共通の HP 管理・ダメージ処理・死亡判定の骨格 |
PlayerStatus |
OnDead() でゲームオーバーシーンへ遷移 |
EnemyStatus |
OnDead() で敵 GameObject を非アクティブ化 |
学習ポイント
| # | 学習ポイント |
|---|---|
| ① | abstract class と abstract メソッドで「必ず実装すべき処理」を強制する |
| ② | virtual / override で「デフォルト実装を持ちつつ上書き可能」にする |
| ③ | protected フィールドで子クラスだけに公開する |
| ④ | 骨格メソッド(Damage())の中で抽象メソッド(OnDead())を呼ぶ仕組みを読む |
| ⑤ | 継承 vs 委譲の使い分け:「is-a 関係」が成立するときに継承を選ぶ判断基準 |
第3回|委譲パターンと UnityEvent
記事ファイル: 03-OOP_委譲とUnityEvent.md
「仕事を別のオブジェクトに委ねる」委譲(Delegation)パターンを、CollisionDetector と UnityEvent<T> の組み合わせで解説します。継承に頼らず柔軟に振る舞いを差し込む手法を学びます。
登場クラス
| クラス | 役割 |
|---|---|
CollisionDetector |
トリガー判定を UnityEvent<Collider> に変換して委譲する汎用コンポーネント |
EnemyMove |
CollisionDetector のイベントを受け取り、追跡処理を開始する |
MobAttack |
同じく CollisionDetector を利用して攻撃範囲判定を委譲する |
学習ポイント
| # | 学習ポイント |
|---|---|
| ① | UnityEvent<T> でコールバックを型安全に定義する |
| ② | [SerializeField] + Inspector でイベントリスナーを登録する方法とコードで登録する方法の違い |
| ③ | CollisionDetector を汎用化することで他のコンポーネントが OnTriggerEnter を直接持たなくて済む理由 |
| ④ | 委譲と継承の違い:「has-a 関係」で機能を組み合わせる |
| ⑤ | 単一の GameObject に複数の CollisionDetector をアタッチして用途別に分ける設計 |
第4回|単一責任の原則とコンポーネント設計
記事ファイル: 04-OOP_単一責任.md
「クラスの変更理由は 1 つだけ」という Single Responsibility Principle(SRP)を、PlayerController と [RequireComponent] の仕組みで読み解きます。MonoBehaviour を小さく保つ設計思想を学びます。
登場クラス
| クラス | 担当責任 |
|---|---|
PlayerController |
入力受付・移動・アニメーション指示の調整役 |
CharacterController |
物理移動・衝突判定(Unity 組み込み) |
PlayerInput |
Input System との橋渡し(Unity 組み込み) |
PlayerStatus |
HP 管理・ダメージ受付 |
LifeGauge |
HP の UI 表示 |
学習ポイント
| # | 学習ポイント |
|---|---|
| ① | [RequireComponent(typeof(T))] でコードで依存関係を宣言する |
| ② | GetComponent<T>() を Awake でキャッシュしてパフォーマンスを保つ |
| ③ | 「入力」「移動」「HP」「UI」を別クラスに分ける理由とメリット |
| ④ | PlayerController が他クラスのメソッドを「呼ぶだけ」になる調整役パターン |
| ⑤ | SRP 違反の例:1 クラスに何でも詰め込んだときの変更コストを考える |
第5回|状態パターン(State Pattern)
記事ファイル: 05-OOP_状態パターン.md
オブジェクトの「内部状態」によって振る舞いを切り替える State パターンを、MobStatus の StateEnum(Normal / Attack / Die)で解説します。if/switch の羅列を排除し、状態遷移を明確に管理する手法を学びます。
登場クラス
| クラス | 役割 |
|---|---|
MobStatus(abstract) |
StateEnum フィールドで現在状態を保持 |
MobAttack |
State == StateEnum.Attack のときだけダメージを与える |
EnemyMove |
State == StateEnum.Die のときに追跡を停止する |
学習ポイント
| # | 学習ポイント |
|---|---|
| ① | protected enum StateEnum で状態の種類を型安全に列挙する |
| ② | State プロパティで状態変化を一か所に集約する |
| ③ | 各コンポーネントが State を参照して処理をガードする「防衛的プログラミング」 |
| ④ | Unity Animator の StateMachine と C# の State パターンの対比 |
| ⑤ | 状態が増えたときの拡張しやすさ(enum に値を追加するだけで済む設計) |
第6回|プロパティとデータ・ビュー分離
記事ファイル: 06-OOP_プロパティとデータビュー分離.md
C# の get / set プロパティを使って、「データが変わったら自動的に UI が更新される」仕組みを ItemButton と ItemsDialog で解説します。MVC / MVP の入り口として、データとビューを疎結合にする設計を学びます。
登場クラス
| クラス | 役割 |
|---|---|
ItemButton |
OwnedItem セッターでアイテムデータを受け取り即座に UI へ反映する |
ItemsDialog |
ItemButton を Instantiate で量産し OwnedItem を渡すだけで画面を構築 |
OwnedItemsData |
JSON + PlayerPrefs でアイテムの所持状態を永続化するデータ層 |
学習ポイント
| # | 学習ポイント |
|---|---|
| ① | set アクセサの中で UI 更新メソッドを呼ぶ「プロパティ駆動更新」 |
| ② | [Serializable] + JsonUtility でオブジェクトを JSON 文字列に変換する |
| ③ | PlayerPrefs.SetString / GetString でデバイスに文字列を保存・読み込みする |
| ④ | GetComponentsInChildren<Toggle>() で動的生成した子オブジェクトを一括取得する |
| ⑤ | データクラス(OwnedItemsData)・UI クラス(ItemButton)・制御クラス(ItemsDialog)を分離するメリット |
パターン早見表
| 回 | パターン名 | 中心クラス | GoF カテゴリ |
|---|---|---|---|
| 第1回 | Singleton | OwnedItemsData・AudioManager・LifeGaugeContainer |
生成 |
| 第2回 | Template Method | MobStatus → PlayerStatus・EnemyStatus |
振る舞い |
| 第3回 | Delegation + Observer | CollisionDetector・UnityEvent<T> |
振る舞い |
| 第4回 | Single Responsibility | PlayerController + 各コンポーネント |
原則(SOLID) |
| 第5回 | State | MobStatus.StateEnum・MobAttack・EnemyMove |
振る舞い |
| 第6回 | Data / View 分離 | ItemButton・ItemsDialog・OwnedItemsData |
構造 |
関連シリーズ
- Unity本格入門 実装編(Chapter 5〜9) — 書籍の各 Chapter に沿って IkinokoBattle の実装を読み解くシリーズ
- Unity本格入門 機能別解説編 — 機能(タイトル・昼夜・Input System・NavMesh・UI・オーディオ)ごとに切り分けた解説シリーズ
最終更新:2026年4月