draw layer manager and final entity renderer tests

pull/5/head
Evan Hemsley 2019-06-19 17:40:01 -07:00
parent f010b39c3c
commit cf6d59bb5b
10 changed files with 280 additions and 94 deletions

View File

@ -6,6 +6,8 @@ namespace Encompass
{ {
internal class ComponentManager internal class ComponentManager
{ {
private DrawLayerManager drawLayerManager;
private Dictionary<Guid, Type> componentIDToType = new Dictionary<Guid, Type>(); private Dictionary<Guid, Type> componentIDToType = new Dictionary<Guid, Type>();
private Dictionary<Guid, IComponent> IDToComponent = new Dictionary<Guid, IComponent>(); private Dictionary<Guid, IComponent> IDToComponent = new Dictionary<Guid, IComponent>();
private Dictionary<Guid, List<Guid>> entityIDToComponentIDs = new Dictionary<Guid, List<Guid>>(); private Dictionary<Guid, List<Guid>> entityIDToComponentIDs = new Dictionary<Guid, List<Guid>>();
@ -25,10 +27,12 @@ namespace Encompass
private List<Guid> entitiesWithRemovedComponents; private List<Guid> entitiesWithRemovedComponents;
public ComponentManager( public ComponentManager(
DrawLayerManager drawLayerManager,
List<Guid> entitiesWithAddedComponents, List<Guid> entitiesWithAddedComponents,
List<Guid> entitiesWithRemovedComponents List<Guid> entitiesWithRemovedComponents
) )
{ {
this.drawLayerManager = drawLayerManager;
this.entitiesWithAddedComponents = entitiesWithAddedComponents; this.entitiesWithAddedComponents = entitiesWithAddedComponents;
this.entitiesWithRemovedComponents = entitiesWithRemovedComponents; this.entitiesWithRemovedComponents = entitiesWithRemovedComponents;
} }
@ -60,12 +64,24 @@ namespace Encompass
entitiesWithAddedComponents.Add(entityID); entitiesWithAddedComponents.Add(entityID);
if (component is IDrawComponent)
{
drawLayerManager.RegisterComponentWithLayer(componentID, (component as IDrawComponent).Layer);
}
return componentID; return componentID;
} }
internal IEnumerable<Guid> GetComponentIDsByEntityID(Guid entityID)
{
return entityIDToComponentIDs.ContainsKey(entityID) ?
entityIDToComponentIDs[entityID] :
Enumerable.Empty<Guid>();
}
internal IEnumerable<KeyValuePair<Guid, IComponent>> GetComponentsByEntity(Guid entityID) internal IEnumerable<KeyValuePair<Guid, IComponent>> GetComponentsByEntity(Guid entityID)
{ {
return entityIDToComponentIDs[entityID].Intersect(activeComponents).Select((id) => new KeyValuePair<Guid, IComponent>(id, IDToComponent[id])); return GetComponentIDsByEntityID(entityID).Intersect(activeComponents).Select((id) => new KeyValuePair<Guid, IComponent>(id, IDToComponent[id]));
} }
internal IEnumerable<KeyValuePair<Guid, TComponent>> GetActiveComponentsByType<TComponent>() where TComponent : struct, IComponent internal IEnumerable<KeyValuePair<Guid, TComponent>> GetActiveComponentsByType<TComponent>() where TComponent : struct, IComponent
@ -103,7 +119,7 @@ namespace Encompass
internal IEnumerable<Type> GetAllComponentTypesOfEntity(Guid entityID) internal IEnumerable<Type> GetAllComponentTypesOfEntity(Guid entityID)
{ {
return entityIDToComponentIDs[entityID].Select((id) => componentIDToType[id]); return GetComponentIDsByEntityID(entityID).Select((id) => componentIDToType[id]);
} }
internal bool EntityHasComponentOfType<TComponent>(Guid entityID) where TComponent : struct, IComponent internal bool EntityHasComponentOfType<TComponent>(Guid entityID) where TComponent : struct, IComponent
@ -152,19 +168,28 @@ namespace Encompass
internal void MarkForActivation(Guid componentID) internal void MarkForActivation(Guid componentID)
{ {
componentsToActivate.Add(componentID); componentsToActivate.Add(componentID);
var entityID = GetEntityIDFromComponentID(componentID);
entitiesWithAddedComponents.Add(entityID);
} }
internal void MarkForDeactivation(Guid componentID) internal void MarkForDeactivation(Guid componentID)
{ {
componentsToDeactivate.Add(componentID); componentsToDeactivate.Add(componentID);
var entityID = GetEntityIDFromComponentID(componentID);
entitiesWithRemovedComponents.Add(entityID);
} }
internal void MarkForRemoval(Guid componentID) internal void MarkForRemoval(Guid componentID)
{ {
componentsToRemove.Add(componentID); componentsToRemove.Add(componentID);
var entityID = GetEntityIDFromComponentID(componentID);
entitiesWithRemovedComponents.Add(entityID);
} }
internal void ActivateComponents() internal void ActivateMarkedComponents()
{ {
foreach (var componentID in componentsToActivate) foreach (var componentID in componentsToActivate)
{ {
@ -178,7 +203,7 @@ namespace Encompass
componentsToActivate.Clear(); componentsToActivate.Clear();
} }
internal void DeactivateComponents() internal void DeactivateMarkedComponents()
{ {
foreach (var componentID in componentsToDeactivate) foreach (var componentID in componentsToDeactivate)
{ {
@ -192,13 +217,28 @@ namespace Encompass
componentsToDeactivate.Clear(); componentsToDeactivate.Clear();
} }
internal void RemoveComponents() internal void RemoveMarkedComponents()
{ {
foreach (var componentID in componentsToRemove) foreach (var componentID in componentsToRemove)
{ {
var component = IDToComponent[componentID]; var component = IDToComponent[componentID];
var type = componentIDToType[componentID];
activeComponents.Remove(componentID); activeComponents.Remove(componentID);
inactiveComponents.Remove(componentID); inactiveComponents.Remove(componentID);
var entityID = componentIDToEntityID[componentID];
entityIDToComponentIDs[entityID].Remove(componentID);
IDToComponent.Remove(componentID);
componentIDToType.Remove(componentID);
componentIDToEntityID.Remove(componentID);
typeToComponentIDs[type].Remove(componentID);
if (component is IDrawComponent)
{
drawLayerManager.UnRegisterComponentWithLayer(componentID, (component as IDrawComponent).Layer);
}
} }
componentsToRemove.Clear(); componentsToRemove.Clear();

View File

@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Encompass
{
internal class DrawLayerManager
{
private SortedList<int, int> layerOrder = new SortedList<int, int>();
private Dictionary<int, HashSet<Guid>> layerIndexToComponentIDs = new Dictionary<int, HashSet<Guid>>();
private Dictionary<int, HashSet<GeneralRenderer>> layerIndexToGeneralRenderers = new Dictionary<int, HashSet<GeneralRenderer>>();
public IEnumerable<int> LayerOrder { get { return layerOrder.Values; } }
public void RegisterGeneralRendererWithLayer(GeneralRenderer renderer, int layer)
{
if (layerIndexToGeneralRenderers.ContainsKey(layer))
{
var set = layerIndexToGeneralRenderers[layer];
set.Add(renderer);
}
else
{
var set = new HashSet<GeneralRenderer>();
layerIndexToGeneralRenderers.Add(layer, set);
set.Add(renderer);
}
if (!layerOrder.ContainsKey(layer))
{
layerOrder.Add(layer, layer);
}
}
public void UnregisterGeneralRendererWithLayer(GeneralRenderer renderer, int layer)
{
if (layerIndexToGeneralRenderers.ContainsKey(layer))
{
layerIndexToGeneralRenderers[layer].Remove(renderer);
}
}
public void AdjustRendererLayer(GeneralRenderer renderer, int oldLayer, int newLayer)
{
UnregisterGeneralRendererWithLayer(renderer, oldLayer);
RegisterGeneralRendererWithLayer(renderer, newLayer);
}
public void RegisterComponentWithLayer(Guid id, int layer)
{
if (layerIndexToComponentIDs.ContainsKey(layer))
{
var set = layerIndexToComponentIDs[layer];
set.Add(id);
}
else
{
var set = new HashSet<Guid>();
layerIndexToComponentIDs.Add(layer, set);
set.Add(id);
}
if (!layerOrder.ContainsKey(layer))
{
layerOrder.Add(layer, layer);
}
}
public void UnRegisterComponentWithLayer(Guid id, int layer)
{
if (layerIndexToComponentIDs.ContainsKey(layer))
{
layerIndexToComponentIDs[layer].Remove(id);
}
}
public void AdjustComponentLayer(Guid id, int oldLayer, int newLayer)
{
UnRegisterComponentWithLayer(id, oldLayer);
RegisterComponentWithLayer(id, newLayer);
}
public IEnumerable<Guid> ComponentIDsByLayer(int layer)
{
return layerIndexToComponentIDs.ContainsKey(layer) ?
layerIndexToComponentIDs[layer] :
Enumerable.Empty<Guid>();
}
public IEnumerable<GeneralRenderer> GeneralRenderersByLayer(int layer)
{
return layerIndexToGeneralRenderers.ContainsKey(layer) ?
layerIndexToGeneralRenderers[layer] :
Enumerable.Empty<GeneralRenderer>();
}
}
}

View File

@ -41,6 +41,21 @@ namespace Encompass
return componentManager.EntityHasComponentOfType(id, type); return componentManager.EntityHasComponentOfType(id, type);
} }
public void ActivateComponent(Guid componentID)
{
componentManager.MarkForActivation(componentID);
}
public void DeactivateComponent(Guid componentID)
{
componentManager.MarkForDeactivation(componentID);
}
public void RemoveComponent(Guid componentID)
{
componentManager.MarkForRemoval(componentID);
}
internal void RemoveAllComponents() internal void RemoveAllComponents()
{ {
componentManager.RemoveAllComponentsFromEntity(id); componentManager.RemoveAllComponentsFromEntity(id);

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace Encompass namespace Encompass
{ {
public interface IEntityTracker internal interface IEntityTracker
{ {
IEnumerable<Type> ComponentTypes { get; } IEnumerable<Type> ComponentTypes { get; }

View File

@ -8,17 +8,19 @@ namespace Encompass
{ {
private EntityManager entityManager; private EntityManager entityManager;
private ComponentManager componentManager; private ComponentManager componentManager;
private DrawLayerManager drawLayerManager;
private SortedList<int, int> layerOrder = new SortedList<int, int>();
private Dictionary<int, HashSet<Guid>> layerIndexToComponentIDs = new Dictionary<int, HashSet<Guid>>();
private Dictionary<int, HashSet<GeneralRenderer>> layerIndexToGeneralRenderers = new Dictionary<int, HashSet<GeneralRenderer>>();
private Dictionary<Type, EntityRenderer> drawComponentTypeToEntityRenderer = new Dictionary<Type, EntityRenderer>(); private Dictionary<Type, EntityRenderer> drawComponentTypeToEntityRenderer = new Dictionary<Type, EntityRenderer>();
public RenderManager(EntityManager entityManager, ComponentManager componentManager) public RenderManager(
EntityManager entityManager,
ComponentManager componentManager,
DrawLayerManager drawLayerManager
)
{ {
this.entityManager = entityManager; this.entityManager = entityManager;
this.componentManager = componentManager; this.componentManager = componentManager;
this.drawLayerManager = drawLayerManager;
} }
public void RegisterEntityRenderer(EntityRenderer renderer) public void RegisterEntityRenderer(EntityRenderer renderer)
@ -32,79 +34,15 @@ namespace Encompass
public void RegisterGeneralRendererWithLayer(GeneralRenderer renderer, int layer) public void RegisterGeneralRendererWithLayer(GeneralRenderer renderer, int layer)
{ {
if (layerIndexToGeneralRenderers.ContainsKey(layer)) drawLayerManager.RegisterGeneralRendererWithLayer(renderer, layer);
{
var set = layerIndexToGeneralRenderers[layer];
set.Add(renderer);
}
else
{
var set = new HashSet<GeneralRenderer>();
layerIndexToGeneralRenderers.Add(layer, set);
set.Add(renderer);
}
if (!layerOrder.ContainsKey(layer))
{
layerOrder.Add(layer, layer);
}
}
public void UnregisterGeneralRendererWithLayer(GeneralRenderer renderer, int layer)
{
if (layerIndexToGeneralRenderers.ContainsKey(layer))
{
layerIndexToGeneralRenderers[layer].Remove(renderer);
}
}
public void AdjustRendererLayer(GeneralRenderer renderer, int oldLayer, int newLayer)
{
UnregisterGeneralRendererWithLayer(renderer, oldLayer);
RegisterGeneralRendererWithLayer(renderer, newLayer);
}
public void RegisterComponentWithLayer(Guid id, int layer)
{
if (layerIndexToComponentIDs.ContainsKey(layer))
{
var set = layerIndexToComponentIDs[layer];
set.Add(id);
}
else
{
var set = new HashSet<Guid>();
layerIndexToComponentIDs.Add(layer, set);
set.Add(id);
}
if (!layerOrder.ContainsKey(layer))
{
layerOrder.Add(layer, layer);
}
}
public void UnRegisterComponentWithLayer(Guid id, int layer)
{
if (layerIndexToComponentIDs.ContainsKey(layer))
{
layerIndexToComponentIDs[layer].Remove(id);
}
}
public void AdjustComponentLayer(Guid id, int oldLayer, int newLayer)
{
UnRegisterComponentWithLayer(id, oldLayer);
RegisterComponentWithLayer(id, newLayer);
} }
public void Draw() public void Draw()
{ {
foreach (var layerKVPair in layerOrder) foreach (var layer in drawLayerManager.LayerOrder)
{ {
var layer = layerKVPair.Key; var componentIDSet = drawLayerManager.ComponentIDsByLayer(layer);
var componentIDSet = layerIndexToComponentIDs[layer]; var generalRendererSet = drawLayerManager.GeneralRenderersByLayer(layer);
var generalRendererSet = layerIndexToGeneralRenderers[layer];
foreach (var componentID in componentIDSet) foreach (var componentID in componentIDSet)
{ {

View File

@ -35,9 +35,9 @@ namespace Encompass
messageManager.ClearMessages(); messageManager.ClearMessages();
entityManager.DestroyMarkedEntities(); entityManager.DestroyMarkedEntities();
componentManager.ActivateComponents(); componentManager.ActivateMarkedComponents();
componentManager.DeactivateComponents(); componentManager.DeactivateMarkedComponents();
componentManager.RemoveComponents(); componentManager.RemoveMarkedComponents();
entityManager.CheckEntitiesWithAddedComponents(); entityManager.CheckEntitiesWithAddedComponents();
entityManager.CheckEntitiesWithRemovedComponents(); entityManager.CheckEntitiesWithRemovedComponents();

View File

@ -13,6 +13,7 @@ namespace Encompass
private ComponentManager componentManager; private ComponentManager componentManager;
private EntityManager entityManager; private EntityManager entityManager;
private MessageManager messageManager; private MessageManager messageManager;
private DrawLayerManager drawLayerManager;
private RenderManager renderManager; private RenderManager renderManager;
private Dictionary<Type, HashSet<Engine>> messageTypeToEmitters = new Dictionary<Type, HashSet<Engine>>(); private Dictionary<Type, HashSet<Engine>> messageTypeToEmitters = new Dictionary<Type, HashSet<Engine>>();
@ -22,10 +23,11 @@ namespace Encompass
{ {
var entitiesWithAddedComponents = new List<Guid>(); var entitiesWithAddedComponents = new List<Guid>();
var entitiesWithRemovedComponents = new List<Guid>(); var entitiesWithRemovedComponents = new List<Guid>();
componentManager = new ComponentManager(entitiesWithAddedComponents, entitiesWithRemovedComponents); drawLayerManager = new DrawLayerManager();
componentManager = new ComponentManager(drawLayerManager, entitiesWithAddedComponents, entitiesWithRemovedComponents);
entityManager = new EntityManager(componentManager, entitiesWithAddedComponents, entitiesWithRemovedComponents); entityManager = new EntityManager(componentManager, entitiesWithAddedComponents, entitiesWithRemovedComponents);
messageManager = new MessageManager(); messageManager = new MessageManager();
renderManager = new RenderManager(entityManager, componentManager); renderManager = new RenderManager(entityManager, componentManager, drawLayerManager);
} }
public Entity CreateEntity() public Entity CreateEntity()
@ -190,9 +192,9 @@ namespace Encompass
renderManager renderManager
); );
componentManager.ActivateComponents(); componentManager.ActivateMarkedComponents();
componentManager.DeactivateComponents(); componentManager.DeactivateMarkedComponents();
componentManager.RemoveComponents(); componentManager.RemoveMarkedComponents();
entityManager.CheckEntitiesWithAddedComponents(); entityManager.CheckEntitiesWithAddedComponents();
entityManager.CheckEntitiesWithRemovedComponents(); entityManager.CheckEntitiesWithRemovedComponents();

View File

@ -24,7 +24,7 @@ namespace Encompass
} }
} }
public bool CheckAndTrackEntity(Guid entityID) bool IEntityTracker.CheckAndTrackEntity(Guid entityID)
{ {
var entity = GetEntity(entityID); var entity = GetEntity(entityID);
var shouldTrack = CheckEntity(entity); var shouldTrack = CheckEntity(entity);
@ -32,10 +32,10 @@ namespace Encompass
return shouldTrack; return shouldTrack;
} }
public bool CheckAndUntrackEntity(Guid entityID) bool IEntityTracker.CheckAndUntrackEntity(Guid entityID)
{ {
var entity = GetEntity(entityID); var entity = GetEntity(entityID);
var shouldUntrack = CheckEntity(entity); var shouldUntrack = !CheckEntity(entity);
if (shouldUntrack) { entityTracker.UntrackEntity(entityID); } if (shouldUntrack) { entityTracker.UntrackEntity(entityID); }
return shouldUntrack; return shouldUntrack;
} }
@ -45,7 +45,7 @@ namespace Encompass
return entityTracker.IsTracking(entityID); return entityTracker.IsTracking(entityID);
} }
internal bool CheckEntity(Entity entity) private bool CheckEntity(Entity entity)
{ {
return EntityChecker.CheckEntity(entity, componentTypes) && return EntityChecker.CheckEntity(entity, componentTypes) &&
entity.HasComponent(DrawComponentType); entity.HasComponent(DrawComponentType);

View File

@ -1,6 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework; using NUnit.Framework;
using Encompass; using Encompass;
@ -57,5 +55,79 @@ namespace Tests
Assert.IsFalse(renderer.IsTracking(entityNotToTrack.id)); Assert.IsFalse(renderer.IsTracking(entityNotToTrack.id));
Assert.IsFalse(renderer.IsTracking(entityWithoutDrawComponent.id)); Assert.IsFalse(renderer.IsTracking(entityWithoutDrawComponent.id));
} }
static bool called = false;
class DeactivatedRenderer : TestRenderer
{
public override void Render(Entity entity)
{
called = true;
}
}
[Test]
public void InactiveDrawComponent()
{
var worldBuilder = new WorldBuilder();
var renderer = worldBuilder.AddRenderer<TestRenderer>();
AComponent aComponent;
BComponent bComponent;
TestDrawComponent testDrawComponent = default(TestDrawComponent);
testDrawComponent.Layer = 0;
var entity = worldBuilder.CreateEntity();
entity.AddComponent(aComponent);
entity.AddComponent(bComponent);
var testDrawComponentID = entity.AddComponent(testDrawComponent);
var world = worldBuilder.Build();
world.Update(0.01f);
entity.DeactivateComponent(testDrawComponentID);
world.Update(0.01f);
Assert.IsFalse(renderer.IsTracking(entity.id));
world.Draw();
Assert.IsFalse(called);
}
static bool calledOnDraw = false;
[Renders(typeof(TestDrawComponent), typeof(AComponent), typeof(CComponent))]
class CalledRenderer : EntityRenderer
{
public override void Render(Entity entity)
{
calledOnDraw = true;
}
}
[Test]
public void RenderMethodCalledOnWorldDraw()
{
var worldBuilder = new WorldBuilder();
var renderer = worldBuilder.AddRenderer<CalledRenderer>();
AComponent aComponent;
CComponent cComponent;
TestDrawComponent testDrawComponent = default(TestDrawComponent);
var entity = worldBuilder.CreateEntity();
entity.AddComponent(aComponent);
entity.AddComponent(cComponent);
entity.AddComponent(testDrawComponent);
var world = worldBuilder.Build();
world.Update(0.01f);
world.Draw();
Assert.IsTrue(renderer.IsTracking(entity.id));
Assert.IsTrue(calledOnDraw);
}
} }
} }

View File

@ -93,11 +93,32 @@ namespace Tests
mockComponent.myInt = 3; mockComponent.myInt = 3;
mockComponent.myString = "hello"; mockComponent.myString = "hello";
entity.AddComponent<MockComponent>(mockComponent); entity.AddComponent(mockComponent);
var world = worldBuilder.Build(); var world = worldBuilder.Build();
Assert.IsTrue(entity.HasComponent<MockComponent>()); Assert.IsTrue(entity.HasComponent<MockComponent>());
} }
[Test]
public void HasComponentWhenInactive()
{
var worldBuilder = new WorldBuilder();
var entity = worldBuilder.CreateEntity();
MockComponent mockComponent;
mockComponent.myInt = 3;
mockComponent.myString = "hello";
var componentID = entity.AddComponent(mockComponent);
var world = worldBuilder.Build();
entity.DeactivateComponent(componentID);
world.Update(0.01f);
Assert.IsFalse(entity.HasComponent<MockComponent>());
}
} }
} }