add initial port of component-entity system
This commit is contained in:
parent
8205f7aa41
commit
2caa638d19
|
@ -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" />
|
||||||
|
|
11
Blarg.GameFramework/Entities/Component.cs
Normal file
11
Blarg.GameFramework/Entities/Component.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
using Blarg.GameFramework.Support;
|
||||||
|
|
||||||
|
namespace Blarg.GameFramework.Entities
|
||||||
|
{
|
||||||
|
public abstract class Component : IPoolable
|
||||||
|
{
|
||||||
|
public abstract void Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
49
Blarg.GameFramework/Entities/ComponentSystem.cs
Normal file
49
Blarg.GameFramework/Entities/ComponentSystem.cs
Normal 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()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
38
Blarg.GameFramework/Entities/Entity.cs
Normal file
38
Blarg.GameFramework/Entities/Entity.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
356
Blarg.GameFramework/Entities/EntityManager.cs
Normal file
356
Blarg.GameFramework/Entities/EntityManager.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
24
Blarg.GameFramework/Entities/EntityPool.cs
Normal file
24
Blarg.GameFramework/Entities/EntityPool.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Blarg.GameFramework.Entities.SystemComponents
|
||||||
|
{
|
||||||
|
public class InactiveComponent : Component
|
||||||
|
{
|
||||||
|
public override void Reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in a new issue