Goでのゲーム開発

http://www.j15r.com/blog/2015/01/25/Game_Development_in_Go

1 comment | 0 points | by WazanovaNews 3年弱前 edited


Jshiike 3年弱前 edited | ▲upvoteする | link

Minecraft的なものをGo言語で試してみた経験をまとめたブログのエントリー。専用のツール / ライブラリ / エンジンなどはまだ充実はしてない中で、Goがゲームづくりにどこまで使えそうかと考えるうえでの参考になればと思います。

採用のポイントとしては、

  • アウトプットスピードがCと同じでなくても、近づきつつある。
  • Cとのインターフェースが簡単。
  • メモリレイアウトの操作のしやすさ。
  • ガベッジコレクションにおいて、メモリモデルを利用してガベージを安易に増やさない工夫ができる。
  • 概ね安全に書ける。
  • コンパイルが早い。
  • オーバーヘッドがほぼかからないGLのバインディング。
  • ビットバンギングにも向いている。
  • 優れた並行処理primitive & network。

注意点としては、

  • 気の利いたデバッガーがまだない。サーバ側の開発では、リクエスト/レスポンスのログメッセージを見ながらデバッグすることが多いので許容できるが、複雑なレンダリングのアルゴリズムや、かなりステートフルなクライアントコードに対処するには辛い。
  • デスクトップ、Android (NDK)は問題なし。iOSサポートはまだ途上の様子。

その他、具体的な感想としては、

Goコンパイラは単一の静的にリンクされたバイナリを生成する。わずかなランタイムはあるが、それ以外は邪魔にならず、システムコールとのやりとりにおいて無駄なハードルはない。とすると、大きなランタイムやVMの話ではなくて、ツールチェーンの問題になるので、コンソールのプラットーフォームをカバーするのも可能ではないかと思った。

GoのstructとポインタはCに似ていて、違いはポインタ arithmeticが不正だということ。つまり、フラットなメモリレイアウトでstructを実装できる。例えば、64ビットのプラットフォームに、正確に 4 (unit32) + 64 (16 float32s) + 8 (64ビット ポインタ)バイトをセットできる。いくつかのarrayやsliceに適用すると、ヒープ上で、境界を挟んだ一つのブロックがつくれる。メモリのレイアウトのコントロールがしやすい。

Cでは安全にstructやarrayの間にポインタを向けることができる。この仕組みは、Goにおいて最適化に応用できる。キャッシュの一貫性だけではなく、独自のpoolアロケータをつくれる。たくさんの同じstructをアロケートしなくてはいけないがガベッジを減らしたいときに、ヒープのアロケーションが一つで済むので有効。

60 fpsを達成するためには、フレーム間の予算は16msになる。そこでガベージコレクタが入ってストップすると悪夢。なので、メモリの安全性を担保したまま、ガベージを減らせるのは大変ありがたい。

OpenGLとのインターフェースには go-glを利用。GLの無数のhandleの型を忘れたことによるエラーが防げたり、他の言語のようなラッパーオブジェクトでないのでランタイムで消えてくれるケースがあることで、機能を気にしなくてもよいというメリットも享受できた。

ハイレベル言語によるゲーム開発でよく陷いるのは、ローレベルに対処したとき、例えばリソースの読み込みの実装が不適切な際に、急速にメモリを消費してしまうケース。Cだとシンプルにリソースファイルをmmmap()などでメモリにマップして、structでvert/index arrayポインタを使って、マップされたファイルに直接向けることができる。Goの場合は、mmap-goが提供してくれるクロスプラットフォーム mmapの抽象化機能で、問題の半分を解決してくれる。その後で、[ ]byteをどうやって[ ]float32にするかなどを考えるとよい。このあたりの工夫をガベージコレクタが気づかないことのリスクはあるが、C++でやるよりは安全で早い。


2014 Topアクセスランキング


Back