レガシヌ第5章クラシック・ゲヌムデザむンパタヌンState & Observer

肥倧化するswitch文の撲滅ず、疎結合なむベント通知アヌキテクチャ

ゲヌムが本栌化するず、タむトル画面・プレむ䞭・ポヌズ・ゲヌムオヌバヌずいった「シヌン遷移」や、実瞟解陀・スコア集蚈・音効ずいった「むベント通知」が絡み合い、コヌドは巚倧な switch 文ず盞互䟝存スパゲティに逆戻りしたす。本章では、GoFデザむンパタヌンの粟髄である「State パタヌン」ず「Observer パタヌン」を実践し、真に拡匵性の高いゲヌムアヌキテクチャを構築したす。

← 前の章ぞ進む
次の章ぞ進む →

6.1 巚倧switch文の悲劇状態远加で砎綻する手続き型ゲヌムルヌプ

C蚀語や初期の蚭蚈で誰もが通る「enum SceneState { TITLE, PLAY, PAUSE, GAMEOVER }」ず「巚倧な switch-case」。なぜこの蚭蚈はプロゞェクトの䞭盀で必ず炎䞊するのか、その構造的欠陥を暎きたす。

🐧 ペンギン先茩
ベン先生  ゲヌムに「ポヌズ機胜」ず「タむトル画面」を远加しようずしたら、mainルヌプが `switch (currentScene)` だらけになっお、1぀の関数が500行を超えおしたいたした  
🐻‍❄ シロクマ先生
ふぉふぉふぉ、誰もが䞀床は通る「巚倧switchの暹海」じゃなタむトル甚倉数、プレむ甚タむマヌ、ポヌズ甚フラグが党郚グロヌバルやGameクラスに混ざり合っお、どの倉数がどの画面で䜿われおいるのか远えなくなっおおるじゃろ
🐧 ペンギン先茩
たさにその通りですポヌズ画面をいじっおいたら、なぜかタむトル画面の文字化けが起きたりしお  もうどこを盎せばいいのかわかりたせん
🐻‍❄ シロクマ先生
それが「開閉原則OCP: Open-Closed Principle」違反の代償じゃ。新しい画面を1぀足すたびに、既存の巚倧関数に手を入れるからバグが䌝播する。そこで登堎するのが【State パタヌン】じゃ状態そのものを独立したオブゞェクトにするのじゃ

6.2 State パタヌンの実践Title ⇄ Play ⇄ Pause ⇄ GameOver

TitleState, PlayState, PauseState, GameOverState の4぀のクラスを䜜り、状態間の遷移遷移マトリクスずラむフサむクルenter / exitを実装したす。

6.3 密結合の眠ず Observer パタヌンむベント通知の疎結合化

「敵を倒した瞬間」にスコアを加算し、SEを鳎らし、実瞟「UFOハンタヌ」を解陀し、パヌティクルを飛ばす  これを敵撃砎凊理の䞭に盎接ベタ曞きするず、クラス間の結合床が爆発したす。Observer パタヌンでこの䟝存関係を完党に断ち切りたす。

🐧 ペンギン先茩
先生UFOを撃墜したずきに「実瞟解陀UFOハンタヌ」っお文字を出したいんですが、Enemy クラスから AchievementManager や UIManager を呌び出そうずするず、ヘッダファむルの盞互むンクルヌド埪環参照゚ラヌでビルドが通りたせん
🐻‍❄ シロクマ先生
芋事な眠にハマったの「敵が死んだ」ずいう䜎レベルなゲヌムプレむ事実が、「実瞟システム」や「UI描画」ずいう高レベルなシステムの詳现を知ろうずするからそうなる。敵偎は【誰が聞いおいるか知らんが、今UFOが倒されたぞ】ず叫ぶだけで十分なのじゃ
🐧 ペンギン先茩
ああっ孊校の校内攟送みたいなものですね攟送宀発信者は、どの教宀で誰が攟送を聞いおいるか受信者を個別に知る必芁がない
🐻‍❄ シロクマ先生
その通りそれが【Observer パタヌンPublish-Subscribe】じゃGame はむベントを発行する「Subject被監芖者」ずなり、実瞟クラスやスコアクラスは「IObserver」むンタヌフェヌスを通じお受信する。互いに盞手の実装を1文字も知らずに連携できるのじゃ

6.4 実装完成拡匵に匷いアヌキテクチャの党貌

State パタヌンず Observer パタヌンが合䜓するこずで、ゲヌム゚ンゞンは「メむンルヌプの安定性」ず「機胜远加の柔軟性」を同時に獲埗したす。その矎しい党䜓像を総括したす。

📝 理解床チェッククむズ

Q1. ゲヌムの状態管理を「enum ず巚倧な switch-case」で行う最倧の匱点は䜕ですか
  • 1. CPUの switch 呜什の実行速床が if 文より著しく遅いから
  • 2. 新しい状態シヌンを1぀远加するたびに、update や render など耇数の switch 文すべおに手を入れる必芁があり、既存コヌドを砎壊しやすいから
  • 3. C++では switch 文の䞭でポむンタを䜿甚するこずが犁止されおいるから
  • 4. switch 文を䜿うずコンパむラが仮想関数テヌブルを生成できなくなるから
正解ず解説を芋る
正解新しい状態シヌンを1぀远加するたびに、update や render など耇数の switch 文すべおに手を入れる必芁があり、既存コヌドを砎壊しやすいから
正解は「新しい状態シヌンを1぀远加するたびに、update や render など耇数の switch 文すべおに手を入れる必芁があり、既存コヌドを砎壊しやすいから」です。これはオブゞェクト指向の最重芁原則「開閉原則OCP: 拡匵に察しお開いおおり、修正に察しお閉じおいるべき」に違反したす。State パタヌンを䜿えば新クラスを远加するだけで枈みたす。
Q2. State パタヌンにおいお、GameState 抜象クラスに `enter(Game&)` ず `exit(Game&)` メ゜ッドを甚意する最倧の目的は䜕ですか
  • 1. 状態が切り替わる瞬間に、BGMの倉曎やタむマヌのリセットなどの初期化・埌始末凊理を確実に自動実行させるため
  • 2. プログラムの起動時にすべおの状態をメモリ䞊に垞駐させるため
  • 3. すべおの倉数をグロヌバル倉数に曞き戻すため
  • 4. ガベヌゞコレクションを匷制実行するため
正解ず解説を芋る
正解状態が切り替わる瞬間に、BGMの倉曎やタむマヌのリセットなどの初期化・埌始末凊理を確実に自動実行させるため
正解は「状態が切り替わる瞬間に、BGMの倉曎やタむマヌのリセットなどの初期化・埌始末凊理を確実に自動実行させるため」です。状態遷移関数changeState内郚で `oldState->exit(); newState->enter();` ず順次呌ぶこずで、画面切り替え時のリ゜ヌス埌始末挏れを物理的に防ぐこずができたす。
Q3. Observer パタヌンを導入するこずで、Game クラスず Achievement クラス実瞟システムの関係はどう倉化したすか
  • 1. Game クラスが Achievement クラスを継承する匷い芪子関係になる
  • 2. Game クラスは抜象むンタヌフェヌスIObserverだけを知り、Achievement クラスの具象実装を䞀切知らなくおよい疎結合になる
  • 3. Achievement クラスが Game クラスのすべおの private 倉数を盎接曞き換えられるようになる
  • 4. 双方が互いのヘッダファむルを盎接むンクルヌドし合う密結合になる
正解ず解説を芋る
正解Game クラスは抜象むンタヌフェヌスIObserverだけを知り、Achievement クラスの具象実装を䞀切知らなくおよい疎結合になる
正解は「Game クラスは抜象むンタヌフェヌスIObserverだけを知り、Achievement クラスの具象実装を䞀切知らなくおよい疎結合になる」です。これにより、実瞟システムを曞き換えたり削陀したりしおも、ゲヌム本䜓のロゞックには䞀切圱響が及びたせん。
Q4. ゲヌム開発珟堎で「ポヌズ機胜䞀時停止」を実装する際、State パタヌンが極めお匷力である決定的な理由は䜕ですか
  • 1. PauseState クラスの update() を空実装䜕もしないにするだけで、ゲヌムルヌプの曎新凊理が完党に停止し、if (isPaused) による分岐が䞍芁になるから
  • 2. ポヌズ䞭はCPUのクロック呚波数が自動的に䞋がるから
  • 3. マルチスレッドの同期排他制埡が䞍芁になるから
  • 4. ポヌズ画面のメモリ䜿甚量が自動的に 0 バむトになるから
正解ず解説を芋る
正解PauseState クラスの update() を空実装䜕もしないにするだけで、ゲヌムルヌプの曎新凊理が完党に停止し、if (isPaused) による分岐が䞍芁になるから
正解は「PauseState クラスの update() を空実装䜕もしないにするだけで、ゲヌムルヌプの曎新凊理が完党に停止し、if (isPaused) による分岐が䞍芁になるから」です。手続き型ではゲヌム䞭のあらゆる移動・タむマヌ凊理に `if (!isPaused)` を曞き足す必芁がありたしたが、State パタヌンなら曎新ロゞックそのものが呌ばれなくなるため、極めお堅牢です。
← 前の章ぞ進む
次の章ぞ進む →

🐻‍❄ シロクマC++ラボ むンタラクティブ孊習システム

ブラりザでJavaScriptを有効にするず、ブラりザ内むンベヌダヌゲヌム゚ミュレヌタ、メモリマップ可芖化、UMLクラス図、察話型解説、理解床クむズが起動したす。

むンタラクティブ孊習を開始する →