ゲームエンティティの破棄を処理する適切な方法


10

エンティティのロードとロードが常に動的にロードされるゲームの世界を想像してみてください。それをエンティティのリストとして表すことができますが、それらを削除することはどうでしょうか?

追加するとき、新しいエンティティを押し戻すことができますが、コンテナ内の任意の場所を削除する必要がある場合があります。要素を検索して削除する位置を見つけるのを避けるには、どのような選択肢がありますか?

エンティティIDをコンテナ内の位置として保存して、直接削除するためのパスを作成できると考えましたが、何らかの相互依存関係「障害」を生成しませんか?

私は正しい方法がList.RemoveAt(whereToRemove);のようなものになることを知っています。しかし、エンティティのみがいつ死ぬべきかを知っている場合はどうでしょうか?

それとも私は何かが欠けているのですか?リストコンテナはオブジェクトが破壊されたときにそれを知って自分のサイズを減らしますか?

回答:


10

条件は次のとおりです。

  • 他のオブジェクトは、削除された後も、削除されたエンティティに依存している可能性があります。

  • エンティティのみが自身の削除を指定するようにします。

あなたは両方を持つことはできません。どうして?エンティティ自体より高いレベルのコード(下の例を参照)が、そのエンティティをいつ使用する必要があるかを決定するためです。したがって、同じレベルのコードだけが、エンティティが削除に適しているかどうかを判断できます。

ただし、発生する可能性があるのは、上位レベルのコードがリッスンしているイベントを発生させることにより、エンティティが自身の削除をリクエストできることです。その上位レベルは、この削除要求をリストに格納します。


例1:イベントなし

あなたはあなたの世界のエンティティ間の衝突をチェックしています。これは上位で処理されます。通常は、メインのゲームループで、すべてのエンティティをお互いに対してチェックします。具体的には、この例では、エンティティが他のエンティティと衝突した場合、そのエンティティの内部ロジックだけが、受けたダメージの大きさ、および「期限切れ」かどうかを判断できます。それでは、A、B、C、Dの世界に4つのエンティティが存在する場合の衝突のロジックフローを見てみましょう。Aは、私たちが関係しているエンティティです。

AとBの衝突をチェックします。衝突があります。Aは50%のダメージを受けます。

AとCの衝突をチェックします。衝突があります。Aは50%のダメージを受けます。ダメージが0になったため、Aは「死んだ」と判断します。リストから自分自身を削除します。

Dとの衝突についてAをチェックします。衝突はなかったでしょうが、それだけではありません。エンティティリストがトラバーサル操作の最中に変更されたため、ランタイム例外が発生します。

例2:イベントあり

以前と同じ設定。

AとBの衝突をチェックします。衝突があります。Aは50%のダメージを受けます。

AとCの衝突をチェックします。衝突があります。Aは50%のダメージを受けます。ダメージが0になったため、Aは「死んだ」と判断します。エンティティ管理コードにイベントを発生させて、「すぐに削除」と言います。エンティティ管理コードは、イベントの一部として送信されたエンティティ参照を確認し、削除するエンティティのリストにその参照を格納します。

AとDの衝突をチェックします。衝突はなく、チェックは正常に機能します。

ここで、現在のゲームループの反復の最後に、削除するエンティティのリストを実行し、これらすべてをメインエンティティリストから削除します。


これにより、問題を完全に回避できることがわかります。イベントを使用する必要はありません。シグナルなどを使用できますが、原則は同じです。安全に削除できるようになるまでエンティティを削除しないでください。このアプローチの反対側は、物事をきれいに整然と保つために、追加するエンティティでも同じことを行っています。必ずそれらへの参照を維持し、次のゲームループ反復の開始時にのみ追加してください。

最後に、メインエンティティリストで追加/削除を実行するたびに、削除リストと追加リストの両方をフラッシュすることを忘れないでください。

PS。メインリストから個別に削除することを恐れないでください。これは、エンティティ管理の一部であり、大規模なリストでさえ、トラバースが非常に高速になる傾向があります。


0

あなたは間違いなくHashMap / HashTableを探しています。ハッシュテーブルは、キーを特定の値と照合するマップです。キーは任意のもの(エンティティIDなど)にすることができます。


0

スマートポインターのアイデアを使用して割り当て解除を処理できると思います。その場合、コード内のすべてのエンティティのリストを保持する必要はありません。

場合によっては、ゲーム内のすべてのオブジェクトを反復処理するためのリストが必要です。このリストは、オブジェクトの挿入と削除に正確にO(1)時間かかるリンクリストである場合があります。

さらに速度を上げるために、静的配列(おそらくベクトル)を使用できます。その場合、同じベクター内の2つのリンクリストを追跡する必要があります。1つは有効なオブジェクトを反復処理し、もう1つはフリーオブジェクトを反復処理します。smartpointerが削除する場所をマークするたびに、そのポインターを削除して、そのスペースを空きスペースリストに追加します。エンティティを追加するときはいつでも、最初に空き領域を削除して、エンティティポインタでそれを満たし、次にそれを有効なオブジェクトリストに追加するだけです。

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