1

I am making a snake game. I have two classes, snake and food. When I call snake->move() it needs to check that there are no collisions and for this purpose it needs to know what food's position is and therefore requires a pointer to food. food has a function that moves it to a new random position, move->setNewPosition(), which needs to know the position of snake so that it doesn't collide with the snake when it moves. For this purpose, it requires a pointer to snake.

Therefore, for both classes, I would need to supply a pointer to the other class which must be initialised. But to initialise the other class I need to initialise the other class and so on. Is there any way to initialise two classes, that require pointers to each other, at the same time?

If not, what would be a better way of structuring my program that would allow me to check the coordinates of the other class?

Damon
  • 67,688
  • 20
  • 135
  • 185
brnby
  • 1,433
  • 1
  • 19
  • 35

6 Answers6

2

If i don't misunderstand you, create init function that call before game loop starts:

void initSnake()
{
   auto snake = new Snake();
   auto food = new Food();   
   snake->setFood(food);
   food->setSnake(snake);
}
Denis Ermolin
  • 5,530
  • 6
  • 27
  • 44
1

You can define one base class for them, which has these methods:

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

Snake should use them too, just override them if you need to. Now both classes can call each other's setPosition and getPosition directly if you give the other object as a parameter with type Base.

An other way would be; In your main()-function, or wherever you define your snake:

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

And whenever you create a new food, give it snake's location: f->setRandomLocation(snake->getLocation()) where the parameter would be coordinates where NOT to place it.

1

They just need the facility to find the location of other snakes and food items when their movement functions are invoked. There's no need to know of their existence at initialisation time!

You can therefore have a collection of snakes and a collection of food items, and pass a reference to those collections to any newly created snakes and food items. Just create those collections first.

You could do this via another class, perhaps, which could also act as a factory.

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;
};

(Just an example. Code not tested to see if it actually compiles. E&OE)

The GameManager ensures that all created snakes are found in the snakes vector because the Snake constructor is private. Each snake can call _manager.Snakes() to get a vector containing all the other snakes in the game which it can then query individually for their positions. This is easily generalised to support food items as well.

This has the small advantage over the "construct-initialise" pattern suggested in other answers in that it ensures that when you get a new Snake object it is actually ready for use... this example isn't quite RAII, but it would require a minimum of effort to make it reasonably exception-safe.

Rook
  • 5,734
  • 3
  • 34
  • 43
0

One alternative would be to have a Manager class which both of them send their requests to, which would make more sense (but doesn't solve your particular problem).

Nevertheless, if you have class A and class B, and each one needs the other, you can do the following:

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);
Shahbaz
  • 46,337
  • 19
  • 116
  • 182
0

Mmn, not sure how your game works but I assume there would be a lot of food objects?

Maybe an idea would be to create a Collision class that accepts a Snake player and stores all the Food players in the game. So the Collision constructor might look like this

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

}

The Collision class would also have an collision update to loop that you call somewhere in your code.. This loop would check if the snake object collides with a food object.. and you can do whatever you want.. remove the food from the foods vector change the food position, whatever.

collison.UpdateCollisions() ; 
Lews Therin
  • 10,907
  • 4
  • 48
  • 72
0

I would suggest breaking the cyclic dependency, instead of hammering it in: make both moving functions take the environment (i.e. a list of things it can collide with) as a parameter.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510