ゲームコード最適化の基本

画像






多くの初心者のインディー開発者は、コードの最適化について考えるのが遅すぎます。 それはエンジンやフレームワークに翻弄されるか、「複雑な」技術と見なされ、理解することはできません。 ただし、より簡単な方法で実装できる最適化方法があり、コードをより効率的に、より多くのシステムで動作させることができます。 コード最適化の非常に基本的なことから見ていきましょう。



プレイヤーと自分のメンタルヘルスの最適化



多くの場合、インディー開発者は大企業の最適化手法を模倣しています。 これは必ずしも悪いことではありませんが、ノーリターンのポイントを過ぎた後にゲームを最適化したいという欲求は、自分を狂わせる良い方法です。 最適化パフォーマンスを追跡するためのスマートな戦術は、ターゲットオーディエンスをセグメント化し、そのマシンの特性を調査することです。 潜在的なプレーヤーのコンピューターとコンソールに基づいたゲームのベンチマークは、最適化とあなた自身の精神的健康のバランスを維持するのに役立ちます。



コード最適化の基本



実際、ゲームの速度を上げるためにほとんど常に使用できる最適化の数はかなり少ないです。 それらのほとんどは特定のプラットフォームに関連付けられていません(一部のエンジンとフレームワークはそれらを考慮に入れています)ので、どこから始めればよいかを知るために、以下に擬似コードの例を示します。



画面からのオブジェクトの影響を最小限に抑える



多くの場合、エンジンがこれを実行し、GPU自体も実行します。 画面外のオブジェクトの計算量を最小限に抑えることは非常に重要です。 独自のアーキテクチャでは、オブジェクトを2つの「レイヤー」に分ける方が適切です。1つ目はオブジェクトのグラフィカルな表現、2つ目はデータと関数(たとえば、その場所)です。 オブジェクトが画面から外れると、レンダリングにリソースを費やして追跡する必要がなくなります。 位置やステータスなどの変数を追跡すると、リソース要件が大幅に削減されます。



多数のオブジェクトを含むゲームまたは大量のデータを含むオブジェクトでは、別の手順を実行して個別の更新手順を作成すると役立つ場合があります。 1つの手順は、オブジェクトが画面上にあるときに更新され、もう1つの手順は、オブジェクトが画面外にあるときに更新されます。 このような分離を設定することにより、オブジェクトが非表示の場合にオプションである多くのアニメーション、アルゴリズム、およびその他の更新を実行する必要性からシステムを節約できます。



フラグと場所の制限を使用したオブジェクトクラスの擬似コードの例を次に示します。



Object NPC { Int locationX, locationY; //    2d- Function drawObject() { //  ,      } //, ,       Function pollObjectDraw( array currentViewport[minX,minY,maxX,maxY] ) { //    , ,     If (this.within(currentViewport)) { Return true; } Else { Return false; } } }
      
      





この例は非常に単純化されていますが、レンダリングの前にオブジェクトを照会してその可視性を決定できるため、完全な描画呼び出しを行う代わりに単純化された機能を実行できます。 グラフィックコールではない関数を分離するには、追加のバッファを作成する必要がある場合があります。たとえば、現時点で見ることができるものだけでなく、すぐに見ることができるすべてのものを含む関数などです。



フレーム更新の独立性



エンジンとフレームワークには、通常、すべてのフレームまたは「サイクル」(ティック)で更新されるオブジェクトがあります。 これはプロセッサに大きな負荷をかけるため、負荷を減らすために、可能な限りすべてのフレームで更新を削除する必要があります。



最初に分離するのは、レンダリング関数です。 通常、このような呼び出しはリソースを非常に積極的に使用するため、プレーヤーの視覚特性が変化したかどうかを示す呼び出しの統合により、レンダリングの量が大幅に削減されました。



別の手順を実行して、オブジェクトの一時画面を使用できます。 オブジェクトを一時コンテナに直接レンダリングすることにより、必要な場合にのみオブジェクトが描画されることを保証できます。



上記の最適化と同様に、コードの最初の反復では単純なポーリングが使用されます。



 Object NPC { boolean hasChanged; //   true,      //,   Function pollObjectChanged( return hasChanged(); } }
      
      





さて、各フレームで、多くの機能を実行する代わりに、最初にそれが必要であることを確認します。 この実装も非常に簡単ですが、特に静的オブジェクトやHUDなどのゆっくり更新されるオブジェクトに関しては、ゲームの有効性を大幅に高めることができます。



ゲームでは、さらに機能を拡張して、フラグをいくつかの小さなコンポーネントに分割して、機能をセグメント化できます。 たとえば、個別のフラグを追加して、データとグラフィックの変更を変更できます。



値の直接計算と検索



この最適化は、ゲーム業界の最初の日から適用されています。 計算と値の検索のトレードオフを選択することにより、処理時間を大幅に削減できます。 ゲームの歴史において、そのような最適化のよく知られた例は、三角関数の値をテーブルに保存することです。ほとんどの場合、オンザフライで計算を実行するよりも大きなテーブルを保存し、そこからデータを取得する方が効率的であるため、プロセッサの負荷が増加します。



今日、結果を保存するかアルゴリズムを実行するかを選択する必要はほとんどありません。 ただし、そのような選択により使用されるリソースの量を減らすことができる状況がまだあり、システムをオーバーロードせずにゲームに新しい機能を追加できます。



このような最適化の実装は、ゲーム内で頻繁に実行される計算または計算の一部を特定することから開始できます。計算が多いほど効果的です。 アルゴリズムの繰り返し部分を一度実行してその値を保存すると、多くの場合、コンピューティングリソースのかなりの部分を節約できます。 これらのパーツを別々のゲームサイクルで強調表示することで、パフォーマンスの最適化に役立ちます。



たとえば、多くのトップダウンシューティングゲームでは、同じアクションを実行する敵の大規模なグループがしばしば存在します。 ゲームに20人の敵がいて、それぞれが弧を描いて動く場合、各動きを個別に計算する代わりに、アルゴリズムの結果をより効率的に保存します。 このため、敵の初期位置に基づいて変更できます。



この方法がゲームで役立つかどうかを理解するには、ベンチマークを使用して、データの計算と保存に使用されるリソースの違いを比較してみてください。



CPUダウンタイム



これは、非アクティブなリソースの使用により多く当てはまりますが、オブジェクトとアルゴリズムに正しく実装されている場合、コードの効率を高めるようにタスクを配置できます。



独自のソフトウェアでダウンタイムに感度を適用するには、まず、タイムクリティカルではなく、必要になる前に計算できるゲーム内タスクを強調表示する必要があります。 まず第一に、ゲームの雰囲気に関連するものと同様の機能を持つコードを探す必要があります。 通常、地理、背景の視覚効果、背景音と相互作用しない気象システムは、ダウンタイム計算と呼ばれます。



大気コンピューティングに加えて、ダウンタイム中のコンピューティングの分野には必須のコンピューティングが含まれます。 プレイヤーから独立した人工知能の計算をより効率的にすることができます(プレイヤーを考慮しないか、プレイヤーと対話するまで)、また、スクリプト化されたイベントなどの計算された動きも同様です。



アイドルモードを使用してシステムを作成すると、効率が向上するだけでなく、視覚的な品質のスケーリングに使用できます。 たとえば、弱いマシンでは、プレーヤーは基本的な(「バニラ」)ゲームプレイにしかアクセスできません。 ただし、計算がほとんど行われないフレームをシステムが検出した場合、それらを使用して、パーティクル、グラフィックイベント、およびゲームにより多くの哀れみを与える他の大気のタッチを追加できます。



この機能を実装するには、選択したエンジン、フレームワーク、または言語で利用可能な機能を使用する必要があります。これにより、プロセッサの使用量を決定できます。 コードにフラグを設定して、「余分な」コンピューティングリソースの量を簡単に判断し、サブシステムがこれらのフラグをチェックして適切に動作するようにサブシステムを構成します。



最適化の組み合わせ



これらの方法を組み合わせることで、コードをより効率的にすることができます。 効率のおかげで、新しい機能、多数のシステムとの互換性を追加し、高品質のゲームプレイを保証できます。



All Articles