Big restructuring - sample game is currently broken

This commit is contained in:
Maddy Thorson
2021-02-04 23:11:51 -08:00
parent 05c79b296e
commit 3d5130b45b
28 changed files with 551 additions and 866 deletions

View File

@ -0,0 +1,288 @@
using System;
using System.Collections;
namespace Strawberry
{
public class Hitbox : Component, IDebugDraw
{
public bool Collidable = true;
public Rect Rect;
public void DebugDraw()
{
Game.Batcher.Rect(SceneHitbox, .Red);
}
public int Width
{
[Inline]
get
{
return Rect.Width;
}
[Inline]
set
{
Rect.Width = value;
}
}
public int Height
{
[Inline]
get
{
return Rect.Height;
}
[Inline]
set
{
Rect.Height = value;
}
}
public Rect SceneHitbox
{
[Inline]
get
{
return Rect + Entity.Position;
}
}
public int Left
{
[Inline]
get
{
return Entity.X + Rect.Left;
}
[Inline]
set
{
Entity.X = value - Rect.Left;
}
}
public int Right
{
[Inline]
get
{
return Entity.X + Rect.Right;
}
[Inline]
set
{
Entity.X = value - Rect.Right;
}
}
public int Top
{
[Inline]
get
{
return Entity.Y + Rect.Top;
}
[Inline]
set
{
Entity.Y = value - Rect.Top;
}
}
public int Bottom
{
[Inline]
get
{
return Entity.Y + Rect.Bottom;
}
[Inline]
set
{
Entity.Y = value - Rect.Bottom;
}
}
// ===== Collisions =====
public bool Check(Point point)
{
return SceneHitbox.Contains(point);
}
public bool Check(Rect rect)
{
return SceneHitbox.Intersects(rect);
}
public bool Check(Grid grid)
{
return grid != null && grid.Check(SceneHitbox);
}
public bool Check(Grid grid, Point offset)
{
return grid != null && grid.Check(SceneHitbox + offset);
}
public bool Check(Hitbox other)
{
return other.Collidable && SceneHitbox.Intersects(other.SceneHitbox);
}
public bool Check(Hitbox other, Point offset)
{
return other.Collidable && (SceneHitbox + offset).Intersects(other.SceneHitbox);
}
public bool CheckOutside(Hitbox other, Point offset)
{
return other.Collidable && !SceneHitbox.Intersects(other.SceneHitbox) && (SceneHitbox + offset).Intersects(other.SceneHitbox);
}
public bool Check<T>(T other) where T : Component, IHasHitbox
{
return Check(other.Hitbox);
}
public bool Check<T>(T other, Point offset) where T : Component, IHasHitbox
{
return Check(other.Hitbox, offset);
}
public bool CheckOutside<T>(T other, Point offset) where T : Component, IHasHitbox
{
return CheckOutside(other.Hitbox, offset);
}
public bool Check<T>() where T : Component, IHasHitbox
{
for (var e in Scene.All<T>(scope List<T>()))
if (Check(e.Hitbox))
return true;
return false;
}
public bool Check<T>(Point offset) where T : Component, IHasHitbox
{
for (var e in Scene.All<T>(scope List<T>()))
if (Check(e.Hitbox, offset))
return true;
return false;
}
public bool CheckOutside<T>(Point offset) where T : Component, IHasHitbox
{
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e.Hitbox, offset))
return true;
return false;
}
public T First<T>() where T : Component, IHasHitbox
{
for (var e in Scene.All<T>(scope List<T>()))
if (Check(e.Hitbox))
return e;
return null;
}
public T First<T>(Point offset) where T : Component, IHasHitbox
{
for (var e in Scene.All<T>(scope List<T>()))
if (Check(e.Hitbox, offset))
return e;
return null;
}
public T FirstOutside<T>(Point offset) where T : Component, IHasHitbox
{
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e.Hitbox, offset))
return e;
return null;
}
public T LeftmostOutside<T>(Point offset) where T : Component, IHasHitbox
{
T ret = null;
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e.Hitbox, offset) && (ret == null || e.Hitbox.Left < ret.Hitbox.Left))
ret = e;
return ret;
}
public T RightmostOutside<T>(Point offset) where T : Component, IHasHitbox
{
T ret = null;
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e.Hitbox, offset) && (ret == null || e.Hitbox.Right > ret.Hitbox.Right))
ret = e;
return ret;
}
public T TopmostOutside<T>(Point offset) where T : Component, IHasHitbox
{
T ret = null;
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e.Hitbox, offset) && (ret == null || e.Hitbox.Top < ret.Hitbox.Top))
ret = e;
return ret;
}
public T BottommostOutside<T>(Point offset) where T : Component, IHasHitbox
{
T ret = null;
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e.Hitbox, offset) && (ret == null || e.Hitbox.Bottom > ret.Hitbox.Bottom))
ret = e;
return ret;
}
public List<T> All<T>(List<T> into) where T : Component, IHasHitbox
{
for (var e in Scene.All<T>(scope List<T>()))
if (Check(e.Hitbox))
into.Add(e);
return into;
}
public List<T> All<T>(Point offset, List<T> into) where T : Component, IHasHitbox
{
for (var e in Scene.All<T>(scope List<T>()))
if (Check(e.Hitbox, offset))
into.Add(e);
return into;
}
public List<T> AllOutside<T>(Point offset, List<T> into) where T : Component, IHasHitbox
{
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e.Hitbox, offset))
into.Add(e);
return into;
}
}
}

View File

@ -1,14 +1,16 @@
using System.Collections;
namespace Strawberry
{
public class OnCollide<T> : Component where T : Entity
public class OnCollide<T> : Component, IHasHitbox, IUpdate where T : Component, IHasHitbox
{
public Hitbox Hitbox { get; private set; }
// Takes as parameter the T collided with. Return false to stop checking for collisions until next frame.
public delegate bool(T) Action;
public this(delegate bool(T) action)
: base(true, false)
public this(Hitbox hitbox, delegate bool(T) action)
{
Hitbox = hitbox;
Action = action;
}
@ -17,13 +19,13 @@ namespace Strawberry
delete Action;
}
public override void Update()
public void Update()
{
if (Action != null)
{
let list = Entity.Scene.All<T>(scope List<T>());
for (let t in list)
if (Entity.Check(t) && !Action(t))
if (Hitbox.Check(t) && !Action(t))
break;
}
}

View File

@ -0,0 +1,19 @@
namespace Strawberry
{
public class DrawHitbox : Component, IHasHitbox, IDraw
{
public Hitbox Hitbox { get; private set; }
public Color Color;
public this(Hitbox hitbox, Color color)
{
Hitbox = hitbox;
Color = color;
}
public void Draw()
{
Game.Batcher.Rect(Hitbox.SceneHitbox, Color);
}
}
}

View File

@ -0,0 +1,8 @@
namespace Strawberry
{
[ComponentInterface]
public interface IDebugDraw
{
public void DebugDraw();
}
}

View File

@ -0,0 +1,8 @@
namespace Strawberry
{
[ComponentInterface]
public interface IDraw
{
public void Draw();
}
}

View File

@ -0,0 +1,8 @@
namespace Strawberry
{
[ComponentInterface]
public interface IHasHitbox
{
public Hitbox Hitbox { get; }
}
}

View File

@ -0,0 +1,8 @@
namespace Strawberry
{
[ComponentInterface]
public interface ILateUpdate
{
public void LateUpdate();
}
}

View File

@ -0,0 +1,8 @@
namespace Strawberry
{
[ComponentInterface]
public interface IUpdate
{
public void Update();
}
}

View File

@ -4,7 +4,7 @@ using System.Diagnostics;
namespace Strawberry
{
public class StateMachine<TIndex> : Component where TIndex : struct, IHashable
public class StateMachine<TIndex> : Component, IUpdate where TIndex : struct, IHashable
{
private Dictionary<TIndex, State> states = new Dictionary<TIndex, State>() ~ delete _;
private TIndex state;
@ -14,7 +14,6 @@ namespace Strawberry
public TIndex NextState { get; private set; }
public this(TIndex startState)
: base(true, false)
{
NextState = PreviousState = state = startState;
}
@ -30,7 +29,7 @@ namespace Strawberry
CallEnter();
}
public override void Update()
public void Update()
{
CallUpdate();
}

View File

@ -3,35 +3,27 @@ using System.Diagnostics;
namespace Strawberry
{
public class Timer : Component
public class Timer : Component, IUpdate
{
private float value;
public Action OnComplete ~ delete _;
public bool RemoveOnComplete;
public this()
: base(false, false)
{
}
public this(Action onComplete, bool destroyOnComplete = false)
: base(false, false)
{
OnComplete = onComplete;
RemoveOnComplete = destroyOnComplete;
}
public this(float value, Action onComplete, bool destroyOnComplete = false)
: base(false, false)
{
Value = value;
OnComplete = onComplete;
RemoveOnComplete = destroyOnComplete;
}
public override void Update()
public void Update()
{
if (value > 0)
{
@ -39,8 +31,6 @@ namespace Strawberry
if (value <= 0)
{
value = 0;
Active = false;
OnComplete?.Invoke();
if (RemoveOnComplete)
RemoveSelf();
@ -60,7 +50,6 @@ namespace Strawberry
set
{
this.value = Math.Max(0, value);
Active = (this.value > 0);
}
}
@ -68,7 +57,6 @@ namespace Strawberry
public void Clear()
{
value = 0;
Active = false;
}
static public implicit operator bool(Timer timer)

View File

@ -1,33 +1,42 @@
using System;
namespace Strawberry
{
public class Tween : Component
public class Tween : Component, IUpdate
{
public Ease.Easer Easer ~ delete _;
public delegate void(float) OnUpdate ~ delete _;
public delegate void() OnComplete ~ delete _;
public bool RemoveOnComplete;
public bool Playing { get; private set; }
public float T { get; private set; }
public this(Ease.Easer easer = null, delegate void(float) onUpdate = null, delegate void() onComplete = null, bool removeOnComplete = true, bool start = true)
: base(start, false)
{
Playing = start;
Easer = easer;
OnUpdate = onUpdate;
OnComplete = onComplete;
RemoveOnComplete = removeOnComplete;
}
[Inline]
public float Eased => Easer != null ? Easer(T) : T;
[Inline]
public void Play()
{
T = 0;
Active = true;
Playing = true;
}
public override void Update()
[Inline]
public void Stop()
{
Playing = false;
}
public void Update()
{
T = Math.Min(T + Time.Delta, 1);
OnUpdate?.Invoke(Eased);
@ -35,7 +44,7 @@ namespace Strawberry
if (T >= 1)
{
OnComplete?.Invoke();
Active = false;
Playing = false;
if (RemoveOnComplete)
RemoveSelf();
}

View File

@ -6,15 +6,6 @@ namespace Strawberry
{
public Entity Entity { get; private set; }
public bool Active;
public bool Visible;
public this(bool active, bool visible)
{
Active = active;
Visible = visible;
}
private void Added(Entity entity)
{
Entity = entity;
@ -27,13 +18,20 @@ namespace Strawberry
public virtual void Started() { }
public virtual void Ended() { }
public virtual void Update() { }
public virtual void Draw() { }
[Inline]
public void RemoveSelf()
{
Entity?.Remove(this);
}
[Inline]
public Scene Scene => Entity?.Scene;
[Inline]
public T SceneAs<T>() where T : Scene
{
return Entity.SceneAs<T>();
}
}
}

View File

@ -0,0 +1,9 @@
using System;
namespace Strawberry
{
public struct ComponentInterfaceAttribute : Attribute
{
}
}

View File

@ -3,13 +3,9 @@ using System.Collections;
namespace Strawberry
{
public abstract class Entity
public sealed class Entity
{
public Scene Scene { get; private set; }
public int Priority;
public bool Active = true;
public bool Visible = true;
public bool Collidable = true;
public bool DeleteOnRemove = true;
private List<Component> components = new List<Component>() ~ delete _;
@ -40,32 +36,18 @@ namespace Strawberry
Scene = null;
}
public virtual void Started()
public void Started()
{
for (var c in components)
c.Started();
}
public virtual void Ended()
public void Ended()
{
for (var c in components)
c.Ended();
}
public virtual void Update()
{
for (var c in components)
if (c.Active)
c.Update();
}
public virtual void Draw()
{
for (var c in components)
if (c.Visible)
c.Draw();
}
[Inline]
public void RemoveSelf()
{
@ -195,302 +177,13 @@ namespace Strawberry
}
}
// ===== Hitbox =====
public Rect Hitbox;
public int Width
{
[Inline]
get
{
return Hitbox.Width;
}
[Inline]
set
{
Hitbox.Width = value;
}
}
public int Height
{
[Inline]
get
{
return Hitbox.Height;
}
[Inline]
set
{
Hitbox.Height = value;
}
}
public Rect SceneHitbox
{
[Inline]
get
{
return Hitbox + Position;
}
}
public Rect SceneHitboxOutline
{
[Inline]
get
{
Rect hb = Hitbox + Position;
hb.X -= 1;
hb.Y -= 1;
hb.Width += 2;
hb.Height += 2;
return hb;
}
}
public int Left
{
[Inline]
get
{
return Position.X + Hitbox.Left;
}
[Inline]
set
{
X = value - Hitbox.Left;
}
}
public int Right
{
[Inline]
get
{
return Position.X + Hitbox.Right;
}
[Inline]
set
{
Y = value - Hitbox.Right;
}
}
public int Top
{
[Inline]
get
{
return Position.Y + Hitbox.Top;
}
[Inline]
set
{
Y = value - Hitbox.Top;
}
}
public int Bottom
{
[Inline]
get
{
return Position.Y + Hitbox.Bottom;
}
[Inline]
set
{
Y = value - Hitbox.Bottom;
}
}
// ===== Collisions =====
public bool Check(Point point)
{
return SceneHitbox.Contains(point);
}
public bool Check(Rect rect)
{
return SceneHitbox.Intersects(rect);
}
public bool Check(Grid grid)
{
return grid != null && grid.Check(SceneHitbox);
}
public bool Check(Grid grid, Point offset)
{
return grid != null && grid.Check(SceneHitbox + offset);
}
public bool Check(Entity other)
{
return other.Collidable && SceneHitbox.Intersects(other.SceneHitbox);
}
public bool Check(Entity other, Point offset)
{
return other.Collidable && (SceneHitbox + offset).Intersects(other.SceneHitbox);
}
public bool CheckOutside(Entity other, Point offset)
{
return other.Collidable && !SceneHitbox.Intersects(other.SceneHitbox) && (SceneHitbox + offset).Intersects(other.SceneHitbox);
}
public bool Check<T>() where T : Entity
{
for (var e in Scene.All<T>(scope List<T>()))
if (Check(e))
return true;
return false;
}
public bool Check<T>(Point offset) where T : Entity
{
for (var e in Scene.All<T>(scope List<T>()))
if (Check(e, offset))
return true;
return false;
}
public bool CheckOutside<T>(Point offset) where T : Entity
{
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e, offset))
return true;
return false;
}
public T First<T>() where T : Entity
{
for (var e in Scene.All<T>(scope List<T>()))
if (Check(e))
return e;
return null;
}
public T First<T>(Point offset) where T : Entity
{
for (var e in Scene.All<T>(scope List<T>()))
if (Check(e, offset))
return e;
return null;
}
public T FirstOutside<T>(Point offset) where T : Entity
{
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e, offset))
return e;
return null;
}
public T LeftmostOutside<T>(Point offset) where T : Entity
{
T ret = null;
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e, offset) && (ret == null || e.Left < ret.Left))
ret = e;
return ret;
}
public T RightmostOutside<T>(Point offset) where T : Entity
{
T ret = null;
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e, offset) && (ret == null || e.Right > ret.Right))
ret = e;
return ret;
}
public T TopmostOutside<T>(Point offset) where T : Entity
{
T ret = null;
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e, offset) && (ret == null || e.Top < ret.Top))
ret = e;
return ret;
}
public T BottommostOutside<T>(Point offset) where T : Entity
{
T ret = null;
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e, offset) && (ret == null || e.Bottom > ret.Bottom))
ret = e;
return ret;
}
public List<T> All<T>(List<T> into) where T : Entity
{
for (var e in Scene.All<T>(scope List<T>()))
if (Check(e))
into.Add(e);
return into;
}
public List<T> All<T>(Point offset, List<T> into) where T : Entity
{
for (var e in Scene.All<T>(scope List<T>()))
if (Check(e, offset))
into.Add(e);
return into;
}
public List<T> AllOutside<T>(Point offset, List<T> into) where T : Entity
{
for (var e in Scene.All<T>(scope List<T>()))
if (CheckOutside(e, offset))
into.Add(e);
return into;
}
// ===== Misc =====
public void DrawHitbox(Color color)
{
Game.Batcher.Rect(SceneHitbox, color);
}
public void DrawHitboxOutline(Color color)
{
Game.Batcher.Rect(SceneHitboxOutline, color);
}
[Inline]
public T SceneAs<T>() where T : Scene
{
Runtime.Assert(Scene is T, "Scene type mismatch!");
return Scene as T;
}
static public int Compare(Entity a, Entity b)
{
return a.Priority <=> b.Priority;
}
}
}

View File

@ -25,8 +25,6 @@ namespace Strawberry
private Scene scene;
private Scene switchToScene;
private bool updating;
private Dictionary<Type, List<Type>> entityAssignableLists;
private Dictionary<Type, List<Type>> componentAssignableLists;
public PlatformLayer PlatformLayer { get; private set; }
public Batcher Batcher { get; private set; }
@ -60,9 +58,9 @@ namespace Strawberry
VirtualInputs = new List<VirtualInput>();
Input.[Friend]Init();
BuildTypeLists();
Tracker.[Friend]BuildAssignmentLists();
Assets.LoadAll();
Strawberry.Console.Init();
Strawberry.StrwConsole.Init();
}
public ~this()
@ -83,9 +81,8 @@ namespace Strawberry
}
Assets.DisposeAll();
DisposeTypeLists();
Input.[Friend]Dispose();
Strawberry.Console.Dispose();
Strawberry.StrwConsole.Dispose();
delete Batcher;
@ -157,7 +154,7 @@ namespace Strawberry
Time.Elapsed += Time.Delta;
}
Strawberry.Console.[Friend]Update();
Strawberry.StrwConsole.[Friend]Update();
}
private void Render()
@ -171,8 +168,8 @@ namespace Strawberry
{
Scene?.Draw();
if (Strawberry.Console.Enabled)
Strawberry.Console.[Friend]Draw();
if (Strawberry.StrwConsole.Enabled)
Strawberry.StrwConsole.[Friend]Draw();
Batcher.Draw();
}
@ -191,57 +188,5 @@ namespace Strawberry
switchToScene = value;
}
}
// Type assignable caching
private void BuildTypeLists()
{
/*
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);
}
}
}
private void DisposeTypeLists()
{
for (let list in entityAssignableLists.Values)
delete list;
delete entityAssignableLists;
for (let list in componentAssignableLists.Values)
delete list;
delete componentAssignableLists;
}
}
}

View File

@ -10,7 +10,6 @@ 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()
@ -19,12 +18,10 @@ namespace Strawberry
toAdd = new HashSet<Entity>();
toRemove = new HashSet<Entity>();
entityTracker = new Dictionary<Type, List<Entity>>();
for (let type in Game.[Friend]entityAssignableLists.Keys)
entityTracker.Add(type, new List<Entity>());
componentTracker = new Dictionary<Type, List<Component>>();
for (let type in Game.[Friend]componentAssignableLists.Keys)
for (let type in Tracker.AssignmentLists.Keys)
componentTracker.Add(type, new List<Component>());
for (let type in Tracker.Interfaces)
componentTracker.Add(type, new List<Component>());
}
@ -42,10 +39,6 @@ namespace Strawberry
delete toRemove;
for (let list in entityTracker.Values)
delete list;
delete entityTracker;
for (let list in componentTracker.Values)
delete list;
delete componentTracker;
@ -59,26 +52,23 @@ namespace Strawberry
public virtual void Update()
{
UpdateLists();
for (let e in entities)
if (e.Active)
e.Update();
}
public virtual void Draw()
{
for (let e in entities)
if (e.Visible)
e.Draw();
}
public T Add<T>(T e) where T : Entity
public Entity Add(Entity e)
{
if (e.Scene == null)
toAdd.Add(e);
return e;
}
public T Remove<T>(T e) where T : Entity
public Entity Remove(Entity e)
{
if (e.Scene == this)
toRemove.Add(e);
@ -92,7 +82,6 @@ namespace Strawberry
for (let e in toRemove)
{
entities.Remove(e);
UntrackEntity(e);
e.[Friend]Removed();
if (e.DeleteOnRemove)
delete e;
@ -106,11 +95,8 @@ namespace Strawberry
for (let e in toAdd)
{
entities.Add(e);
TrackEntity(e);
e.[Friend]Added(this);
}
entities.Sort(scope => Entity.Compare);
}
for (let e in entities)
@ -126,33 +112,15 @@ namespace Strawberry
// Tracking
private void TrackEntity(Entity e)
{
for (let t in Game.[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 Game.[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 Game.[Friend]componentAssignableLists[c.GetType()])
for (let t in Tracker.AssignmentLists[c.GetType()])
componentTracker[t].Add(c);
}
private void UntrackComponent(Component c)
{
for (let t in Game.[Friend]componentAssignableLists[c.GetType()])
for (let t in Tracker.AssignmentLists[c.GetType()])
componentTracker[t].Remove(c);
}
@ -171,75 +139,6 @@ namespace Strawberry
return (TimeElapsed - offset) % (interval * 2) >= interval;
}
// Finding Entities
public int Count<T>() where T : Entity
{
return entityTracker[typeof(T)].Count;
}
public bool Check<T>(Point point) where T : Entity
{
for (let e in entityTracker[typeof(T)])
if (e.Check(point))
return true;
return false;
}
public bool Check<T>(Rect rect) where T : Entity
{
for (let e in entityTracker[typeof(T)])
if (e.Check(rect))
return true;
return false;
}
public T First<T>() where T : Entity
{
for (let e in entityTracker[typeof(T)])
return e as T;
return null;
}
public T First<T>(Point point) where T : Entity
{
for (let 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 (let 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 (let 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 (let 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 (let e in entityTracker[typeof(T)])
if (e.Check(rect))
into.Add(e as T);
return into;
}
/*
Finding Components
*/
@ -249,25 +148,64 @@ namespace Strawberry
return componentTracker[typeof(T)].Count;
}
public List<T> All<T>(List<T> into) where T : Component
public bool Check<T>(Point point) where T : Component, IHasHitbox
{
for (let c in componentTracker[typeof(T)])
for (T c in componentTracker[typeof(T)])
if (c.Hitbox.Check(point))
return true;
return false;
}
public bool Check<T>(Rect rect) where T : Component, IHasHitbox
{
for (T c in componentTracker[typeof(T)])
if (c.Hitbox.Check(rect))
return true;
return false;
}
public T First<T>() where T : Component, IHasHitbox
{
for (T c in componentTracker[typeof(T)])
return c;
return null;
}
public T First<T>(Point point) where T : Component, IHasHitbox
{
for (T c in componentTracker[typeof(T)])
if (c.Hitbox.Check(point))
return c as T;
return null;
}
public T First<T>(Rect rect) where T : Component, IHasHitbox
{
for (T c in componentTracker[typeof(T)])
if (c.Hitbox.Check(rect))
return c as T;
return null;
}
public List<T> All<T>(List<T> into) where T : Component, IHasHitbox
{
for (T c in componentTracker[typeof(T)])
into.Add(c as T);
return into;
}
public List<T> All<T>(Point point, List<T> into) where T : Component
public List<T> All<T>(Point point, List<T> into) where T : Component, IHasHitbox
{
for (let c in componentTracker[typeof(T)])
if (c.Entity.Check(point))
for (T c in componentTracker[typeof(T)])
if (c.Hitbox.Check(point))
into.Add(c as T);
return into;
}
public List<T> All<T>(Rect rect, List<T> into) where T : Component
public List<T> All<T>(Rect rect, List<T> into) where T : Component, IHasHitbox
{
for (let c in componentTracker[typeof(T)])
if (c.Entity.Check(rect))
for (T c in componentTracker[typeof(T)])
if (c.Hitbox.Check(rect))
into.Add(c as T);
return into;
}

View File

@ -143,9 +143,14 @@ namespace Strawberry
return p.X >= 0 && p.Y >= 0 && p.X < CellsX && p.Y < CellsY;
}
public bool Check(Entity entity)
public bool Check(Hitbox hitbox)
{
return Check(entity.SceneHitbox);
return Check(hitbox.SceneHitbox);
}
public bool Check(IHasHitbox other)
{
return Check(other.Hitbox.SceneHitbox);
}
public bool Check(Rect rect)

View File

@ -19,7 +19,7 @@ namespace Strawberry
}
[Reflect]
static public class Console
static public class StrwConsole
{
static public bool Open;

38
src/Static/Tracker.bf Normal file
View File

@ -0,0 +1,38 @@
using System.Collections;
using System;
namespace Strawberry
{
static public class Tracker
{
static public Dictionary<Type, List<Type>> AssignmentLists = new .() ~ DeleteDictionaryAndValues!(_);
static public List<Type> Interfaces = new .() ~ delete _;
static private void BuildAssignmentLists()
{
// Find all interfaces with ComponentInterfaceAttribute
for (let type in Type.Enumerator())
if (type.IsInterface && type.HasCustomAttribute<ComponentInterfaceAttribute>())
Interfaces.Add(type);
/*
For each Type that extends Component, we build a list of all the tracked Interfaces it implements.
We use these lists later to bucket Components as they are added to the Scene.
This allows us to retrieve Components by their type or by any of their implemented interface types.
*/
for (let type in Type.Enumerator())
{
if (type != typeof(Component) && type.IsSubtypeOf(typeof(Component)))
{
let list = new List<Type>();
list.Add(type);
for (let check in Interfaces)
if (type.IsSubtypeOf(check))
list.Add(check);
AssignmentLists.Add(type, list);
}
}
}
}
}