I have a class named GameObject that has a dynamic List of Components. Those components can be removed and added at any time. A Component could possibly be a Texture, Sound or Transition etc. What's the best way to ensure that this list always has one Transition component? Only one component of each type is allowed.
I have two posibble solutions in my mind. Which one of these is the best? And are there any better solutions to this problem?
Approach 1:
class GameObject {
private List<Component> components;
public T GetComponent<T>() where T : Component {
// search the requested component and return it
foreach(Component comp in components) {
if(comp is T) return (T)comp;
}
// return null or throw exception when not found
return null;
}
public void RemoveComponent<T>() where T : Component {
if(typeof(T) != typeof(Transition)) {
// only remove the componenent if it's not a Transition component
Component tmp;
foreach(Component comp in components) {
if(comp is T) tmp = comp;
break;
}
components.Remove(tmp);
}
}
}
Approach 2:
class GameObject {
// separate variable for the transition component
private Transition transition;
private List<Component> components;
public T GetComponent<T>() where T : Component {
// if a transition is requestet just return it
if(typeof(T) == typeof(Transition)) {
return transition;
}
// else: search the requested component in the list
foreach(Component comp in components) {
if(comp is T) return (T)comp;
}
// return null or throw exception when not found
return null;
}
public void RemoveComponent<T>() where T : Component {
if(typeof(T) != typeof(Transition)) {
// only remove the componenent if it's not a Transition component
Component tmp;
foreach(Component comp in components) {
if(comp is T) tmp = comp;
break;
}
components.Remove(tmp);
}
}
}
Seems like you are trying to create what is known as an entity component model. I suggest analyzing some engines which use that model, such as the Paradox Game Engine.
The Entity (GameObject) and PropertyContainer (component collection) should be of particular interest for you.
It's probably a good idea to keep the transition component both as a separate field and also store it in the components list. Since it's something that is guaranteed to be part of each game object, you could provide a separate getter property for direct access to this component to bypass any lookup cost.
Since you seem to allow only one component per type, it would be efficient to store the components in a
Dictionary<Type, Component>
. That would provide really quick lookups in comparison to iterating over the the components and doing type comparisons.A slightly modified version of your 2nd approach: