Proper Entity and Component bucketing/tracking

This commit is contained in:
Matt Thorson 2020-05-21 21:24:04 -07:00
parent df00a1ec82
commit 0b1a938fe2
6 changed files with 180 additions and 14 deletions

View File

@ -88,6 +88,7 @@ namespace Strawberry
for (var c in toRemove) for (var c in toRemove)
{ {
components.Remove(c); components.Remove(c);
Scene.[Friend]UntrackComponent(c);
c.Removed(); c.Removed();
delete c; delete c;
} }
@ -100,6 +101,7 @@ namespace Strawberry
for (var c in toAdd) for (var c in toAdd)
{ {
components.Add(c); components.Add(c);
Scene.[Friend]TrackComponent(c);
c.Added(this); c.Added(this);
} }

View File

@ -77,6 +77,8 @@ namespace Strawberry
SDLImage.Init(.PNG | .JPG); SDLImage.Init(.PNG | .JPG);
SDLMixer.OpenAudio(44100, SDLMixer.MIX_DEFAULT_FORMAT, 2, 4096); SDLMixer.OpenAudio(44100, SDLMixer.MIX_DEFAULT_FORMAT, 2, 4096);
SDLTTF.Init(); SDLTTF.Init();
TypeTree.[Friend]Build();
Input.[Friend]Init(gamepadLimit); Input.[Friend]Init(gamepadLimit);
} }
@ -97,6 +99,7 @@ namespace Strawberry
delete VirtualInputs; delete VirtualInputs;
} }
TypeTree.[Friend]Dispose();
Input.[Friend]Dispose(); Input.[Friend]Dispose();
Game = null; Game = null;
} }

View File

@ -12,12 +12,22 @@ namespace Strawberry
private List<Entity> entities; private List<Entity> entities;
private HashSet<Entity> toRemove; private HashSet<Entity> toRemove;
private HashSet<Entity> toAdd; private HashSet<Entity> toAdd;
private Dictionary<Type, List<Entity>> entityTracker;
private Dictionary<Type, List<Component>> componentTracker;
public this() public this()
{ {
entities = new List<Entity>(); entities = new List<Entity>();
toAdd = new HashSet<Entity>(); toAdd = new HashSet<Entity>();
toRemove = new HashSet<Entity>(); toRemove = new HashSet<Entity>();
entityTracker = new Dictionary<Type, List<Entity>>();
for (let type in TypeTree.[Friend]EntityAssignableLists.Keys)
entityTracker.Add(type, new List<Entity>());
componentTracker = new Dictionary<Type, List<Component>>();
for (let type in TypeTree.[Friend]ComponentAssignableLists.Keys)
componentTracker.Add(type, new List<Component>());
} }
public ~this() public ~this()
@ -36,6 +46,14 @@ namespace Strawberry
delete toAdd; delete toAdd;
delete toRemove; delete toRemove;
for (let list in entityTracker.Values)
delete list;
delete entityTracker;
for (let list in componentTracker.Values)
delete list;
delete componentTracker;
} }
public virtual void Started() public virtual void Started()
@ -79,6 +97,7 @@ namespace Strawberry
for (var e in toRemove) for (var e in toRemove)
{ {
entities.Remove(e); entities.Remove(e);
UntrackEntity(e);
e.Removed(); e.Removed();
if (e.DeleteOnRemove) if (e.DeleteOnRemove)
delete e; delete e;
@ -92,6 +111,7 @@ namespace Strawberry
for (var e in toAdd) for (var e in toAdd)
{ {
entities.Add(e); entities.Add(e);
TrackEntity(e);
e.Added(this); e.Added(this);
} }
} }
@ -108,6 +128,38 @@ namespace Strawberry
} }
} }
// Tracking
private void TrackEntity(Entity e)
{
for (let t in TypeTree.[Friend]EntityAssignableLists[e.GetType()])
entityTracker[t].Add(e);
for (let c in e.[Friend]components)
TrackComponent(c);
}
private void UntrackEntity(Entity e)
{
for (let t in TypeTree.[Friend]EntityAssignableLists[e.GetType()])
entityTracker[t].Remove(e);
for (let c in e.[Friend]components)
UntrackComponent(c);
}
private void TrackComponent(Component c)
{
for (let t in TypeTree.[Friend]ComponentAssignableLists[c.GetType()])
componentTracker[t].Add(c);
}
private void UntrackComponent(Component c)
{
for (let t in TypeTree.[Friend]ComponentAssignableLists[c.GetType()])
componentTracker[t].Remove(c);
}
// Time // Time
public float TimeElapsed => Time.Elapsed - TimeStarted; public float TimeElapsed => Time.Elapsed - TimeStarted;
@ -125,52 +177,62 @@ namespace Strawberry
// Finding Entities // Finding Entities
public int Count<T>() where T : Entity
{
return entityTracker[typeof(T)].Count;
}
public T First<T>() where T : Entity public T First<T>() where T : Entity
{ {
for (var e in entities) for (var e in entityTracker[typeof(T)])
if (e is T) return e as T;
return e as T;
return null; return null;
} }
public T First<T>(Point point) where T : Entity public T First<T>(Point point) where T : Entity
{ {
for (var e in entities) for (var e in entityTracker[typeof(T)])
if (e is T && e.Check(point)) if (e.Check(point))
return e as T; return e as T;
return null; return null;
} }
public T First<T>(Rect rect) where T : Entity public T First<T>(Rect rect) where T : Entity
{ {
for (var e in entities) for (var e in entityTracker[typeof(T)])
if (e is T && e.Check(rect)) if (e.Check(rect))
return e as T; return e as T;
return null; return null;
} }
public List<T> All<T>(List<T> into) where T : Entity public List<T> All<T>(List<T> into) where T : Entity
{ {
for (var e in entities) for (var e in entityTracker[typeof(T)])
if (e is T) into.Add(e as T);
into.Add(e as T);
return into; return into;
} }
public List<T> All<T>(Point point, List<T> into) where T : Entity public List<T> All<T>(Point point, List<T> into) where T : Entity
{ {
for (var e in entities) for (var e in entityTracker[typeof(T)])
if (e is T && e.Check(point)) if (e.Check(point))
into.Add(e as T); into.Add(e as T);
return into; return into;
} }
public List<T> All<T>(Rect rect, List<T> into) where T : Entity public List<T> All<T>(Rect rect, List<T> into) where T : Entity
{ {
for (var e in entities) for (var e in entityTracker[typeof(T)])
if (e is T && e.Check(rect)) if (e.Check(rect))
into.Add(e as T); into.Add(e as T);
return into; return into;
} }
// Finding Components
public int Count<T>() where T : Component
{
return componentTracker[typeof(T)].Count;
}
} }
} }

View File

@ -53,5 +53,13 @@ namespace Strawberry
v.ToString(string); v.ToString(string);
Debug.WriteLine(string); Debug.WriteLine(string);
} }
[Inline]
static public void Log(delegate void(String) del)
{
String string = scope String();
del(string);
Debug.WriteLine(string);
}
} }
} }

61
src/Static/TypeTree.bf Normal file
View File

@ -0,0 +1,61 @@
using System.Collections;
using System;
namespace Strawberry
{
static public class TypeTree
{
static private Dictionary<Type, List<Type>> EntityAssignableLists;
static private Dictionary<Type, List<Type>> ComponentAssignableLists;
static private void Build()
{
/*
For each Type that extends Entity, we build a list of all the other Entity Types that it is assignable to.
We cache these lists, and use them later to bucket Entities as they are added to the Scene.
This allows us to retrieve Entities by type very easily.
*/
EntityAssignableLists = new Dictionary<Type, List<Type>>();
for (let type in Type.Enumerator())
{
if (type != typeof(Entity) && type.IsSubtypeOf(typeof(Entity)))
{
let list = new List<Type>();
for (let check in Type.Enumerator())
if (check != typeof(Entity) && check.IsSubtypeOf(typeof(Entity)) && type.IsSubtypeOf(check))
list.Add(check);
EntityAssignableLists.Add(type, list);
}
}
/*
And then we also do this for components
*/
ComponentAssignableLists = new Dictionary<Type, List<Type>>();
for (let type in Type.Enumerator())
{
if (type != typeof(Component) && type.IsSubtypeOf(typeof(Component)))
{
let list = new List<Type>();
for (let check in Type.Enumerator())
if (check != typeof(Component) && check.IsSubtypeOf(typeof(Component)) && type.IsSubtypeOf(check))
list.Add(check);
ComponentAssignableLists.Add(type, list);
}
}
}
static private void Dispose()
{
for (let list in EntityAssignableLists.Values)
delete list;
delete EntityAssignableLists;
for (let list in ComponentAssignableLists.Values)
delete list;
delete ComponentAssignableLists;
}
}
}

View File

@ -1,3 +1,5 @@
using System;
namespace Strawberry namespace Strawberry
{ {
public enum Cardinals public enum Cardinals
@ -66,5 +68,33 @@ namespace Strawberry
return Point.Down; return Point.Down;
} }
} }
static public Result<Cardinals> FromPoint(Point p)
{
if (p.X > 0 && p.Y == 0)
return .Right;
else if (p.X < 0 && p.Y == 0)
return .Left;
else if (p.Y < 0 && p.X == 0)
return .Up;
else if (p.Y > 0 && p.X == 0)
return .Down;
else
return .Err;
}
static public Result<Cardinals> FromVector(Vector v)
{
if (v.X > 0 && v.Y == 0)
return .Right;
else if (v.X < 0 && v.Y == 0)
return .Left;
else if (v.Y < 0 && v.X == 0)
return .Up;
else if (v.Y > 0 && v.X == 0)
return .Down;
else
return .Err;
}
} }
} }