Jump to content
  • Advertisement
Sign in to follow this  
Zakwayda

Opinions on entity management code

This topic is 5400 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

I've been working on my entity management system, and would like to post some code in the hopes of getting some feedback on it. I know it takes time to go through other people's code, so I'll be very appreciative if anyone takes the time to look at this. Basically, I'm trying to solve the standard problem of dealing with multiple object types (related through inheritance) through a standard interface. The main things I'm trying to avoid are a) hard coding the object types (i.e. no 'if (type == TYPE_BULLET) return new Bullet'), and b) using rtti and dynamic_cast. I haven't succeeded with b, but the usage is limited and is contained within the factory class, so the client doesn't have to worry about it. The idea is that EntityMgr uses a templated member function to return an Entity-derived class of any type. The EntityMgr maintains a map of templated EntityFactories keyed to the class name (which is where the rtti comes in). When an entity is requested, the EntityMgr first checks to see if it has a factory for that type; if it doesn't, it creates one. Then, it obtains a new entity from the factory and returns it to the caller. Here is the code, stripped of all but the relevant stuff. (Note that eventually a smart pointer or handle system will be used). The Entity class:
class Entity
{
public:

    Entity() {}
    ~Entity() {}
	
    virtual bool Update() {}
    virtual void Render() {}
};


The EntityFactory interface class:

class IEntityFactory
{
public:

    IEntityFactory() {}
    virtual ~IEntityFactory() {}
	
    virtual Entity* NewEntity() = 0;
};



The EntityFactory class:

template <class T> class EntityFactory : public IEntityFactory
{
public:

    EntityFactory() : IEntityFactory() {}
    virtual ~EntityFactory()
    {
        for (int i = 0; i < m_activelist.size(); i++)
            delete m_activelist;
        for (int i = 0; i < m_freelist.size(); i++)
            delete m_freelist;
    }

    virtual Entity* NewEntity()
    {
        T* ep;
        if (m_freelist.size())
        {
            ep = m_freelist.back();
            m_freelist.pop_back();
        }
        else
            ep = new T;
			
        m_activelist.push_back(ep);
        return ep;
    }

private:

    vector<T*>	m_activelist;
    vector<T*>	m_freelist;	
};





//

The entity manager class:

class EntityMgr
{
public:

    EntityMgr() {}
    ~EntityMgr()
    {
        map<string, IEntityFactory*>::iterator itor;
        for (itor = m_factories.begin(); itor != m_factories.end(); itor++)
            delete itor->second;
    }
	
    template <class T> T* NewEntity()
    {
        string classname(typeid(T).name());

        if (m_factories.find(classname) == m_factories.end())
            m_factories[classname] = new EntityFactory<T>;

        return dynamic_cast<T*>(m_factories[classname]->NewEntity());
    }

private:

    typedef map<string, IEntityFactory*> m_factories;	
};





//

If anyone has any advice, can point out any problems, or can recommend a better system, I'd love to hear about it. Thanks very much. [Edit: tried to improve the code formatting, but without much luck. For some reason, I couldn't add blank lines between the classes. I know it makes it harder to read - sorry about that.] [Edit: improved code formatting] [Edited by - jyk on October 4, 2004 12:24:05 AM]

Share this post


Link to post
Share on other sites
Advertisement
80 views and no replies - ouch! Well, if there's anything I could have done to make my post more clear or easier to read, let me know. I know there are many people here who are extremely knowledgeable in regards to object-oriented software design, so I figured someone would be able to give me some feedback on the methods I'm using. I tried to strip the code down to its bare essentials, but maybe it was still too much to look through...

Share this post


Link to post
Share on other sites
Hmmm, it looks like you are creating a new entity factory for every entity derived class, am I right?

An easier solution may be to simply "register" all entity classes with one factory class. This single factory class would basically replace all your multiple factory classes.

This article should hopefully explain how to do this.


- Houdini

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Yeah, it looks fine. But as always, how it will turn out in reality largely depends on its context. There are many ways to solve any problem. The OOP-design is the forte of your approach.

Some ideas though:

Do you really need a factory class? Usually I let my objects register themselves, or let the manager class handle that. Not saying that is always better, of course.

Also, when registering an entity, I sometimes prefer to directly assign it to a specific list depending on its type. That saves a lot of type-checking later on.

Share this post


Link to post
Share on other sites
Thanks very much for your replies!

Quote:
I have to worry that your tougher problems are to come, however.


Did you have anything specific in mind? Anything I should be thinking about?

Quote:
Hmmm, it looks like you are creating a new entity factory for every entity derived class, am I right?

An easier solution may be to simply "register" all entity classes with one factory class. This single factory class would basically replace all your multiple factory classes.

This article should hopefully explain how to do this.


Thanks very much for the link - I read both the article and the original pluggable factories article, and went over all the source carefully.

Actually, the original article does create a separate factory or 'maker' for each class. The gamedev article uses function pointers, but the concept is the same - a registry mapping a key (integer constant, class name, etc.) to an object creator (templated factory, pointer to creator function, etc.).

Although my implementation is a little more involved than the gamedev article, it does support some additional functionality that I thought was important. One thing is that it doesn't create a new entity every time one is requested - instead, it maintains a 'free' list of inactive entities, and returns one from there if any are available. This requires that the 'creator' component of the registry be a little more complicated than a simple function pointer - in this case, a separate class that maintains a list of 'active' and 'inactive' entities.

As far as registering classes go, my idea was to make the first request for an entity of a specific type also register that type. That way, you don't have to call a RegisterClass() function for every class you want to support - just ask for one via the NewEntity() function, and it will automatically be registered.

These are just my thoughts though. If I've misunderstood any of your points, please feel free to clarify. I do want my implementation to be as simple and streamlined as possible. But at this point I'm not sure how I would support the same functionality while removing the 'intermediate' step of the EntityFactory.

Further thoughts are welcome!

Share this post


Link to post
Share on other sites
Just another way to think about things, what I'll most likely be doing in my game soon for entity management. I'm planning on having a text file (or something similar) which holds the definitions of a creature, like:

"Orc noncombatant", "entities.intelligent.Basic", "30", "25", "3", "passive"
"Orc warrior", "entities.intelligent.Basic", "60", "45", "7", "aggressive"
"Gunkhort the Mighty", "entities.intelligent.named.Gunkhort"
"Rabbit", "entities.Animal", "5", "10", "timid"
"Ancient Blue Dragon", "entities.intelligent.AncientBlueDragon", "3"

Where each line contains the display name of the creature, the class which implements it, and a variable set of parameters which will be passed to the class constructor. Note I am using Java as a language, so I don't have to register a class factory or anything, I can just use Class.forName() to get an instance of my creature object, thus the human-readable class name as the second parameter.

Specific creatures may not need all the parameters of others. The "generic" types of creatures obviously need more than specific ones, as demonstrated by comparing the Orc entries to Gunkhort and the dragon. The orcs have attack value, defense value, level, and AI mode, where as the dragon only has a level (obviously a level 3 Ancient Blue Dragon is vastly more powerful than a level 3 Orc, but that difference is handled by the creature class), and Gunkhort needs no parameters, since he is a unique creature with custom AI and hardcoded stats.

Anyway, just some more thoughts for you. Good luck with your game!

Share this post


Link to post
Share on other sites
Quote:
Original post by jyk
Thanks very much for the link - I read both the article and the original pluggable factories article, and went over all the source carefully.

Actually, the original article does create a separate factory or 'maker' for each class. The gamedev article uses function pointers, but the concept is the same - a registry mapping a key (integer constant, class name, etc.) to an object creator (templated factory, pointer to creator function, etc.).

True, it's close, but with your multiple factory implementation, you need to create new instances of the each entity factory class, which is slower than just storing a function pointer (this is assuming you use a decent compiler such as VC++ 2003).

Quote:
Original post by jyk
Although my implementation is a little more involved than the gamedev article, it does support some additional functionality that I thought was important. One thing is that it doesn't create a new entity every time one is requested - instead, it maintains a 'free' list of inactive entities, and returns one from there if any are available. This requires that the 'creator' component of the registry be a little more complicated than a simple function pointer - in this case, a separate class that maintains a list of 'active' and 'inactive' entities.

Yes, I noticed this after I posted the link. However, if you are familiar with template policies, you could easily create a object factory class that contains a "creation policy". The default creation policy could just call new/delete, while a more involved one would keep a free/used list.

While it may make the code a little more involved it does make for a truely generic, useful factory class that can be reused over and over. So if you want to create a similar system for something other than entities, such as resources, you don't have to copy/paste the current entity one, make changes, etc.

Quote:
Original post by jyk
As far as registering classes go, my idea was to make the first request for an entity of a specific type also register that type. That way, you don't have to call a RegisterClass() function for every class you want to support - just ask for one via the NewEntity() function, and it will automatically be registered.

Good point. This, of course, results in a more of compile time implementation of the object factory compared to the run-time implementation of the object factory article. Nothing wrong with that, however. Each has their place.

Also, keep in mind that, however, that using type_info::name() could cause issues on other compilers. The C++ Standard does not say that type_info::name() must be unique for every class. That is, type_info::name() could possibly return the same name for two different classes.

Of course, with any well known compiler this shouldn't be an issue, but it's always something to keep in mind if you wanted the code to be portable to as many compilers as possible.


- Houdini

Share this post


Link to post
Share on other sites
Thanks for the excellent info.

I have heard of (but don't know much about) policies, and will look into them.

It would be cool if this could be abstracted further and be used for all resources - textures, shaders, sounds, entities, etc. - so I'll keep working towards that.

The thought of type_info.name() possibly not being unique for every class is disconcerting. What about .rawname()? It seems that by definition that would have to be unique? Then again, maybe I'll end up using some other method entirely...

Thanks again for taking the time to look at my code.

Share this post


Link to post
Share on other sites
Quote:
Original post by jyk
Thanks for the excellent info.

I have heard of (but don't know much about) policies, and will look into them.

Modern C++ Design by Andrei Alexandrescu is a great book that introduces, among other things, policies.

Quote:
Original post by jyk
The thought of type_info.name() possibly not being unique for every class is disconcerting. What about .rawname()? It seems that by definition that would have to be unique? Then again, maybe I'll end up using some other method entirely...

While raw_name() is a faster, and less readable, version of name() it unfortunately is a MSVC only function. Other compilers won't support it.

You may want to instead store type_info in your map instead of the class string name. However, since type_info doesn't have copy/assignment operators it can't be stored, so you'll need to write a simple wrapper class that stores a pointer to a type_info class, and create your own copy/assignment functions. Again, Modern C++ Design shows how this is done, or you can simply download the source from the book and use the type_info wrapper class provided.


- Houdini

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!