0

ポインターと参照の基本は理解していますが、最大の問題は、それらをいつ (そしてどちらを) 使用するかを決定することです。私が与える主な例は、基本的なゲームの 1 つです。セットアップが次のようなものであると仮定します。

  • 新世界
    • カメラ
    • 地図

ゲームが新しいセーブを開始するか、既存のワールドをロードするたびに、ワールドを削除して新しいワールドをロードするため、ワールドはポインタです。ただし、World の内部では、Camera と Map の存在は 1 つだけ存在し、World の期間だけ存在する必要があります。World が破壊された場合、明らかにそれらも破壊されるはずです。ただし、Map がカメラにアクセスする必要があるとしましょう (ただし、他のオブジェクトも同様です)。Camera は、参照によって Map に渡すか、ポインターとして渡す必要がありますか? たとえば、参照によるものであると想定されている場合、次のようにする必要があります。

map = Map(&camera);
(inside map class) Map(Camera camera) {...}

またはもっと好き:

map = Map(camera);
(inside map class) Map(Camera &camera) {...}

また、Map が grid と呼ばれるタイルの 2D ベクトルを保持しているとします。何かのようなもの:

std::vector< std::vector< Tile > > > grid;

ここで、そのグリッドを渡す必要がある PathFinder クラスがあるとします。タイルを直接編集して、f、g などの値を (パスファインディング用に) 変更する必要があります。その 2D ベクトルは、Tile の通常の 2D ベクトルであり、パスファインダーへの参照によって全体が渡されるべきでしょうか? それとも、Tile ポインターの 2D ベクトルである必要がありますか?

また、NPC とプレイヤーには、現在いるタイルである currentTile があります。そのタイルへの参照またはポインタが必要になるため、NPC/Player クラス内の次のようなものを介して、そのタイルの占有者として自分自身を設定することもできます。

currentTile = tile;
currentTile->SetOccupant(this);

もう 1 つの懸念は、そのグリッドを破棄して新しいマップをロードするときに発生します。存在しなくなったタイルを指しているものがないことを確認するにはどうすればよいでしょうか。これらのクラスをループして currentTile を NULL に設定するだけでよいのでしょうか?

これは、私がこのことで本当に混乱し始めたところです。私は明らかにかなり初心者なので、どんな助けも大歓迎です。@_@; これが実際にゲームのトピックに関連していない場合は申し訳ありません。別のスタック交換に移動する必要がある場合は、お知らせいただくか、移動してください (可能であれば)。>_<

4

1 に答える 1

1

Map クラスを考えてみましょう。Camera は、参照またはポインターとして渡すことができます。それは本当に問題ではありません。重要なのは、渡されたカメラで何が起こるかです。カメラ* であるメンバーに割り当てますか? そうしないと、コンストラクターで Camera を設定してもあまり効果がありません。カメラを必要とする Map へのすべての呼び出しで、カメラ ポインター/参照を提供する必要があります。

Tile オブジェクトを格納するには、単一次元の std::vector<> で十分です。簡単な計算を使用すると、このタイル グリッドを非常に簡単に移動できます。内部に別のベクトルをネストしても、不要なオーバーヘッドが発生するだけです。これを行うためのサンプル アルゴリズムを次に示します。

std::vector<Tile> tiles = makeTiles();
for (int y=0; y<mapHeight; y++)
{
   for (int x=0; x<mapWidth; x++)
   {
      Tile tile = tiles.at(x + y*mapWidth);
      tile.doSomethingWithTile();
   }
}

Map から PathFinder にタイル データを取得する方法を決定することは、実際には Map のデータをどの程度保護したいかによって決まります。すべてのタイル データへの参照を提供することで、基本的にパブリック アクセスが可能になります。PathFinder は個々のタイルを編集する必要がありますが、タイル配列全体を編集する必要はないため、次のようなメソッドを使用することをお勧めします。

Tile* Map::AccessTile(int tx, int ty);

このように、タイル データのベクトル全体は公開されませんが、PathFinder は必要なものを取得できます。さらに、Map::AccessTile() を非公開にし、PathFinder を Map のフレンドとして宣言することもできます。もう 1 つのアプローチは、Map::SetTileF(int tx, int ty, float f) のようなメソッドを提供することです。ただし、これは面倒な場合があります。

NPC とプレイヤーについても、同様のソリューションが利用可能です。実際には、タイルに直接書き込みアクセスする必要はありません。Map::SetTileOccupant(Entity *entity) のようなメソッドと、対応する Map::GetTileOccupant() を追加します。

オブジェクトの削除に関する懸念。C++ によって提供されるエミュレートされたポインター (特にstd::shared_ptr<>およびstd::weak_ptr<> )のいくつかを確認する必要があります。これらの簡単な説明は、shared_ptr はオブジェクトを「所有」するポインターであり、weak_ptr はオブジェクトにアクセスする場所を知っていますが、実際にはオブジェクトを「所有」していません。

これらのエミュレートされたポインターを使用すると、次のようなことができます。

//prototype for setWorld
//note that shared_ptr<> casts to weak_ptr<> nicely
Camera::setWorld(std::weak_ptr<World> world);

//setup the camera and world
std::shared_ptr<World> world(new World);
Camera camera;
camera.setWorld(world);

上記のコードでは、カメラはワールドへのポインタを持っています。何らかの理由でワールドが削除された場合、カメラは次の方法でこれを把握できます。

bool Camera::worldIsValid()
{
   return (this->mWorld.expired() == false);
}

また、カメラをワールド内にカプセル化していますが、これはおそらく行う必要のないことです。代わりに、Camera はスタンドアロンで、World に関する情報または World に含まれる Map が必要なときはいつでも World を参照することができます。

于 2013-10-15T02:29:19.777 に答える