I’m considering porting the java library Artemis. An entity system framework. I havn’t started yet. Instead I have been analyzing the internal works of how the java code is put together. I know there is half worked up CPP port.
I’ve looked at both codes and noticed that the java code puts certain things more elegantly.
And mainly the following:
package com.artemis;
import java.util.HashMap;
public class ComponentTypeManager {
private static HashMap<Class<? extends Component>, ComponentType> componentTypes = new HashMap<Class<? extends Component>, ComponentType>();
public static final ComponentType getTypeFor(Class<? extends Component> c){
ComponentType type = componentTypes.get(c);
if(type == null){
type = new ComponentType();
componentTypes.put(c, type);
}
return type;
}
public static long getBit(Class<? extends Component> c){
return getTypeFor(c).getBit();
}
public static int getId(Class<? extends Component> c){
return getTypeFor(c).getId();
}
}
And the componentType “object”
package com.artemis;
public class ComponentType {
private static long nextBit = 1;
private static int nextId = 0;
private long bit;
private int id;
public ComponentType() {
init();
}
private void init() {
bit = nextBit;
nextBit = nextBit << 1;
id = nextId++;
}
public long getBit() {
return bit;
}
public int getId() {
return id;
}
}
Basically what the componentTypeManager does is map a componentType to a class type.
Which makes it dynamic when adding new components.
The C++ port solution is as follows:
#ifndef __COMPONENT_TYPE_H__
#define __COMPONENT_TYPE_H__
namespace SGF
{
enum ComponentType
{
CT_TRANSFORM = 0,
CT_HEALTH,
CT_RENDERABLE,
CT_RIGID_BODY,
CT_JOINT,
CT_LAST
};
// Component type bits. Used by the entity systems to determine if an entity is compatible.
const unsigned int CT_TRANSFORM_BIT = 1 << CT_TRANSFORM;
const unsigned int CT_HEALTH_BIT = 1 << CT_HEALTH;
const unsigned int CT_RENDERABLE_BIT = 1 << CT_RENDERABLE;
const unsigned int CT_RIGID_BODY_BIT = 1 << CT_RIGID_BODY;
const unsigned int CT_JOINT_BIT = 1 << CT_JOINT;
};
#endif
Here the ComponentManager is completely left out. Instead an enum is used.
My problem with this is the fact you have to add new component types to the enumerator and the constants as “type” identifiers. The java framework allows you to pass a component class type to identify it’s id.
My question is, how would I go about to get a similar effect of passing a type to map it’s id like the Java code without hard coding enumerator types for every new component?
I know C++ doesn’t support class types as arguments. So this is rather mind boggling to me.
As long as you are not planning to instantiate components given their component type, and assuming that
Componenthas one or morevirtualfunction, using RTTI should be sufficient for your purposes. You can useunordered_mapin place ofHashMap, and replace theClass<C>withtype_info.One thing I’m not certain about is how
ComponentTypewould know what exact bits to return: the code instantiatesComponentTypewith no parameters when one is not found in the map, yet it’s assumed that different instances would return different patterns of set and unset bits. I assume this is because your hash map is pre-populated for known component types, though.