some basic entity and component structure
parent
4e2aa1ac98
commit
d94d6bc8f3
|
@ -1,7 +1,4 @@
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
public abstract class Component
|
public abstract class Component {}
|
||||||
{
|
|
||||||
public int EntityID { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue