SlideShare a Scribd company logo
ゲームエンジンの中の話
釜井政義 <@i_love_falcom>
2015/12/1 モバイル・コンシューマ「開発比較」勉強会 #3
誰?
 釜井政義(@i_love_falcom)
 コンシューマでアクション系開発ばかり10数年
 描画やシステム低層側実装が主な仕事
 昔は(社内)インフラなんかもやってました
 バイク命
注意!
ゲームエンジンが提供する機能は、
• Game Editor(+Tool群)
• Run-time Framework
大きく分けてこの二つに別れますが、
今日はRun-time Frameworkの話をします
本日のお題
 ゲームエンジンを理解する
 ゲームループ内で実行する処理
 ゲームループ外の処理
 まとめ
ゲームエンジンを理解する
ゲームエンジンを理解しようとするとき、
どこから手を付ければいい?
取りあえずソースコードとか読んでみる?
ゲームエンジンの中の話
うん、無理!
関連技術を確認しながらならどう?
ゲームエンジンの中の話
やっぱ、無理!
じゃあどこから理解する?
複雑でよく分からないなら、
基本に立ち戻ってシンプルに考える
更新
描画
終了?
終了
ゲームループ
開始
Yes
No
フレーム同期
なぜゲームループ?
 どんなRun-time Frameworkにも必ずある(はず)
 最外の処理なので全体の流れを見るのに都合がいい
 対象となるプラットフォームによって、目的のコードが何処
にあるのかある程度見当がつく
 例えばAndroidの場合、SurfaceViewを継承しているクラ
スを探す等
古典的ループ
CPU
GPU
同期
GPU待ち
CPU待ち 更新
更新 更新
CPU-GPU並列ループ
N+1 Frame
更新
N Frame
描画
N Frame
描画
CPU
GPU
同
期
N+1 Frame
描画
N+1 Frame
描画
2スレッドループ
N Frame
更新
N Frame
描画初期化
N-1 Frame
描画
CPU2
GPU
同
期
CPU1
N Frame
描画
同
期
N+1 Frame
更新
N Frame
描画
N-1 Frame
描画
2スレッド+ジョブ並列化ループ
N Frame
更新
N Frame
描画初期化
N-1 Frame
描画
CPU2
GPU
同
期
CPU1
N Frame
描画
同
期
N+1 Frame
更新
N Frame
描画
N-1 Frame
描画
CPU3~ CPU1/2発行ジョブ
2スレッド+ジョブ
+非同期コンピュート並列ループ
N Frame
更新
N Frame
描画初期化
N-1 Frame 描画
CPU2
GPU
同
期
CPU1
N Frame
描画同
期
N+1 Frame
更新
N Frame 描画
N-1 Frame
描画
CPU3~ CPU1/2発行ジョブ
GPGPU
並列・非同期化の方向へ進化する事によって、
CPU/GPU使用率が向上!
 複雑なエンティティを大量に処理できるようになる
 反面、入力~描画間レイテンシが増大
 対戦格闘やシューティングなど、低レイテンシであることが
必須のゲームに向かない
 描画で使用していない間、汎用計算リソースとしてGPUを使用
する事で、これまで出来なかった事が可能になった
ゲームループ内で実行する処理
ゲームループ内で実行する処理
 エンティティシステム(タスクシステム)
 エンティティの生成と破棄、およびリソース管理
 エンティティ更新、休止管理
 描画システム
 描画リソースの生成、破棄、解決処理
 描画コマンドの発行、Kick
 ゲームステート
 ゲームの状態・遷移管理
 ゲームシーン(ステージ)管理
エンティティ
 ゲーム内オブジェクト全ての基底
 エンティティシステムによって生成・破棄の管理を行う
 通常一意のIDを持ち、これによって他のエンティティから検
索、参照する機能を提供する
 エンティティ間を疎結合にするため、メッセージ通信機能を
提供する場合も多い
class ClassicalEntity {
public:
void Register();
void Unregister();
const char * GetID();
ClassicalEntity & Find(const char * id);
protected:
virtual void Update(const float delta) = 0;
virtual void Draw() {}
ClassicalEntity(const char * id) {}
virtual ~ClassicalEntity() {}
private:
std::string myId;
};
古典的なエンティティの例
新しいエンティティを実装するには、
このクラスを継承して以下のように使う
1 一意のIDを設定
2 更新処理をUpdateに実装
3 必要なら描画処理をDrawに実装
4 Register/Unregisterを使って自身の登録処理、
登録解除処理を行う
5 Findを使って他エンティティを検索
古典的なエンティティの問題点
 継承によって機能追加を行うため、多重継承、菱形継承問題
が発生してしまう可能性が高い
 本来不要な機能までも継承してしまうため、本来必要のない
無駄な処理が行われてしまう可能性がある
多重継承、菱形継承の例
Game Object
Movable Object
Collidable Object
Animation Object
Skeletal Object
CatDogHuman
Game Object
乗りもの 武器
戦車
is-a関係からhas-a関係へ
Game Object Component
Mesh Renderer
Transform
Rigid Body
Animation Controller
1 *
エンティティの更新処理
 更新処理は複数のステージに分ける事が一般的
 更新タイミングによっての分類
 アニメーション処理前の更新
 剛体物理処理後の更新
 処理方法による分類
 ジョブを使った並列更新
 他エンティティはRead参照のみ可
 単一スレッドによる逐次更新
 他エンティティをRead/Write参照可
描画システム
 全エンティティから描画情報(メッシュなど)を収集
 更新・描画の並列化を行う場合ダブルバッファ化が必要
 収集した描画情報が描画対象となるかを判定
 各描画パス毎に描画コマンドを生成、GPUへKick
 ジョブが使用可能なら並列に描画コマンドを生成
 使用しなくなった描画リソースの生存管理
 リソースを保持するエンティティが破棄されても、GPU側
で使用中の可能性があるのでリソースは描画システムが管
理する
タイトル
オプション
ステージ1
ステージ2
ステージ3
エンディング
ゲームステート
スタート
 ゲーム全体を管理するステート
 ステージ管理ステートなどを持つ場合、
ゲームステート下に階層的に持つ
 各種イベントをここからトリガ
 ステートの内容をスクリプトで記述でき
るようにしたエンジンも多い
ゲームループ外の処理
ゲームループ外の処理とは、
描画と同期しなくない処理
 ファイルのロード処理
 各種リソースの初期化処理
 GPUリソースなどは、例外的にゲームループと同期する必
要がある
 サウンド処理
 ネットワーク処理
ファイルのロード処理
 ファイルをロードしている間ゲームループを止めるわけには
いかない為、通常非同期ロードが必要とされる
 デバッグ時を除き、通常ファイルは圧縮されているので解凍
処理も実行される
 解凍処理はジョブや非同期コンピュート(GPU)で実行
 解凍されたリソースはリソースマネージャへ登録、解決処理
などが実行される
 解決処理とは、名前などを用いて外部のリソースとの関
連付けを行う処理
 解決処理の例
 メッシュと頂点データとの解決
 マテリアルとシェーダとの解決
サウンド処理
 ゲームループが処理落ちしてしまった場合など、もしサウン
ドの更新がゲームループと同期しているとプチノイズ等が発
生してしまう
ネットワーク処理
 通信データの送受信は、その時々のトラフィック状態によっ
てレイテンシが大きく異なってしまうため、描画と同期する
わけにはいかない(ネットワークの遅延でゲームループが止
まってしまう)
まとめ
 ゲームエンジンの処理は複雑でよく分からないが、ゲームル
ープを追う事で全体的な流れを理解しやすくなる
 ゲームループはCPU、GPUの利用効率を上げることで大量の
エンティティを扱うことができるようになった反面、レイテ
ンシが犠牲になってしまった
 ゲームループの内で処理を行うか、または外で行うかの基準
は、主に描画と同期する必要があるかどうかで決まる
更にゲームエンジンについて学ぶなら・・・
絶賛発売中
質問?

More Related Content

ゲームエンジンの中の話