component update mechanism
parent
4b9610762a
commit
cb872b7c42
|
@ -5,6 +5,7 @@ using System.Linq;
|
|||
namespace Encompass {
|
||||
internal class ComponentManager {
|
||||
private Dictionary<uint, List<IComponent>> entityIDToComponents = new Dictionary<uint, List<IComponent>>();
|
||||
private Dictionary<IComponent, uint> componentToEntityID = new Dictionary<IComponent, uint>();
|
||||
|
||||
private Dictionary<Type, List<IComponent>> activeComponents = new Dictionary<Type, List<IComponent>>();
|
||||
private Dictionary<Type, List<IComponent>> inactiveComponents = new Dictionary<Type, List<IComponent>>();
|
||||
|
@ -19,6 +20,7 @@ namespace Encompass {
|
|||
}
|
||||
|
||||
entityIDToComponents[entityID].Add(component);
|
||||
componentToEntityID[component] = entityID;
|
||||
|
||||
if (!activeComponents.ContainsKey(typeof(TComponent))) {
|
||||
activeComponents.Add(typeof(TComponent), new List<IComponent>());
|
||||
|
@ -50,6 +52,37 @@ namespace Encompass {
|
|||
return GetComponentsByEntityAndType<TComponent>(entityID).Any();
|
||||
}
|
||||
|
||||
/** Replaces the component with another. */
|
||||
internal void UpdateComponent<TComponent>(TComponent originalComponent, TComponent newComponent) where TComponent : struct, IComponent {
|
||||
var entityID = componentToEntityID[originalComponent];
|
||||
|
||||
entityIDToComponents[entityID].Remove(originalComponent);
|
||||
entityIDToComponents[entityID].Add(newComponent);
|
||||
|
||||
componentToEntityID.Remove(originalComponent);
|
||||
componentToEntityID.Add(newComponent, entityID);
|
||||
|
||||
if (activeComponents[originalComponent.GetType()].Remove(originalComponent)) {
|
||||
activeComponents[originalComponent.GetType()].Add(newComponent);
|
||||
}
|
||||
|
||||
if (inactiveComponents[originalComponent.GetType()].Remove(originalComponent)) {
|
||||
inactiveComponents[originalComponent.GetType()].Add(newComponent);
|
||||
}
|
||||
|
||||
if (componentsToActivate.Remove(originalComponent)) {
|
||||
componentsToActivate.Add(newComponent);
|
||||
}
|
||||
|
||||
if (componentsToDeactivate.Remove(originalComponent)) {
|
||||
componentsToDeactivate.Add(newComponent);
|
||||
}
|
||||
|
||||
if (componentsToRemove.Remove(originalComponent)) {
|
||||
componentsToRemove.Add(newComponent);
|
||||
}
|
||||
}
|
||||
|
||||
internal void RemoveAllComponentsFromEntity(uint entityID) {
|
||||
var components = GetComponentsByEntity(entityID);
|
||||
|
||||
|
@ -65,6 +98,10 @@ namespace Encompass {
|
|||
componentsToActivate.Add(component);
|
||||
}
|
||||
|
||||
internal void MarkForDeactivation(IComponent component) {
|
||||
componentsToDeactivate.Add(component);
|
||||
}
|
||||
|
||||
internal void MarkForRemoval(IComponent component) {
|
||||
componentsToRemove.Add(component);
|
||||
}
|
||||
|
@ -78,6 +115,13 @@ namespace Encompass {
|
|||
componentsToActivate.Clear();
|
||||
}
|
||||
|
||||
internal void DeactivateComponents() {
|
||||
foreach (var component in componentsToDeactivate) {
|
||||
activeComponents[component.GetType()].Remove(component);
|
||||
inactiveComponents[component.GetType()].Add(component);
|
||||
}
|
||||
}
|
||||
|
||||
internal void RemoveComponents() {
|
||||
foreach (var component in componentsToRemove) {
|
||||
activeComponents[component.GetType()].Remove(component);
|
||||
|
|
|
@ -1,10 +1,21 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Encompass {
|
||||
public abstract class Engine {
|
||||
public readonly List<Type> mutateComponentTypes = new List<Type>();
|
||||
|
||||
private EntityManager entityManager;
|
||||
private ComponentManager componentManager;
|
||||
|
||||
public Engine() {
|
||||
var mutatesAttribute = this.GetType().GetCustomAttribute<Mutates>(false);
|
||||
if (mutatesAttribute != null) {
|
||||
mutateComponentTypes = mutatesAttribute.mutateComponentTypes;
|
||||
}
|
||||
}
|
||||
|
||||
internal void AssignEntityManager(EntityManager entityManager) {
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
|
@ -26,5 +37,13 @@ namespace Encompass {
|
|||
protected TComponent ReadComponent<TComponent>() where TComponent : struct, IComponent {
|
||||
return this.componentManager.GetActiveComponentByType<TComponent>();
|
||||
}
|
||||
|
||||
protected void UpdateComponent<TComponent>(TComponent originalComponent, TComponent newComponent) where TComponent : struct, IComponent {
|
||||
if (mutateComponentTypes.Contains(typeof(TComponent))) {
|
||||
this.componentManager.UpdateComponent(originalComponent, newComponent);
|
||||
} else {
|
||||
throw new IllegalComponentMutationException("Engine {0} tried to mutate undeclared Component {1}", this.GetType().ToString(), typeof(TComponent).ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Encompass {
|
||||
[System.AttributeUsage(System.AttributeTargets.Class)]
|
||||
public class Mutates : System.Attribute
|
||||
{
|
||||
public readonly List<Type> mutateComponentTypes;
|
||||
|
||||
public Mutates(params Type[] mutateComponentTypes)
|
||||
{
|
||||
this.mutateComponentTypes = new List<Type>(mutateComponentTypes);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,5 +13,7 @@
|
|||
<Content Include="ComponentManager.cs" />
|
||||
<Content Include="WorldBuilder.cs" />
|
||||
<Content Include="Engine.cs" />
|
||||
<Content Include="attributes\Mutates.cs" />
|
||||
<Content Include="exceptions\IllegalComponentMutationException.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace Encompass {
|
||||
public class IllegalComponentMutationException : Exception {
|
||||
public IllegalComponentMutationException(
|
||||
string format,
|
||||
params object[] args
|
||||
) : base(string.Format(format, args)) { }
|
||||
}
|
||||
}
|
|
@ -98,5 +98,73 @@ namespace Tests {
|
|||
|
||||
Assert.Throws<InvalidOperationException>(() => world.Update(0.01f));
|
||||
}
|
||||
|
||||
[Mutates(typeof(MockComponent))]
|
||||
public class UpdateComponentTestEngine : Engine
|
||||
{
|
||||
public override void Update(float dt)
|
||||
{
|
||||
var originalComponent = this.ReadComponent<MockComponent>();
|
||||
var newComponent = this.ReadComponent<MockComponent>();
|
||||
newComponent.myInt = 420;
|
||||
newComponent.myString = "blaze it";
|
||||
this.UpdateComponent(originalComponent, newComponent);
|
||||
component = this.ReadComponent<MockComponent>();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateComponent()
|
||||
{
|
||||
var worldBuilder = new WorldBuilder();
|
||||
worldBuilder.AddEngine<UpdateComponentTestEngine>();
|
||||
|
||||
var entity = worldBuilder.CreateEntity();
|
||||
|
||||
MockComponent mockComponent;
|
||||
mockComponent.myInt = 0;
|
||||
mockComponent.myString = "hello";
|
||||
|
||||
entity.AddComponent(mockComponent);
|
||||
|
||||
var world = worldBuilder.Build();
|
||||
|
||||
world.Update(0.01f);
|
||||
|
||||
Assert.AreEqual(420, component.myInt);
|
||||
Assert.AreEqual("blaze it", component.myString);
|
||||
}
|
||||
|
||||
public class UndeclaredUpdateComponentTestEngine : Engine
|
||||
{
|
||||
public override void Update(float dt)
|
||||
{
|
||||
var originalComponent = this.ReadComponent<MockComponent>();
|
||||
var newComponent = this.ReadComponent<MockComponent>();
|
||||
newComponent.myInt = 420;
|
||||
newComponent.myString = "blaze it";
|
||||
this.UpdateComponent(originalComponent, newComponent);
|
||||
component = this.ReadComponent<MockComponent>();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateUndeclaredComponent()
|
||||
{
|
||||
var worldBuilder = new WorldBuilder();
|
||||
worldBuilder.AddEngine<UndeclaredUpdateComponentTestEngine>();
|
||||
|
||||
var entity = worldBuilder.CreateEntity();
|
||||
|
||||
MockComponent mockComponent;
|
||||
mockComponent.myInt = 0;
|
||||
mockComponent.myString = "hello";
|
||||
|
||||
entity.AddComponent(mockComponent);
|
||||
|
||||
var world = worldBuilder.Build();
|
||||
|
||||
Assert.Throws<IllegalComponentMutationException>(() => world.Update(0.01f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue