作業ログ

独自Engine設計|Part 1:ゲーム固有処理と汎用Engineの分離

ゲーム固有の処理と、VeEngineとして切り出す汎用処理の境界をどこに引くか。Application・Engine・GameLogicの役割を整理した。

  • game-engine
  • software-design
  • cpp

背景

新しく作る3Dアクションゲームでは、ゲーム固有の処理と、将来的にVeEngineとして分離する汎用処理を意識して実装していく。

この分離の目的は、単にクラスやファイルを増やすことではない。「この処理は何を知る必要があるのか」「どのクラスが判断するのか」を整理し、RenderingやPhysicsなどの汎用機能を、ゲーム固有のルールから独立させることが目的になる。

基本構造

現時点では、次のような構成をベースに考えている。

main
 └─ Application
     ├─ Engine
     │   ├─ WindowSystem
     │   ├─ TimeSystem
     │   ├─ InputSystem
     │   ├─ PhysicsSystem
     │   ├─ RenderSystem
     │   └─ LogSystem
     │
     └─ GameLogic

大きく分けると、EngineとGameLogicで役割を分ける。

Engine側

Engine側には、ゲームの内容に依存しない機能を置く。例えば、

  • Windowを管理する
  • Inputを取得する
  • 時間を管理する
  • Physics Simulationを進める
  • Renderingを行う
  • Logを出力する

といった処理になる。

これらは3Dアクションゲーム固有のルールを知らなくても実装できる。将来的に別のゲームを作る場合にも利用できる部分として、VeEngineへ切り出す候補になる。

GameLogic側

GameLogicには、この3Dアクションゲーム固有の状態やルールを置く。Engineが提供するInputやPhysics、Renderingなどを利用して、実際のゲームを構成する部分になる。

ここで重要なのは、Engine側からゲーム固有のルールを知らない状態を保つこと。GameLogicからEngineの機能を利用する方向に依存させる。

3D Action Game
      ↓
   VeEngine

逆に、VeEngine側から特定のゲームへ依存すると、別のゲームへ再利用しにくくなる。

Applicationの役割

Applicationは、EngineとGameLogicを接続する。

class Application
{
public:
    void Run();

private:
    void GameLoop();

    bool m_isRunning = false;
    VeEngine::Engine m_engine;
    GameLogic m_gameLogic;
};

Application自身がRenderingやPhysicsを実装するのではなく、アプリケーション全体の進行を管理する。現時点では、

  • EngineとGameLogicを所有する
  • 実行状態を管理する
  • Game Loopを実行する
  • 各SystemとGameLogicを適切な順序で呼び出す

といった役割を想定している。

Game Loopの具体的な設計については次の記事で整理する。

どちらに置くかをどう判断するか

ゲームを実装していくと、処理をGameLogicとEngineのどちらへ置くべきか迷う場面が出てくる。現時点では、次を一つの判断基準にする。

その処理は、このゲーム固有の知識を必要とするか

ゲーム固有のルールや状態を知らなければ実装できない処理はGame側。ゲームの内容に関係なく成立するInput、Rendering、Physicsなどの処理はEngine側に置く。

ただし、最初からすべての境界を確定させるつもりはない。実際に3Dアクションゲームを作りながら、責務や依存関係に問題が出てきた場合は見直していく。

まとめ

現時点では、役割を次のように整理している。

Application
    EngineとGameLogicを接続し、実行順序を管理する

Engine
    ゲーム非依存のSystemを所有・提供する

GameLogic
    3Dアクションゲーム固有の状態とルールを担当する

まずはこの境界を意識しながら、1本の3Dアクションゲームを完成させる。その後、実際にゲームで使用した汎用部分を切り出し、VeEngineとして分離していく。

次回は、Applicationがこれらをどのような順序で実行するのか、Game Loopと固定時間のPhysics Updateについて整理する。