Sign in to follow this  

Game Object Creation System

This topic is 3488 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So I have this object creation system and am interested to get some of you guys-es opinions on it: Here is an example of a wrapper function we use to create a Game Object. The idea behind this object creation approach was to avoid using singletons as managers as well as avoid complicated constructors with tons of dependencies on loaders. We also wanted the system to be data driven, so we could specify values in XML files for the objects. In addition, we needed to be able to tweak those values at object creation time. This is our solution: --------------------- 1) The Game Object Factory contains a PropertyFactory which it provides access to. Passing a path to an objects XML properties file will validate and parse the XML file, deserializing all of the data into proper data types which are then stored in a PropertyObject and associated with whatever name they are given by the XML. This PropertyObject is return to the calling code. 2) The the individual properties in the PropertyObject can be tweaked and new ones can be added here. 3) The final PropertyObject is passed to the GameObjectFactory. The GOFactory contains references to all of the support systems for loading every type of data (Models, textures, ect...). 4) The property object is passed to the constructor of the object that is being created so basic information not dependent on external support systems can be attained by the object's constructor. 5) Then the GOFactory takes the property object and loads data for any elements that require loading and sends just the resource handles to the newly created object. The resource handles are assigned to the objects using optional interfaces. 6) Finally if the object is created successfully, a pointer to it is returned. If any step of the process failed, the allocated memory (if any) is deleted, and an ObjectCreationFailed exception is thrown with information about what failed.
GOBox* FStateBattle::createBox( const Vertex& position, const Rotation3D& rotation, const Vertex& initialVelocity ) {
        GOBox* box = NULL;
        
        Property_ptr properties = m_gameObjectFactory.getPropertiesFor( DESC_PATH_GO_BOX ); // Step 1
        if( properties.get() == NULL ) {
                mdLog( ( "GeneralError", "Properties were NULL for GO_BOX\n" ) );
        }
        else {
                try {
                        properties->setProperty<Vertex>( GO_PROP_POSITION, position ); // Step 2
                        properties->setProperty<Rotation3D>( GO_PROP_ROTATION, rotation ); // Step 2
                        box = m_gameObjectFactory.createGameObject<GOBox>( properties ); // Step 3-6
                }
                catch( RequiredPropertyNotFound rpe ) {
                        mdLog( ( "GeneralError", "Caught Exception: %s\n", rpe.what() ) );
                }
                catch( ObjectCreationFailed ocf ) {
                        mdLog( ( "GeneralError", "Caught Exception: %s\n", ocf.what() ) );
                }
        }
        return box;
}

// So the final top level code for creating a box looks like:
GOBox* box = createBox(); // The arguments all have default values to default constructed objects of their type

Share this post


Link to post
Share on other sites
There are several complex (and possibly more robust) methods of doing this sort of thing and I'm sure before long somebody will post something containing templates to solves your problem (and all the other problems in the world) very well.

I can only really present a solution that I've found to work just fine in the past, and continue to use to this day. Apologies if my code appears a little 'old school' (and thus a little unsafe looking)

I've left out the functions that don't really mean much in the context of your problem and aside from a couple of comments I've left out the error checking just to keep things easier to read.

The system I'm about to ramble in great length about basically uses parameter classes that act as factories for particular game objects. so making a particular game object is a simple case of getting a parameter object, filling it in and then using it to create a game object.

Ok, on with the code.

First I'll assume you have some sort of generic list management system. i.e. a class (such as ListItem) that you can derive from and add and remove from a list class (such as List).

Now you'll need a few basic classes.

The basic abstract game object

//HEADER -------------------------------------
//< GameObject - base class for an actual in game object of any kind
class GameObject : public ListItem
{
public:
GameObject() {;};

protected:

virtual void Init (GameObjectParams* params) = 0;

friend class GameObjectParams;
};



The basic abstract game parameters object

//HEADER -------------------------------------
//< GameObjectParams - base class for a block of parameters that describe an in game object
class GameObjectParams : public ListItem
{
public:
GameObjectParams(){;};

protected:

virtual GameObject* Create () = 0; //< this does the creating of objects
virtual void SetDefaults (){;}; //< set any values in these parameters to default values
virtual const uint GetTypeID () = 0; //< each parameter object should return a different (preferably unique) value from this

friend class GameObjectParamsManager;
};



Somewhere to store the parameters for game objects

//HEADER-------------------------------------
//< GameObjectParamsManager - a class that contains a list of all possible parameter objects
class GameObjectParamsManager
{
public:
GameObjectParamsManager(){;};
~GameObjectParamsManager(){ m_Parameters.Empty();};

GameObjectParams* GetParams (const uint typeID); //< search the parameters list and return one of the right type if it exists
GameObject* CreateGameObject(GameObjectParams* params); //< create a game object from a series of parameters

void AddParameters (GameObjectParams* params); //< add a parameter object for a specific type of game object

private:

GameObjectParams* NextParam (GameObjectParams* curr); //< get the next parameter object in the m_Parameters list
List m_Parameters;
};


// CPP ----------------------------------

GameObjectParams* GameObjectParamsManager::GetParams(const uint typeID)
{
GameObjectParams* params = NULL;

while((params = NextParam(params))) //< single equals intended
{
if (typeID == params->GetTypeID())
{
params->SetDefaults();
return params;
}
}

return NULL;
}

GameObject* GameObjectParamsManager::CreateGameObject(GameObjectParams* params)
{
if (params)
{
GameObject* object = params->Create();
if (object)
{
object->Init(params);
return object;
}
//< you could throw an exception here if you wnted to.
}

return NULL;
}



That's basically all you'll need. now you just have to write the code to describe real game objects.

Real Game Objects

//< EXAMPLE CODE

//< HEADER

#define UID_ObjectTypeA 1210508 //< this can be any number as long as it's unique within the scope of your game - use RTTI instead if you like

class GameObjectTypeA : public GameObject
{
public:

int m_ObjectAData;

protected:
virtual void Init (GameObjectParams* params)
}

class GameObjectTypeAParams : public GameObjectParams
{
public:

int m_ObjectAData;

protected:

virtual GameObject* Create () { return new GameObjectTypeA;};
virtual void SetDefaults () { ObjectAData = 0;};
virtual const uint GetTypeID () { return UID_ObjectTypeA;};
}

//< GAME OBJECT SOURCE

void GameObjectTypeA::Init(GameObjectParams* params)
{
GameObjectTypeAParams* tparams = (GameObjectTypeAParams*) params; //< this cast is always safe - but feel free to use templates, dynamic casting or what ever here

///< transfer the parameters
m_ObjectAData = tparams->m_ObjectAData;
}




That's it for defining a real game object, now you just need some code to create them. despite using the rather cheesy 'MyGame' class here, I'm sure you get the idea.

Game Code

//< SOURCE

void MyGame::AddGameObjectParams(GameObjectParamsManager& GameObjectMan)
{
//< add all the different types of game parameters into the manager
GameObjectMan.AddParameters(new GameObjectTypeAParams);

/* obviously new object type would need new calls such as below
GameObjectMan.AddParameters(new GameObjectTypeBParams);
GameObjectMan.AddParameters(new GameObjectTypeCParams);
GameObjectMan.AddParameters(new GameObjectTypeDParams);
*/

}

void MyGame::CreateGameObjects(GameObjectParamsManager& GameObjectMan)
{
GameObjectParams* params = GameObjectMan.GetParams(UID_ObjectTypeA);

if (params)
{
//< cast and fill in any changes to the default parameters here

GameObject* object = GameObjectMan.CreateGameObject(params);

//< add the created object to your game
m_GameObjectsList.InsertAtEnd(object); //<
}
else
{
//< throw an exception or what ever you fancy here
}
}




Every time you need to add a new type of GameObject to your code you just make a parameter object as well (usually just a few extra lines). Remember, all the different types of parameter object should be added into the manager (using AddParameters) when the game starts up, then whenever you need a new object, just call GetParams, fill in the values and the send it into
CreateGameObject. Result, the correct game object all filled in and ready to go.

Obviously I've missed out some areas where the pointer coming out of a function would need to be cast into a real (useful) pointer (i.e. the return from GetParams) this is because your choice of casting will no doubt be different to mine.

Cast how ever you like. then fill in the parameters how ever you like (my choice is usually to read them from a file) then the cast or un-cast parameters pointer can just be sent into CreateGameObject.



I hope all the ramble helps.

Share this post


Link to post
Share on other sites
Hey sorry man, been swamped at work,
I've been pouring over your reply in little bits of time I can find,
and it seems like maybe a bit more lightweight approach to the same method
I am using, which is probably a good thing.

Thanks for the reply, I just haven't had a second to breath lately.

Share this post


Link to post
Share on other sites
I will reply later this weekend with what I think is an even better system that is a lot more generic and extendable. I just have to leave the house so people can come look at it and make an offer *fingers crossed* then food shopping and spend time with the wife. So it might not be until Monday. Hopefully the wait will be worth it.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mike2343
I will reply later this weekend with what I think is an even better system that is a lot more generic and extendable. I just have to leave the house so people can come look at it and make an offer *fingers crossed* then food shopping and spend time with the wife. So it might not be until Monday. Hopefully the wait will be worth it.


Looking forward to hearing it.

Share this post


Link to post
Share on other sites
My solution is a hybrid between Sneftel's posting on Outboard component-based entity system architecture and T=Machine's articles on Entity Systems. You can also find a nice compilation of links on the subject in this post by Nairb.

I basically leaned more towards T=Machine's Entity System then Sneftel's Component system. I just felt it was more game oriented but you can use which ever you think is better or not :)

My entity system is used to create game objects, gui components and other in game items (I made a generic EntitySystem that different systems can use).

So I can create a window entity that loads from an xml file (currently just text files as I threw it together as a test system) and it knows it needs 4 buttons, a text window with a vertical scroll bar. Each of these items are components that make up the larger window component. The window itself has no clue how to interact with each of its sub components. The scroll bar knows how to scroll the text in it's text window. The buttons know (says in the text file) what messages to fire to the system when clicked. So the window is basically dumb as it should be and the logic is held and handled in the components where it should be.

I was thinking about how you could update your objects upon loading and thought of a UpdateComponent which takes itself and passes it to another system that updates all it's data?

Anyways instead of writing up a boat load of information in it, it's already done for me in the links above. So I will let you read them instead of my boring stuff :)

I just thought it would be a great system for your issue which minimizes programmers requirements (aka work) and maximizes designers ability to design and create. It also makes things very, very data driven.

For example the button took me 10 minutes to write up the logic for it and it now works for all buttons. If I needed to add more functionality to it, I could create a different button component OR just add to the one I have. It would still be very trivial either way. I know the button wasn't the best example as I still have to code more logic in to handle the message it dispatches to the engine, but it's what I worked on most recently so it was "close to mind". The articles above give better examples more geared towards your current work.

Hope, in some way, this is handy and/or helpful.

Mike

Share this post


Link to post
Share on other sites
Interesting topic! Those two links you provided, Mike2343, sounds really interesting, I'll have to read up on those!

I've been working on a component based entity system myself for some time, and I've landed on a component based thing for data driven xml definitions of entityTypes that I can then use in my code as a prototype to copy other entities of the same type from.

To prevent many to many relationships between countless components, I've also used a publish/subscribe event system, sigslot, for communication between components, which have worked really well for me.

Here's a link to my code with some explanations (though this is a slightly old version, so the entity factory isn't as safe to use as it is now, and the entityType concept hasn't been implemented in this version):

http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=27319

Share this post


Link to post
Share on other sites
Here is another cool thing about these types of systems and shows how versatile they are.

Say you have a tree, it could be made up of a SeasonComponent that physically changes the look of the tree as the seasons of the game roll by. Even allowing a growth period where the tree expands, etc. You could also make it have a BurnableComponent that allows it to be destroyed, or partially. Then the SeasonComponent could start to regrow it after x seasons, etc.

The above idea came to me after one of our designers was asking how we could add seasons easily to the engine a few months ago. I then happened upon a thread on here about scene graphs where dmatter (sorry no link @ 3:40am) mentioned something like the above solution but which was contained in the scene graph. I rolled it into a component/entity system way of doing it.

It's easy to make a decent system if you have a nice communications system that doesn't make things interdependent. Otherwise the beauty of this system is completely lost. I've not looked over Trefall's event system but what most people call event systems I decided to call a message system ;-). From the sounds of it, his communicates between components (I've been wrong before) where mine is the engine communications system, though my system uses subscription to templated messages so you don't get every listener in the engine getting every message.

Ok, it's late and I likely rambled and made little sense.

Share this post


Link to post
Share on other sites
By interdependent, do you mean that components depend on each other through #include, or that they talk to each other via an event/message system?

I've managed to keep my components #include independent, but I'm using the event/message manager to channel events that updates multiple components for an entity.

With my event manager I can update components that subscribe to events per entity or all subscribers. I find myself using the per entity events more than the global one though. I also subscribes member functors instead of switching through enums.

I read briefly over T=Machine's blog, and it looks interesting. I'll have to read through it more thoroughly, but my impression was that there are one system class per component type. So if you have an InputReceiver component, you'd have an InputSystem to manage the component, or if you have a physicalBody component, you have a PhysicsSystem that manages every instance of that component.

I have that in my system too, only that in addition, the components can talk to each other through an EventSystem, or MessageSystem. I like to call it an Event System because a subscriber's functor to an event describes a logical reaction to that event for the component to perform.

If there's an entity that holds a SceneNode component, an InputReceiver component and an OverTheShoulderCameraController component (practically a player controlled entity), then if the SceneNode component subscribes it's onMoveForward functor to the event "OnKeyWPressed", and the OverTheShouldCameraController component subscribes it's onFollowTarget functor to the event "OnMoveForward", then that results in a logical chain of events and reactions to those events, at least in my mind, that result in a completeness of the system, where each component plays out it's designated functionality to an event.

Of course, I could also have had both the onMoveForward functor of SceneNode com and the onFollowTarget functor of OTSCamCtrl com both listen to the InputReceiver com, but then that would be a breach in logical reaction in my mind, because the camera doesn't logically react on an input event, but rather on the event that the scenenode's position changed.

Share this post


Link to post
Share on other sites
No I don't use #includes between components that would defeat the whole system in my mind. No component should directly know of another (it might know how to request information through the messaging system of course) otherwise you need to re-examine your component(s) to see if they need to be merged or something.

I call things messages within the engine because anything can message something else if it knows how to listen (I use templated messages). I reserve the term "events" for input from the player or anything in the game (a door opening event, etc). But it's basically tomato, toMATo :)

****

If I have an ogre that is AI controlled it has an AIComponent and that gets passed on to the AI system (a separate DLL in my case, that expects to take in an AIComponent) and controlled from there. The AIComponent just holds data values for the object in question. I read over my posts above and decided how they were handled in my system wasn't overly clear.

Share this post


Link to post
Share on other sites
Ah, I don't include either, but use publish instead of request. So I do an operation then emit a new event with any data I might have created in the current functor, as I made an example of in my last post here.

I think it's quite interesting how you describe the system - component relationship though. So, the component are only holding properties, so to speak, while the system holds the actual logic that it performs on the properties of the component? That sounds very abstract.

In my approach, each component holds on to their own logic, and since it's the components that get instanced, while the system is a singleton (in my framework anyway), I'm sure you save some resource and optimize it better doing it your way.

But for different kinds of AI, or different levels of AI, for example, would you then have to have two or more AISystems? Or would the AISystem's logic be so generic that you only have to change the properties/data in the component? Or isn't this an issue at all?

I'm getting close to the point where AI will be implemented now, and I'm not sure yet if I want to do it using a base AIComp to inherit from and then make a hierarchy of different types of AI behaviors, or if I want to make it more modular. I generally prefer modular approaches though... but I'm not even sure if I will have to go any of those directions. Maybe just changing the properties/data of the component would be good enough.

Oh, and I actually call Messages for Actions, keeping the Events reserved for the same purpose as yourself.

It's quite complex to break up components though, especially when you're using this approach on top of other thirdparty libraries and can't integrate it completely with the engine. So in some occassions I've failed to find optimal clean solutions for component seperation, but I strive to keep it as seperate as possible. Like, my PhysicalBody component needs the SceneNode component's node pointer to do some initialization and to store it in the body's userData (using NewtonDynamics). But this dependency is handled through the init function on the component, so I've defined it as alright to pass in variables from other components here, but that's it. I know that's not an optimal solution though.

Share this post


Link to post
Share on other sites
I just got home now and don't have the mental energy to reply. I'll reply on Friday hopefully either give you ideas for your AI or at least shed light on how we do it. Long days suck! :)

Share this post


Link to post
Share on other sites
Spring Framework, according to the wiki is just a collection of tools basically. The Inversion of Control container seems to have some features similar to Component-Based System Architecture but if you click on the link in the Sprint Framework to Inversion of Control it's actually not. So... *shrug* no idea. Not a java guy :)

Share this post


Link to post
Share on other sites
Quote:

I think it's quite interesting how you describe the system - component relationship though. So, the component are only holding properties, so to speak, while the system holds the actual logic that it performs on the properties of the component? That sounds very abstract.


Yes, it was more the way T=Machine described it and I like abstract like that. So its how I went. So far, very, very happy with it. With the GUI it's a bit different in that there isn't a "system" for each widget, instead a message is fired if a button is hit. The message is then dispatched to the function that requests its info and is passed the ButtonComponent which contains the needed info. With AI you just pass each AIComponent on each update to the AI System.

Quote:

In my approach, each component holds on to their own logic, and since it's the components that get instanced, while the system is a singleton (in my framework anyway), I'm sure you save some resource and optimize it better doing it your way.


That seems to be more the Component-Based System Architecture way, which is fine too. I just like simple and abstract when possible. You likely don't need it to be a singleton, likely a global might work a lot better. I won't get into my disdain for the singleton here lol.

Quote:

But for different kinds of AI, or different levels of AI, for example, would you then have to have two or more AISystems? Or would the AISystem's logic be so generic that you only have to change the properties/data in the component? Or isn't this an issue at all?


Actually, I'm not the one doing the AI coding butttttttttt I do peek at the code now and then ;-) So AIComponent holds a lot of data. Object type (grunt, orc, etc). It looks like once the AI System gets the AIComponent it fires off the data to different areas based on different criteria. Like, "Oh your an Orc, you are handled by this class/function, oh your a Human NPC, you are handled by this other class/function".

I'll finish up addressing the last two paragraphs either later tonight or tomorrow. Sorry, just one of those days.

*** EDIT ***

Just finishing up my reply:

Quote:

I'm getting close to the point where AI will be implemented now, and I'm not sure yet if I want to do it using a base AIComp to inherit from and then make a hierarchy of different types of AI behaviors, or if I want to make it more modular. I generally prefer modular approaches though... but I'm not even sure if I will have to go any of those directions. Maybe just changing the properties/data of the component would be good enough.


I would just store the information in data for different types and dispatch it off to the different handlers for those AI types. One variable like we have would work great. Could be a char or int depending on how many different types you have, or sub types.

Quote:

It's quite complex to break up components though, especially when you're using this approach on top of other thirdparty libraries and can't integrate it completely with the engine. So in some occassions I've failed to find optimal clean solutions for component seperation, but I strive to keep it as seperate as possible. Like, my PhysicalBody component needs the SceneNode component's node pointer to do some initialization and to store it in the body's userData (using NewtonDynamics). But this dependency is handled through the init function on the component, so I've defined it as alright to pass in variables from other components here, but that's it. I know that's not an optimal solution though.


Separation is great and something I always strive for. I use a layer between 3rd party libraries all the time, this way I can pass in my components easily. It's more work but means I can change say physics libraries very easily and only the layer code needs to be changed the engine has no clue or do the components.

Hope this helps. You can message me personally if you have more specific questions.

[Edited by - Mike2343 on June 1, 2008 3:09:00 PM]

Share this post


Link to post
Share on other sites

This topic is 3488 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this