Game Object Creation System

Started by
18 comments, last by CrazyCdn 15 years, 10 months ago
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

==============================
A Developers Blog | Dark Rock Studios - My Site
Advertisement
No one has any comments on it at all?
==============================
A Developers Blog | Dark Rock Studios - My Site
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 kindclass 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 objectclass 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 objectsclass 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 objectprivate:	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 likeclass 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 SOURCEvoid 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
//< SOURCEvoid 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.
After asking a question, and getting a (long and rambling) reply I think it's usually common courtesy to reply, or say thanks ... or anything !!
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.
==============================
A Developers Blog | Dark Rock Studios - My Site
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.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

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.

Yes I'm very much looking forward to it as well
==============================
A Developers Blog | Dark Rock Studios - My Site
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

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

This sounds like a pretty darn cool system, not entirely exclusive it seems either, i mean it could be integrated with some of what I already do.
==============================
A Developers Blog | Dark Rock Studios - My Site

This topic is closed to new replies.

Advertisement