diff --git a/Engine.Core/Collectors/ActiveBehaviourCollectorOrdered.cs b/Engine.Core/Collectors/ActiveBehaviourCollectorOrdered.cs index fbc14e4..502e45c 100644 --- a/Engine.Core/Collectors/ActiveBehaviourCollectorOrdered.cs +++ b/Engine.Core/Collectors/ActiveBehaviourCollectorOrdered.cs @@ -3,77 +3,61 @@ using System.Collections.Generic; namespace Engine.Core; -public class ActiveBehaviourCollectorOrdered : ActiveBehaviourCollector where T : class, IBehaviour +public class ActiveBehaviourCollectorOrdered : ActiveBehaviourCollector where TItem : class, IBehaviour where TIndex : IComparable { private readonly Event.EventHandler delegateOnPriorityChanged = null!; - private readonly LinkedList behaviours = new(); - private readonly List sortList = []; + private readonly SortedDictionary> behaviours = null!; - private IComparer? _sortBy = null; - public IComparer? SortBy - { - get => _sortBy; - set - { - _sortBy = value; + private readonly Func getIndexFunc = null!; + private readonly IComparer sortBy = null!; - if (value is not null) - Sort(value); - } - } + private int count = 0; + public override int Count => count; - public override int Count => behaviours.Count; - - public override T this[Index index] + public override TItem this[Index index] { get { int actualIndex = index.IsFromEnd - ? behaviours.Count - index.Value + ? count - index.Value : index.Value; - if (actualIndex < 0 || actualIndex >= behaviours.Count) + if (actualIndex < 0 || actualIndex >= count) throw new IndexOutOfRangeException(); - int currentIndex = 0; - foreach (T item in behaviours) - if (currentIndex++ == actualIndex) - return item; - + int leftIndex = actualIndex; + foreach ((TIndex i, FastList list) in behaviours) + { + if (leftIndex < list.Count) + return list[leftIndex]; + leftIndex -= list.Count; + } throw new IndexOutOfRangeException(); } } - protected override bool RemoveBehaviour(T tBehaviour) => behaviours.Remove(tBehaviour); - protected override void AddBehaviour(T behaviour) + protected override bool RemoveBehaviour(TItem tBehaviour) { - if (SortBy is null) - { - behaviours.AddLast(behaviour); - return; - } + TIndex index = getIndexFunc(tBehaviour); + if (!behaviours.TryGetValue(index, out FastList? list)) + throw new Exceptions.NotFoundException($"Index of '{index}' is not found in the collector"); - LinkedListNode? insertionNode = FindInsertionNodeFor(behaviour, SortBy); + if (!list.Remove(tBehaviour)) + return false; - if (insertionNode is not null) - behaviours.AddAfter(insertionNode, behaviour); - else - behaviours.AddLast(behaviour); + count--; + return true; } - private LinkedListNode? FindInsertionNodeFor(T behaviour, IComparer sortBy) + protected override void AddBehaviour(TItem behaviour) { - LinkedListNode? node = behaviours.First; + TIndex key = getIndexFunc(behaviour); + if (!behaviours.TryGetValue(key, out FastList? list)) + behaviours[key] = list = []; - while (node is not null) - { - int compareValue = sortBy.Compare(node.Value, behaviour); - if (compareValue < 0) - return node.Previous; - node = node.Next; - } - return null; + count++; + list.Add(behaviour); } protected override void OnBehaviourAdd(IBehaviour behaviour) => behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged); @@ -81,23 +65,40 @@ public class ActiveBehaviourCollectorOrdered : ActiveBehaviourCollector wh private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args) { - T behaviour = (T)sender; - behaviours.Remove(behaviour); + TItem behaviour = (TItem)sender; + RemoveBehaviour(behaviour); AddBehaviour(behaviour); } - private void Sort(IComparer comparer) - { - sortList.Sort(comparer); - behaviours.Clear(); - foreach (T item in sortList) - behaviours.AddLast(item); - } - - public ActiveBehaviourCollectorOrdered() => delegateOnPriorityChanged = OnPriorityChanged; - public ActiveBehaviourCollectorOrdered(IUniverse universe, Comparison sortBy) : base(universe) + public ActiveBehaviourCollectorOrdered(Func getIndexFunc, Comparison sortBy) { delegateOnPriorityChanged = OnPriorityChanged; - SortBy = Comparer.Create(sortBy); + this.getIndexFunc = getIndexFunc; + this.sortBy = Comparer.Create(sortBy); + behaviours = new(this.sortBy); + } + + public ActiveBehaviourCollectorOrdered(IUniverse universe, Func getIndexFunc, Comparison sortBy) : base(universe) + { + delegateOnPriorityChanged = OnPriorityChanged; + this.getIndexFunc = getIndexFunc; + this.sortBy = Comparer.Create(sortBy); + behaviours = new(this.sortBy); + } + + public ActiveBehaviourCollectorOrdered(Func getIndexFunc, IComparer sortBy) + { + this.getIndexFunc = getIndexFunc; + delegateOnPriorityChanged = OnPriorityChanged; + this.sortBy = sortBy; + behaviours = new(sortBy); + } + + public ActiveBehaviourCollectorOrdered(IUniverse universe, Func getIndexFunc, IComparer sortBy) : base(universe) + { + delegateOnPriorityChanged = OnPriorityChanged; + this.getIndexFunc = getIndexFunc; + this.sortBy = sortBy; + behaviours = new(sortBy); } } diff --git a/Engine.Core/Collectors/BehaviourCollectorOrdered.cs b/Engine.Core/Collectors/BehaviourCollectorOrdered.cs index 5558aa2..6f1077a 100644 --- a/Engine.Core/Collectors/BehaviourCollectorOrdered.cs +++ b/Engine.Core/Collectors/BehaviourCollectorOrdered.cs @@ -3,76 +3,61 @@ using System.Collections.Generic; namespace Engine.Core; -public class BehaviourCollectorOrdered : BehaviourCollectorBase where T : class +public class BehaviourCollectorOrdered : BehaviourCollectorBase where TItem : class where TIndex : IComparable { private readonly Event.EventHandler delegateOnPriorityChanged = null!; - private readonly LinkedList behaviours = new(); - private readonly List sortList = []; + private readonly SortedDictionary> behaviours = null!; - private IComparer? _sortBy = null; - public IComparer? SortBy - { - get => _sortBy; - set - { - _sortBy = value; + private readonly Func getIndexFunc = null!; + private readonly IComparer sortBy = null!; - if (value is not null) - Sort(value); - } - } + private int count = 0; + public override int Count => count; - public override int Count => behaviours.Count; - public override T this[Index index] + public override TItem this[Index index] { get { int actualIndex = index.IsFromEnd - ? behaviours.Count - index.Value + ? count - index.Value : index.Value; - if (actualIndex < 0 || actualIndex >= behaviours.Count) + if (actualIndex < 0 || actualIndex >= count) throw new IndexOutOfRangeException(); - int currentIndex = 0; - foreach (T item in behaviours) - if (currentIndex++ == actualIndex) - return item; - + int leftIndex = actualIndex; + foreach ((TIndex i, FastList list) in behaviours) + { + if (leftIndex < list.Count) + return list[leftIndex]; + leftIndex -= list.Count; + } throw new IndexOutOfRangeException(); } } - protected override bool RemoveBehaviour(T tBehaviour) => behaviours.Remove(tBehaviour); - protected override void AddBehaviour(T behaviour) + protected override bool RemoveBehaviour(TItem tBehaviour) { - if (SortBy is null) - { - behaviours.AddLast(behaviour); - return; - } + TIndex index = getIndexFunc(tBehaviour); + if (!behaviours.TryGetValue(index, out FastList? list)) + throw new Exceptions.NotFoundException($"Index of '{index}' is not found in the collector"); - LinkedListNode? insertionNode = FindInsertionNodeFor(behaviour, SortBy); + if (!list.Remove(tBehaviour)) + return false; - if (insertionNode is not null) - behaviours.AddAfter(insertionNode, behaviour); - else - behaviours.AddLast(behaviour); + count--; + return true; } - private LinkedListNode? FindInsertionNodeFor(T behaviour, IComparer sortBy) + protected override void AddBehaviour(TItem behaviour) { - LinkedListNode? node = behaviours.First; + TIndex key = getIndexFunc(behaviour); + if (!behaviours.TryGetValue(key, out FastList? list)) + behaviours[key] = list = []; - while (node is not null) - { - int compareValue = sortBy.Compare(node.Value, behaviour); - if (compareValue < 0) - return node.Previous; - node = node.Next; - } - return null; + count++; + list.Add(behaviour); } protected override void OnBehaviourAdd(IBehaviour behaviour) => behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged); @@ -80,23 +65,40 @@ public class BehaviourCollectorOrdered : BehaviourCollectorBase where T : private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args) { - T behaviour = (T)sender; - behaviours.Remove(behaviour); + TItem behaviour = (TItem)sender; + RemoveBehaviour(behaviour); AddBehaviour(behaviour); } - private void Sort(IComparer comparer) - { - sortList.Sort(comparer); - behaviours.Clear(); - foreach (T item in sortList) - behaviours.AddLast(item); - } - - public BehaviourCollectorOrdered() => delegateOnPriorityChanged = OnPriorityChanged; - public BehaviourCollectorOrdered(IUniverse universe, Comparison sortBy) : base(universe) + public BehaviourCollectorOrdered(Func getIndexFunc, Comparison sortBy) { delegateOnPriorityChanged = OnPriorityChanged; - SortBy = Comparer.Create(sortBy); + this.getIndexFunc = getIndexFunc; + this.sortBy = Comparer.Create(sortBy); + behaviours = new(this.sortBy); + } + + public BehaviourCollectorOrdered(IUniverse universe, Func getIndexFunc, Comparison sortBy) : base(universe) + { + delegateOnPriorityChanged = OnPriorityChanged; + this.getIndexFunc = getIndexFunc; + this.sortBy = Comparer.Create(sortBy); + behaviours = new(this.sortBy); + } + + public BehaviourCollectorOrdered(Func getIndexFunc, IComparer sortBy) + { + this.getIndexFunc = getIndexFunc; + delegateOnPriorityChanged = OnPriorityChanged; + this.sortBy = sortBy; + behaviours = new(sortBy); + } + + public BehaviourCollectorOrdered(IUniverse universe, Func getIndexFunc, IComparer sortBy) : base(universe) + { + delegateOnPriorityChanged = OnPriorityChanged; + this.getIndexFunc = getIndexFunc; + this.sortBy = sortBy; + behaviours = new(sortBy); } } diff --git a/Engine.Core/Systems/DrawManager.cs b/Engine.Core/Systems/DrawManager.cs index 719147c..13706ae 100644 --- a/Engine.Core/Systems/DrawManager.cs +++ b/Engine.Core/Systems/DrawManager.cs @@ -5,11 +5,12 @@ namespace Engine.Core; public class DrawManager : Behaviour { // We use Descending order because draw calls are running from last to first - private static Comparer SortByDescendingPriority() => Comparer.Create((x, y) => y.Priority.CompareTo(x.Priority)); + private static Comparer SortByDescendingPriority() => Comparer.Create((x, y) => y.CompareTo(x)); + private static System.Func GetPriority() => (b) => b.Priority; - private readonly ActiveBehaviourCollectorOrdered preDrawEntities = new() { SortBy = SortByDescendingPriority() }; - private readonly ActiveBehaviourCollectorOrdered drawEntities = new() { SortBy = SortByDescendingPriority() }; - private readonly ActiveBehaviourCollectorOrdered postDrawEntities = new() { SortBy = SortByDescendingPriority() }; + private readonly ActiveBehaviourCollectorOrdered preDrawEntities = new(GetPriority(), SortByDescendingPriority()); + private readonly ActiveBehaviourCollectorOrdered drawEntities = new(GetPriority(), SortByDescendingPriority()); + private readonly ActiveBehaviourCollectorOrdered postDrawEntities = new(GetPriority(), SortByDescendingPriority()); private void OnPreDraw(IUniverse sender) { diff --git a/Engine.Core/Systems/UniverseEntranceManager.cs b/Engine.Core/Systems/UniverseEntranceManager.cs index a421913..502c6a6 100644 --- a/Engine.Core/Systems/UniverseEntranceManager.cs +++ b/Engine.Core/Systems/UniverseEntranceManager.cs @@ -5,10 +5,11 @@ namespace Engine.Core; public class UniverseEntranceManager : Behaviour { // We use Ascending order because we are using reverse for loop to call them - private static Comparer SortByAscendingPriority() => Comparer.Create((x, y) => x.Priority.CompareTo(y.Priority)); + private static Comparer SortByAscendingPriority() => Comparer.Create((x, y) => x.CompareTo(y)); + private static System.Func GetPriority() => (b) => b.Priority; - private readonly ActiveBehaviourCollectorOrdered enterUniverses = new() { SortBy = SortByAscendingPriority() }; - private readonly ActiveBehaviourCollectorOrdered exitUniverses = new() { SortBy = SortByAscendingPriority() }; + private readonly ActiveBehaviourCollectorOrdered enterUniverses = new(GetPriority(), SortByAscendingPriority()); + private readonly ActiveBehaviourCollectorOrdered exitUniverses = new(GetPriority(), SortByAscendingPriority()); private readonly List toCallEnterUniverses = new(32); private readonly List toCallExitUniverses = new(32); diff --git a/Engine.Core/Systems/UpdateManager.cs b/Engine.Core/Systems/UpdateManager.cs index 3712c26..f44076a 100644 --- a/Engine.Core/Systems/UpdateManager.cs +++ b/Engine.Core/Systems/UpdateManager.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; namespace Engine.Core; @@ -6,13 +5,14 @@ namespace Engine.Core; public class UpdateManager : Behaviour { // We use Ascending order because we are using reverse for loop to call them - private static Comparer SortByAscendingPriority() => Comparer.Create((x, y) => x.Priority.CompareTo(y.Priority)); + private static Comparer SortByAscendingPriority() => Comparer.Create((x, y) => x.CompareTo(y)); + private static System.Func GetPriority() => (b) => b.Priority; - private readonly ActiveBehaviourCollectorOrdered firstFrameUpdates = new() { SortBy = SortByAscendingPriority() }; + private readonly ActiveBehaviourCollectorOrdered firstFrameUpdates = new(GetPriority(), SortByAscendingPriority()); private readonly ActiveBehaviourCollector lastFrameUpdates = new(); - private readonly ActiveBehaviourCollectorOrdered preUpdateEntities = new() { SortBy = SortByAscendingPriority() }; - private readonly ActiveBehaviourCollectorOrdered updateEntities = new() { SortBy = SortByAscendingPriority() }; - private readonly ActiveBehaviourCollectorOrdered postUpdateEntities = new() { SortBy = SortByAscendingPriority() }; + private readonly ActiveBehaviourCollectorOrdered preUpdateEntities = new(GetPriority(), SortByAscendingPriority()); + private readonly ActiveBehaviourCollectorOrdered updateEntities = new(GetPriority(), SortByAscendingPriority()); + private readonly ActiveBehaviourCollectorOrdered postUpdateEntities = new(GetPriority(), SortByAscendingPriority()); private readonly List toCallFirstFrameUpdates = new(32); diff --git a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/LoadContentManager.cs b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/LoadContentManager.cs index 4377086..18fd80c 100644 --- a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/LoadContentManager.cs +++ b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/LoadContentManager.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; + using Engine.Core; namespace Engine.Integration.MonoGame; @@ -6,9 +7,10 @@ namespace Engine.Integration.MonoGame; public class LoadContentManager : Behaviour, IFirstFrameUpdate { // We use Ascending order because we are using reverse for loop to call them - private static Comparer SortByAscendingPriority() => Comparer.Create((x, y) => x.Priority.CompareTo(y.Priority)); + private static Comparer SortByAscendingPriority() => Comparer.Create((x, y) => x.CompareTo(y)); + private static System.Func GetPriority() => (b) => b.Priority; - private readonly ActiveBehaviourCollectorOrdered loadContents = new() { SortBy = SortByAscendingPriority() }; + private readonly ActiveBehaviourCollectorOrdered loadContents = new(GetPriority(), SortByAscendingPriority()); private readonly List toCallLoadContents = new(32); private MonoGameWindowContainer monoGameWindowContainer = null!; diff --git a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatcher.cs b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatcher.cs index 73b2a72..9f39e1d 100644 --- a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatcher.cs +++ b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/SpriteBatcher.cs @@ -6,12 +6,13 @@ namespace Engine.Integration.MonoGame; public class SpriteBatcher : BehaviourBase, IFirstFrameUpdate, IDraw { - private static Comparer SortByPriority() => Comparer.Create((x, y) => y.Priority.CompareTo(x.Priority)); + private static Comparer SortByPriority() => Comparer.Create((x, y) => y.CompareTo(x)); + private static System.Func GetPriority() => (b) => b.Priority; private ISpriteBatch spriteBatch = null!; private MonoGameCamera2D camera2D = null!; - private readonly ActiveBehaviourCollectorOrdered drawableSprites = new() { SortBy = SortByPriority() }; + private readonly ActiveBehaviourCollectorOrdered drawableSprites = new(GetPriority(), SortByPriority()); public void FirstActiveFrame() { diff --git a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/TriangleBatcher.cs b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/TriangleBatcher.cs index 666a2a6..40827a3 100644 --- a/Engine.Integration/Engine.Integration.MonoGame/Behaviours/TriangleBatcher.cs +++ b/Engine.Integration/Engine.Integration.MonoGame/Behaviours/TriangleBatcher.cs @@ -8,11 +8,13 @@ namespace Engine.Integration.MonoGame; public class TriangleBatcher : BehaviourBase, ITriangleBatch, IFirstFrameUpdate, IDraw { - private static Comparer SortByAscendingPriority() => Comparer.Create((x, y) => x.Priority.CompareTo(y.Priority)); + private static Comparer SortByAscendingPriority() => Comparer.Create((x, y) => x.CompareTo(y)); + private static System.Func GetPriority() => (b) => b.Priority; private TriangleBatch triangleBatch = null!; private MonoGameCamera2D camera2D = null!; - private readonly ActiveBehaviourCollectorOrdered drawableShapes = new() { SortBy = SortByAscendingPriority() }; + + private readonly ActiveBehaviourCollectorOrdered drawableShapes = new(GetPriority(), SortByAscendingPriority()); public void FirstActiveFrame() { diff --git a/Engine.Physics2D/PhysicsEngine2D.cs b/Engine.Physics2D/PhysicsEngine2D.cs index 52c91eb..d2071c3 100644 --- a/Engine.Physics2D/PhysicsEngine2D.cs +++ b/Engine.Physics2D/PhysicsEngine2D.cs @@ -17,11 +17,12 @@ public class PhysicsEngine2D : Behaviour, IPreUpdate, IPhysicsEngine2D protected readonly ICollisionResolver2D collisionResolver = null!; protected readonly IRaycastResolver2D raycastResolver = null!; - private static Comparer SortByPriority() => Comparer.Create((x, y) => y.Priority.CompareTo(x.Priority)); - protected ActiveBehaviourCollectorOrdered physicsPreUpdateCollector = new() { SortBy = SortByPriority() }; - protected ActiveBehaviourCollectorOrdered physicsUpdateCollector = new() { SortBy = SortByPriority() }; - protected ActiveBehaviourCollectorOrdered physicsIterationCollector = new() { SortBy = SortByPriority() }; - protected ActiveBehaviourCollectorOrdered physicsPostUpdateCollector = new() { SortBy = SortByPriority() }; + private static Comparer SortByPriority() => Comparer.Create((x, y) => y.CompareTo(x)); + private static System.Func GetPriority() => (b) => b.Priority; + protected ActiveBehaviourCollectorOrdered physicsPreUpdateCollector = new(GetPriority(), SortByPriority()); + protected ActiveBehaviourCollectorOrdered physicsUpdateCollector = new(GetPriority(), SortByPriority()); + protected ActiveBehaviourCollectorOrdered physicsIterationCollector = new(GetPriority(), SortByPriority()); + protected ActiveBehaviourCollectorOrdered physicsPostUpdateCollector = new(GetPriority(), SortByPriority()); protected BehaviourCollector rigidBodyCollector = new(); protected BehaviourCollector colliderCollector = new();