0
\$\begingroup\$

I´m currently trying to develop a Game, which uses Component based Entities. The problem I`m facing right now is how to mask my Components and retrieve them from the Entities. At the Moment i use a enumeration which has ab entry for each Component. Entities define then masks based on which Components they have associated. When I query for a Component i pass the correspoding enumeration value.

Here is a basic example to show how my Code works:

class Component
{
    public:
        enum Type
        {
            A       = (1u << 0),
            B       = (1u << 1)
        };
        virtual TypeBit() = 0;
};

class Entity
{
    public:
        shared_ptr<Component> GetComponent(Component::Type type);
        unsigned int TypeMask();
    private:
        std::list<shared_ptr<Component>> _components;
}

What I like i my approach is the simplicity of the Bitmasks with logic operations, i.e. to see if a System is interested in an Entity. The problem I have is, that, everytime when I add a new Component I have to add a new enumeration value. This adds potential for errors which is why I would prefer a more generic solution.

\$\endgroup\$
0
\$\begingroup\$

You're going to run out of bits soon, too.

Try turning your Type into a CRC created from a descriptive string and instead of a list use a dictionary for _components. That will remove the hard upper limit on types and maintain access speed. Also, no need to add new values all over the place which solves your immediate problem.

The long term view for the future is that with these strings and static factories you can later define your entities in a human friendly data file like XML (or even flat text files) and build entities at runtime from entries in that data file. Once you get deeper into coding you now have a basis for serialization and you can save and restore entire entities and their current state, but that's a really big task.

If you want to get fancy you can create a dictionary of strings to CRC to make runtime lookup cleaner and a reverse dictionary of CRC to string for debugging and human-friendly display.

\$\endgroup\$
  • \$\begingroup\$ so what currently is a bitmask for entities and systems in my setup would be a array of CRCs? \$\endgroup\$ – Horstinator Nov 30 '13 at 20:45
  • \$\begingroup\$ A dictionary that maps from CRC to the shared_ptr, much like your list is actually a mapping from bit to the shared_ptr. If you're unfamiliar with STL containers this is a quick tutorial on the map template cprogramming.com/tutorial/stl/stlmap.html If you want you can skip the CRC and use the string directly, which is what that example uses. The advantage here is that you can keep adding new types and you never have to change enumerations, plus the map can grow as large as needed. \$\endgroup\$ – Patrick Hughes Nov 30 '13 at 21:37
  • \$\begingroup\$ Is there a good C++ CRC implementation you can recommend? Or do I have to write one myself? \$\endgroup\$ – Horstinator Nov 30 '13 at 21:49
  • \$\begingroup\$ You could use an std::bitset. \$\endgroup\$ – jmegaffin Dec 1 '13 at 0:03
  • 1
    \$\begingroup\$ @Horstinator simplest way: the component ids are ints and you use this: lolengine.net/blog/2011/12/20/cpp-constant-string-hash , a compile time hashing algorithm that is technically not compile time, but the compiler will optimize it away in your release build. \$\endgroup\$ – TravisG Dec 1 '13 at 10:16
1
\$\begingroup\$

I am using strings as component type identifiers, and dictionaries with the type string as key and the component as value. But I am using C# which enumerates the strings for faster dictionary access, so you might want to do that in c++ by yourself, or just use the string. Any way, your systems need to have a list of keys it accepts, and then compare the list to the entity component collection.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.