public abstract class ComponentSystem<T> where T : Component
{
protected readonly List<T> components = new List<T>();
public void RegisterComponent(T component)
{
components.Add(component);
}
public void UnregisterComponent(T component)
{
components.Remove(component);
}
}
public sealed class StateSystem : ComponentSystem<StateComponent>
{
private static readonly StateSystem instance = new StateSystem();
public static StateSystem Instance
{
get { return instance; }
}
private StateSystem()
{
...
}
}
public class StateComponent : Component
{
public string State { get; set; }
public override void Register()
{
StateSystem.Instance.RegisterComponent(this);
}
public override void Unregister()
{
StateSystem.Instance.UnregisterComponent(this);
}
}
I was wondering if there's some way to set it up so that a Component can specify what system it belongs to and the base Component class code can just handle calling the Register/Unregister functions without the need of repeatedly implementing them. Thoughts?
Generic way of registering entity component with system
public abstract class Component
{
public Actor Entity { get; set; }
public bool Enabled { get; set; }
protected ComponentSystem<SomethingNeedsToBeHere> system;
protected Component()
{
Enabled = true;
}
/// <summary>
/// Called after a component is added to an entity.
/// </summary>
public virtual void Register()
{
system.RegisterComponent(this);
}
/// <summary>
/// Called before a component is removed from an entity. Clean up should be done here
/// </summary>
public virtual void Unregister() { ... }
}
I would do it slightly differently. In your system, implement an Initialise or Configure method that adds the relevant components to itself.
Something like:
public abstract class ComponentSystem<T> where T : Component
{
protected readonly List<T> components = new List<T>();
public abstract void Configure();
public void RegisterComponent(T component)
{
components.Add(component);
}
public void UnregisterComponent(T component)
{
components.Remove(component);
}
}
public sealed class StateSystem : ComponentSystem<StateComponent>
{
private static readonly StateSystem instance = new StateSystem();
public static StateSystem Instance
{
get { return instance; }
}
public void Configure()
{
this.RegisterComponent(new StateComponent() { State="New" });
}
private StateSystem()
{
...
}
}
public class StateComponent : Component
{
public string State { get; set; }
}
This way, the system manages the components, not the components managing their memberships of systems. And it also means that the components no longer depend on the system.
The second issue is that it would register the component the instant it's created, rather than after it's been attached to an entity. Probably a mostly meaningless concern, but it does change the intent of the register function and require an extra "if component.Entity != null" check.
The most straight-forward solution to your problem would probably be to make ComponentSystem<T> implement an interface that knows RegisterComponent(Component) and UnregisterComponent(Component) and make ComponentSystem<T> cast the argument to T so it can call the generic RegisterComponent(T).
The system I designed for my current project is a bit more generic, because I want it to allow components registered to multiple systems, etc. It basically looks like this:
public class Entity {
public List<Component> Components { get; set; }
}
// holds only data
public class Component {
public Entity Parent { get; set; } // may not even need this
}
public abstract class ComponentSystem {
public abstract void Initialize(ComponentSystemManager csm);
public abstract void Update();
}
public class ComponentSystemManager {
private Dictionary<Type, List<Action<Component>>> onComponentCreated;
public void SubscribeComponentCreated<T>(Action<T> onAdded) where T : Component
{
var key = typeof(T);
Action<Component> value = c => onAdded((T)c);
this.onComponentCreated[key].Add(value);
}
// this is the only place where component are created
public void CreateComponent<T>(Entity parent, Action<T> init) where T : Component, new()
{
var key = typeof(T);
var component = new T();
component.Parent = parent;
init(component);
parent.Components.Add(component);
foreach (var subscriber in onComponentCreated[key]) {
subscriber(component);
}
}
public void DestroyComponent(Component c) { ... }
}
public class ExampleComponent : Component
{
}
public class ExampleSystem : ComponentSystem
{
public override void Initialize(ComponentSystemManager csm)
{
csm.SubscribeComponentCreated<ExampleComponent>(this.ExampleComponentCreated);
}
private void ExampleComponentCreated(ExampleComponent c)
{
// ...
}
}
I see. My system is sort of similar. My model is based off Unity3d. I have an Entity class (GameObject) and a Component class. Components are created and added to the Entities, and the Component holds a reference back to the Entity it is attached to. This reference is set by the process of adding a component to the entity.
I don't have ComponentSystems, as Entities can have any types of Component added to them. If I we're to introduce Systems, I'd look at making them manage Entities, and then grab the required components off them. My GameObject class allows me to get a component by type, for example. I have constrained it by allowing only one component of a given type to be attached, but this was arbitrary.
Evolutional: What you described is pretty much exactly what I've done, especially the retrieving by type thing. How are you managing without any systems though? One of the main things I'm using systems for is rendering. I have a Renderable component that can be attached to an entity which holds a reference to a model. Then there's a RenderableSystem that has the code for going through and drawing any Renderable components