From d94d6bc8f34f2be2f79ef7059251d3688b8d3aa0 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 13 Jun 2019 20:28:26 -0700 Subject: [PATCH] some basic entity and component structure --- src/Component.cs | 5 +-- src/ComponentManager.cs | 90 +++++++++++++++++++++++++++++++++++++++++ src/Entity.cs | 39 +++++------------- src/EntityManager.cs | 45 +++++++++++++++++++++ src/World.cs | 23 +++++++++++ src/encompass-cs.csproj | 27 +++++++------ test/EntityTest.cs | 14 +++---- 7 files changed, 190 insertions(+), 53 deletions(-) create mode 100644 src/ComponentManager.cs create mode 100644 src/EntityManager.cs create mode 100644 src/World.cs diff --git a/src/Component.cs b/src/Component.cs index c3117a0..d0660f8 100644 --- a/src/Component.cs +++ b/src/Component.cs @@ -1,7 +1,4 @@ namespace Encompass { - public abstract class Component - { - public int EntityID { get; set; } - } + public abstract class Component {} } diff --git a/src/ComponentManager.cs b/src/ComponentManager.cs new file mode 100644 index 0000000..06be097 --- /dev/null +++ b/src/ComponentManager.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Encompass { + internal class ComponentManager { + private Dictionary> entityIDToComponents = new Dictionary>(); + + private Dictionary> activeComponents = new Dictionary>(); + private Dictionary> inactiveComponents = new Dictionary>(); + + private List componentsToActivate = new List(); + private List componentsToDeactivate = new List(); + private List componentsToRemove = new List(); + + internal TComponent CreateComponent(uint entityID) where TComponent : Component, new() { + var component = new TComponent(); + + if (!entityIDToComponents.ContainsKey(entityID)) { + entityIDToComponents.Add(entityID, new List()); + } + + entityIDToComponents[entityID].Add(component); + + if (!activeComponents.ContainsKey(typeof(TComponent))) { + activeComponents.Add(typeof(TComponent), new List()); + inactiveComponents.Add(typeof(TComponent), new List()); + } + + MarkForActivation(component); + + return component; + } + + internal IEnumerable GetComponentsByEntity(uint entityID) { + return entityIDToComponents[entityID]; + } + + internal IEnumerable GetActiveComponentsByType() where TComponent : Component { + return activeComponents[typeof(TComponent)].Cast(); + } + + internal IEnumerable GetComponentsByEntityAndType(uint entityID) where TComponent : Component { + var entity_components = GetComponentsByEntity(entityID); + var active_components_by_type = GetActiveComponentsByType(); + return entity_components.Intersect(active_components_by_type).Cast(); + } + + internal bool EntityHasComponentOfType(uint entityID) where TComponent : Component { + return GetComponentsByEntityAndType(entityID).Any(); + } + + internal void RemoveAllComponentsFromEntity(uint entityID) { + var components = GetComponentsByEntity(entityID); + + foreach (var component in components) { + activeComponents[component.GetType()].Remove(component); + inactiveComponents[component.GetType()].Remove(component); + } + + entityIDToComponents.Remove(entityID); + } + + internal void MarkForActivation(Component component) { + componentsToActivate.Add(component); + } + + internal void MarkForRemoval(Component component) { + componentsToRemove.Add(component); + } + + internal void ActivateComponents() { + foreach (var component in componentsToActivate) { + activeComponents[component.GetType()].Add(component); + inactiveComponents[component.GetType()].Remove(component); + } + + componentsToActivate.Clear(); + } + + internal void RemoveComponents() { + foreach (var component in componentsToRemove) { + activeComponents[component.GetType()].Remove(component); + inactiveComponents[component.GetType()].Remove(component); + } + + componentsToRemove.Clear(); + } + } +} diff --git a/src/Entity.cs b/src/Entity.cs index b52d3e3..9b76c5f 100644 --- a/src/Entity.cs +++ b/src/Entity.cs @@ -6,41 +6,21 @@ namespace Encompass { public class Entity { - public readonly static List Empty = new List(); + public readonly uint id; - public readonly int id; + private ComponentManager componentManager; - private readonly Dictionary> componentBag = new Dictionary>(); - private readonly Dictionary> activeComponents = new Dictionary>(); - - public Entity(int id) { + internal Entity(uint id, ComponentManager componentManager) { this.id = id; + this.componentManager = componentManager; } public TComponent AddComponent() where TComponent : Component, new() { - TComponent component = new TComponent(); - - if (!componentBag.ContainsKey(typeof(TComponent))) { - var componentList = new List(); - var activeComponentList = new List(); - componentBag.Add(typeof(TComponent), componentList); - activeComponents.Add(typeof(TComponent), activeComponentList); - componentList.Add(component); - activeComponentList.Add(component); - } else { - componentBag[typeof(TComponent)].Add(component); - activeComponents[typeof(TComponent)].Add(component); - } - - return component; + return componentManager.CreateComponent(id); } public IEnumerable GetComponents() where TComponent : Component { - if (activeComponents.ContainsKey(typeof(TComponent))) { - return activeComponents[typeof(TComponent)].Cast(); - } else { - return Enumerable.Empty(); - } + return componentManager.GetComponentsByEntityAndType(id); } public TComponent GetComponent() where TComponent : Component { @@ -48,8 +28,11 @@ namespace Encompass } public bool HasComponent() where TComponent : Component { - return activeComponents.ContainsKey(typeof(TComponent)) && - activeComponents[typeof(TComponent)].Count != 0; + return componentManager.EntityHasComponentOfType(id); + } + + internal void RemoveAllComponents() { + componentManager.RemoveAllComponentsFromEntity(id); } } } diff --git a/src/EntityManager.cs b/src/EntityManager.cs new file mode 100644 index 0000000..e6ea3e9 --- /dev/null +++ b/src/EntityManager.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Encompass { + internal class EntityManager { + private uint nextID = 1; + + private List entities = new List(); + private Dictionary IDToEntity = new Dictionary(); + + private List entitiesMarkedForDestroy = new List(); + + private ComponentManager componentManager; + + public EntityManager( + ComponentManager componentManager + ) { + this.componentManager = componentManager; + } + + public Entity CreateEntity() { + return new Entity(NextID(), componentManager); + } + + public Entity GetEntity(uint id) { + return this.IDToEntity[id]; + } + + public void MarkForDestroy(Entity entity) { + entitiesMarkedForDestroy.Add(entity); + } + + internal void DestroyMarkedEntities() { + foreach (var entity in entitiesMarkedForDestroy) { + entity.RemoveAllComponents(); + } + } + + private uint NextID() { + var id = this.nextID; + this.nextID++; + return id; + } + } +} diff --git a/src/World.cs b/src/World.cs new file mode 100644 index 0000000..a934d3e --- /dev/null +++ b/src/World.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Encompass { + public class World { + EntityManager entityManager; + ComponentManager componentManager; + + public World() { + this.componentManager = new ComponentManager(); + this.entityManager = new EntityManager(componentManager); + } + + public void Update() { + componentManager.ActivateComponents(); + componentManager.RemoveComponents(); + } + + public Entity CreateEntity() { + return entityManager.CreateEntity(); + } + } +} diff --git a/src/encompass-cs.csproj b/src/encompass-cs.csproj index fab04c3..214ca26 100644 --- a/src/encompass-cs.csproj +++ b/src/encompass-cs.csproj @@ -1,12 +1,15 @@ - - - - netstandard2.0 - Encompass - - - - - - - + + + + netstandard2.0 + Encompass + + + + + + + + + + \ No newline at end of file diff --git a/test/EntityTest.cs b/test/EntityTest.cs index 32df1db..a36f937 100644 --- a/test/EntityTest.cs +++ b/test/EntityTest.cs @@ -12,25 +12,21 @@ namespace Encompass public class EntityTest { - /* - [SetUp] - public void Setup() - { - } - */ - [Test] public void AddComponent() { - var entity = new Entity(0); + var world = new World(); + var entity = world.CreateEntity(); + var mockComponent = entity.AddComponent(); mockComponent.myString = "hello"; mockComponent.myInt = 3; + world.Update(); + Assert.IsTrue(entity.HasComponent()); Assert.AreEqual(3, entity.GetComponent().myInt); Assert.AreEqual("hello", entity.GetComponent().myString); - Assert.AreEqual(0, entity.GetComponent().EntityID); } } }