wickedworx

June 24, 2010

WickedWorx and Components

Filed under: Technical — wickedworx dev clone 1 @ 11:19 am
(this is a post I wrote on tigsource forums… I know a lot of this has been covered here before)
I thought I’d write a little about how the ‘dynamic aggregation’ game object model works in terms of EGV…
this horrible diagram probably doesn’t show very well what’s happening, so I’ll explain further below
so, the game runs on two ‘main’ threads..
  • render / state – the main game’s render loop, and also state machine (out of game update)
  • update – update, physics (in game update)
there is also a network thread for the minor bits of networking the game does…
ignoring the state machine, it’s best just to see this as render/update.
when an object is spawned, it can either be spawned from
a) a .object file (looks like this)
<block>
    <component type="color" r="200" g="200" b="200" />
    <component type="position" x="0" y="0" z="0" rx="0" ry="0" rz="0" />
    <component type="physics_body" points="bridge.poly" density="0.1" static="true" renderable="false"/>
    <component type="outline" points="bridge.poly" />
    <component type="texture" points="bridge.poly" texture="machine.png" sx="5" sy="5" ox="0" oy="0" layer="3"/>
</block>
b) a .scene file referencing multiple object files, e.g. here’s one _block.object being overriden
<object name="Object_block.object">
    <override override="component" unique="type" name="color" index="0">
        <data r="0" g="100" b="0" />
    </override>
    <override override="component" unique="type" name="physics_body" index="0">
        <data points="G_crashsite_ground.poly" />
    </override>
    <override override="component" unique="type" name="outline" index="0">
        <data points="G_crashsite_ground.poly" />
    </override>
    <override override="component" unique="type" name="texture" index="0">
        <data points="G_crashsite_ground.poly" texture="rock.png" sx="0.07" sy="0.07" />
    </override>
</object>
(the .scene file is created by componentiator, see original post for screenshot)
c) an inline object definition in script
<wait time="2" />
<spawn_object_data>
    <object>
        <component type="color" r="255" g="255" b="255" />
        <component type="alpha" alpha="1" />
        <component type="position" x="0.5" y="0.4" z="0" rx="0" ry="0" rz="0" />
        <component type="sprite" texture="credits_jon.png" sx="0.4" sy="0.1" layer="6" use_color="true"/>
        <component type="fade_in_out" />
    </object>
</spawn_object_data>
The data is merged as required (e.g. using the overrides supplied in the .scene) and then sent to the GameObjectManager.
From here, each component definition is separated and sent to the ComponentBuilder. Each component is built (the correct component type is built depending on the type=””, using a templated factory thingy.. i know templated isn’t the right word in C#, but it’s the nearest equivalent C# does to C++ templating and i forget what C# calls it…) and sent its data.. e.g., here is how a “alpha” component builds:
public override void componentInitialise(string name, DataNode node, GameResource gameResource, GameObjectManager objectManager, GameObject gameObject)
{
m_alpha = node.getNode(“alpha”).getValueF();
}
Once all the components are built and added to the object, a ‘linkup’ stage is performed to allow Components to register with render, physics and update (or any other systems) as appropriate. This is usually not done in the componentInitialise as the whole object has not been created by this point.
e.g. a “sprite” component will register with render, but the “fade_in_out” component will register with just update.
when an object is destroyed, it calls an ‘unregister’ function on all of its components, allowing them to unregister with systems they have registered with.
Components can query the root object for other components, like this:
getRootObject().getComponent(“position”);
so, for example – the “sprite” component will get the “position” component, and use this to determine where to render itself.
if you have more than one “position” component in an object, it can be accessed as such:
getRootObject().getComponent(“position”, 0);
getRootObject().getComponent(“position”, 1);
etc..
there’s quite a bit of thread safety involved, especially with management of registered lists (it may be registering or deregistering with ‘render’ from the ‘update’ thread, for example).. to avoid any stalling, an intermediate ‘waiting list’ is used, and then flushed in to the main list on the next local update.. this means there is no holding on to mutexes during actual render/update, only during the flushing of the lists immediately before render/update.
destroying an object is never instant, it happens at the end of the current update frame.
well, there you have it – that’s how the whole of our game works. every time we need a new behaviour or new rendering method – it’s just a case of writing a new simple component… it’s quite neat!
watch the trailer and you can see where one of the objects detailed above is spawned in script.. 😉
next time i think i’ll write a bit about the scripting system, which works in a ‘mixed mode’ synchronous/asynchronous per-instruction timeline against the game updates.. it’s a custom scripting system (all in xml), but it allows us to make it very powerful.
Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: