add initial port of component-entity system

This commit is contained in:
Gered 2013-08-22 15:29:38 -04:00
parent 8205f7aa41
commit 2caa638d19
7 changed files with 498 additions and 0 deletions

View file

@ -144,7 +144,13 @@
<Compile Include="Events\Event.cs" /> <Compile Include="Events\Event.cs" />
<Compile Include="Events\EventManager.cs" /> <Compile Include="Events\EventManager.cs" />
<Compile Include="Events\IEventListener.cs" /> <Compile Include="Events\IEventListener.cs" />
<Compile Include="Entities\Component.cs" />
<Compile Include="Entities\EntityManager.cs" />
<Compile Include="Entities\ComponentSystem.cs" />
<Compile Include="Events\EventListener.cs" /> <Compile Include="Events\EventListener.cs" />
<Compile Include="Entities\Entity.cs" />
<Compile Include="Entities\EntityPool.cs" />
<Compile Include="Entities\SystemComponents\InactiveComponent.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<ItemGroup> <ItemGroup>
@ -160,6 +166,8 @@
<Folder Include="Graphics\CustomShaders\" /> <Folder Include="Graphics\CustomShaders\" />
<Folder Include="Graphics\Helpers\" /> <Folder Include="Graphics\Helpers\" />
<Folder Include="Events\" /> <Folder Include="Events\" />
<Folder Include="Entities\" />
<Folder Include="Entities\SystemComponents\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Resources\Fonts\Vera.ttf" /> <EmbeddedResource Include="Resources\Fonts\Vera.ttf" />

View file

@ -0,0 +1,11 @@
using System;
using Blarg.GameFramework.Support;
namespace Blarg.GameFramework.Entities
{
public abstract class Component : IPoolable
{
public abstract void Reset();
}
}

View file

@ -0,0 +1,49 @@
using System;
using Blarg.GameFramework.Events;
namespace Blarg.GameFramework.Entities
{
public class ComponentSystem : EventListener, IDisposable
{
public readonly EntityManager EntityManager;
public ComponentSystem(EntityManager entityManager, EventManager eventManager)
: base(eventManager)
{
if (entityManager == null)
throw new ArgumentNullException("entityManager");
EntityManager = entityManager;
}
public virtual void OnAppPause()
{
}
public virtual void OnAppResume()
{
}
public virtual void OnResize()
{
}
public virtual void OnRender(float delta)
{
}
public virtual void OnUpdate(float delta)
{
}
public override bool Handle(Event e)
{
return false;
}
public virtual void Dispose()
{
}
}
}

View file

@ -0,0 +1,38 @@
using System;
namespace Blarg.GameFramework.Entities
{
public class Entity
{
EntityManager _entityManager;
internal Entity(EntityManager entityManager)
{
if (entityManager == null)
throw new ArgumentNullException("entityManager");
_entityManager = entityManager;
}
public T Get<T>() where T : Component
{
return null;
}
public T Add<T>() where T : Component
{
return null;
}
public void Remove<T>() where T : Component
{
return;
}
public bool Has<T>() where T : Component
{
return false;
}
}
}

View file

@ -0,0 +1,356 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Blarg.GameFramework.Entities.SystemComponents;
using Blarg.GameFramework.Events;
using Blarg.GameFramework.Support;
namespace Blarg.GameFramework.Entities
{
using EntityList = List<Entity>;
using ComponentList = List<Component>;
using EntityToComponentMap = Dictionary<Entity, Component>;
using ComponentStore = Dictionary<Type, Dictionary<Entity, Component>>;
using GlobalComponentStore = Dictionary<Type, Component>;
using ComponentSystemList = List<ComponentSystem>;
public class EntityManager : IDisposable
{
public readonly EventManager EventManager;
EntityList _entities;
ComponentStore _components;
GlobalComponentStore _globalComponents;
ComponentSystemList _componentSystems;
EntityPool _entityPool;
EntityList _tempEntityList;
public EntityManager(EventManager eventManager)
{
if (eventManager == null)
throw new ArgumentNullException("eventManager");
EventManager = eventManager;
_entities = new EntityList();
_components = new ComponentStore();
_globalComponents = new GlobalComponentStore();
_componentSystems = new ComponentSystemList();
_entityPool = new EntityPool(this);
_tempEntityList = new EntityList(100);
}
#region ComponentSystem management
public T AddSubsystem<T>() where T : ComponentSystem
{
if (GetSubsystem<T>() != null)
throw new InvalidOperationException("ComponentSystem of that type is already registered.");
T subsystem = (T)Activator.CreateInstance(typeof(T), this, EventManager);
_componentSystems.Add(subsystem);
return subsystem;
}
public T GetSubsystem<T>() where T : ComponentSystem
{
int i = GetSubsystemIndex(typeof(T));
if (i == -1)
return null;
else
return (T)_componentSystems[i];
}
public void RemoveSubsystem<T>() where T : ComponentSystem
{
int i = GetSubsystemIndex(typeof(T));
if (i == -1)
return;
else
_componentSystems.RemoveAt(i);
}
public void RemoveAllSubsystems()
{
for (int i = 0; i < _componentSystems.Count; ++i)
_componentSystems[i].Dispose();
_componentSystems.Clear();
}
#endregion
#region Entity management
public Entity Add()
{
var entity = _entityPool.Take();
_entities.Add(entity);
return entity;
}
public Entity GetFirstWith<T>() where T : Component
{
EntityToComponentMap componentEntities;
_components.TryGetValue(typeof(T), out componentEntities);
if (componentEntities == null)
return null;
if (componentEntities.Count > 0)
return componentEntities.Keys.GetEnumerator().Current;
else
return null;
}
public void GetAllWith<T>(EntityList list) where T : Component
{
if (list == null)
throw new ArgumentNullException("list", "Must provide a list to store matching Entity's in.");
EntityToComponentMap componentEntities;
_components.TryGetValue(typeof(T), out componentEntities);
if (componentEntities == null)
return;
else
{
foreach (var i in componentEntities)
list.Add(i.Key);
}
}
public void Remove(Entity entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
RemoveAllComponentsFrom(entity);
_entities.Remove(entity);
_entityPool.Free(entity);
}
public void RemoveAll()
{
foreach (var entity in _entities)
{
RemoveAllComponentsFrom(entity);
_entityPool.Free(entity);
}
_entities.Clear();
}
#endregion
#region Component management
public T AddComponent<T>(Entity entity) where T : Component
{
if (GetComponent<T>(entity) != null)
throw new InvalidOperationException("Component of that type has been added to this entity already.");
EntityToComponentMap componentEntities;
_components.TryGetValue(typeof(T), out componentEntities);
if (componentEntities == null)
{
// need to create the component-to-entity list
componentEntities = new EntityToComponentMap();
_components.Add(typeof(T), componentEntities);
}
T component = ObjectPools.Take<T>();
componentEntities.Add(entity, component);
return component;
}
public T GetComponent<T>(Entity entity) where T : Component
{
EntityToComponentMap componentEntities;
_components.TryGetValue(typeof(T), out componentEntities);
if (componentEntities == null)
return null;
Component existing;
componentEntities.TryGetValue(entity, out existing);
if (existing == null)
return null;
else
return (T)existing;
}
public void RemoveComponent<T>(Entity entity) where T : Component
{
EntityToComponentMap componentEntities;
_components.TryGetValue(typeof(T), out componentEntities);
if (componentEntities == null)
return;
Component existing;
componentEntities.TryGetValue(entity, out existing);
if (existing == null)
throw new InvalidOperationException("Entity does not have this component.");
componentEntities.Remove(entity);
ObjectPools.Free<T>((T)existing);
}
public bool HasComponent<T>(Entity entity) where T : Component
{
EntityToComponentMap componentEntities;
_components.TryGetValue(typeof(T), out componentEntities);
if (componentEntities == null)
return false;
return componentEntities.ContainsKey(entity);
}
public void GetAllComponentsFor(Entity entity, ComponentList list)
{
if (list == null)
throw new ArgumentNullException("Must provide a list to store the Components for this Entity.");
foreach (var i in _components)
{
EntityToComponentMap entitiesWithComponent = i.Value;
Component component;
entitiesWithComponent.TryGetValue(entity, out component);
if (component != null)
list.Add(component);
}
}
#endregion
#region Global Component management
public T AddGlobalComponent<T>() where T : Component
{
if (GetGlobalComponent<T>() != null)
throw new InvalidOperationException("Global component of that type has been added already.");
T component = ObjectPools.Take<T>();
_globalComponents.Add(typeof(T), component);
return component;
}
public T GetGlobalComponent<T>() where T : Component
{
Component existing;
_globalComponents.TryGetValue(typeof(T), out existing);
if (existing == null)
return null;
else
return (T)existing;
}
public void RemoveGlobalComponent<T>() where T : Component
{
Component existing;
_globalComponents.TryGetValue(typeof(T), out existing);
if (existing == null)
throw new InvalidOperationException("No global component of that type exists.");
else
{
_globalComponents.Remove(typeof(T));
ObjectPools.Free<T>((T)existing);
}
}
public bool HasGlobalComponent<T>() where T : Component
{
return _globalComponents.ContainsKey(typeof(T));
}
public void RemoveAllGlobalComponents()
{
foreach (var i in _globalComponents)
ObjectPools.Free(i.Key, i.Value);
}
#endregion
#region Events
public void OnAppResume()
{
for (int i = 0; i < _componentSystems.Count; ++i)
_componentSystems[i].OnAppResume();
}
public void OnAppPause()
{
for (int i = 0; i < _componentSystems.Count; ++i)
_componentSystems[i].OnAppPause();
}
public void OnResize()
{
for (int i = 0; i < _componentSystems.Count; ++i)
_componentSystems[i].OnResize();
}
public void OnRender(float delta)
{
for (int i = 0; i < _componentSystems.Count; ++i)
_componentSystems[i].OnRender(delta);
}
public void OnUpdate(float delta)
{
_tempEntityList.Clear();
GetAllWith<InactiveComponent>(_tempEntityList);
foreach (var entity in _tempEntityList)
Remove(entity);
for (int i = 0; i < _componentSystems.Count; ++i)
_componentSystems[i].OnUpdate(delta);
}
#endregion
#region Misc support methods
private void RemoveAllComponentsFrom(Entity entity)
{
if (entity == null)
throw new ArgumentNullException("entity");
foreach (var i in _components)
{
var entitiesWithComponent = i.Value;
Component component;
entitiesWithComponent.TryGetValue(entity, out component);
if (component != null)
{
ObjectPools.Free(i.Key, component);
entitiesWithComponent.Remove(entity);
}
}
}
private int GetSubsystemIndex(Type type)
{
for (int i = 0; i < _componentSystems.Count; ++i)
{
if (_componentSystems[i].GetType() == type)
return i;
}
return -1;
}
#endregion
#region Disposable
public void Dispose()
{
RemoveAll();
RemoveAllGlobalComponents();
RemoveAllSubsystems();
}
#endregion
}
}

View file

@ -0,0 +1,24 @@
using System;
using Blarg.GameFramework.Support;
namespace Blarg.GameFramework.Entities
{
internal class EntityPool : ObjectPool<Entity>
{
EntityManager _entityManager;
public EntityPool(EntityManager entityManager)
{
if (entityManager == null)
throw new ArgumentNullException("entityManager");
_entityManager = entityManager;
}
protected override Entity Allocate()
{
return new Entity(_entityManager);
}
}
}

View file

@ -0,0 +1,12 @@
using System;
namespace Blarg.GameFramework.Entities.SystemComponents
{
public class InactiveComponent : Component
{
public override void Reset()
{
}
}
}