Design considerations:
I cannot recommend inheriting Game objects from their graphical representation. What for? You might want to have several graphic images of one game object (for example, in game mode or in a minimap or something else). The "Player" relationship has a "graphical representation", not the "Player" - this is a "graphical representation". The best solution is to use composition, not inheritance. Another nice effect is the possibility of encapsulating another collision detection, if you are unhappy with the fact that Qt is provided, decoupling ... It is also true that for a simple game this may be enough.
For a fairly simple game logic, inheritance is when other objects respond to the active object. Probably too simplistic for any more complex game mechanics.
class Asteroid { public: virtual void CollideWithPlayer(Player&) { p.loseHealth(100); } }; class ExplodingAsteroid: Asteroid { public: virtual void CollideWithPlayer(Player&) { explode(); p.loseHealth(1000); } };
If the interaction becomes complicated (many active objects behave on their own), you may need to define your objects:
There is RTTI, but is it not recommended that you recommend: How much does RTTI cost? In short: expensive, hard to maintain.
You can use double dispatch. Identifies objects using two virtual calls. Problems. Just a little syntax, sometimes difficult to maintain (especially when you add new objects), property rights issues (see more). Wikipedia game example:
class SpaceShip {}; class GiantSpaceShip : public SpaceShip {}; class Asteroid { public: virtual void CollideWith(SpaceShip&) { cout << "Asteroid hit a SpaceShip" << endl; } virtual void CollideWith(GiantSpaceShip&) { cout << "Asteroid hit a GiantSpaceShip" << endl; } }; class ExplodingAsteroid : public Asteroid { public: virtual void CollideWith(SpaceShip&) { cout << "ExplodingAsteroid hit a SpaceShip" << endl; } virtual void CollideWith(GiantSpaceShip&) { cout << "ExplodingAsteroid hit a GiantSpaceShip" << endl; } };
virtual id function
class GameObject() { virtual getId() { return GAME_OBJECT; } }; class Asteroid() { virtual getId() { return ASTEROID; } };
or as a member
class GameObject() { ID getId() { return id; } protected: GameObject(ID id):id(id) {} private: ID id; };
or using a template with automatic id initialization (small syntax for the mind, leave it: o)
Now for the game loop:
for each object update by (fixed) time step detect collisions and resolve them
you will encounter:
Ownership Issues:
the player loses health when hit by an asteroid, and the asteroid is subsequently destroyed.
Asteorid::collideWithPlayer(Player& p) { p.loseHealth(100); this->explode(); }
now consider also
Player::collideWithAsteroid(Asteroid& a) { this->loseHealth(100); a.explode(); }
Result
: duplicity of code or fuzzy game mechanics
The solution for the poor: call someone else to help you: o)
Asteorid::collideWithPlayer(Player& p) { resolveCollision(p, *this); } Player::collideWithAsteroid(Asteroid& a) { resolveCollision(*this, a); } resolveCollision(Player, Asteroid) { p.loseHealth(100); a.explode(); }