some basic entity and component structure

pull/5/head
Evan Hemsley 2019-06-13 20:28:26 -07:00
parent 4e2aa1ac98
commit d94d6bc8f3
7 changed files with 190 additions and 53 deletions

View File

@ -1,7 +1,4 @@
namespace Encompass namespace Encompass
{ {
public abstract class Component public abstract class Component {}
{
public int EntityID { get; set; }
}
} }

90
src/ComponentManager.cs Normal file
View File

@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Encompass {
internal class ComponentManager {
private Dictionary<uint, List<Component>> entityIDToComponents = new Dictionary<uint, List<Component>>();
private Dictionary<Type, List<Component>> activeComponents = new Dictionary<Type, List<Component>>();
private Dictionary<Type, List<Component>> inactiveComponents = new Dictionary<Type, List<Component>>();
private List<Component> componentsToActivate = new List<Component>();
private List<Component> componentsToDeactivate = new List<Component>();
private List<Component> componentsToRemove = new List<Component>();
internal TComponent CreateComponent<TComponent>(uint entityID) where TComponent : Component, new() {
var component = new TComponent();
if (!entityIDToComponents.ContainsKey(entityID)) {
entityIDToComponents.Add(entityID, new List<Component>());
}
entityIDToComponents[entityID].Add(component);
if (!activeComponents.ContainsKey(typeof(TComponent))) {
activeComponents.Add(typeof(TComponent), new List<Component>());
inactiveComponents.Add(typeof(TComponent), new List<Component>());
}
MarkForActivation(component);
return component;
}
internal IEnumerable<Component> GetComponentsByEntity(uint entityID) {
return entityIDToComponents[entityID];
}
internal IEnumerable<TComponent> GetActiveComponentsByType<TComponent>() where TComponent : Component {
return activeComponents[typeof(TComponent)].Cast<TComponent>();
}
internal IEnumerable<TComponent> GetComponentsByEntityAndType<TComponent>(uint entityID) where TComponent : Component {
var entity_components = GetComponentsByEntity(entityID);
var active_components_by_type = GetActiveComponentsByType<TComponent>();
return entity_components.Intersect(active_components_by_type).Cast<TComponent>();
}
internal bool EntityHasComponentOfType<TComponent>(uint entityID) where TComponent : Component {
return GetComponentsByEntityAndType<TComponent>(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();
}
}
}

View File

@ -6,41 +6,21 @@ namespace Encompass
{ {
public class Entity public class Entity
{ {
public readonly static List<Component> Empty = new List<Component>(); public readonly uint id;
public readonly int id; private ComponentManager componentManager;
private readonly Dictionary<Type, List<Component>> componentBag = new Dictionary<Type, List<Component>>(); internal Entity(uint id, ComponentManager componentManager) {
private readonly Dictionary<Type, List<Component>> activeComponents = new Dictionary<Type, List<Component>>();
public Entity(int id) {
this.id = id; this.id = id;
this.componentManager = componentManager;
} }
public TComponent AddComponent<TComponent>() where TComponent : Component, new() { public TComponent AddComponent<TComponent>() where TComponent : Component, new() {
TComponent component = new TComponent(); return componentManager.CreateComponent<TComponent>(id);
if (!componentBag.ContainsKey(typeof(TComponent))) {
var componentList = new List<Component>();
var activeComponentList = new List<Component>();
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;
} }
public IEnumerable<TComponent> GetComponents<TComponent>() where TComponent : Component { public IEnumerable<TComponent> GetComponents<TComponent>() where TComponent : Component {
if (activeComponents.ContainsKey(typeof(TComponent))) { return componentManager.GetComponentsByEntityAndType<TComponent>(id);
return activeComponents[typeof(TComponent)].Cast<TComponent>();
} else {
return Enumerable.Empty<TComponent>();
}
} }
public TComponent GetComponent<TComponent>() where TComponent : Component { public TComponent GetComponent<TComponent>() where TComponent : Component {
@ -48,8 +28,11 @@ namespace Encompass
} }
public bool HasComponent<TComponent>() where TComponent : Component { public bool HasComponent<TComponent>() where TComponent : Component {
return activeComponents.ContainsKey(typeof(TComponent)) && return componentManager.EntityHasComponentOfType<TComponent>(id);
activeComponents[typeof(TComponent)].Count != 0; }
internal void RemoveAllComponents() {
componentManager.RemoveAllComponentsFromEntity(id);
} }
} }
} }

45
src/EntityManager.cs Normal file
View File

@ -0,0 +1,45 @@
using System.Collections.Generic;
using System.Linq;
namespace Encompass {
internal class EntityManager {
private uint nextID = 1;
private List<Entity> entities = new List<Entity>();
private Dictionary<uint, Entity> IDToEntity = new Dictionary<uint, Entity>();
private List<Entity> entitiesMarkedForDestroy = new List<Entity>();
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;
}
}
}

23
src/World.cs Normal file
View File

@ -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();
}
}
}

View File

@ -1,12 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Encompass</RootNamespace> <RootNamespace>Encompass</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Content Include="encompass-cs.sln" /> <Content Include="encompass-cs.sln" />
<Content Include="Entity.cs" /> <Content Include="Entity.cs" />
<Content Include="Component.cs" /> <Content Include="Component.cs" />
</ItemGroup> <Content Include="World.cs" />
</Project> <Content Include="EntityManager.cs" />
<Content Include="ComponentManager.cs" />
</ItemGroup>
</Project>

View File

@ -12,25 +12,21 @@ namespace Encompass
public class EntityTest public class EntityTest
{ {
/*
[SetUp]
public void Setup()
{
}
*/
[Test] [Test]
public void AddComponent() public void AddComponent()
{ {
var entity = new Entity(0); var world = new World();
var entity = world.CreateEntity();
var mockComponent = entity.AddComponent<MockComponent>(); var mockComponent = entity.AddComponent<MockComponent>();
mockComponent.myString = "hello"; mockComponent.myString = "hello";
mockComponent.myInt = 3; mockComponent.myInt = 3;
world.Update();
Assert.IsTrue(entity.HasComponent<MockComponent>()); Assert.IsTrue(entity.HasComponent<MockComponent>());
Assert.AreEqual(3, entity.GetComponent<MockComponent>().myInt); Assert.AreEqual(3, entity.GetComponent<MockComponent>().myInt);
Assert.AreEqual("hello", entity.GetComponent<MockComponent>().myString); Assert.AreEqual("hello", entity.GetComponent<MockComponent>().myString);
Assert.AreEqual(0, entity.GetComponent<MockComponent>().EntityID);
} }
} }
} }