Engineクラスはなぜ必要か
ApplicationがSubsystemを直接持つのではなく、間にEngineを挟んでいる理由を整理した。
背景
現在の構成では、Applicationの下にEngineを置き、そのEngineが各Subsystemを所有する形にしている。
Application
├─ Engine
│ ├─ WindowSystem
│ ├─ TimeSystem
│ ├─ InputSystem
│ ├─ PhysicsSystem
│ ├─ RenderSystem
│ └─ LogSystem
│
└─ GameLogic
ここで一つ疑問になるのが、次の点。
Applicationが各Systemを直接持てばよいのではないか
実際、規模が小さいうちはその構成でも動かせる。
class Application
{
private:
WindowSystem m_windowSystem;
TimeSystem m_timeSystem;
InputSystem m_inputSystem;
PhysicsSystem m_physicsSystem;
RenderSystem m_renderSystem;
LogSystem m_logSystem;
GameLogic m_gameLogic;
};
この形でも、各Systemを順番に呼び出してGame Loopを実装することはできる。
Engineを挟む理由
それでもEngineを分けているのは、Applicationと各Subsystemで役割を分けたいから。
Applicationには、
- アプリケーションの起動
- Game Loopの管理
- 終了条件の管理
- EngineとGameLogicの接続
を担当させる。一方、Engineには、
- Subsystemを所有する
- 初期化する
- 終了する
- 利用側へSubsystemの参照を提供する
という役割を持たせる。つまり、次のような境界になる。
Application
アプリケーション全体の進行を管理
Engine
ゲーム非依存のSubsystemを管理
Applicationが直接持つ場合
ApplicationがすべてのSystemを直接所有すると、Systemが増えるたびにApplication側の責務も広がっていく。たとえば、
Window
Input
Time
Physics
Rendering
Audio
Resource
Scene
Profiler
と増えていくと、Applicationがゲーム全体の進行だけでなく、Engine内部の構成まで詳しく知ることになる。
ゲーム側から見れば、本来必要なのは「Engineの機能を使うこと」であって、Engine内部にどのSystemがいくつ存在するかを毎回意識したいわけではない。そこで、各SubsystemをEngineの内側へまとめる。
Engineを入口にする
Engineを置くことで、ゲーム側から見たEngine機能への入口も一つにできる。
m_engine.Input().Update();
m_engine.Physics().Step(FixedDeltaTimeSeconds);
m_engine.Renderer().Render();
利用側はEngineを通して必要なSubsystemへアクセスする。これにより、Subsystemの所有関係をApplicationから少し切り離せる。
将来的にSubsystemの構成を変更した場合でも、その変更をEngine内部に閉じ込めやすくなる。
Engineは何でもやるクラスではない
ただし、Engineを作ったからといって、すべての処理をEngineへ集めるわけではない。たとえば、
m_engine.Render();
m_engine.CheckCollision();
m_engine.UpdateInput();
の内部で、Engine自身がRenderingやCollision、Input処理まで直接実装し始めると、今度はEngineが巨大なクラスになる。
現在の方針では、EngineはあくまでSubsystemを管理する側に置く。具体的な処理は、それぞれのSystemへ任せる。
Engine
├─ InputSystem
├─ PhysicsSystem
├─ RenderSystem
└─ ...
まとめ
Engineを分けている理由は、単に1クラス増やしたいからではない。ApplicationとSubsystem管理の責務を分けるため。
Application
Game Loopとアプリケーション全体の進行を管理
Engine
ゲーム非依存のSubsystemを所有・管理
Subsystem
それぞれの専門処理を実装
小規模な段階ではApplicationが各Systemを直接持っても動く。ただ、今後Systemが増えていくことや、完成後にVeEngineとして切り出すことを考えると、Engineを一つの境界として置いておく方が整理しやすいと考えている。