Saturday, March 18, 2006

Game Logic II

Right, mulled over for some time now, just had generally positive feedback from workmates. Yeah the system is okay, probably quite slow in practice compared to hard coded solutions, but it is rather extendable, so may get the vote anyway. I want to submit this to game gems or something in the future, so some comments would be cool. (Game Gems 6 is out very soon, so i guess it'll be at least Game Gems 7 till i get "on paper" ;) )
  • Minimal entities
  • Behaviours as Tags/labels
  • Behaviour containers
  • Messages
  • Conversations
The entities in this logic system are simply an ID (which can be the pointer to the entity if you want), plus the TagList item. This makes "thousands of entities" sound nice and cheap, but the data has got to be stored somewhere, and this is where the behaviours come in. Behaviours are like public inherited base classes, they add functionality, get themselves contructed and destroyed when the entity is constructed and destroyed, but they also handle messages, and just as importantly, they store their data in BehaviourContainers. To get access to the correct behaviour container, you can access the BehaviourContainerRegistry. Seeing as the behaviour containers are registered, they can be linked in as seperate modules, or even loaded at run time through dll's or even scripts such as Lua.
Behaviour containers contain a message handler which takes all the standard arguments, plus the ID of the entity that this behaviour is acting for. If the behaviour requires per entity unique data, the behaviour container will also have a pool of entity states. For memory's sake, only entities that have differences from their creation prototype get their behaviour state instanced.
Obviously, there is also the immediate speed benefit of using pools of entity states too, but that may be counterbalanced by the inherent slowdown of such a dynamic system.
Some behaviours have prerequisites of other behaviours, such as "IsCollidable" requires "HasWorldPresence".

All entities get around their game world via messages, and all messages can be simple, but for complex message sequences, it might be better to "strike up a conversation", when i mentioned this to someone they said that ratchet and clank(tm) used this system, so even though i think i thought of it alone, i can't claim "new idea". The system is straightforward enough, you create a reference counted conversation object, you send it along with your message, elements get filled in, and you get messaged back with "done filling it in" messages which allows you to carry on with the rest of the complex sequence you started.

For the system to be fully dynamic, the tags (after the compiled in ones) are stored in the tag manager, and you can forward and reverse search the tags (tag->string->tag).

So, you have a behaviour container registry that lets you get the correct behaviour container by tag (which you can get by name from the tag manager, or from the entity you are talking about just by getting one of the tags in the member taglist), and the functionality of that behaviour is either uniform across all entities that have that tag, or is unique per entity by getting the behaviour struct contained in the behaviour container. Scripted logical tick functions can be written easily by having the Tick tag call a script once a tick, or alternatively call a standard format tick function in C++.

No comments: