5

For a two player game where, your opponent could be on the network, CPU itself or near you where you would play turn by turn on the same machine.

How do people design classes for re-use ? I am in a similar situation and have no experience in making such complex games.

But here is what I have thought,

If I am a player object , I should only be interacting with the GameManager or GameEngine Singleton , from which I will get various notifications about the game status.

I dont care where and who my opponent is, this GameManager depending upon the game mode, will interact with gameNetworkManager , or AI tell me what the opponent played.

I am not sure about the scenario where we play and pass [turn by turn on same machine].

Hoping for a brief but clear explanation or at least a link to a similar resource.:)

1

1 Answer 1

18

There is no clear-cut answer, and class design for games is a very broad topic. I can hint you at two very common pitfalls though:

  1. It is tempting to use inheritance to model polymorphism on your game entities, so that you have a BaseEntity, a PlayerCharacter, etc., and give them a dozen or so methods to model how they move, draw, decide what to do, and interact with the rest of the world. However, this makes for quite tight coupling and doesn't exactly favor reuse. A better approach is composition: make your Entity class non-polymorphic, but give it a bunch of polymorphic members to describe different aspects, e.g. a Brain (which determines their behavior; this can be a HumanPlayerBrain, an AIBrain, a NetworkBrain, etc.), an Appearance (which takes care of selecting the right models / sprites and animating them as needed), a Physics (describing properties of the entity's physics model). Each of these has its own class hierarchy, but they are otherwise mostly independent from each other, and you can mix and match them as needed.
  2. It is also tempting to write self-updating entities, and many introductory game tutorials even recommend this. A ball that updates its own position every time you call its tick() method sounds like an elegant solution, but as soon as interactions become more complex, you'll face nasty problems - what if a hundred entities of different types are moving at the same time? Who is responsible for checking for collisions, and when one is found, which of the two objects is the 'active' one and which the 'passive'? Is it a.collideWith(b), or b.collideWith(a)? The solution is to make all your entities mostly passive; they simply expose accessors to query and update their physical properties (position, size, mass, inertia, etc.), and an overall GamePhysics object is responsible for checking all your objects and updating them. The collision handler is now world.collide(a, b), perfectly straightforward.

And then another word of caution: Making the game state a singleton seems like a logical decision, but it locks you down into no more than one game state at a time. This has two important disadvantages:

  1. If you want a client/server architecture, the server will only ever be able to run one game at a time.
  2. Unit-testing anything that depends on the game state is going to be harder.

Personally, I prefer passing the game state around as just another object. An additional advantage of this is that I can pass only parts of the game state to objects that have no business fiddling with the rest, e.g., an object's render() method is not supposed to modify the game logic at all, so I can pass it as const; the physics part is not supposed to do anything graphics-related, so I don't pass it a reference to the resource manager. This keeps the potential number of cross-dependencies low, which in turn leads to less complexity.

6
  • +1. I never made a computer game, but what you say makes a lot of sense. I bet there are a lot more such pitfalls. Jul 10, 2012 at 6:23
  • 1
    +1 just for your first point alone: one of the best examples of 'favour composition over inheritance' I've seen
    – stijn
    Jul 10, 2012 at 7:14
  • by singleton, I meant the entity on each client that will manage the game interactions for the player, whether its with a player or cpu. Jul 10, 2012 at 8:47
  • +1 for the HumanPlayerBrain, an AIBrain, a NetworkBrain advice . Jul 10, 2012 at 8:48
  • @AmoghTalpallikar: 'Singleton' is a common design pattern that enforces that there can only ever be one instance of a certain type. It appears elegant and clever, but it has some severe drawbacks and is often not worth using.
    – tdammers
    Jul 10, 2012 at 10:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.