1

スネークゲームを作っています。私は2つのクラスを持っていsnakeますfood. 私が呼び出すsnake->move()と、衝突がないことを確認する必要があり、この目的のために位置を知るfood必要があるため、へのポインターが必要foodです。foodには、新しいランダムな位置 に移動する機能があります。これは、移動時にヘビと衝突しないようにmove->setNewPosition()の位置を知る必要があります。snakeこの目的のために、へのポインタが必要snakeです。

したがって、両方のクラスに対して、初期化する必要がある他のクラスへのポインターを提供する必要があります。しかし、他のクラスを初期化するには、他のクラスを初期化する必要があります。相互へのポインタを必要とする 2 つのクラスを同時に初期化する方法はありますか?

そうでない場合、他のクラスの座標を確認できるようにするプログラムを構築するより良い方法は何でしょうか?

4

6 に答える 6

2

誤解していなければ、initゲーム ループが開始する前に呼び出す関数を作成します。

void initSnake()
{
   auto snake = new Snake();
   auto food = new Food();   
   snake->setFood(food);
   food->setSnake(snake);
}
于 2012-11-29T12:25:24.447 に答える
1

移動関数が呼び出されたときに、他のヘビや食べ物の場所を見つける機能が必要なだけです。初期化時にそれらの存在を知る必要はありません!

したがって、ヘビのコレクションと食品のコレクションを作成し、これらのコレクションへの参照を新しく作成されたヘビと食品に渡すことができます。最初にそれらのコレクションを作成するだけです。

おそらく、ファクトリとしても機能する別のクラスを介してこれを行うことができます。

class GameManager;

class Snake
{
    friend class GameManager;

    public:
        int getX() { return _x; }
        int getY() { return _y; }

        void setPosition(int x, y) { /* ... */ }

    private: 
        Snake(GameManager* manager, int x, int y) : _manager(manager), _x(x), _y(y) {}

        GameManager* _manager;
        int _x, _y;
};

class GameManager
{
    public: 
        const std::vector<Snake*>& Snakes() { return _snakes; }

        Snake* SpawnSnake(int x, int y) 
        {
            Snake* newSnake = new Snake(this, x, y);
            snakes.push_back(newSnake);
            return snake;
        }

    private:
        std::vector<Snake*> _snakes;
};

(ほんの一例です。コードは実際にコンパイルされるかどうかテストされていません。E&OE)

コンストラクターがプライベートであるため、作成されたすべてのGameManagerスネークがスネーク ベクトルで見つかることが保証されます。各スネークは、ゲーム内の他のすべてのスネークを含むベクターを取得するためにSnake呼び出すことができ、その後、それらの位置を個別に照会できます。_manager.Snakes()これは、食品もサポートするように簡単に一般化できます。

これには、新しいオブジェクトを取得したときに実際に使用する準備ができていることを保証するという点で、他の回答で提案されている「construct-initialise」パターンよりも小さな利点がありSnakeます...この例は完全なRAIIではありませんが、合理的に例外安全にするための最小限の努力。

于 2012-11-29T12:29:13.587 に答える
1

これらのメソッドを持つ基本クラスを 1 つ定義できます。

virtual void setPosition(const int x, const int y)
virtual void getPosition(int &x, int &y) const

Snake もそれらを使用する必要があります。必要に応じてオーバーライドしてください。他のオブジェクトを type のパラメーターとして指定すると、両方のクラスが互いのsetPositionと をgetPosition直接呼び出すことができるようになりましたBase

別の方法は次のとおりです。main()関数内、またはスネークを定義する場所:

int main()
{
    Snake* s = new Snake;
    Food* f = new Food;
    Snake->setLocation(0,0); // Wherever you want the snake to start from
}

そして、新しい食べ物を作成するときはいつでも、ヘビの位置を与えます。f->setRandomLocation(snake->getLocation())ここで、パラメータは配置しない場所の座標になります。

于 2012-11-29T12:27:32.057 に答える
0

循環依存関係を打ち破るのではなく、壊すことをお勧めします。両方の移動関数が環境(つまり、衝突する可能性のあるもののリスト)をパラメーターとして受け取るようにします。

于 2012-11-29T12:45:05.637 に答える
0

うーん、あなたのゲームがどのように機能するかはわかりませんが、食べ物のオブジェクトがたくさんあると思いますか?

おそらく、CollisionSnake プレーヤーを受け入れ、すべての Food プレーヤーをゲームに格納するクラスを作成するというアイデアがあります。したがって、Collision コンストラクターは次のようになります。

Collison(Snake &snake, Vector<Food*> &foods)
{

}

Collision クラスには、コードのどこかで呼び出すループへの衝突更新もあります。このループは、ヘビ オブジェクトが食品オブジェクトと衝突するかどうかを確認します。そして、必要なことは何でもできます。foods vector 変更から食品を削除します。食べ物の位置、何でも。

collison.UpdateCollisions() ; 
于 2012-11-29T12:30:20.377 に答える
0

1 つの選択肢は、Manager両方がリクエストを送信するクラスを持つことです。これはより理にかなっています (ただし、特定の問題は解決しません)。

それにもかかわらず、 と がclass Aありclass B、それぞれが他を必要とする場合は、次のことができます。

A *a = new A;
B *b = new B;
// check a and b to make sure they are not NULL
a->set_b(b);
b->set_a(a);
于 2012-11-29T12:27:17.500 に答える