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

View File

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

View File

@ -12,12 +12,22 @@ namespace Strawberry
private List<Entity> entities;
private HashSet<Entity> toRemove;
private HashSet<Entity> toAdd;
private Dictionary<Type, List<Entity>> entityTracker;
private Dictionary<Type, List<Component>> componentTracker;
public this()
{
entities = new List<Entity>();
toAdd = 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()
@ -36,6 +46,14 @@ namespace Strawberry
delete toAdd;
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()
@ -79,6 +97,7 @@ namespace Strawberry
for (var e in toRemove)
{
entities.Remove(e);
UntrackEntity(e);
e.Removed();
if (e.DeleteOnRemove)
delete e;
@ -92,6 +111,7 @@ namespace Strawberry
for (var e in toAdd)
{
entities.Add(e);
TrackEntity(e);
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
public float TimeElapsed => Time.Elapsed - TimeStarted;
@ -125,52 +177,62 @@ namespace Strawberry
// Finding Entities
public int Count<T>() where T : Entity
{
return entityTracker[typeof(T)].Count;
}
public T First<T>() where T : Entity
{
for (var e in entities)
if (e is T)
return e as T;
for (var e in entityTracker[typeof(T)])
return e as T;
return null;
}
public T First<T>(Point point) where T : Entity
{
for (var e in entities)
if (e is T && e.Check(point))
for (var e in entityTracker[typeof(T)])
if (e.Check(point))
return e as T;
return null;
}
public T First<T>(Rect rect) where T : Entity
{
for (var e in entities)
if (e is T && e.Check(rect))
for (var e in entityTracker[typeof(T)])
if (e.Check(rect))
return e as T;
return null;
}
public List<T> All<T>(List<T> into) where T : Entity
{
for (var e in entities)
if (e is T)
into.Add(e as T);
for (var e in entityTracker[typeof(T)])
into.Add(e as T);
return into;
}
public List<T> All<T>(Point point, List<T> into) where T : Entity
{
for (var e in entities)
if (e is T && e.Check(point))
for (var e in entityTracker[typeof(T)])
if (e.Check(point))
into.Add(e as T);
return into;
}
public List<T> All<T>(Rect rect, List<T> into) where T : Entity
{
for (var e in entities)
if (e is T && e.Check(rect))
for (var e in entityTracker[typeof(T)])
if (e.Check(rect))
into.Add(e as T);
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);
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
{
public enum Cardinals
@ -66,5 +68,33 @@ namespace Strawberry
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;
}
}
}