Monday, 2 August 2010

Entity, tick thy self!

When developing in OO C++, you tend to think "entities, bunches of them, then tick them once a frame"...
However, I have come across TickAll(), Think(), Advance(), Update(), PreUpdate(), PreRender(), Step() and many other functions in my history of games development with C++. Not all the tick functions were even OOD, but the ideas behind why they were ticking generic entities were definitely coming from some OOD way of thinking.

Many engines have a form of scheduling their entities to do things in some specific order, so data is ready just in time for the next stage of it's processing. Think about how your game engine ticks movement, before doing collisions, then after collisions, ticks responses to collisions... so, you're already serially ticking sub parts of your entities. Funny thing is that you're normally ticking the entities that aren't involved in physics along with the ones that are, just in some post physics or pre rendering tick because you can't think where else to put them, or more often than not, in a function that used to be called MainTick(), but it's now called PostMovePreRender() because other ticks needed to be added to sync up data in stages over the years the engine's been evolving.

Simple example:
1. Do movement on all the moving things.
2. Do collision on all the colliding things.
3. Do collision response on all the collided things.
4. Do a general tick based on general state.

The object oriented approach is normally to MoveTick all objects in the moving things list (if you have the foresight to actually have an awake list), then Collide in the collision system (that caches and spatially coordinates stuff its own way), then CollisionResponse all objects that emerged from that tick, then GeneralTick all objects in the system that aren't hibernating. This stalls the things that don't interact from updating until their interactive brethren have finished poking each other.

It works, but it's a series of calls. So when you get around to re-writing your code as data oriented, remember that you were already calling a series of functions even when doing OO, so don't look down on a long list of function calls as if it's something horrible you'd never have done in the days of object oriented. You did before, you will again.

Splitting out the ticks like this is a habit of necessity. Coding, for games, like many successful games themselves, is a set of simple rules and a very large number of exceptions. Thinking you can get away with one Tick method is like saying that "if you hit, you deal damage"... except that's not always true.

It should also be considered as another reason why everyone should move away from entities containing all their data. Entities containing data for all circumstances is bad. Simply because if you put everyone's exceptions in your data size goes up unnecessarily. Also, if your entities share data (simple stuff like their position) then an update function has to be called before or after some other tick. This is a stall somewhere. If instead you assume prev-frame data is good enough, then you can make a read-only reference for all the things using the entity's position, while still updating the physics position multiple times due to collision and response before committing ready for the next frame.

A series of logical steps at a high level isn't bad, in fact, having your main thread a series of discrete steps through the logical transforms gives you massive benefits when it comes to debugging, performance analysis, and tuning. Consider this: if you start out by knowing how everything fits together you can reason about the whole system better and make much larger changes without fear of damage, and a general idea of what to fix/change.

Just because it seems easy, doesn't make it wrong.
Post a Comment