Component basedgame engine design@DADA246
自己紹介• ゲームプログラマやってます• 低レベルから GPU,web,DB まで幅広く書いてます• Steam,Origin,iPad で海外ゲームを遊んでいます• Starcraft2 hots 楽しいですね
はじめに• 今回の話は 1999 ~ 2003 年付近で議論されていたものです• 特に新しい話ではありません• ゲームごとに最適な設計は異なるので、今回の話が正しい設計ということではありません
stackoverflow• http://stackoverflow.com/questions/1901251/componen「コンポーネント主体のゲームプログラムについて情報を教えてほしい」→ コンポーネント関係のリンク集になっている
Entity• プレイヤーや敵などを表現する• Game Object とも呼ばれるclass Entity{public:void Update(float time);void Render();}
継承• 継承で Entity を構築した場合
継承問題• 継承はハードコーディングなので、変化に弱い• FPS にて、ゲームデザイナーから「弾を操作したい」と言われたら?例: Unreal TournamentRedeemer→ 撃った弾を操作出来る
継承の追加• 弾を操作したいため、弾クラスを継承して「操作可能な弾クラス」を作る→Player クラスと似たクラスが出来てしまう→ 継承をコーディングしなければならない→ コンパイルも必要
継承問題• ゲーム開発には試行錯誤が必要→ 開発が終盤になるほど継承関係を変更する手間が増える• Entity の種類が増えると基底クラスの機能が肥大化する
has-a• 継承を避ける→is-a ではなく、 has-a にする
コンポーネント• コンポーネントを基底クラスとする
Entity• Entity はユニークな ID とコンポーネントのリストを持つ→ ユニークな ID はコンポーネント管理クラスからコンポーネントを参照するときに使うclass Entity{private:int32_t id;std::li...
Entity の構築• コンパイル時ではなく、実行時に Entity の種類が決まるauto pPlayer = new Entity();pPlayer->RegisterComponent(new Human());pPlayer->Reg...
Data Driven• Entity の構築はコードに書かなくても良い<Entity><Name>Player</Name><Component>Human</Component><Component>Player</Component></...
ゲームエディタ• ゲームエディタの入力から Entity を構築する→ ゲームデザイナが Entity を構築できる→ コンポーネントの組み合わせで多様なEntity を生成出来る
コンポーネントの種類• 更新処理や描画処理もコンポーネントとして抽象化出来る
コンポーネントの例• Input( コントローラー入力 )• Updatable• Renderable• Physics• Collision• Motion• Actor• Audio• Network• AI• Health( 体力 )…
コンポーネントの組み合わせ• 賑やかしのための NPC→Collision を外して軽量化する• 壁→Updatable を外して軽量化する• 音の発生地点→Renderable を外して描画させない
LOD• コンポーネントを動的に付け外しすると、処理負荷を下げられる例:カメラから遠い NPC はアニメーションしないpNPC->RegisterComponent(COMPONENT_MOTION );pNPC->UnRegisterComp...
更新頻度の変更• 数フレームごとに実行される Updatable を作ると、処理負荷を下げられる例:ドアは 15 フレームに一度しか更新しないauto pDoor = new Entity();pDoor ->RegisterComponent...
更新処理• 継承ベースの設計でよく見かける処理→ 全 Entity の Update を呼ぶ
更新処理• Entity を処理するのではなく、登録されているコンポーネントを処理する→ 全 Entity を検索する必要がなくなる
Messaging• Update 処理を抽象化してしまったら、何を呼べば良い?→ コンポーネントに対してメッセージを投げる→ 処理負荷は掛かるが、ポインタよりも疎結合に出来るclass Component{private:Entity* pO...
Messaging• メッセージに対する処理を書いていくvoid PlayerComponent::HandleMessage(const Message& message){switch(message.GetType() ){defalut...
Messaging• メッセージはコンポーネント間のやりとりにも使えるvoid PlayerComponent::HandleMessage(const Message& message){…//Entity のユニーク ID を指定してメッセ...
実装例• コンポーネントはあくまでも設計論なので、様々な実装例がある
実装例• Entity にコンポーネントのリストを持たせるパターン→ 純粋なコンポーネント実装class Entity{public:void RegisterComponent(Component* pComponent);void GetC...
実装例• 処理速度を上げるために、 Update とRender はコンポーネントにしないパターン→ コンポーネント化は設計論の一つなので、ゲームごとに最適解は異なるclass Entity{public:void Update(float t...
実装例• コンポーネントを継承させていくパターン→ コントローラー入力の代わりに自動テスト用ダミー入力を使うなど
実装例• コンポーネントは C++ で書かれていなくても良い→Entity の一部をゲームデザイナーが書く
懸念点• メッセージを多用すると、ポインタアクセスに比べて処理速度が落ちる→ 入力処理など、処理速度が遅くても良い箇所に限定してメッセージを使用する• データドリブンの場合、コンパイラを通せないので、エラーが見つかりにくい→ デバッグ機能を強化...
まとめ• Entity を継承ではなく、 has-a にしてコンポーネント化する設計もある• ゲームタイトルごとにデザイン、対象プラットフォーム、開発規模が違うので、コンポーネント化が常に正しいとは限らない設計手法の一つとして考慮するのも面白い...
参考文献• A Data Driven Game Object System(GDC 2002)• Theory and Practice of Game Object Component Architecture(GDC Canada 200...
Question?
ご清聴ありがとうございました
Upcoming SlideShare
Loading in...5
×

Component basedgameenginedesign

1,763

Published on

Component basedgameenginedesign

  1. 1. Component basedgame engine design@DADA246
  2. 2. 自己紹介• ゲームプログラマやってます• 低レベルから GPU,web,DB まで幅広く書いてます• Steam,Origin,iPad で海外ゲームを遊んでいます• Starcraft2 hots 楽しいですね
  3. 3. はじめに• 今回の話は 1999 ~ 2003 年付近で議論されていたものです• 特に新しい話ではありません• ゲームごとに最適な設計は異なるので、今回の話が正しい設計ということではありません
  4. 4. stackoverflow• http://stackoverflow.com/questions/1901251/componen「コンポーネント主体のゲームプログラムについて情報を教えてほしい」→ コンポーネント関係のリンク集になっている
  5. 5. Entity• プレイヤーや敵などを表現する• Game Object とも呼ばれるclass Entity{public:void Update(float time);void Render();}
  6. 6. 継承• 継承で Entity を構築した場合
  7. 7. 継承問題• 継承はハードコーディングなので、変化に弱い• FPS にて、ゲームデザイナーから「弾を操作したい」と言われたら?例: Unreal TournamentRedeemer→ 撃った弾を操作出来る
  8. 8. 継承の追加• 弾を操作したいため、弾クラスを継承して「操作可能な弾クラス」を作る→Player クラスと似たクラスが出来てしまう→ 継承をコーディングしなければならない→ コンパイルも必要
  9. 9. 継承問題• ゲーム開発には試行錯誤が必要→ 開発が終盤になるほど継承関係を変更する手間が増える• Entity の種類が増えると基底クラスの機能が肥大化する
  10. 10. has-a• 継承を避ける→is-a ではなく、 has-a にする
  11. 11. コンポーネント• コンポーネントを基底クラスとする
  12. 12. Entity• Entity はユニークな ID とコンポーネントのリストを持つ→ ユニークな ID はコンポーネント管理クラスからコンポーネントを参照するときに使うclass Entity{private:int32_t id;std::list<component*> componentList;}
  13. 13. Entity の構築• コンパイル時ではなく、実行時に Entity の種類が決まるauto pPlayer = new Entity();pPlayer->RegisterComponent(new Human());pPlayer->RegisterComponent(new Player());
  14. 14. Data Driven• Entity の構築はコードに書かなくても良い<Entity><Name>Player</Name><Component>Human</Component><Component>Player</Component></Entity>{“Name”:”Player”,“Component”:[“Human”,”Player”]}
  15. 15. ゲームエディタ• ゲームエディタの入力から Entity を構築する→ ゲームデザイナが Entity を構築できる→ コンポーネントの組み合わせで多様なEntity を生成出来る
  16. 16. コンポーネントの種類• 更新処理や描画処理もコンポーネントとして抽象化出来る
  17. 17. コンポーネントの例• Input( コントローラー入力 )• Updatable• Renderable• Physics• Collision• Motion• Actor• Audio• Network• AI• Health( 体力 )…
  18. 18. コンポーネントの組み合わせ• 賑やかしのための NPC→Collision を外して軽量化する• 壁→Updatable を外して軽量化する• 音の発生地点→Renderable を外して描画させない
  19. 19. LOD• コンポーネントを動的に付け外しすると、処理負荷を下げられる例:カメラから遠い NPC はアニメーションしないpNPC->RegisterComponent(COMPONENT_MOTION );pNPC->UnRegisterComponent(COMPONENT_MOTION );
  20. 20. 更新頻度の変更• 数フレームごとに実行される Updatable を作ると、処理負荷を下げられる例:ドアは 15 フレームに一度しか更新しないauto pDoor = new Entity();pDoor ->RegisterComponent(new DefferedUpdatable() );
  21. 21. 更新処理• 継承ベースの設計でよく見かける処理→ 全 Entity の Update を呼ぶ
  22. 22. 更新処理• Entity を処理するのではなく、登録されているコンポーネントを処理する→ 全 Entity を検索する必要がなくなる
  23. 23. Messaging• Update 処理を抽象化してしまったら、何を呼べば良い?→ コンポーネントに対してメッセージを投げる→ 処理負荷は掛かるが、ポインタよりも疎結合に出来るclass Component{private:Entity* pOwnerEntity;public:virtual void HandleMessage(const Message& message);}
  24. 24. Messaging• メッセージに対する処理を書いていくvoid PlayerComponent::HandleMessage(const Message& message){switch(message.GetType() ){defalut:break;case CREATED:// コンポーネント生成時の処理break;case JUMP:// ジャンプ時の処理break;case GAME_OVER:// ゲームオーバー時の処理break;}}
  25. 25. Messaging• メッセージはコンポーネント間のやりとりにも使えるvoid PlayerComponent::HandleMessage(const Message& message){…//Entity のユニーク ID を指定してメッセージを発行PostMessage(enemyEntityId,new Message(DAMAGE) );// 全 Entity にメッセージを発行BroadcastMessage(new Message(SAVE) );…}
  26. 26. 実装例• コンポーネントはあくまでも設計論なので、様々な実装例がある
  27. 27. 実装例• Entity にコンポーネントのリストを持たせるパターン→ 純粋なコンポーネント実装class Entity{public:void RegisterComponent(Component* pComponent);void GetComponent(std::list<Component*> pComponentList);}
  28. 28. 実装例• 処理速度を上げるために、 Update とRender はコンポーネントにしないパターン→ コンポーネント化は設計論の一つなので、ゲームごとに最適解は異なるclass Entity{public:void Update(float time);void Render();void RegisterComponent(Component* pComponent);void GetComponent(std::list<Component*> pComponentList);}
  29. 29. 実装例• コンポーネントを継承させていくパターン→ コントローラー入力の代わりに自動テスト用ダミー入力を使うなど
  30. 30. 実装例• コンポーネントは C++ で書かれていなくても良い→Entity の一部をゲームデザイナーが書く
  31. 31. 懸念点• メッセージを多用すると、ポインタアクセスに比べて処理速度が落ちる→ 入力処理など、処理速度が遅くても良い箇所に限定してメッセージを使用する• データドリブンの場合、コンパイラを通せないので、エラーが見つかりにくい→ デバッグ機能を強化する• Generic なプログラムを求められる
  32. 32. まとめ• Entity を継承ではなく、 has-a にしてコンポーネント化する設計もある• ゲームタイトルごとにデザイン、対象プラットフォーム、開発規模が違うので、コンポーネント化が常に正しいとは限らない設計手法の一つとして考慮するのも面白いと思います
  33. 33. 参考文献• A Data Driven Game Object System(GDC 2002)• Theory and Practice of Game Object Component Architecture(GDC Canada 2009)• Game Engine Architecture• Game Programming Gems 4: A System for Managing GameEntities• Game Programming Gems 5: Component Based ObjectManagement• Game Programming Gems 5: A Generic Component Library• Game Programming Gems 6: Game Object Component System• MSDN XNA Programming Guide “Application Model Overview”
  34. 34. Question?
  35. 35. ご清聴ありがとうございました
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×