Advertisement

C++ game implementation

Started by March 06, 2025 06:20 PM
5 comments, last by smer4 3 days, 13 hours ago

I need some help with a question. In its most simple version, it's a life game in C++. We have a main class, Bunny, which is an abstract class, and 2 classes that extend it, FemaleBunny and MaleBunny. A bunny has the following attributes (age, name, gender, and cords (x,y) on the game board). We use the 2 different bunny classes because a male bunny should have the ability to reproduce - when he turns 3, he can look for 2 non-pregnant female bunnies and make them pregnant.

Female bunnies can be pregnant when they turn 3, and a year after they are pregnant, they can try to have a baby bunny with a random gender at an adjacent square. If they are all taken, she will die. Also when a bunny turns 6, he will die and disappear.

there are many more rules but I just want help with the simple concept so I can go on with it.

At the start, I tried doing it with the 3 bunny class, along side a Board class, which held a 2d array with pointers for bunny object, the size of the board is chosen by the user.

Then I thought it would be a "better design" to add a GameMaster class to control the game.

My main problem is that a male bunny needs to be able to iterate over every living bunny to look for ones to reproduce with, and I ran into a circular dependency problem, a bunny is trying to have an instance of the "GameMaster" in order to look at the array of all active bunnies.

So, I need an idea of how I can solve this. Feel free to change the architecture of the project and add or remove any classes if required. Let me know if there is any relevant concept I should learn to solve it.

ps I don't have the code I starting writing on this PC, but if it'll help I can try and recreate it here.

pizi42 said:

I need some help with a question. In its most simple version, it's a life game in C++. We have a main class, Bunny, which is an abstract class, and 2 classes that extend it, FemaleBunny and MaleBunny. A bunny has the following attributes (age, name, gender, and cords (x,y) on the game board). We use the 2 different bunny classes because a male bunny should have the ability to reproduce - when he turns 3, he can look for 2 non-pregnant female bunnies and make them pregnant.

That's not a good enough reason to use multiple classes.

My main problem is that a male bunny needs to be able to iterate over every living bunny to look for ones to reproduce with, and I ran into a circular dependency problem, a bunny is trying to have an instance of the "GameMaster" in order to look at the array of all active bunnies.

Wouldn't it make more sense to only search for sexual partners locally? Or is it an important part of your design that male bunnies can impregnate female bunnies on the other side of the board?

Regardless, circular dependencies between classes aren't much of a problem in C++. You can cycle by splitting one of the classes into an abstract interface class and a concrete implementation class, but you don't have to. The following is perfectly valid C++:

class B;
class A { public: B *b; };
class B { public: A *a; };
Advertisement

I agree that there is no need for more than one bunny class. Extra classes in this case just leads to more code and work without much benefit. Inheritance is not needed. You can cleanly represent all bunny types in a data-driven way using the following:

enum class BunnyGender
{
	MALE, FEMALE
};

class Bunny
{
	std::string name;
	BunnyGender gender;
	int age;
	Vector2i position;
};

I would implement the game logic in a centralized place. I would avoid trying to implement bunny operations inside the Bunny class, since it doesn't have enough context to do everything without knowing about the entire game state (your circular dependency issue). Game logic (i.e. your GameMaster) should be implemented separately from the data (i.e. the Bunny class), and in a location where it has access to all needed information.

Something like this:

class Board
{
	// flat 2D array, with each cell having either a bunny or nullptr.
	std::vector<Bunny*> cells;
	size_t width;
	size_t height;
};

class GameManager
{
	void updateGame()
	{
		// for each bunny in the game, look for nearby bunnies to reproduce with.
		// create / destroy bunnies
	}
	
	Board board;
	// all currently alive bunnies.
	std::vector<Bunny*> bunnies;
};

pizi42 said:
I ran into a circular dependency problem, a bunny is trying to have an instance of the "GameMaster" in order to look at the array of all active bunnies.

Some options:

  1. Include GameMaster.h to Bunny.cpp, and add a forwards declaration of the class GameMaster to Bunny.h. Then Bunny member functions can access the game class without problem, but the implementation of the member function must be in the Bunny.cpp file, not in the h file.
    This said assuming you're a beginner with cpp and with circular dependencies you mean issues related to file inclusion order. A solution of this is always possible.
  2. Implement the search in the game class, not in the bunny class.
  3. Give the map data structure as a parameter to the search implemented in the bunny class, which may require to make the map its own class which can be included by all others.

It's a matter of personal preference.
Btw, this is not a game design but a programming question.

pizi42 said:
My main problem is that a male bunny needs to be able to iterate over every living bunny to look for ones to reproduce with

That's what in the real world would happen indeed.

Games (and programming in general) is all about smoke and mirrors. You don't need to simulate reality, you just have to produce the same effect (as in, an observer cannot see the difference).

Producing the same effect can be done with any means you can think of. @aressera mentions one, do it in a central place, such as your GameMaster class.

By doing it centrally you can more easily manage things like several male bunnies trying to impregnate one female, but also several bunnies ending up at the same spot at the board.

I would not make FemaleBunny and MaleBunny, instead, other approach is generally used in games and any other logic, create 2 lists of Bunny, one females, other males. Sort one of this arrays once - you will get random pairs of male- female units to reproduce.
Then, turn based logic, Bunny can have “tick” class, where you update everything what happens in this turn, like pregnancy, etc, etc.

Advertisement