ある時点で、エンジンはゲームに関する情報を特化し、知る必要があります。ここで接線から出発します。
RTSでリソースを取得します。一つのゲームが持っていることCredits
とCrystal
、他Metal
とPotatoes
オブジェクト指向の概念を適切に使用し、最大限に活用する必要があります。コードの再利用。の概念Resource
がここに存在することは明らかです。
したがって、リソースには次のものがあると判断します。
- 自分自身をインクリメント/デクリメントするメインループのフック
- 現在の金額を取得する方法(を返します
int
)
- 任意に減算/加算する方法(プレイヤーがリソースを移動したり、購入したり...)
このaの概念はResource
、ゲームでのキルまたはポイントを表す可能性があることに注意してください!あまり強力ではありません。
次に、ゲームについて考えてみましょう。ペニーを処理し、出力に小数点を追加することにより、通貨をソートできます。私たちができないことは、「瞬間的な」リソースです。「電力グリッドの生成」と言うように
InstantResource
同様のメソッドを持つクラスを追加するとしましょう。これで、エンジンをリソースで汚染し始めています。
問題
RTSの例をもう一度見てみましょう。プレイヤーが何かCrystal
を他のプレイヤーに寄付するとします。あなたは次のようなことをしたい:
if(transfer.target == engine.getPlayerId()) {
engine.hud.addIncoming("You got "+transfer.quantity+" of "+
engine.resourceDictionary.getNameOf(transfer.resourceId)+
" from "+engine.getPlayer(transfer.source).name);
}
engine.getPlayer(transfer.target).getResourceById(transfer.resourceId).add(transfer.quantity)
engine.getPlayer(transfer.source).getResourceById(transfer.resourceId).add(-transfer.quantity)
しかし、これは非常に面倒です。それは一般的な目的ですが、面倒です。すでにそれはa resourceDictionary
を課していますが、これはあなたのリソースが名前を持たなければならないことを意味します!そして、それはプレイヤーごとですので、チームのリソースを持つことができなくなります。
これは「多すぎる」抽象化です(私が認める素晴らしい例ではありません)代わりに、ゲームにプレイヤーとクリスタルが含まれていることを受け入れて、(たとえば)
engine.getPlayer(transfer.target).crystal().receiveDonation(transfer)
engine.getPlayer(transfer.source).crystal().sendDonation(transfer)
クラスとPlayer
そのクラスのオブジェクトが自動的に寄付金の送信/転送用HUD上のものを表示します。CurrentPlayer
CurrentPlayer
crystal
これにより、クリスタル、クリスタルの寄付、現在のプレイヤー向けのHUD上のメッセージ、その他すべてでエンジンが汚染されます。読み取り/書き込み/保守がより高速で簡単です(大幅に高速ではないため、より重要です)
最後の挨拶
リソースのケースは素晴らしいものではありません。それでもあなたがポイントを見ることができることを望みます。特定のゲームに必要なものとして、またリソースのすべての概念に適用できるものとして、「リソースはエンジンに属していません」ということを実証しました。通常、3(または4)個の「レイヤー」があります
- 「コア」-これはエンジンの教科書定義であり、イベントフックを備えたシーングラフであり、シェーダーとネットワークパケット、およびプレーヤーの抽象的な概念を扱います。
- 「GameCore」-これは、すべてのゲームではなく、ゲームの種類にかなり一般的です-たとえば、RTSのリソースやFPSの弾薬。ここからゲームロジックが浸透し始めます。これは、以前のリソースの概念が存在する場所です。ほとんどのRTSリソースに意味のあるこれらのものを追加しました。
- 作成中の実際のゲームに非常に固有の「GameLogic」。あなたのような名前を持つ変数見つける
creature
か、ship
またはをsquad
。使い方継承あなたはすべての3つの層にまたがるクラス取得します(たとえばことCrystal
で Resource
これです GameLoopEventListener
と言います)
- 「資産」は他のゲームには役に立たない。たとえば、半減期2のAIスクリプトの組み合わせを考えてみましょう。これらは、同じエンジンを搭載したRTSで使用されることはありません。
古いエンジンから新しいゲームを作成する
これは非常に一般的です。フェーズ1では、レイヤー3と4(ゲームがまったく異なるタイプの場合は2)をリッピングします。古いRTSからRTSを作成しているとします。クリスタルやリソースではなく、リソースがまだあります。したがって、レイヤー2および1の基本クラスは依然として意味があり、3および4で参照されているクリスタルはすべて破棄できます。だからそうする。しかし、私たちがやりたいことの参考としてそれをチェックするかもしれません。
レイヤー1の汚染
これは起こる可能性があります。抽象化とパフォーマンスは敵です。たとえば、UE4は最適化された合成のケースを多数提供します(したがって、XとYが必要な場合、誰かがXとYを非常に高速に一緒に実行するコードを作成した場合-両方を実行していることがわかります)、結果として非常に大きなものになります。これは悪くありませんが、時間がかかります。レイヤー1は、「シェーダーにデータを渡す方法」や「アニメーション化する方法」などを決定します。プロジェクトに最適な方法でそれを行うことは常に良いことです。未来に向けて計画してみてください。コードの再利用はあなたの友人であり、意味のある場所を継承します。
レイヤーの分類
最後に(私は約束します)レイヤーをあまり恐れません。エンジンは、固定機能パイプラインの昔からの古語であり、エンジンはほぼ同じようにグラフィカルに機能しました(その結果、多くの共通点がありました)。開発者が達成したかったあらゆる効果。AIは(無数のアプローチのため)エンジンの際立った機能でしたが、現在はAIとグラフィックスです。
コードをこれらのレイヤーにファイルしないでください。有名なUnrealエンジンでさえ、それぞれが異なるゲームに固有の多くの異なるバージョンを持っています。変更されていないファイル(データ構造のようなものを除く)はほとんどありません。これは結構です!別のゲームから新しいゲームを作成する場合、30分以上かかります。重要なのは、どのビットをコピーして貼り付け、何を残すかを計画し、知ることです。