タイルベースの柔軟なエンジンの設計


8

宝石をちりばめた、文明、倉庫番などと同じように、あらゆる種類の非リアルタイムパズルゲームを作成するための柔軟なタイルベースのゲームエンジンを作成しようとしています。

私が最初に行ったアプローチは、Tileオブジェクトの2D配列を用意し、次にゲームオブジェクトを表すTileから継承するクラスを用意することでした。残念ながら、その方法では、3D配列がなければ、同じタイルにゲーム要素をさらに積み上げることができませんでした。

次に、別のことを行いました。Tileオブジェクトの2D配列はまだありましたが、すべてのTileオブジェクトには、配置したリストと異なるエンティティが含まれていました。これは、20分前まではうまくいきました。多くのことを行うにはコストがかかりすぎることに気付いたとき、次の例を見てください。

壁エンティティがあります。更新ごとに、隣接する8つのタイルをチェックし、次にタイルのリスト内のすべてのエンティティをチェックし、それらのエンティティのいずれかが壁であるかどうかをチェックし、最後に正しいスプライトを描画します。(これは、互いに隣接する壁をシームレスに描画するために行われます)

私が今見ている唯一の解決策は、あらゆる状況に適する可能性のある多くのレイヤーを備えた3Dアレイを持つことです。しかし、その方法では、同じタイル上の同じレイヤーを共有する2つのエンティティをスタックできません。やりたいときはいつでも、新しいレイヤーを作成する必要があります。

より良い解決策はありますか?あなたならどうしますか?


3D配列を使用すると、壁チェックの状況に関する問題がどのように解決されますか。それはまだ同じではないでしょうか?
Michael Coleman、

壁はレイヤー番号1にのみ残ることを知っています。したがって、私は次のようにできます:Tiles [Wall.X-1、Wall.Y、1]は壁ですか?
ヴィー

リストの最初の要素を確認するだけでは不十分ですか?リストがどのように問題を引き起こすのかわかりません。
Michael Coleman、

2番目の方法では、壁はリストのどこにあってもかまいません。すべてのエンティティをループして、それが壁であるかどうかを確認する必要があります。
Vee

4
実際にパフォーマンスの問題がありましたか、それとも心配していますか?あなたはそれをプロファイリングしましたか?
立派な

回答:


2

あなたは実際にこの問題をましたか、それとも考えましたか?オブジェクトリストの繰り返し処理がパフォーマンスに顕著な影響を与えることを確認できなかったためです。これを問題にするには、タイルごとに何百ものオブジェクトが必要です。私が考えることができるほとんどのゲームには10個のトップがあります。

本当に問題がある場合は、表現を変更するのではなく、データをキャッシュすることをお勧めします。あなたの例では、壁の構成はおそらくすべてのフレームを変更しません。正しいスプライトタイプをキャッシュするだけで、常に再計算しないでください。

たくさんのオブジェクトを持つクレイジーなゲームを作成したいが、それらが常に変化する場合、異なるセマンティクスで異なるレイヤーを作成できます。たとえば、壁レイヤーには壁のみが含まれ、タイルごとに1つ以下です。たとえば、装飾レイヤーには、変更されないオブジェクトのリストが含まれます。

最後に、すべての可能なゲームを理想的にサポートする超柔軟なアーキテクチャが必要な場合-運が良ければ、そのようなことはありません。


2

2つの提案。まず、タイルマップ/レベルの読み込み中に各タイルが描画されるスプライトを解決する必要があります。レベルがロードされた状態で2D配列をトラバースし、バージニアの壁をL形状にし、もう1つの壁を|形状にする必要があると判断するのは簡単です形状。

次に、タイルに関連する静的データをアクティブデータとは別の場所に格納します。したがって、タイルオブジェクトには、タイルから出入りするオブジェクトのリストが含まれている場合がありますが、これをたどって、タイルがウォーク可能かどうかを確認する必要があるかどうかを確認する必要はありません。

この疑似コードは、タイルベースのシステムに私がアプローチした方法とほぼ同じです。

Tile {
  Texture tex;
  //...other static data...
  List currentObjects;
}

Tile t = Tiles[x][y];

これは、ゲームに静的なタイルがあることを前提としていますが、壁などを扱う多くのタイルベースのゲームではかなり良い前提です。


1

あなたが言った:

私はTileオブジェクトの2D配列を用意し、次にゲームオブジェクトを表すTileから継承するクラスを用意する必要がありました。残念ながら、その方法では、3D配列がなければ、同じタイルにゲーム要素をさらに積み上げることができませんでした。

次に、別のことを行いました。Tileオブジェクトの2D配列はまだありましたが、すべてのTileオブジェクトには、配置したリストと異なるエンティティが含まれていました。これは20分前までうまくいきました。

これは、MVC(モデルビューコントローラー)パターンを使用してモデルをビューから分離することで解決したい状況です。MVCはこの問題を2つの部分に分けます。

  • タイルのスタックをモデル化する方法
  • タイルのスタックを表示する方法

タイルの2D配列またはタイルのリストの2D配列を持つ代わりに、モデルはゲームオブジェクトの2D配列を格納します。次に、タイルクラスの2D配列は、対応するゲームオブジェクトを調べ、それらのレンダリング方法を決定します。

単一のTileインスタンスで単一のゲームオブジェクトをレンダリングする代わりに、単一のTileインスタンスでオブジェクトのスタックのように見えるものをレンダリングできます。これはより効率的であり、コアコードロジックとその外観を明確に分離できます。

壁のように。ロジックは非常に簡単ですが、レンダリングはより複雑です。


3
MVC(私の経験ではゲームでは一般的ではありません)がここでどのように役立つかわかりません。どちらかと言えば、それはさらに悪化します。同期を保つ必要があるモデルとビューの間に冗長性が生じることになります。
立派な

1
ええ、問題があるときは、<buzzword>を使用してください。ここで2つの問題があります。
Nevermind

1
np、詳細をフラッシュしました。
ashes999

はい、私は自分の反対票を取り戻しました。まだ、ここではMVCは役に立たないと思います。ほとんどの場合、オブジェクトは、グラフィカルな表現だけではなく、ロジックによって異なります。
Nevermind

みんなを喜ばせることはできないと思います。私にとって、MVCは問題の解決策の一部としてすぐに飛び出しました。しかし、私はすべての問題に対する完全な解決策を提供しているわけではないことに同意します。
ashes999

0

@Omnionに同意します。リストアプローチを使用しますが、パフォーマンスに問題がある場合はソートしてください。つまり、ハイブリッドアプローチを使用します。リストを3番目の次元として使用しますが、最初の5つのアイテムを特定のタイプとして識別し、その後はインク固有のタイプ、またはフレームごとに複数回チェックする必要がないタイプを識別します。


0

タイルのようなもののために別々のクラスを作成することは「絶対に」しないでください。タイルとその上のオブジェクトのタイプを参照するバイト、short、intから構造体を作成する必要があります。64ビットシステムでは、パフォーマンスに優れたintが最適です。ただし、マップを保存する場合は、特に巨大なマップの場合は、可能な限りバイトまたはショートを使用する必要があります。

私のゲームでは、次のようなフィールドのみを持つマップクラスがあります。このゲームでは、256種類の地形タイプで十分です。1バイトを使用します。ushort tileObject; 65,536種類のオブジェクトを組み合わせれば十分です。2バイトなどが必要

上記の例をとると、各タイルはメモリで3バイトしかかかりません。したがって、10000x10000はメモリ内で300MBであり、問​​題にはなりません。何かを探す必要があるときはいつでも、地図上のどこを見たいか、何を探しているかを決定し、それに応じて配列を反復処理します。

マップ全体に動的なものがある場合は、プレーヤーがビューポートから遠く離れていることに本当に気づいているかどうかを自問してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.