開発ガイドの目次に戻る

高速化のヒント

はじめに

このページでは、ゲームの高速化のためのいくつかのヒントを挙げます。

  1. 読み込み中画面を利用して、ユーザの負担を減らす。
  2. ゲームの実行中にテクスチャやサウンドを読み込まない。
  3. 敵の生成を becameActive() で行ってしまう。
  4. テクスチャの切り替え回数を抑える。
  5. テクスチャ利用の切り替え回数を抑える。
  6. オブジェクトの管理方法を見直す。
  7. BGM・効果音の音質を調整する。

1. 読み込み中画面を利用して、ユーザの負担を減らす。

これは実際の高速化ではありませんが、ユーザの負担を軽減するための重要なポイントです。becameActive() 関数でのリソース読み込みに0.3秒以上の時間がかかる場合には、必ず KarakuriWorld クラスのサブクラスで getLoadingScreenWorldName() 関数をオーバーライドし、読み込み画面を使用するようにしてください。

ただし、0.7秒未満で読み込み中画面が消えてしまうのも、ユーザの負担となる場合があります。必要に応じて、KRCurrentTime() 関数と KRSleep() 関数をうまく利用して、読み込み中画面が表示される長さを調整してください。

2. ゲームの実行中にテクスチャやサウンドを読み込まない。

ゲームの実行中にテクスチャの生成やサウンドの生成を行うと、とにかくフレームレートが安定しなくなります。必要なオブジェクトは becameActive() 関数の中で生成しておくようにしてください。

複数の敵クラスでテクスチャやサウンドを共有する場合には、その敵クラスを管理するワールドが生成と破棄を担当するように設計するべきでしょう。

3. 敵の生成を becameActive() で行ってしまう。

これも本質的には、ヒント2と同じ事です。

敵を生成するために新しいオブジェクトを new するためには、一定のコストがかかります。必要な敵の情報はあらかじめ becameActive() 関数の中で作ってしまい、表示されている敵のリストとそうでない敵のリストを分けてもっておいたり、表示するかどうかを制御するフラグを使用すると良いでしょう。

なおこのテクニックは、敵を削除する場合も同様です。delete で敵のオブジェクトを削除するためにも一定のコストが必要です。resignedActive() 関数が実行されるまで、できるだけオブジェクトを delete しない設計にする方が良い場合が多いでしょう。

4. テクスチャの切り替え回数を抑える。

利用するテクスチャ(=画像ファイル)を切り替える度に、一定のコストが発生します。このコストはかなり大きな物で、最適化の重要なポイントとなります。

GameMain.cpp の setShowsFPS() 関数の設定で FPS 情報を表示するようにすると、「TPF」という情報も表示されるようになりますが、これは1フレームあたりの平均のテクスチャ切り替え回数を示しています。この回数を少なくすることにより、高速化が見込めます。

たとえば、敵1〜敵10に対応した画像ファイルを enemy01.png 〜 enemy10.png といった別個の画像ファイルとして用意しているのであれば、これを統合した enemy_all.png という画像を用意し、KRTexture2DAtlas クラスを利用して、すべての敵クラスでテクスチャを共有することで、高速化を見込むことができます。

また敵の爆発画像などは、通常の敵の画像とは分けて用意することになると思いますが、これを単純に使用すると、敵の数と爆発の割合に比例した回数のテクスチャの切り替えが発生してしまいます。

たとえば次の例では、4回のテクスチャ切り替えが発生しています。

これを、爆発していない敵と爆発している敵の描画を分けて処理することで、テクスチャの切り替え回数を抑えることができます。

次のように変更すると、2回のテクスチャ切り替えに抑えることができます。

同じテクスチャに対して描画処理が行われる間、フレームワークは同じテクスチャの描画をできるだけまとめようとするバッチ処理を行います。まとめられたテクスチャ描画のバッチ処理は、以下の場合に実行されます。

バッチ処理が行われた回数は、FPT 情報表示の「BPF」で確認することができます。

5. テクスチャ利用の切り替え回数を抑える。

Karakuri Framework では、KRPrimitive2D クラスで単純図形の描画をサポートしていますが、単純図形の描画を行う度に、テクスチャを利用しない設定に切り替わります。テクスチャの切り替え程ではありませんが、これにも一定のコストが生じます。

そのため、単純図形の描画は、できるだけ画面描画のシーケンスの一部でまとめて行うようにしてください。

6. オブジェクトの管理方法を見直す。

通常の C++ のプログラムにおいては std::vector クラスがよく使われますが、弾や敵などの「毎フレームごとに、すべての要素にアクセスし、頻繁に要素の追加や削除が行われる」情報を管理する場合には、std::list クラスを利用する方が効率的に動作します。

また、STL のコンテナを利用するよりも、固定サイズの配列を利用する方が効率的に動作するケースも多くあります。

固定サイズの配列を C++ で利用するために、new 演算子や delete 演算子をオーバーライドして、あらかじめ確保しておいた領域を振り直していくのもひとつの方法です。

7. BGM・効果音の音質を調整する。

ゲームのための BGM と効果音に通常の音楽に使われる音質(サンプリング周波数が 44.1kHz)のものを使用すると、データ量の関係でゲーム実行の性能にも影響が出てしまいます。音質を下げた音源データを用意してください。詳しくは、サウンド形式についてを参照してください。

また iPhone 用のゲームであれば、BGM にはユーザが iPod ライブラリの曲を流すと仮定する方が良いでしょう。

また、テクスチャと同じく、爆発の効果音なども複数の敵で共有して使うようにしてください(KRSound クラスの play() 関数は、再生中に呼び出すと現在の再生を中断し、頭から再生を開始します)。