11
\$\begingroup\$

I'm a developer that's just now starting to mess around with game development. I'm a .Net guy, so I've messed with XNA and am now playing around with Cocos2d for the iPhone. My question really is more general though.

Let's say I'm building a simple Pong game. I'd have a Ball class and a Paddle class. Coming from the business world development, my first instinct is to not have any drawing or input handling code in either of these classes.

//pseudo code
class Ball
{
   Vector2D position;
   Vector2D velocity;
   Color color;
   void Move(){}
}

Nothing in the ball class handles input, or deals with drawing. I'd then have another class, my Game class, or my Scene.m (in Cocos2d) which would new up the Ball, and during the game loop, it would manipulate the ball as needed.

The thing is though, in many tutorials for both XNA and Cocos2d, I see a pattern like this:

//pseudo code
class Ball : SomeUpdatableComponent
{
   Vector2D position;
   Vector2D velocity;
   Color color;
   void Update(){}
   void Draw(){}
   void HandleInput(){}
}

My question is, is this right? Is this the pattern that people use in game development? It somehow goes against everything I'm used to, to have my Ball class do everything. Furthermore, in this second example, where my Ball knows how to move around, how would I handle collision detection with the Paddle? Would the Ball need to have knowledge of the Paddle? In my first example, the Game class would have references to both the Ball and the Paddle, and then ship both of those off to some CollisionDetection manager or something, but how do I deal with the complexity of various components, if each individual component does everything by itself? (I hope I'm making sense.....)

\$\endgroup\$
4
  • 2
    \$\begingroup\$ Unfortunately that is really how it's done in many games. I wouldn't take that as meaning it's best practice though. Many of the tutorials you're reading could be aimed at beginners, and so they're not going to start explaining model/view/controller or yoke patterns to the reader. \$\endgroup\$
    – tenpn
    Commented Feb 17, 2011 at 15:42
  • \$\begingroup\$ @tenpn, your comment seems to suggest that you don't think this is good practice, I wondered if you could explain further? I've always thought it was the most suitable arrangement due to those methods containing code that is likely very specific to each type; but I have little experience myself so I would be interested to hear your thoughts. \$\endgroup\$
    – sebf
    Commented Feb 18, 2011 at 22:29
  • 1
    \$\begingroup\$ @sebf it doesn't work if you're into data-orientated design, and it doesn't work if you like object-orientated design. See Uncle Bob's SOLID princples: butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod \$\endgroup\$
    – tenpn
    Commented Feb 21, 2011 at 14:02
  • \$\begingroup\$ @tenpn. That article and document linked within are very interesting, thank you! \$\endgroup\$
    – sebf
    Commented Feb 21, 2011 at 15:28

7 Answers 7

10
\$\begingroup\$

My question is, is this right? Is this the pattern that people use in game development?

Game developers tend to use whatever works. It's not rigorous, but hey, it ships.

It somehow goes against everything I'm used to, to have my Ball class do everything.

So, a more generalized idiom for what you have there is handleMessages/update/draw. In systems that make heavy use of messages (which has pros and cons as you would expect) a game entity grabs whatever messages it cares about, performs logic on those messages, and then draws itself.

Note that that draw() call might not actually mean that the entity calls putPixel or whatever inside itself; in some cases, it could just mean updating data that is later polled by the code responsible for drawing. In more advanced cases, it "draws" itself by calling methods exposed by a renderer. In the tech I'm working on right now, the object would draw itself using renderer calls and then every frame the rendering thread organizes all calls made by all objects, optimizes for things like state changes, and then draws the entire thing out (all of this happening on a thread separate from the game logic, so we get asynchronous rendering).

The delegation of responsibility is up to the programmer; for a simple pong game, it makes sense that each object handles its own drawing (complete with low-level calls) completely. It's a matter of style and wisdom.

Furthermore, in this second example, where my Ball knows how to move around, how would I handle collision detection with the Paddle? Would the Ball need to have knowledge of the Paddle?

So, one natural way of solving the problem here is to have every object take every other object as some sort of parameter for checking collisions. This scales poorly, and can have weird results.

Having each class implement some sort of Collidable interface and then having a high-level bit of code that just loops over all Collidable objects in the update phase of your game and handles collisions, setting the object positions as needed.

Again, you just have to develop a sense (or make up your mind) on how responsibility for different things in your game needs to be delegated. Rendering is a solitary activity and can be handled by an object in a vacuum; collision and physics generally can't.

In my first example, the Game class would have references to both the Ball and the Paddle, and then ship both of those off to some CollisionDetection manager or something, but how do I deal with the complexity of various components, if each individual component does everything themselves?

See the above for an exploration of this. If you are in a language that supports interfaces easily (i.e., Java, C#), this is easy. If you are in C++, this can be... interesting. I'm a favor of using messaging to solve these issues (classes handle messages they can, ignore others), some other folks like component composition.

Again, whatever works and is easiest for you.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Oh, and always remember: YAGNI (You ain't gonna need it) is really important here. You can waste a lot of time trying to come up with the ideal flexible system to handle every possible problem, and then never get anything done. I mean, if you really wanted a good multiplayer backbone for all possible outcomes, you'd use CORBA, right? :) \$\endgroup\$
    – ChrisE
    Commented Feb 17, 2011 at 18:03
5
\$\begingroup\$

I recently made a simple Space Invadors game using an 'entity system'. It's a pattern that separates attributes and behaviours extremely well. It took me a few iterations to fully understand it, but once you get a few components designed it becomes extremely simples to compose new objects using your existing components.

You should read this:

http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/

It's updated frequently by an extremely knowledgable guy. It's also the only entity system discussion with concrete code examples.

My iterations went as follows:

The first iteration had an "EntitySystem" object which was as Adam describes; however my components still had methods- my 'renderable' component had a paint() method, and my position component had a move() method and etc. When I began to flesh out the entities I realized that I needed to start passing message between components and ordering the execution of components updates....way too messy.

So, I went back and re-read T-machines blog. There is a lot of information in the comment threads- and in them he really emphasizes that components do not have behaviours- behaviours are provided by the entity systems. In this way you do not need to pass messages between components and order component updates because the ordering is determined by the global order of system execution. Ok. Maybe that's too abstract.

Anyway for iteration #2 this is what I gleaned from the blog:

EntityManager - acts as the component "database", which can be queried for entities which contain certain types of components. This can even be backed by an in-memory database for speedy access...see t-machine part 5 for more info.

EntitySystem - Each system is essentially just a method which operates on a set of entites. Each system will use component x,y and z of an entity to get it's work done. So you would query the manager for entities with components x,y and z then pass that result to the system.

Entity - just an id, like a long. The entity is what groups a set of components instances together into an 'entity'.

Component - a set of fields....no behaviours! when you start adding behaviours it starts to get messy...even in a simple Space Invadors game.

Edit: by the way, 'dt' is the delta time since the last main loop invocation

So my main Invadors loop is this:

Collection<Entity> entitiesWithGuns = manager.getEntitiesWith(Gun.class);
Collection<Entity> entitiesWithDamagable =
manager.getEntitiesWith(BulletDamagable.class);
Collection<Entity> entitiesWithInvadorDamagable = manager.getEntitiesWith(InvadorDamagable.class);

keyboardShipControllerSystem.update(entitiesWithGuns, dt);
touchInputSystem.update(entitiesWithGuns, dt);
Collection<Entity> entitiesWithInvadorMovement = manager.getEntitiesWith(InvadorMovement.class);
invadorMovementSystem.update(entitiesWithInvadorMovement);

Collection<Entity> entitiesWithVelocity = manager.getEntitiesWith(Velocity.class);
movementSystem.move(entitiesWithVelocity, dt);
gunSystem.update(entitiesWithGuns, System.currentTimeMillis());
Collection<Entity> entitiesWithPositionAndForm = manager.getEntitiesWith(Position.class, Form.class);
collisionSystem.checkCollisions(entitiesWithPositionAndForm);

It looks a little weird at first, but it's incredibly flexible. It's also very easy to optimize; for different component types you can have different backing datastores to make retrieval faster. For the 'form' class you can have it backed with a quadtree to speed access for collision detection.

I'm like you; I'm a seasoned developer but had no experience writing games. I spent a some time researching gave dev patterns, and this one caught my eye. It is in no way the only way to do things, but I've found it very intuitive and robust. I believe the pattern was officially discussed in book 6 of the series "Game Programming Gems" - http://www.amazon.com/Game-Programming-Gems/dp/1584500492. I haven't read any of the books myself but I hear they are the de-facto reference for game programming.

\$\endgroup\$
1
\$\begingroup\$

There are no explicit rules you -have- to follow when programming games. I find both patterns perfectly acceptable, as long as you follow the same design pattern all over your game. You'd be surprised that there are many more design patterns for games, several of which are not even on top of OOP.

Now, onto my personal preference, I prefer separating code by behavior (one class/thread to draw, another to update), while having minimalist objects. I find it easier to parallelize, and I often find myself working on fewer files at the same time. I'd say this is more a procedural way of doing things.

But if you come from the business world, you're probably more comfortable around writing classes that know how to do everything for themselves.

Once again, I recommend you write what you feel is most natural to you.

\$\endgroup\$
2
  • \$\begingroup\$ I think you misunderstood my question. I'm saying I DON'T like having classes that do everything themselves. I fell like a Ball should just be a logical representation of a Ball, however it should know nothing about the game loop, input handling etc... \$\endgroup\$
    – BFree
    Commented Feb 17, 2011 at 16:01
  • \$\begingroup\$ To be fair, in business programming if you boil it down, there are two trains: business objects that load, persist and perform logic on themselves, and DTO + AppLogic + Repository/Persitance Layer... \$\endgroup\$
    – Nate
    Commented Feb 17, 2011 at 16:19
1
\$\begingroup\$

the 'Ball' object has attributes & behaviors. I find it makes sense to include the object's unique attributes & behaviors in their own class. The way a Ball object updates is different from the way a paddle would update so it makes sense that these are unique behaviors warranting being included it the class. Same with drawing. There often are unique difference in the way a paddle is drawn vs a Ball and I find it easier to modify the draw method of an individual object to suit these needs than work out conditional evaluations in another class to resolve them.

Pong is a relatively simple game in terms of number of objects & behaviors but when you get into the dozens or hundreds of unique game objects you might find your 2nd example a bit easier to modularize everything.

Most folks do use an input class whose results are available to all the game objects through either a Service or a static class.

\$\endgroup\$
0
\$\begingroup\$

I think what you're probably use to in the business world is separating abstraction and implementation.

In the game dev world, you usually want to think in terms of speed. The more objects you have the more context switches will occur which may slow things down depending on the current load.

This is only my speculation since I'm a wannabe game developer but a professonial developer.

\$\endgroup\$
0
\$\begingroup\$

No, it's not 'right', or 'wrong', it's just a simplification.

Some business code is exactly the same, unless you're working with a system that forcibly separates presentation and logic.

Here, a VB.NET example, where "business logic" (adding a number) is written in a GUI event handler - http://www.homeandlearn.co.uk/net/nets1p12.html

how do I deal with the complexity of various components, if each individual component does everything themselves?

If and when it gets that complex, then you can factor it out.

class Ball
{
    GraphicalModel ballVisual;
    void Draw()
    {
        ballVisual.Draw();
    }
};
\$\endgroup\$
0
\$\begingroup\$

From my experience in development, there is no right or wrong way to do things, unless there is an accepted practice in the group you work with. I have met with opposition from developers who are averse to separating out behaviors, skins etc. And I am sure they will say the same about my reservation to writing a class that includes everything under the sun. Remember you have to not only write it, but be able to read your code tomorrow and at a future date, debug it and possibly build on it in the next iteration. You should choose a path that works for you (and team). Picking a route that others use (and is counter-intuitive to you) will slow you down.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .