views:

196

answers:

5

I'm trying to design a simple game ---Pong, Arkanoid--- using strictly "Proper OO", whatever that means.

So, by designing myself to death, I'm trying to get to a point where I'll know what to do or not do next time...

Who should handle, for example, colissions? And scorekeeping?

My first idea was giving a couple jobs to the ball, but that started expanding exponentially into a god object: The ball'd know where it is, who it crashed into, and report to the scorekeeping objects.

And that's too much for the poor ball.

+1  A: 

It really depends on your implementation, but I imagine you'd have a "gameboard" object to manage score keeping, or maybe a goal object on each side. As far as collisions I think you might want to pass events between the objects. I think any object should know its location though.

dickeytk
+5  A: 

rule of thumb:

  • if an object logically owns all of the state involved, then it owns the methods that use that state
  • if a method requires state from more than one object:
    • if a container object owns all of the objects used by the method, then it owns the method, too
    • otherwise you need a 'bridge' object to own the utility method
    • unless there is a strong argument for one object to be the 'controller' for the method (can't think of an example offhand though)

in your case, the 'gameboard' or 'game environment' would probably have a 'game physics' class (or group of methods) that owned the collision-detection (utility/bridge) methods

Steven A. Lowe
I think I understand some of these, like the first: Since a scorekeeping object keeps all the score state, it should also have the methods that modify the score.I don't understand 1.1, though: Since every colission happens within the board, I should have board.collides(ball, goal1)?
Tordek
@[Tordek]: yes - actually you would have board.CheckCollisions(AllObjects), to check for collisions among all balls and goals and any other collidable object w/in the active game scope. Use MovingObjects X CollidableObjects for the collision test, and check bounding rectangles for a quick test.
Steven A. Lowe
A: 

in most games you have statics and actors . .. actors move around and each of them independently figures out when they collide with something since they are aware of their shape and extents

Scott Evernden
In this case, my actors would be the ball and the paddles, right?What happens when a colission occurs? Should the ball and the paddle agree on the new direction?Are the walls and goals Statics?What if, for a challenge, I added moving walls? When does an object quit being a static?
Tordek
+2  A: 

A good or bad design reveals itself by how well it accomodates unexpected requirements, so I would suggest keeping a stock of potential "game features" handy to inform your design reflexions. Since you're doing this as a learning project you can afford to go crazy.

Arkanoid is a very good choice for this, it offers so many options. Make different bricks score different amounts of points. Make some bricks change the score of other bricks when hit. Make some bricks require multiple hits. Give superpowers to the ball, paddle, or bricks. Vary these powers: one of them makes the ball keyboard-controllable, another makes it transparent, another reverses "gravity", and so on. Make bricks drop objects.

The goal is that when you make such a change, it impacts the minimum possible number of classes and methods. Get a feel for how your design must change to fit this criterion.

Use an IDE that has a Refactoring menu, in particular the move method refactoring. (If you haven't, read the book Refactoring.) Experiment with placing your various methods here and there. Notice what becomes hard to change when the method is placed "wrong", and what becomes easier when you place it elsewhere. Methods are placed right when objects take care of their own state; you can "tell" an object to do something, rather than "ask" it questions about its state and then make decisions based on its answers.

Let's assume that in your design each sprite is an object instance. (You could choose other strategies.) Generally, motion alters the state of a sprite, so the method that describes motion for a particular kind of sprite probably belongs on that sprite's class.

Collision detection is a sensitive part of the code, as it potentially involves checking all possible pairs of sprites. You'll want to distinguish checking for collisions and informing objects of collisions. Your ball object needs to alter its motion on colliding with the paddle, for instance. But the algorithm for detecting collisions in general won't belong on the ball class, since other pairs of objects may collide with consequences that matter to the game.

And so on...

Morendil
+1  A: 

Keep in mind that objects can also exist for logical elements of a given problem (not only real elements, like balls and boards).

So for collision detection, you could have a CollidingElement class that handles the position and shape states. This object can then be embedded by composition in any object that should collide in the game and delegate any needed method call to it.

total
This is an important remark. Too many novices seem to think that OO programming is just coupling every possible logic to physical objects that exist in the real world.
Daniel Daranas