public abstract class Entity
{
private List<Component> _components = new List<Component>();
private List<Entity> _children = new List<Entity>();
public void AddChild(Entity child)
{
_children.Add(child);
}
public void RemoveChild(Entity child)
{
_children.Remove(child);
}
public Entity[] GetChildren()
{
return _children.ToArray();
}
public void AddComponent<T>()
where T : Component
{
if (_components.Find((c) => c is T) != null) {
return; // each entity can only contains one type of component at the same time
}
var component = (T)Activator.CreateInstance(typeof(T));
component.Owner = this;
_components.Add(component);
}
public void RemoveComponent<T>()
where T : Component
{
var component = _components.Find((c) => c is T);
if (component == null) {
return;
}
component.Owner = null;
_components.Remove(component);
}
public Component[] GetComponents()
{
return _components.ToArray();
}
}
public class Scene : IRenderable, IUpdatable, IInputable
{
private List<Entity> _entities = new List<Entity>();
public bool Enabled { get; set; }
public bool Visible { get; set; }
public void Add(Entity entity)
{
_entities.Add(entity);
}
public void Remove(Entity entity)
{
_entities.Remove(entity);
}
// Render, Update and Input function in the Scene will automatically called at the game loop by game window
public void Render(RenderTarget target, RenderStates states)
{
if (Visible)
{
foreach (var entity in _entities)
{
if (entity is IRenderable) {
((IRenderable)entity).Render(target, states);
}
}
}
}
public void Update(double delta)
{
if (Enabled)
{
foreach (var entity in _entities)
{
if (entity is IUpdatable) {
((IUpdatable)entity).Update(delta);
}
}
}
}
public void Input(InputEventArgs e)
{
if (Enabled)
{
foreach (var entity in _entities)
{
if (entity is IInputable) {
((IInputable)entity).Input(e);
}
}
}
}
}
At the shown code above, the
Sceneis not responsible to check theEntitychildren and it's components, and it also possible to add anotherEntityas a child while implementing interface that not implemented by it's parent. Consider following example:public class CustomEntity : Entity { // Some codes here... } public class Sprite : Entity, IRenderable { public bool Visible { get; set; } // ... public void Render(RenderTarget target, RenderStates states) { // If the sprite is not visible, it should not render itself and ignore the children if (!Visible) { return; } // Render the sprite here... // Since scene does not check the Entity children, // We need to render the child and components in case they implement IRenderable foreach (var child in GetChildren()) { if (child is IRenderable) { if (((IRenderable)child).Visible) { ((IRenderable)child).Render(target, states); } } } foreach (var component in GetComponents()) { if (component is IRenderable) { if (((IRenderable)component).Visible) { ((IRenderable)component).Render(target, states); } } } } }