14
\$\begingroup\$

Is it possible to describe an "optimal" (in terms of performance) layout for a 2D side-scroller's game loop? In this context the "game loop" takes user input, updates the states of game objects and draws the game objects.

For example having a GameObject base class with a deep inheritance hierarchy could be good for maintenance... you can do something like the following:

foreach(GameObject g in gameObjects) g.update();

However I think this approach can create performance issues.

On the other hand all game objects' data and functions could be global. Which would be a maintenance headache but might be closer to an optimally performing game loop.

Any thoughts? I'm interested in practical applications of near optimal game loop structure... even if I get a maintenance headache in exchange for great performance.

\$\endgroup\$
1

2 Answers 2

45
\$\begingroup\$

For example having a GameObject base class with a deep inheritance hierarchy could be good for maintenance...

Actually, deep hierarchies are generally worse for maintainability than shallow ones, and the modern architectural style for game objects is trending towards shallowing, aggregation-based approaches.

However I think this approach can create performance issues. On the other hand all game objects' data and functions could be global. Which would be a maintenance headache but might be closer to an optimally performing game loop.

The loop you've shown potentially has performance issues, but not, as is implied by your subsequent statement, because you have instance data and member functions in the GameObject class. Rather, the problem is that you if you treat every object in the game as exactly the same, you probably aren't grouping those objects intelligently -- they're likely randomly scattered about throughout that list. Potentially, then, every call to the update method for that object (whether that method is a global function or not, and whether than object has instance data or "global data" floating around in some table you're indexing into or whatever) is different from the update call in the last loop iterations.

This can put increased pressure on the system as you may need to page the memory with the relevant function in and out of memory and re-fill the instruction cache more frequently, resulting in a slower loop. Whether or not this is observable by the naked eye (or even in a profiler) depends on exactly what is a considered a "game object," how many of them exist on average, and what else is going on in your application.

Component-oriented object systems are a popular trend right now, leveraging the philosophy that aggregation is preferable to inheritance. Such systems potentially allow you to split the "update" logic of components (where "component" is roughly defined as some unit of functionality, such as the thing that represents the physically-simulated portion of some object, which is processed by the physics system) on to multiple threads -- discriminated by component type -- if possible and desired, which could have a performance gain. At the very least you can organize the components such that all components of a given type update together, making optimal use of the CPU's cache. An example of a such component-oriented system is discussed in this thread.

Such systems are often highly decoupled, which is a boon to maintenance as well.

Data-oriented design is a related approach -- it's about orienting yourself around the data required of objects as a first priority, so that that data can be effectively processed in bulk (for example). This generally means an organization that tries to keep data used for the same purpose cluster together and operated on all at once. It is not fundamentally incompatible with OO design, and you can find some chatter on the subject here at GDSE in this question.

In effect, a more optimal approach to the game loop would be, instead of your original

foreach(GameObject g in gameObjects) g.update();

something more like

ProcessUserInput();
UpdatePhysicsForAllObjects();
UpdateScriptsForAllObjects();
UpdateRenderDataForAllObjects();
RenderEverything();

In such a world, each GameObject might have a pointer or reference to its own PhysicsData or Script or RenderData, for the cases where you might need to interact with objects on an individual basis, but the actual PhysicsData, Scripts, RenderData, et cetera would all be owned by their respective subsystems (physics simulator, script hosting environment, renderer) and processed in bulk as indicated above.

It is very important to note that this approach isn't a magic bullet and will not always yield performance improvement (although it is generally a better design than a deep inheritance tree). You're especially likely to notice basically no performance difference if you have very few objects, or very many objects you cannot effectively parallelize the updates for.

Unfortunately, there is no such magic loop that is the most optimal -- every game is different and may need performance tuning in different ways. So it's very important to measure (profile) things before you blindly go taking the advice of some random guy on the internet.

\$\endgroup\$
1
  • 5
    \$\begingroup\$ Good lord, this is a great answer. \$\endgroup\$
    – Raveline
    Feb 6, 2011 at 7:46
2
\$\begingroup\$

Game-object style of programming is fine for smaller projects.As the project becomes really huge you will end up with deep inheritance hierarchy and the Game-object base will become really heavy!

As an example... Suppose you started creating Game-object base with minimum attributes say Position(for x and y),displayObject(this refers to the image if its a drawing element),width,height etc...

Now later on if we need to add a sub class which will have an animation state,then you probably move 'animation control code' (say currentAnimationId,Number of frames for this animation,etc..) to GameObjectBase in the thought that most of the objects will have animation.
Later if you want to add a rigid body which is static (doesn't have any animation),you need to check the 'animation control code'in the update function of GameObject Base(eventhough its a check whether animation is there or not...it matters!) Contrary to this if you follow Component based Structure, you will have a 'animation Control Component' attached to your object.If its needed you will attach it.For a Static body you will not attach that component.This way, we can avoid un-necessary checks.

So, the selection of choosing the style depends on the size of the project.GameObject structure is only easy to master for smaller projects.Hope this helps a bit.

\$\endgroup\$
3
  • \$\begingroup\$ @Josh Petrie - Really a great answer! \$\endgroup\$
    – Ayyappa
    Feb 8, 2011 at 18:54
  • \$\begingroup\$ @Josh Petrie - Really Good answer with useful links!(sry don't know how to place this comment next to your post :P) \$\endgroup\$
    – Ayyappa
    Feb 8, 2011 at 19:00
  • \$\begingroup\$ You can click the "add comment" link under my answer, normally, but that requires more reputation than you current have (see gamedev.stackexchange.com/privileges/comment). And thanks! \$\endgroup\$
    – user1430
    Feb 8, 2011 at 20:15

You must log in to answer this question.

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