using System.Collections; using System; namespace Strawberry { public class Scene { public float TimeStarted { get; private set; } private List entities = new .() ~ delete _; private HashSet toRemove = new .() ~ delete _; private HashSet toAdd = new .() ~ delete _; private Dictionary> componentTracker = new .() ~ DeleteDictionaryAndValues!(_); public this() { for (let type in Tracker.AssignmentLists.Keys) componentTracker.Add(type, new List()); for (let type in Tracker.Interfaces) componentTracker.Add(type, new List()); } public ~this() { for (var e in entities) if (e.DeleteOnRemove) delete e; for (var e in toAdd) if (e.DeleteOnRemove) delete e; } public virtual void Started() { TimeStarted = Time.Elapsed; } public virtual void Update() { ForEach(scope (u) => u.EarlyUpdate()); ForEach(scope (u) => u.Update()); ForEach(scope (u) => u.LateUpdate()); UpdateLists(); } public virtual void Draw() { ForEach(scope (d) => d.Draw()); } /* Entities */ public Entity Add(Entity e) { if (e.Scene == null) toAdd.Add(e); return e; } public Entity Remove(Entity e) { if (e.Scene == this) toRemove.Add(e); return e; } private void UpdateLists() { if (toRemove.Count > 0) { for (let e in toRemove) { entities.Remove(e); e.[Friend]Removed(); if (e.DeleteOnRemove) delete e; } toRemove.Clear(); } if (toAdd.Count > 0) { for (let e in toAdd) { entities.Add(e); e.[Friend]Added(this); } toAdd.Clear(); } for (let e in entities) e.[Friend]UpdateLists(); for (let e in entities) e.[Friend]AwakeCheck(); } /* Tracking */ private void TrackComponent(Component c) { for (let t in Tracker.AssignmentLists[c.GetType()]) componentTracker[t].Add(c); } private void UntrackComponent(Component c) { for (let t in Tracker.AssignmentLists[c.GetType()]) componentTracker[t].Remove(c); } /* Time */ public float TimeElapsed => Time.Elapsed - TimeStarted; public float PreviousTimeElapsed => Time.PreviousElapsed - TimeStarted; public bool TimeOnInterval(float interval, float offset = 0) { return (int)((TimeElapsed - offset) / interval) != (int)((PreviousTimeElapsed - offset) / interval); } public bool TimeBetweenInterval(float interval, float offset = 0) { return (TimeElapsed - offset) % (interval * 2) >= interval; } /* Finding Components */ public int Count() where T : Component { return componentTracker[typeof(T)].Count; } public int Count(delegate bool(T) condition) where T : Component { int count = 0; for (T c in componentTracker[typeof(T)]) if (condition(c)) count++; return count; } public bool Check(delegate bool(T) condition) where T : Component { for (T c in componentTracker[typeof(T)]) if (condition(c)) return true; return false; } public bool Check(Point point) where T : Component, IHasHitbox { for (T c in componentTracker[typeof(T)]) if (c.Hitbox.Check(point)) return true; return false; } public bool Check(Point point, delegate bool(T) condition) where T : Component, IHasHitbox { for (T c in componentTracker[typeof(T)]) if (c.Hitbox.Check(point) && condition(c)) return true; return false; } public bool Check(Rect rect) where T : Component, IHasHitbox { for (T c in componentTracker[typeof(T)]) if (c.Hitbox.Check(rect)) return true; return false; } public bool Check(Rect rect, delegate bool(T) condition) where T : Component, IHasHitbox { for (T c in componentTracker[typeof(T)]) if (c.Hitbox.Check(rect) && condition(c)) return true; return false; } public T First() where T : Component { for (T c in componentTracker[typeof(T)]) return c; return null; } public T First(delegate bool(T) condition) where T : Component { for (T c in componentTracker[typeof(T)]) if (condition(c)) return c; return null; } public T First(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(Point point, delegate bool(T) condition) where T : Component, IHasHitbox { for (T c in componentTracker[typeof(T)]) if (c.Hitbox.Check(point) && condition(c)) return c as T; return null; } public T First(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 T First(Rect rect, delegate bool(T) condition) where T : Component, IHasHitbox { for (T c in componentTracker[typeof(T)]) if (c.Hitbox.Check(rect) && condition(c)) return c as T; return null; } public List All(List into) where T : Component { for (T c in componentTracker[typeof(T)]) into.Add(c as T); return into; } public List All(List into, delegate bool(T) condition) where T : Component { for (T c in componentTracker[typeof(T)]) if (condition(c)) into.Add(c as T); return into; } public List All(Point point, List into) where T : Component, IHasHitbox { for (T c in componentTracker[typeof(T)]) if (c.Hitbox.Check(point)) into.Add(c as T); return into; } public List All(Point point, List into, delegate bool(T) condition) where T : Component, IHasHitbox { for (T c in componentTracker[typeof(T)]) if (c.Hitbox.Check(point) && condition(c)) into.Add(c as T); return into; } public List All(Rect rect, List into, delegate bool(T) condition) where T : Component, IHasHitbox { for (T c in componentTracker[typeof(T)]) if (c.Hitbox.Check(rect) && condition(c)) into.Add(c as T); return into; } public void ForEach(delegate void(T) action) where T : interface { List list; if (componentTracker.TryGetValue(typeof(T), out list)) for (let c in list) action(c as T); } public void ForEach(delegate void(T) action) where T : Component { List list; if (componentTracker.TryGetValue(typeof(T), out list)) for (T c in list) action(c); } } }