20 Commits

Author SHA1 Message Date
dbd15cbbc2 chore: updated submodule link from ssh to https 2025-10-18 11:18:54 +03:00
e051f5cfb4 fix: removed git issue caused by submodule issue 2025-10-18 11:11:07 +03:00
e70b7f112f chore: coroutine manager moved to correct directory 2025-10-17 21:27:49 +03:00
f55ba499b6 fix: int vectors not rounding float values on regular vector conversions 2025-10-16 15:37:31 +03:00
b75f30f864 fix: math round methods not working properly 2025-10-16 15:37:03 +03:00
6f1f30bd53 feat: intervectoral implicit conversions added 2025-10-16 14:38:27 +03:00
92a5c276a4 feat: integer vector 2d & 3d added 2025-10-16 14:12:24 +03:00
69bc6573d1 feat: added IEquatable interfaces to primitives 2025-10-16 13:59:49 +03:00
28bc022587 perf: forgotten memory allocation on triangle batch 2025-10-16 08:43:40 +03:00
25db60e436 perf: memory allocations reduced on universe update 2025-10-16 08:25:02 +03:00
7c62440bba chore: added an experimental ordered fast list class 2025-10-14 12:06:47 +03:00
4bec7bce6e fix: fast list readonly mode not throwing exceptions 2025-10-14 11:42:05 +03:00
8d31372c24 refactor: universe and objects now use fast list 2025-10-13 12:40:43 +03:00
a2e704916e feat: fast list now implements IList 2025-10-13 12:39:49 +03:00
c7d170fad9 perf: significant performance optimizations on ordered behaviour collectors by using a sorted dictionary 2025-10-13 09:58:58 +03:00
9ccf7b754d perf: ordered behaviour collectors now use linked lists for performance 2025-10-11 16:07:26 +03:00
e3d4899112 refactor: renamed behaviour collectors from sorted to ordered 2025-10-11 16:05:47 +03:00
566c16d09c refactor: active behaviour collector base added 2025-10-11 15:36:58 +03:00
ae9d4f02ef chore: moved behaviour collectors into subdirectory 2025-10-11 15:36:06 +03:00
e77772cbc2 refactor: behaviour collector base added 2025-10-11 15:08:02 +03:00
43 changed files with 1318 additions and 330 deletions

2
.gitmodules vendored
View File

@@ -1,3 +1,3 @@
[submodule "Engine.Integration/YamlDotNet"]
path = Engine.Integration/YamlDotNet
url = git@github.com:Syntriax/YamlDotNet.git
url = https://github.com/Syntriax/YamlDotNet.git

View File

@@ -1,67 +0,0 @@
using System;
using System.Collections.Generic;
namespace Engine.Core;
public class ActiveBehaviourCollectorSorted<T> : ActiveBehaviourCollector<T> where T : class, IBehaviour
{
private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!;
private IComparer<T>? _sortBy = null;
public IComparer<T>? SortBy
{
get => _sortBy;
set
{
_sortBy = value;
if (value is not null)
activeBehaviours.Sort(value);
}
}
protected override void AddBehaviour(T behaviour)
{
if (SortBy is null)
{
activeBehaviours.Add(behaviour);
return;
}
int insertionIndex = activeBehaviours.BinarySearch(behaviour, SortBy);
if (insertionIndex < 0)
insertionIndex = ~insertionIndex;
activeBehaviours.Insert(insertionIndex, behaviour);
}
protected override void OnBehaviourAdd(IBehaviour behaviour)
{
behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged);
}
protected override void OnBehaviourRemove(IBehaviour behaviour)
{
behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged);
}
private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args)
{
T behaviour = (T)sender;
activeBehaviours.Remove(behaviour);
AddBehaviour(behaviour);
}
public ActiveBehaviourCollectorSorted()
{
delegateOnPriorityChanged = OnPriorityChanged;
}
public ActiveBehaviourCollectorSorted(IUniverse universe, Comparison<T> sortBy) : base(universe)
{
delegateOnPriorityChanged = OnPriorityChanged;
SortBy = Comparer<T>.Create(sortBy);
}
}

View File

@@ -1,67 +0,0 @@
using System;
using System.Collections.Generic;
namespace Engine.Core;
public class BehaviourCollectorSorted<T> : BehaviourCollector<T> where T : class
{
private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!;
private IComparer<T>? _sortBy = null;
public IComparer<T>? SortBy
{
get => _sortBy;
set
{
_sortBy = value;
if (value is not null)
behaviours.Sort(value);
}
}
protected override void AddBehaviour(T behaviour)
{
if (SortBy is null)
{
behaviours.Add(behaviour);
return;
}
int insertionIndex = behaviours.BinarySearch(behaviour, SortBy);
if (insertionIndex < 0)
insertionIndex = ~insertionIndex;
behaviours.Insert(insertionIndex, behaviour);
}
protected override void OnBehaviourAdd(IBehaviour behaviour)
{
behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged);
}
protected override void OnBehaviourRemove(IBehaviour behaviour)
{
behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged);
}
private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args)
{
T behaviour = (T)sender;
behaviours.Remove(behaviour);
AddBehaviour(behaviour);
}
public BehaviourCollectorSorted()
{
delegateOnPriorityChanged = OnPriorityChanged;
}
public BehaviourCollectorSorted(IUniverse universe, Comparison<T> sortBy) : base(universe)
{
delegateOnPriorityChanged = OnPriorityChanged;
SortBy = Comparer<T>.Create(sortBy);
}
}

View File

@@ -0,0 +1,16 @@
using System;
namespace Engine.Core;
public class ActiveBehaviourCollector<T> : ActiveBehaviourCollectorBase<T> where T : class, IBehaviour
{
protected readonly FastList<T> activeBehaviours = new(32);
public override T this[Index index] => activeBehaviours[index];
public override int Count => activeBehaviours.Count;
public ActiveBehaviourCollector() { }
public ActiveBehaviourCollector(IUniverse universe) : base(universe) { }
protected override void AddBehaviour(T behaviour) => activeBehaviours.Add(behaviour);
protected override bool RemoveBehaviour(T tBehaviour) => activeBehaviours.Remove(tBehaviour);
}

View File

@@ -3,12 +3,10 @@ using System.Collections.Generic;
namespace Engine.Core;
public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : class, IBehaviour
public abstract class ActiveBehaviourCollectorBase<T> : IBehaviourCollector<T> where T : class, IBehaviour
{
public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourCollectedArguments> OnCollected { get; } = new();
public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourRemovedArguments> OnRemoved { get; } = new();
public Event<IHasUniverse> OnUniverseAssigned { get; } = new();
public Event<IAssignable>? OnUnassigned { get; } = new();
protected readonly Dictionary<IActive, T> monitoringActiveToBehaviour = new(32);
protected readonly FastList<T> monitoringBehaviours = new(32);
private readonly Event<IBehaviourController, IBehaviourController.BehaviourAddedArguments>.EventHandler delegateOnBehaviourAdded = null!;
private readonly Event<IBehaviourController, IBehaviourController.BehaviourRemovedArguments>.EventHandler delegateOnBehaviourRemoved = null!;
@@ -16,80 +14,16 @@ public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : clas
private readonly Event<IUniverse, IUniverse.UniverseObjectRegisteredArguments>.EventHandler delegateOnUniverseObjectRegistered = null!;
private readonly Event<IUniverse, IUniverse.UniverseObjectUnRegisteredArguments>.EventHandler delegateOnUniverseObjectUnregistered = null!;
private readonly FastList<T> monitoringBehaviours = new(32);
protected readonly FastList<T> activeBehaviours = new(32);
protected readonly Dictionary<IActive, T> monitoringActiveToBehaviour = new(32);
public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourCollectedArguments> OnCollected { get; } = new();
public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourRemovedArguments> OnRemoved { get; } = new();
public Event<IHasUniverse> OnUniverseAssigned { get; } = new();
public Event<IAssignable>? OnUnassigned { get; } = new();
public abstract int Count { get; }
public abstract T this[Index index] { get; }
public IUniverse Universe { get; private set; } = null!;
private void OnUniverseObjectRegistered(IUniverse manager, IUniverse.UniverseObjectRegisteredArguments args)
{
IUniverseObject universeObject = args.UniverseObjectRegistered;
universeObject.BehaviourController.OnBehaviourAdded.AddListener(delegateOnBehaviourAdded);
universeObject.BehaviourController.OnBehaviourRemoved.AddListener(delegateOnBehaviourRemoved);
for (int i = 0; i < universeObject.BehaviourController.Count; i++)
OnBehaviourAdded(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
}
private void OnUniverseObjectUnregistered(IUniverse manager, IUniverse.UniverseObjectUnRegisteredArguments args)
{
IUniverseObject universeObject = args.UniverseObjectUnregistered;
universeObject.BehaviourController.OnBehaviourAdded.RemoveListener(delegateOnBehaviourAdded);
universeObject.BehaviourController.OnBehaviourRemoved.RemoveListener(delegateOnBehaviourRemoved);
for (int i = 0; i < universeObject.BehaviourController.Count; i++)
OnBehaviourRemoved(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
}
protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
private void OnBehaviourAdded(IBehaviourController controller, IBehaviourController.BehaviourAddedArguments args)
{
if (args.BehaviourAdded is not T tBehaviour)
return;
monitoringBehaviours.Add(tBehaviour);
monitoringActiveToBehaviour.Add(tBehaviour, tBehaviour);
tBehaviour.OnActiveChanged.AddListener(delegateOnBehaviourStateChanged);
OnBehaviourStateChanged(tBehaviour, new(!tBehaviour.IsActive));
}
protected virtual void AddBehaviour(T behaviour) => activeBehaviours.Add(behaviour);
private void OnBehaviourStateChanged(IActive sender, IActive.ActiveChangedArguments args)
{
T behaviour = monitoringActiveToBehaviour[sender];
if (sender.IsActive)
{
AddBehaviour(behaviour);
OnBehaviourAdd(behaviour);
OnCollected?.Invoke(this, new(behaviour));
}
else if (activeBehaviours.Remove(behaviour))
{
OnBehaviourRemove(behaviour);
OnRemoved?.Invoke(this, new(behaviour));
}
}
protected virtual void OnBehaviourRemove(IBehaviour behaviour) { }
private void OnBehaviourRemoved(IBehaviourController controller, IBehaviourController.BehaviourRemovedArguments args)
{
if (args.BehaviourRemoved is not T tBehaviour)
return;
if (!monitoringBehaviours.Remove(tBehaviour) || !monitoringActiveToBehaviour.Remove(tBehaviour))
return;
tBehaviour.OnActiveChanged.RemoveListener(delegateOnBehaviourStateChanged);
if (activeBehaviours.Remove(tBehaviour))
{
OnBehaviourRemove(tBehaviour);
OnRemoved?.Invoke(this, new(tBehaviour));
}
}
public bool Assign(IUniverse universe)
{
if (Universe is not null)
@@ -123,10 +57,75 @@ public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : clas
return true;
}
public int Count => activeBehaviours.Count;
public T this[Index index] => activeBehaviours[index];
protected abstract void AddBehaviour(T behaviour);
protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
private void OnBehaviourAdded(IBehaviourController controller, IBehaviourController.BehaviourAddedArguments args)
{
if (args.BehaviourAdded is not T tBehaviour)
return;
public ActiveBehaviourCollector()
monitoringBehaviours.Add(tBehaviour);
monitoringActiveToBehaviour.Add(tBehaviour, tBehaviour);
tBehaviour.OnActiveChanged.AddListener(delegateOnBehaviourStateChanged);
OnBehaviourStateChanged(tBehaviour, new(!tBehaviour.IsActive));
}
protected abstract bool RemoveBehaviour(T behaviour);
protected virtual void OnBehaviourRemove(IBehaviour behaviour) { }
private void OnBehaviourRemoved(IBehaviourController controller, IBehaviourController.BehaviourRemovedArguments args)
{
if (args.BehaviourRemoved is not T tBehaviour)
return;
if (!monitoringBehaviours.Remove(tBehaviour) || !monitoringActiveToBehaviour.Remove(tBehaviour))
return;
tBehaviour.OnActiveChanged.RemoveListener(delegateOnBehaviourStateChanged);
if (!RemoveBehaviour(tBehaviour))
return;
OnBehaviourRemove(tBehaviour);
OnRemoved?.Invoke(this, new(tBehaviour));
}
private void OnBehaviourStateChanged(IActive sender, IActive.ActiveChangedArguments args)
{
T behaviour = monitoringActiveToBehaviour[sender];
if (sender.IsActive)
{
AddBehaviour(behaviour);
OnBehaviourAdd(behaviour);
OnCollected?.Invoke(this, new(behaviour));
}
else if (RemoveBehaviour(behaviour))
{
OnBehaviourRemove(behaviour);
OnRemoved?.Invoke(this, new(behaviour));
}
}
private void OnUniverseObjectRegistered(IUniverse manager, IUniverse.UniverseObjectRegisteredArguments args)
{
IUniverseObject universeObject = args.UniverseObjectRegistered;
universeObject.BehaviourController.OnBehaviourAdded.AddListener(delegateOnBehaviourAdded);
universeObject.BehaviourController.OnBehaviourRemoved.AddListener(delegateOnBehaviourRemoved);
for (int i = 0; i < universeObject.BehaviourController.Count; i++)
OnBehaviourAdded(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
}
private void OnUniverseObjectUnregistered(IUniverse manager, IUniverse.UniverseObjectUnRegisteredArguments args)
{
IUniverseObject universeObject = args.UniverseObjectUnregistered;
universeObject.BehaviourController.OnBehaviourAdded.RemoveListener(delegateOnBehaviourAdded);
universeObject.BehaviourController.OnBehaviourRemoved.RemoveListener(delegateOnBehaviourRemoved);
for (int i = 0; i < universeObject.BehaviourController.Count; i++)
OnBehaviourRemoved(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
}
public ActiveBehaviourCollectorBase()
{
delegateOnBehaviourAdded = OnBehaviourAdded;
delegateOnBehaviourRemoved = OnBehaviourRemoved;
@@ -135,7 +134,7 @@ public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : clas
delegateOnUniverseObjectUnregistered = OnUniverseObjectUnregistered;
}
public ActiveBehaviourCollector(IUniverse universe)
public ActiveBehaviourCollectorBase(IUniverse universe)
{
delegateOnBehaviourAdded = OnBehaviourAdded;
delegateOnBehaviourRemoved = OnBehaviourRemoved;

View File

@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
namespace Engine.Core;
public class ActiveBehaviourCollectorOrdered<TIndex, TItem> : ActiveBehaviourCollector<TItem> where TItem : class, IBehaviour where TIndex : IComparable
{
private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!;
private readonly SortedDictionary<TIndex, FastList<TItem>> behaviours = null!;
private readonly Func<TItem, TIndex> getIndexFunc = null!;
private readonly IComparer<TIndex> sortBy = null!;
private int count = 0;
public override int Count => count;
public override TItem this[Index index]
{
get
{
int actualIndex = index.IsFromEnd
? count - index.Value
: index.Value;
if (actualIndex < 0 || actualIndex >= count)
throw new IndexOutOfRangeException();
int leftIndex = actualIndex;
foreach ((TIndex i, FastList<TItem> list) in behaviours)
{
if (leftIndex < list.Count)
return list[leftIndex];
leftIndex -= list.Count;
}
throw new IndexOutOfRangeException();
}
}
protected override bool RemoveBehaviour(TItem tBehaviour)
{
TIndex index = getIndexFunc(tBehaviour);
if (!behaviours.TryGetValue(index, out FastList<TItem>? list))
throw new Exceptions.NotFoundException($"Index of '{index}' is not found in the collector");
if (!list.Remove(tBehaviour))
return false;
count--;
return true;
}
protected override void AddBehaviour(TItem behaviour)
{
TIndex key = getIndexFunc(behaviour);
if (!behaviours.TryGetValue(key, out FastList<TItem>? list))
behaviours[key] = list = [];
count++;
list.Add(behaviour);
}
protected override void OnBehaviourAdd(IBehaviour behaviour) => behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged);
protected override void OnBehaviourRemove(IBehaviour behaviour) => behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged);
private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args)
{
TItem behaviour = (TItem)sender;
RemoveBehaviour(behaviour);
AddBehaviour(behaviour);
}
public ActiveBehaviourCollectorOrdered(Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy)
{
delegateOnPriorityChanged = OnPriorityChanged;
this.getIndexFunc = getIndexFunc;
this.sortBy = Comparer<TIndex>.Create(sortBy);
behaviours = new(this.sortBy);
}
public ActiveBehaviourCollectorOrdered(IUniverse universe, Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy) : base(universe)
{
delegateOnPriorityChanged = OnPriorityChanged;
this.getIndexFunc = getIndexFunc;
this.sortBy = Comparer<TIndex>.Create(sortBy);
behaviours = new(this.sortBy);
}
public ActiveBehaviourCollectorOrdered(Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy)
{
this.getIndexFunc = getIndexFunc;
delegateOnPriorityChanged = OnPriorityChanged;
this.sortBy = sortBy;
behaviours = new(sortBy);
}
public ActiveBehaviourCollectorOrdered(IUniverse universe, Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy) : base(universe)
{
delegateOnPriorityChanged = OnPriorityChanged;
this.getIndexFunc = getIndexFunc;
this.sortBy = sortBy;
behaviours = new(sortBy);
}
}

View File

@@ -0,0 +1,17 @@
using System;
namespace Engine.Core;
public class BehaviourCollector<T> : BehaviourCollectorBase<T> where T : class
{
protected readonly FastList<T> behaviours = new(32);
public override T this[Index index] => behaviours[index];
public override int Count => behaviours.Count;
protected override void AddBehaviour(T behaviour) => behaviours.Add(behaviour);
protected override bool RemoveBehaviour(T tBehaviour) => behaviours.Remove(tBehaviour);
public BehaviourCollector() { }
public BehaviourCollector(IUniverse universe) : base(universe) { }
}

View File

@@ -2,70 +2,24 @@ using System;
namespace Engine.Core;
public class BehaviourCollector<T> : IBehaviourCollector<T> where T : class
public abstract class BehaviourCollectorBase<T> : IBehaviourCollector<T> where T : class
{
public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourCollectedArguments> OnCollected { get; } = new();
public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourRemovedArguments> OnRemoved { get; } = new();
public Event<IHasUniverse> OnUniverseAssigned { get; } = new();
public Event<IAssignable>? OnUnassigned { get; } = new();
private readonly Event<IBehaviourController, IBehaviourController.BehaviourAddedArguments>.EventHandler delegateOnBehaviourAdded = null!;
private readonly Event<IBehaviourController, IBehaviourController.BehaviourRemovedArguments>.EventHandler delegateOnBehaviourRemoved = null!;
private readonly Event<IUniverse, IUniverse.UniverseObjectRegisteredArguments>.EventHandler delegateOnUniverseObjectRegistered = null!;
private readonly Event<IUniverse, IUniverse.UniverseObjectUnRegisteredArguments>.EventHandler delegateOnUniverseObjectUnregistered = null!;
protected readonly FastList<T> behaviours = new(32);
public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourCollectedArguments> OnCollected { get; } = new();
public Event<IBehaviourCollector<T>, IBehaviourCollector<T>.BehaviourRemovedArguments> OnRemoved { get; } = new();
public Event<IHasUniverse> OnUniverseAssigned { get; } = new();
public Event<IAssignable>? OnUnassigned { get; } = new();
public IUniverse Universe { get; private set; } = null!;
private void OnUniverseObjectRegistered(IUniverse manager, IUniverse.UniverseObjectRegisteredArguments args)
{
IUniverseObject universeObject = args.UniverseObjectRegistered;
public abstract int Count { get; }
universeObject.BehaviourController.OnBehaviourAdded.AddListener(delegateOnBehaviourAdded);
universeObject.BehaviourController.OnBehaviourRemoved.AddListener(delegateOnBehaviourRemoved);
public abstract T this[Index index] { get; }
for (int i = 0; i < universeObject.BehaviourController.Count; i++)
OnBehaviourAdded(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
}
private void OnUniverseObjectUnregistered(IUniverse manager, IUniverse.UniverseObjectUnRegisteredArguments args)
{
IUniverseObject universeObject = args.UniverseObjectUnregistered;
universeObject.BehaviourController.OnBehaviourAdded.RemoveListener(delegateOnBehaviourAdded);
universeObject.BehaviourController.OnBehaviourRemoved.RemoveListener(delegateOnBehaviourRemoved);
for (int i = 0; i < universeObject.BehaviourController.Count; i++)
OnBehaviourRemoved(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
}
protected virtual void AddBehaviour(T behaviour) => behaviours.Add(behaviour);
protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
private void OnBehaviourAdded(IBehaviourController controller, IBehaviourController.BehaviourAddedArguments args)
{
if (args.BehaviourAdded is not T tBehaviour)
return;
AddBehaviour(tBehaviour);
OnBehaviourAdd(args.BehaviourAdded);
OnCollected?.Invoke(this, new(tBehaviour));
}
protected virtual void OnBehaviourRemove(IBehaviour behaviour) { }
private void OnBehaviourRemoved(IBehaviourController controller, IBehaviourController.BehaviourRemovedArguments args)
{
if (args.BehaviourRemoved is not T tBehaviour)
return;
if (!behaviours.Remove(tBehaviour))
return;
OnBehaviourRemove(args.BehaviourRemoved);
OnRemoved?.Invoke(this, new(tBehaviour));
}
protected virtual void OnAssign(IUniverse universe) { }
public bool Assign(IUniverse universe)
{
if (Universe is not null)
@@ -100,10 +54,57 @@ public class BehaviourCollector<T> : IBehaviourCollector<T> where T : class
return true;
}
public int Count => behaviours.Count;
public T this[Index index] => behaviours[index];
protected virtual void OnAssign(IUniverse universe) { }
public BehaviourCollector()
protected abstract void AddBehaviour(T behaviour);
protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
private void OnBehaviourAdded(IBehaviourController controller, IBehaviourController.BehaviourAddedArguments args)
{
if (args.BehaviourAdded is not T tBehaviour)
return;
AddBehaviour(tBehaviour);
OnBehaviourAdd(args.BehaviourAdded);
OnCollected?.Invoke(this, new(tBehaviour));
}
protected abstract bool RemoveBehaviour(T tBehaviour);
protected virtual void OnBehaviourRemove(IBehaviour behaviour) { }
private void OnBehaviourRemoved(IBehaviourController controller, IBehaviourController.BehaviourRemovedArguments args)
{
if (args.BehaviourRemoved is not T tBehaviour)
return;
if (!RemoveBehaviour(tBehaviour))
return;
OnBehaviourRemove(args.BehaviourRemoved);
OnRemoved?.Invoke(this, new(tBehaviour));
}
private void OnUniverseObjectRegistered(IUniverse manager, IUniverse.UniverseObjectRegisteredArguments args)
{
IUniverseObject universeObject = args.UniverseObjectRegistered;
universeObject.BehaviourController.OnBehaviourAdded.AddListener(delegateOnBehaviourAdded);
universeObject.BehaviourController.OnBehaviourRemoved.AddListener(delegateOnBehaviourRemoved);
for (int i = 0; i < universeObject.BehaviourController.Count; i++)
OnBehaviourAdded(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
}
private void OnUniverseObjectUnregistered(IUniverse manager, IUniverse.UniverseObjectUnRegisteredArguments args)
{
IUniverseObject universeObject = args.UniverseObjectUnregistered;
universeObject.BehaviourController.OnBehaviourAdded.RemoveListener(delegateOnBehaviourAdded);
universeObject.BehaviourController.OnBehaviourRemoved.RemoveListener(delegateOnBehaviourRemoved);
for (int i = 0; i < universeObject.BehaviourController.Count; i++)
OnBehaviourRemoved(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
}
public BehaviourCollectorBase()
{
delegateOnBehaviourAdded = OnBehaviourAdded;
delegateOnBehaviourRemoved = OnBehaviourRemoved;
@@ -111,7 +112,7 @@ public class BehaviourCollector<T> : IBehaviourCollector<T> where T : class
delegateOnUniverseObjectUnregistered = OnUniverseObjectUnregistered;
}
public BehaviourCollector(IUniverse universe)
public BehaviourCollectorBase(IUniverse universe)
{
delegateOnBehaviourAdded = OnBehaviourAdded;
delegateOnBehaviourRemoved = OnBehaviourRemoved;

View File

@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
namespace Engine.Core;
public class BehaviourCollectorOrdered<TIndex, TItem> : BehaviourCollectorBase<TItem> where TItem : class where TIndex : IComparable
{
private readonly Event<IBehaviour, IBehaviour.PriorityChangedArguments>.EventHandler delegateOnPriorityChanged = null!;
private readonly SortedDictionary<TIndex, FastList<TItem>> behaviours = null!;
private readonly Func<TItem, TIndex> getIndexFunc = null!;
private readonly IComparer<TIndex> sortBy = null!;
private int count = 0;
public override int Count => count;
public override TItem this[Index index]
{
get
{
int actualIndex = index.IsFromEnd
? count - index.Value
: index.Value;
if (actualIndex < 0 || actualIndex >= count)
throw new IndexOutOfRangeException();
int leftIndex = actualIndex;
foreach ((TIndex i, FastList<TItem> list) in behaviours)
{
if (leftIndex < list.Count)
return list[leftIndex];
leftIndex -= list.Count;
}
throw new IndexOutOfRangeException();
}
}
protected override bool RemoveBehaviour(TItem tBehaviour)
{
TIndex index = getIndexFunc(tBehaviour);
if (!behaviours.TryGetValue(index, out FastList<TItem>? list))
throw new Exceptions.NotFoundException($"Index of '{index}' is not found in the collector");
if (!list.Remove(tBehaviour))
return false;
count--;
return true;
}
protected override void AddBehaviour(TItem behaviour)
{
TIndex key = getIndexFunc(behaviour);
if (!behaviours.TryGetValue(key, out FastList<TItem>? list))
behaviours[key] = list = [];
count++;
list.Add(behaviour);
}
protected override void OnBehaviourAdd(IBehaviour behaviour) => behaviour.OnPriorityChanged.AddListener(delegateOnPriorityChanged);
protected override void OnBehaviourRemove(IBehaviour behaviour) => behaviour.OnPriorityChanged.RemoveListener(delegateOnPriorityChanged);
private void OnPriorityChanged(IBehaviour sender, IBehaviour.PriorityChangedArguments args)
{
TItem behaviour = (TItem)sender;
RemoveBehaviour(behaviour);
AddBehaviour(behaviour);
}
public BehaviourCollectorOrdered(Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy)
{
delegateOnPriorityChanged = OnPriorityChanged;
this.getIndexFunc = getIndexFunc;
this.sortBy = Comparer<TIndex>.Create(sortBy);
behaviours = new(this.sortBy);
}
public BehaviourCollectorOrdered(IUniverse universe, Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy) : base(universe)
{
delegateOnPriorityChanged = OnPriorityChanged;
this.getIndexFunc = getIndexFunc;
this.sortBy = Comparer<TIndex>.Create(sortBy);
behaviours = new(this.sortBy);
}
public BehaviourCollectorOrdered(Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy)
{
this.getIndexFunc = getIndexFunc;
delegateOnPriorityChanged = OnPriorityChanged;
this.sortBy = sortBy;
behaviours = new(sortBy);
}
public BehaviourCollectorOrdered(IUniverse universe, Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy) : base(universe)
{
delegateOnPriorityChanged = OnPriorityChanged;
this.getIndexFunc = getIndexFunc;
this.sortBy = sortBy;
behaviours = new(sortBy);
}
}

View File

@@ -3,17 +3,30 @@ using System.Collections.Generic;
namespace Engine.Core;
public class FastList<T> : IReadOnlyList<T>, IEnumerable<T> where T : notnull
public class FastList<T> : IList<T>, IReadOnlyList<T>, IEnumerable<T> where T : notnull
{
private readonly List<T> items = [];
private readonly Dictionary<T, int> indexMap = [];
public bool IsReadOnly { get; set; } = false;
public int Count => items.Count;
public T this[int index]
{
get => items[index];
set
{
if (IsReadOnly)
throw new System.Data.ReadOnlyException();
public T this[int index] => items[index];
items[index] = value;
}
}
public void Add(T item)
{
if (IsReadOnly)
throw new System.Data.ReadOnlyException();
indexMap[item] = items.Count;
items.Add(item);
}
@@ -21,6 +34,9 @@ public class FastList<T> : IReadOnlyList<T>, IEnumerable<T> where T : notnull
public void RemoveAt(int i) => Remove(items[i], i);
public bool Remove(T item)
{
if (IsReadOnly)
throw new System.Data.ReadOnlyException();
if (!indexMap.TryGetValue(item, out int index))
return false;
@@ -43,6 +59,9 @@ public class FastList<T> : IReadOnlyList<T>, IEnumerable<T> where T : notnull
public void Insert(int index, T item)
{
if (IsReadOnly)
throw new System.Data.ReadOnlyException();
items.Insert(index, item);
for (int i = index; i < items.Count; i++)
@@ -51,21 +70,30 @@ public class FastList<T> : IReadOnlyList<T>, IEnumerable<T> where T : notnull
public void Clear()
{
if (IsReadOnly)
throw new System.Data.ReadOnlyException();
items.Clear();
indexMap.Clear();
}
public bool Contains(T item) => indexMap.ContainsKey(item);
public int IndexOf(T item) => items.IndexOf(item);
public int BinarySearch(T item, IComparer<T>? comparer = null) => items.BinarySearch(item, comparer);
public void Sort(IComparer<T> comparer)
{
if (IsReadOnly)
throw new System.Data.ReadOnlyException();
items.Sort(comparer);
for (int i = 0; i < items.Count; i++)
indexMap[items[i]] = i;
}
public void CopyTo(T[] array, int arrayIndex) => items.CopyTo(array, arrayIndex);
public IEnumerator<T> GetEnumerator() => items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

View File

@@ -0,0 +1,172 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Engine.Core;
/// <summary>
/// TODO This is VEERY experimental, and doesn't work well with the indices access. Use with caution
/// </summary>
/// <typeparam name="TIndex"></typeparam>
/// <typeparam name="TItem"></typeparam>
public class FastListOrdered<TIndex, TItem> : IList<TItem>, IReadOnlyList<TItem>, IEnumerable<TItem> where TItem : notnull where TIndex : IComparable
{
private readonly SortedDictionary<TIndex, FastList<TItem>> items = null!;
private readonly Func<TItem, TIndex> getIndexFunc = null!;
private readonly IComparer<TIndex> sortBy = null!;
private int count = 0;
public int Count => count;
public bool IsReadOnly { get; set; } = false;
public TItem this[int index]
{
get { (TIndex tIndex, int i) = GetAt(index); return items[tIndex][i]; }
set
{
if (IsReadOnly)
throw new System.Data.ReadOnlyException();
(TIndex tIndex, int i) = GetAt(index); items[tIndex][i] = value;
}
}
private (TIndex TIndex, int i) GetAt(Index index)
{
int actualIndex = index.IsFromEnd
? count - index.Value
: index.Value;
if (actualIndex < 0 || actualIndex >= count)
throw new IndexOutOfRangeException();
int leftIndex = actualIndex;
foreach ((TIndex i, FastList<TItem> list) in items)
{
if (leftIndex < list.Count)
return (i, leftIndex);
leftIndex -= list.Count;
}
throw new IndexOutOfRangeException();
}
public int IndexOf(TItem item)
{
int indexCounter = 0;
foreach ((TIndex index, FastList<TItem> list) in items)
{
int i = list.IndexOf(item);
if (i != -1)
return indexCounter + i;
indexCounter += list.Count;
}
return -1;
}
public void Add(TItem item)
{
if (IsReadOnly)
throw new System.Data.ReadOnlyException();
TIndex key = getIndexFunc(item);
if (!items.TryGetValue(key, out FastList<TItem>? list))
items[key] = list = [];
list.Add(item);
count++;
}
public void Insert(int index, TItem item)
{
if (IsReadOnly)
throw new System.Data.ReadOnlyException();
TIndex tIndex = getIndexFunc(item);
if (!items.TryGetValue(tIndex, out FastList<TItem>? list))
items[tIndex] = list = [];
list.Insert(index, item);
count++;
}
public bool Remove(TItem item)
{
if (IsReadOnly)
throw new System.Data.ReadOnlyException();
TIndex index = getIndexFunc(item);
if (!items.TryGetValue(index, out FastList<TItem>? list))
throw new Exceptions.NotFoundException($"Index of '{index}' is not found in the collector");
if (!list.Remove(item))
return false;
count--;
return true;
}
public void RemoveAt(int index)
{
if (IsReadOnly)
throw new System.Data.ReadOnlyException();
(TIndex tIndex, int i) = GetAt(index);
items[tIndex].RemoveAt(i);
count--;
}
public void Clear()
{
if (IsReadOnly)
throw new System.Data.ReadOnlyException();
foreach ((TIndex index, FastList<TItem> list) in items)
list.Clear();
count = 0;
}
public bool Contains(TItem item)
{
foreach ((TIndex index, FastList<TItem> list) in items)
if (list.Contains(item))
return true;
return false;
}
public void CopyTo(TItem[] array, int arrayIndex)
{
int indexCounter = 0;
foreach ((TIndex index, FastList<TItem> list) in items)
{
list.CopyTo(array, indexCounter);
indexCounter += list.Count;
}
}
public IEnumerator<TItem> GetEnumerator()
{
foreach ((TIndex index, FastList<TItem> list) in items)
foreach (TItem item in list)
yield return item;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public FastListOrdered(Func<TItem, TIndex> getIndexFunc, Comparison<TIndex> sortBy)
{
this.getIndexFunc = getIndexFunc;
this.sortBy = Comparer<TIndex>.Create(sortBy);
items = new(this.sortBy);
}
public FastListOrdered(Func<TItem, TIndex> getIndexFunc, IComparer<TIndex> sortBy)
{
this.getIndexFunc = getIndexFunc;
this.sortBy = sortBy;
items = new(sortBy);
}
}

View File

@@ -240,21 +240,33 @@ public static class Math
public static T Lerp<T>(T x, T y, T t) where T : IFloatingPoint<T> => x + (y - x) * t;
/// <summary>
/// Rounds a number to a specified number of fractional digits.
/// Rounds a number to the closest integer.
/// </summary>
/// <param name="x">The number to round.</param>
/// <param name="digits">The number of fractional digits in the return value.</param>
/// <param name="mode">Specification for how to round <paramref name="x"/> if it is midway between two other numbers.</param>
/// <returns>The number <paramref name="x"/> rounded to <paramref name="digits"/> fractional digits.</returns>
public static float Round(float x, int digits, MidpointRounding mode) => MathF.Round(x, digits, mode);
/// <param name="roundMode">Specification for how to round <paramref name="x"/> if it is midway between two other numbers.</param>
/// <returns>The number <paramref name="x"/> rounded to the closest integer.</returns>
public static float Round(float x, RoundMode roundMode) => RoundToInt(x, roundMode);
/// <summary>
/// Rounds a number to an integer.
/// Rounds a number to the closest integer.
/// </summary>
/// <param name="x">The number to round.</param>
/// <param name="roundMode">Specification for how to round <paramref name="x"/> if it's midway between two numbers</param>
/// <returns></returns>
public static int RoundToInt(float x, RoundMode roundMode = RoundMode.Ceil) => (int)MathF.Round(x, 0, roundMode == RoundMode.Ceil ? MidpointRounding.ToPositiveInfinity : MidpointRounding.ToNegativeInfinity);
/// <returns>The number <paramref name="x"/> rounded to the closest integer.</returns>
public static int RoundToInt(float x, RoundMode roundMode = RoundMode.Ceil)
{
float remainder = x.Mod(1f);
if (remainder == .5f)
if (roundMode == RoundMode.Floor)
return (int)x;
else
return (int)(x + .5f);
if (x < 0f)
return (int)(x - .5f);
return (int)(x + .5f);
}
public enum RoundMode { Ceil, Floor };
/// <summary>

View File

@@ -81,7 +81,7 @@ public static class MathExtensions
public static T Lerp<T>(this T x, T y, T t) where T : IFloatingPoint<T> => Math.Lerp(x, y, t);
/// <inheritdoc cref="Math.Round(float, int, MidpointRounding)" />
public static float Round(this float x, int digits, MidpointRounding mode) => Math.Round(x, digits, mode);
public static float Round(this float x, Math.RoundMode mode) => Math.Round(x, mode);
/// <inheritdoc cref="Math.RoundToInt(float, Math.RoundMode)" />
public static int RoundToInt(this float x, Math.RoundMode roundMode = Math.RoundMode.Ceil) => Math.RoundToInt(x, roundMode);

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
namespace Engine.Core;
@@ -11,7 +12,7 @@ namespace Engine.Core;
/// Initializes a new instance of the <see cref="AABB"/> struct with the specified lower and upper boundaries.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("LowerBoundary: {LowerBoundary.ToString(), nq}, UpperBoundary: {UpperBoundary.ToString(), nq}")]
public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary)
public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary) : IEquatable<AABB>
{
/// <summary>
/// The lower boundary of the <see cref="AABB"/>.
@@ -82,6 +83,7 @@ public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary)
/// <param name="obj">The object to compare with the current <see cref="AABB"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="AABB"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is AABB aabb && this == aabb;
public bool Equals(AABB other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="AABB"/>.

View File

@@ -1,3 +1,4 @@
using System;
using System.Diagnostics;
namespace Engine.Core;
@@ -11,7 +12,7 @@ namespace Engine.Core;
/// Initializes a new instance of the <see cref="Circle"/> struct with the specified center and radius.
/// </remarks>
[DebuggerDisplay("Center: {Center.ToString(),nq}, Radius: {Radius}")]
public readonly struct Circle(Vector2D center, float radius)
public readonly struct Circle(Vector2D center, float radius) : IEquatable<Circle>
{
/// <summary>
/// The center of the circle.
@@ -87,6 +88,7 @@ public readonly struct Circle(Vector2D center, float radius)
/// <param name="obj">The object to compare with the current <see cref="Circle"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Circle"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is Circle circle && this == circle;
public bool Equals(Circle other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="Circle"/>.

View File

@@ -1,3 +1,5 @@
using System;
namespace Engine.Core;
/// <summary>
@@ -10,7 +12,7 @@ namespace Engine.Core;
/// Initializes a new instance of the <see cref="ColorHSV"/> struct with the specified values.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
public readonly struct ColorHSV(float hue, float saturation, float value)
public readonly struct ColorHSV(float hue, float saturation, float value) : IEquatable<ColorHSV>
{
/// <summary>
/// The Hue value of the <see cref="ColorHSV"/>.
@@ -112,6 +114,7 @@ public readonly struct ColorHSV(float hue, float saturation, float value)
/// <param name="obj">The object to compare with the current <see cref="ColorHSV"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorHSV"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is ColorHSV colorHSV && this == colorHSV;
public bool Equals(ColorHSV other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="ColorHSV"/>.

View File

@@ -1,3 +1,5 @@
using System;
namespace Engine.Core;
/// <summary>
@@ -11,7 +13,7 @@ namespace Engine.Core;
/// Initializes a new instance of the <see cref="ColorHSVA"/> struct with the specified values.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
public readonly struct ColorHSVA(float hue, float saturation, float value, float alpha = 1)
public readonly struct ColorHSVA(float hue, float saturation, float value, float alpha = 1) : IEquatable<ColorHSVA>
{
/// <summary>
/// The Hue value of the <see cref="ColorHSVA"/>.
@@ -150,6 +152,7 @@ public readonly struct ColorHSVA(float hue, float saturation, float value, float
/// <param name="obj">The object to compare with the current <see cref="ColorHSVA"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorHSVA"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is ColorHSVA colorHSVA && this == colorHSVA;
public bool Equals(ColorHSVA other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="ColorHSVA"/>.

View File

@@ -1,3 +1,5 @@
using System;
namespace Engine.Core;
/// <summary>
@@ -10,7 +12,7 @@ namespace Engine.Core;
/// Initializes a new instance of the <see cref="ColorRGB"/> struct with the specified values.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
public readonly struct ColorRGB(byte r, byte g, byte b)
public readonly struct ColorRGB(byte r, byte g, byte b) : IEquatable<ColorRGB>
{
/// <summary>
/// The Red value of the <see cref="ColorRGB"/>.
@@ -102,6 +104,7 @@ public readonly struct ColorRGB(byte r, byte g, byte b)
/// <param name="obj">The object to compare with the current <see cref="ColorRGB"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorRGB"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is ColorRGB colorRGB && this == colorRGB;
public bool Equals(ColorRGB other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="ColorRGB"/>.

View File

@@ -1,3 +1,5 @@
using System;
namespace Engine.Core;
/// <summary>
@@ -11,7 +13,7 @@ namespace Engine.Core;
/// Initializes a new instance of the <see cref="ColorRGBA"/> struct with the specified values.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255)
public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255) : IEquatable<ColorRGBA>
{
/// <summary>
/// The Red value of the <see cref="ColorRGBA"/>.
@@ -132,6 +134,7 @@ public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255)
/// <param name="obj">The object to compare with the current <see cref="ColorRGBA"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="ColorRGBA"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is ColorRGBA colorRGBA && this == colorRGBA;
public bool Equals(ColorRGBA other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="ColorRGBA"/>.

View File

@@ -1,3 +1,4 @@
using System;
using System.Diagnostics.CodeAnalysis;
namespace Engine.Core;
@@ -11,7 +12,7 @@ namespace Engine.Core;
/// Initializes a new instance of the <see cref="Line2D"/> struct with the specified endpoints.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("From: {From.ToString(),nq}, To: {To.ToString(),nq}, Direction: {Direction.ToString(),nq}, Length: {Length}")]
public readonly struct Line2D(Vector2D from, Vector2D to)
public readonly struct Line2D(Vector2D from, Vector2D to) : IEquatable<Line2D>
{
/// <summary>
/// The starting point of the <see cref="Line2D"/> segment.
@@ -196,6 +197,7 @@ public readonly struct Line2D(Vector2D from, Vector2D to)
/// <param name="obj">The object to compare with the current <see cref="Line2D"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Line2D"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is Line2D line2D && this == line2D;
public bool Equals(Line2D other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="Line2D"/>.

View File

@@ -1,3 +1,5 @@
using System;
namespace Engine.Core;
/// <summary>
@@ -9,7 +11,7 @@ namespace Engine.Core;
/// Initializes a new instance of the <see cref="Line2DEquation"/> struct with the specified slope and Y intercept.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("y = {Slope}x + {OffsetY}")]
public readonly struct Line2DEquation(float slope, float offsetY)
public readonly struct Line2DEquation(float slope, float offsetY) : IEquatable<Line2DEquation>
{
/// <summary>
/// The slope of the <see cref="Line2DEquation"/>.
@@ -48,6 +50,7 @@ public readonly struct Line2DEquation(float slope, float offsetY)
/// <param name="obj">The object to compare with the current <see cref="Line2DEquation"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Line2DEquation"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is Line2DEquation lineEquation && this == lineEquation;
public bool Equals(Line2DEquation other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="Line2DEquation"/>.

View File

@@ -1,3 +1,5 @@
using System;
namespace Engine.Core;
/// <summary>
@@ -9,7 +11,7 @@ namespace Engine.Core;
/// Initializes a new instance of the <see cref="Projection1D"/> struct with the specified minimum and maximum values.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("Min: {Min}, Max: {Max}")]
public readonly struct Projection1D(float min, float max)
public readonly struct Projection1D(float min, float max) : IEquatable<Projection1D>
{
/// <summary>
/// Gets the minimum value of the projection.
@@ -90,6 +92,7 @@ public readonly struct Projection1D(float min, float max)
/// <param name="obj">The object to compare with the current <see cref="Projection1D"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Projection1D"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is Projection1D projection1D && this == projection1D;
public bool Equals(Projection1D other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="Projection1D"/>.

View File

@@ -1,3 +1,5 @@
using System;
namespace Engine.Core;
/// <summary>
@@ -11,7 +13,7 @@ namespace Engine.Core;
/// Initializes a new instance of the <see cref="Quaternion"/> struct with the specified positions.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized.ToString(),nq}")]
public readonly struct Quaternion(float x, float y, float z, float w)
public readonly struct Quaternion(float x, float y, float z, float w) : IEquatable<Quaternion>
{
/// <summary>
/// The X(i) imaginary of the <see cref="Quaternion"/>.
@@ -288,6 +290,7 @@ public readonly struct Quaternion(float x, float y, float z, float w)
/// <param name="obj">The object to compare with the current <see cref="Quaternion"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Quaternion"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is Quaternion quaternion && this == quaternion;
public bool Equals(Quaternion other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="Quaternion"/>.

View File

@@ -1,3 +1,5 @@
using System;
namespace Engine.Core;
/// <summary>
@@ -5,7 +7,7 @@ namespace Engine.Core;
/// </summary>
/// <param name="Origin">The <see cref="Vector2D"/> in 2D space where the ray starts from.</param>
/// <param name="Direction">Normalized <see cref="Vector2D"/> indicating the ray's is direction.</param>
public readonly struct Ray2D(Vector2D Origin, Vector2D Direction)
public readonly struct Ray2D(Vector2D Origin, Vector2D Direction) : IEquatable<Ray2D>
{
/// <summary>
/// The starting point of the <see cref="Ray2D"/>.
@@ -72,6 +74,7 @@ public readonly struct Ray2D(Vector2D Origin, Vector2D Direction)
/// <param name="obj">The object to compare with the current <see cref="Ray2D"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Ray2D"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is Ray2D ray2D && this == ray2D;
public bool Equals(Ray2D other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="Ray2D"/>.

View File

@@ -1,7 +1,9 @@
using System;
namespace Engine.Core;
[System.Diagnostics.DebuggerDisplay("A: {A.ToString(), nq}, B: {B.ToString(), nq}, B: {C.ToString(), nq}")]
public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C)
public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C) : IEquatable<Triangle>
{
public readonly Vector2D A { get; init; } = A;
public readonly Vector2D B { get; init; } = B;
@@ -54,6 +56,7 @@ public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C)
/// <param name="obj">The object to compare with the current <see cref="Triangle"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Triangle"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is Triangle triangle && this == triangle;
public bool Equals(Triangle other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="Triangle"/>.

View File

@@ -1,3 +1,5 @@
using System;
namespace Engine.Core;
/// <summary>
@@ -9,7 +11,7 @@ namespace Engine.Core;
/// Initializes a new instance of the <see cref="Vector2D"/> struct with the specified positions.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized.ToString(),nq}")]
public readonly struct Vector2D(float x, float y)
public readonly struct Vector2D(float x, float y) : IEquatable<Vector2D>
{
/// <summary>
/// The X coordinate of the <see cref="Vector2D"/>.
@@ -82,6 +84,7 @@ public readonly struct Vector2D(float x, float y)
public static implicit operator System.Numerics.Vector2(Vector2D vector) => new(vector.X, vector.Y);
public static implicit operator Vector2D(System.Numerics.Vector2 vector) => new(vector.X, vector.Y);
public static implicit operator Vector2D(Vector2DInt vector) => new(vector.X, vector.Y);
public static implicit operator Vector2D(Vector3D vector) => new(vector.X, vector.Y);
public static implicit operator Vector2D(System.Numerics.Vector3 vector) => new(vector.X, vector.Y);
@@ -308,6 +311,7 @@ public readonly struct Vector2D(float x, float y)
/// <param name="obj">The object to compare with the current <see cref="Vector2D"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Vector2D"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is Vector2D vector2D && this == vector2D;
public bool Equals(Vector2D other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="Vector2D"/>.

View File

@@ -0,0 +1,306 @@
using System;
namespace Engine.Core;
/// <summary>
/// Represents a two-dimensional integer vector.
/// </summary>
/// <param name="x">X position of the <see cref="Vector2DInt"/>.</param>
/// <param name="y">Y position of the <see cref="Vector2DInt"/>.</param>
/// <remarks>
/// Initializes a new instance of the <see cref="Vector2DInt"/> struct with the specified positions.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
public readonly struct Vector2DInt(int x, int y) : IEquatable<Vector2DInt>
{
/// <summary>
/// The X coordinate of the <see cref="Vector2DInt"/>.
/// </summary>
public readonly int X = x;
/// <summary>
/// The Y coordinate of the <see cref="Vector2DInt"/>.
/// </summary>
public readonly int Y = y;
/// <summary>
/// The magnitude (length) of the <see cref="Vector2DInt"/>.
/// </summary>
public float Magnitude => Length(this);
/// <summary>
/// The squared magnitude (length) of the <see cref="Vector2DInt"/>.
/// </summary>
public float MagnitudeSquared => LengthSquared(this);
/// <summary>
/// Gets a <see cref="Vector2DInt"/> with the direction reversed.
/// </summary>
public readonly Vector2DInt Reversed => -this;
/// <summary>
/// Represents the unit <see cref="Vector2DInt"/> pointing upwards.
/// </summary>
public readonly static Vector2DInt Up = new(0, 1);
/// <summary>
/// Represents the unit <see cref="Vector2DInt"/> pointing downwards.
/// </summary>
public readonly static Vector2DInt Down = new(0, -1);
/// <summary>
/// Represents the unit <see cref="Vector2DInt"/> pointing leftwards.
/// </summary>
public readonly static Vector2DInt Left = new(-1, 0);
/// <summary>
/// Represents the unit <see cref="Vector2DInt"/> pointing rightwards.
/// </summary>
public readonly static Vector2DInt Right = new(1, 0);
/// <summary>
/// Represents the zero <see cref="Vector2DInt"/>.
/// </summary>
public readonly static Vector2DInt Zero = new(0, 0);
/// <summary>
/// Represents the <see cref="Vector2DInt"/> with both components equal to 1.
/// </summary>
public readonly static Vector2DInt One = new(1, 1);
public static Vector2DInt operator -(Vector2DInt vector) => new(0 - vector.X, 0 - vector.Y);
public static Vector2DInt operator +(Vector2DInt left, Vector2DInt right) => new(left.X + right.X, left.Y + right.Y);
public static Vector2DInt operator -(Vector2DInt left, Vector2DInt right) => new(left.X - right.X, left.Y - right.Y);
public static Vector2DInt operator *(Vector2DInt vector, int value) => new(vector.X * value, vector.Y * value);
public static Vector2DInt operator *(int value, Vector2DInt vector) => new(vector.X * value, vector.Y * value);
public static Vector2DInt operator /(Vector2DInt vector, int value) => new(vector.X / value, vector.Y / value);
public static bool operator ==(Vector2DInt left, Vector2DInt right) => left.X == right.X && left.Y == right.Y;
public static bool operator !=(Vector2DInt left, Vector2DInt right) => left.X != right.X || left.Y != right.Y;
public static implicit operator Vector2DInt(Vector2D vector) => new(vector.X.RoundToInt(), vector.Y.RoundToInt());
public static implicit operator Vector2DInt(Vector3DInt vector) => new(vector.X, vector.Y);
/// <summary>
/// Calculates the length of the <see cref="Vector2DInt"/>.
/// </summary>
/// <param name="vector">The <see cref="Vector2DInt"/>.</param>
/// <returns>The length of the <see cref="Vector2DInt"/>.</returns>
public static float Length(Vector2DInt vector) => Engine.Core.Math.Sqrt(LengthSquared(vector));
/// <summary>
/// Calculates the squared length of the <see cref="Vector2DInt"/>.
/// </summary>
/// <param name="vector">The <see cref="Vector2DInt"/>.</param>
/// <returns>The squared length of the <see cref="Vector2DInt"/>.</returns>
public static float LengthSquared(Vector2DInt vector) => vector.X * vector.X + vector.Y * vector.Y;
/// <summary>
/// Calculates the distance between two <see cref="Vector2DInt"/>s.
/// </summary>
/// <param name="from">The start <see cref="Vector2DInt"/>.</param>
/// <param name="to">The end <see cref="Vector2DInt"/>.</param>
/// <returns>The distance between the two <see cref="Vector2DInt"/>s.</returns>
public static float Distance(Vector2DInt from, Vector2DInt to) => Length(FromTo(from, to));
/// <summary>
/// Inverts the direction of the <see cref="Vector2DInt"/>.
/// </summary>
/// <param name="vector">The <see cref="Vector2DInt"/>.</param>
/// <returns>The inverted <see cref="Vector2DInt"/>.</returns>
public static Vector2DInt Invert(Vector2DInt vector) => -vector;
/// <summary>
/// Adds two <see cref="Vector2DInt"/>s.
/// </summary>
/// <param name="left">The first <see cref="Vector2DInt"/>.</param>
/// <param name="right">The second <see cref="Vector2DInt"/>.</param>
/// <returns>The sum of the two <see cref="Vector2DInt"/>s.</returns>
public static Vector2DInt Add(Vector2DInt left, Vector2DInt right) => left + right;
/// <summary>
/// Subtracts one <see cref="Vector2DInt"/> from another.
/// </summary>
/// <param name="left">The <see cref="Vector2DInt"/> to subtract from.</param>
/// <param name="right">The <see cref="Vector2DInt"/> to subtract.</param>
/// <returns>The result of subtracting the second <see cref="Vector2DInt"/> from the first.</returns>
public static Vector2DInt Subtract(Vector2DInt left, Vector2DInt right) => left - right;
/// <summary>
/// Multiplies a <see cref="Vector2DInt"/> by a scalar value.
/// </summary>
/// <param name="vector">The <see cref="Vector2DInt"/>.</param>
/// <param name="value">The scalar value.</param>
/// <returns>The result of multiplying the <see cref="Vector2DInt"/> by the scalar value.</returns>
public static Vector2DInt Multiply(Vector2DInt vector, int value) => vector * value;
/// <summary>
/// Divides a <see cref="Vector2DInt"/> by a scalar value.
/// </summary>
/// <param name="vector">The <see cref="Vector2DInt"/>.</param>
/// <param name="value">The scalar value.</param>
/// <returns>The result of dividing the <see cref="Vector2DInt"/> by the scalar value.</returns>
public static Vector2DInt Divide(Vector2DInt vector, int value) => vector / value;
/// <summary>
/// Calculates the absolute value of each component of the vector.
/// </summary>
/// <param name="vector">The <see cref="Vector2DInt"/>.</param>
/// <returns>The <see cref="Vector2DInt"/> with each component's absolute value.</returns>
public static Vector2DInt Abs(Vector2DInt vector) => new(Engine.Core.Math.Abs(vector.X), Engine.Core.Math.Abs(vector.Y));
/// <summary>
/// Calculates the <see cref="Vector2DInt"/> from one point to another.
/// </summary>
/// <param name="from">The starting point.</param>
/// <param name="to">The ending point.</param>
/// <returns>The <see cref="Vector2DInt"/> from the starting point to the ending point.</returns>
public static Vector2DInt FromTo(Vector2DInt from, Vector2DInt to) => to - from;
/// <summary>
/// Scales a <see cref="Vector2DInt"/> by another <see cref="Vector2DInt"/> component-wise.
/// </summary>
/// <param name="vector">The <see cref="Vector2DInt"/> to scale.</param>
/// <param name="scale">The <see cref="Vector2DInt"/> containing the scaling factors for each component.</param>
/// <returns>The scaled <see cref="Vector2DInt"/>.</returns>
public static Vector2DInt Scale(Vector2DInt vector, Vector2DInt scale) => new(vector.X * scale.X, vector.Y * scale.Y);
/// <summary>
/// Calculates a perpendicular <see cref="Vector2DInt"/> to the given <see cref="Vector2DInt"/>.
/// </summary>
/// <param name="vector">The input <see cref="Vector2DInt"/>.</param>
/// <returns>A <see cref="Vector2DInt"/> perpendicular to the input <see cref="Vector2DInt"/>.</returns>
public static Vector2DInt Perpendicular(Vector2DInt vector) => new(-vector.Y, vector.X);
/// <summary>
/// Returns the component-wise minimum of two <see cref="Vector2DInt"/>s.
/// </summary>
/// <param name="left">The first <see cref="Vector2DInt"/>.</param>
/// <param name="right">The second <see cref="Vector2DInt"/>.</param>
/// <returns>The <see cref="Vector2DInt"/> containing the minimum components from both input <see cref="Vector2DInt"/>s.</returns>
public static Vector2DInt Min(Vector2DInt left, Vector2DInt right) => new((left.X < right.X) ? left.X : right.X, (left.Y < right.Y) ? left.Y : right.Y);
/// <summary>
/// Returns the component-wise maximum of two <see cref="Vector2DInt"/>s.
/// </summary>
/// <param name="left">The first <see cref="Vector2DInt"/>.</param>
/// <param name="right">The second <see cref="Vector2DInt"/>.</param>
/// <returns>The <see cref="Vector2DInt"/> containing the maximum components from both input <see cref="Vector2DInt"/>s.</returns>
public static Vector2DInt Max(Vector2DInt left, Vector2DInt right) => new((left.X > right.X) ? left.X : right.X, (left.Y > right.Y) ? left.Y : right.Y);
/// <summary>
/// Clamps each component of a <see cref="Vector2DInt"/> between the corresponding component of two other <see cref="Vector2DInt"/>s.
/// </summary>
/// <param name="vector">The <see cref="Vector2DInt"/> to clamp.</param>
/// <param name="min">The <see cref="Vector2DInt"/> representing the minimum values for each component.</param>
/// <param name="max">The <see cref="Vector2DInt"/> representing the maximum values for each component.</param>
/// <returns>A <see cref="Vector2DInt"/> with each component clamped between the corresponding components of the min and max <see cref="Vector2DInt"/>s.</returns>
public static Vector2DInt Clamp(Vector2DInt vector, Vector2DInt min, Vector2DInt max) => new(Engine.Core.Math.Clamp(vector.X, min.X, max.X), Engine.Core.Math.Clamp(vector.Y, min.Y, max.Y));
/// <summary>
/// Performs linear interpolation between two <see cref="Vector2DInt"/>s.
/// </summary>
/// <param name="from">The starting <see cref="Vector2DInt"/> (t = 0).</param>
/// <param name="to">The ending <see cref="Vector2DInt"/> (t = 1).</param>
/// <param name="t">The interpolation parameter.</param>
/// <returns>The interpolated <see cref="Vector2DInt"/>.</returns>
public static Vector2DInt Lerp(Vector2DInt from, Vector2DInt to, int t) => from + FromTo(from, to) * t;
/// <summary>
/// Calculates the cross product of two <see cref="Vector2DInt"/>s.
/// </summary>
/// <param name="left">The first <see cref="Vector2DInt"/>.</param>
/// <param name="right">The second <see cref="Vector2DInt"/>.</param>
/// <returns>The cross product of the two <see cref="Vector2DInt"/>s.</returns>
public static int Cross(Vector2DInt left, Vector2DInt right) => left.X * right.Y - left.Y * right.X;
/// <summary>
/// Calculates the dot product of two <see cref="Vector2DInt"/>s.
/// </summary>
/// <param name="left">The first <see cref="Vector2DInt"/>.</param>
/// <param name="right">The second <see cref="Vector2DInt"/>.</param>
/// <returns>The dot product of the two <see cref="Vector2DInt"/>s.</returns>
public static int Dot(Vector2DInt left, Vector2DInt right) => left.X * right.X + left.Y * right.Y;
/// <summary>
/// Determines whether the specified object is equal to the current <see cref="Vector2DInt"/>.
/// </summary>
/// <param name="obj">The object to compare with the current <see cref="Vector2DInt"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Vector2DInt"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is Vector2DInt vector2DInt && this == vector2DInt;
public bool Equals(Vector2DInt other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="Vector2DInt"/>.
/// </summary>
/// <returns>A hash code for the <see cref="Vector2DInt"/>.</returns>
public override int GetHashCode() => System.HashCode.Combine(X, Y);
/// <summary>
/// Converts the <see cref="Vector2DInt"/> to its string representation.
/// </summary>
/// <returns>A string representation of the <see cref="Vector2DInt"/>.</returns>
public override string ToString() => $"{nameof(Vector2DInt)}({X}, {Y})";
}
/// <summary>
/// Provides extension methods for <see cref="Vector2DInt"/> type.
/// </summary>
public static class Vector2DIntExtensions
{
/// <inheritdoc cref="Vector2DInt.Length(Vector2DInt)" />
public static float Length(this Vector2DInt vector) => Vector2DInt.Length(vector);
/// <inheritdoc cref="Vector2DInt.LengthSquared(this vector) => Vector2DInt/>
public static float LengthSquared(this Vector2DInt vector) => Vector2DInt.LengthSquared(vector);
/// <inheritdoc cref="Vector2DInt.Distance(Vector2DInt, Vector2DInt)" />
public static float Distance(this Vector2DInt from, Vector2DInt to) => Vector2DInt.Distance(from, to);
/// <inheritdoc cref="Vector2DInt.Invert(this vector) => Vector2DInt/>
public static Vector2DInt Invert(this Vector2DInt vector) => Vector2DInt.Invert(vector);
/// <inheritdoc cref="Vector2DInt.Add(Vector2DInt, Vector2DInt)" />
public static Vector2DInt Add(this Vector2DInt vector, Vector2DInt vectorToAdd) => Vector2DInt.Add(vector, vectorToAdd);
/// <inheritdoc cref="Vector2DInt.Subtract(Vector2DInt, Vector2DInt)" />
public static Vector2DInt Subtract(this Vector2DInt vector, Vector2DInt vectorToSubtract) => Vector2DInt.Subtract(vector, vectorToSubtract);
/// <inheritdoc cref="Vector2DInt.Multiply(Vector2DInt, int)" />
public static Vector2DInt Multiply(this Vector2DInt vector, int value) => Vector2DInt.Multiply(vector, value);
/// <inheritdoc cref="Vector2DInt.Divide(Vector2DInt, int)" />
public static Vector2DInt Divide(this Vector2DInt vector, int value) => Vector2DInt.Divide(vector, value);
/// <inheritdoc cref="Vector2DInt.Abs(Vector2DInt)" />
public static Vector2DInt Abs(this Vector2DInt vector) => Vector2DInt.Abs(vector);
/// <inheritdoc cref="Vector2DInt.FromTo(Vector2DInt, Vector2DInt)" />
public static Vector2DInt FromTo(this Vector2DInt from, Vector2DInt to) => Vector2DInt.FromTo(from, to);
/// <inheritdoc cref="Vector2DInt.Scale(Vector2DInt, Vector2DInt)" />
public static Vector2DInt Scale(this Vector2DInt vector, Vector2DInt scale) => Vector2DInt.Scale(vector, scale);
/// <inheritdoc cref="Vector2DInt.Perpendicular(Vector2DInt)" />
public static Vector2DInt Perpendicular(this Vector2DInt vector) => Vector2DInt.Perpendicular(vector);
/// <inheritdoc cref="Vector2DInt.Min(Vector2DInt, Vector2DInt)" />
public static Vector2DInt Min(this Vector2DInt left, Vector2DInt right) => Vector2DInt.Min(left, right);
/// <inheritdoc cref="Vector2DInt.Max(Vector2DInt, Vector2DInt)" />
public static Vector2DInt Max(this Vector2DInt left, Vector2DInt right) => Vector2DInt.Max(left, right);
/// <inheritdoc cref="Vector2DInt.Clamp(Vector2DInt, Vector2DInt,Vector2DInt)" />
public static Vector2DInt Clamp(this Vector2DInt vector, Vector2DInt min, Vector2DInt max) => Vector2DInt.Clamp(vector, min, max);
/// <inheritdoc cref="Vector2DInt.Lerp(Vector2DInt, Vector2DInt," />
public static Vector2DInt Lerp(this Vector2DInt from, Vector2DInt to, int t) => Vector2DInt.Lerp(from, to, t);
/// <inheritdoc cref="Vector2DInt.Cross(Vector2DInt, Vector2DInt)" />
public static int Cross(this Vector2DInt left, Vector2DInt right) => Vector2DInt.Cross(left, right);
/// <inheritdoc cref="Vector2D.Angle(Vector2D, Vector2D)" />
public static float AngleBetween(this Vector2D left, Vector2D right) => Vector2D.Angle(left, right);
/// <inheritdoc cref="Vector2DInt.Dot(Vector2DInt, Vector2DInt)" />
public static int Dot(this Vector2DInt left, Vector2DInt right) => Vector2DInt.Dot(left, right);
}

View File

@@ -1,3 +1,5 @@
using System;
namespace Engine.Core;
/// <summary>
@@ -10,7 +12,7 @@ namespace Engine.Core;
/// Initializes a new instance of the <see cref="Vector3D"/> struct with the specified positions.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized.ToString(),nq}")]
public readonly struct Vector3D(float x, float y, float z)
public readonly struct Vector3D(float x, float y, float z) : IEquatable<Vector3D>
{
/// <summary>
/// The X coordinate of the <see cref="Vector3D"/>.
@@ -92,6 +94,7 @@ public readonly struct Vector3D(float x, float y, float z)
public static implicit operator System.Numerics.Vector3(Vector3D vector) => new(vector.X, vector.Y, vector.Z);
public static implicit operator Vector3D(System.Numerics.Vector3 vector) => new(vector.X, vector.Y, vector.Z);
public static implicit operator Vector3D(Vector3DInt vector) => new(vector.X, vector.Y, vector.Z);
public static implicit operator Vector3D(Vector2D vector) => new(vector.X, vector.Y, 0f);
public static implicit operator Vector3D(System.Numerics.Vector2 vector) => new(vector.X, vector.Y, 0f);
@@ -277,6 +280,7 @@ public readonly struct Vector3D(float x, float y, float z)
/// <param name="obj">The object to compare with the current <see cref="Vector3D"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Vector3D"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is Vector3D vector3D && this == vector3D;
public bool Equals(Vector3D other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="Vector3D"/>.

View File

@@ -0,0 +1,314 @@
using System;
namespace Engine.Core;
/// <summary>
/// Represents a three-dimensional integer vector.
/// </summary>
/// <param name="x">X position of the <see cref="Vector3DInt"/>.</param>
/// <param name="y">Y position of the <see cref="Vector3DInt"/>.</param>
/// <param name="z">Z position of the <see cref="Vector3DInt"/>.</param>
/// <remarks>
/// Initializes a new instance of the <see cref="Vector3DInt"/> struct with the specified positions.
/// </remarks>
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}")]
public readonly struct Vector3DInt(int x, int y, int z) : IEquatable<Vector3DInt>
{
/// <summary>
/// The X coordinate of the <see cref="Vector3DInt"/>.
/// </summary>
public readonly int X = x;
/// <summary>
/// The Y coordinate of the <see cref="Vector3DInt"/>.
/// </summary>
public readonly int Y = y;
/// <summary>
/// The Z coordinate of the <see cref="Vector3DInt"/>.
/// </summary>
public readonly int Z = z;
/// <summary>
/// The magnitude (length) of the <see cref="Vector3DInt"/>.
/// </summary>
public float Magnitude => Length(this);
/// <summary>
/// The squared magnitude (length) of the <see cref="Vector3DInt"/>.
/// </summary>
public float MagnitudeSquared => LengthSquared(this);
/// <summary>
/// Represents the unit <see cref="Vector3DInt"/> pointing upwards.
/// </summary>
public readonly static Vector3DInt Up = new(0, 1, 0);
/// <summary>
/// Represents the unit <see cref="Vector3DInt"/> pointing downwards.
/// </summary>
public readonly static Vector3DInt Down = new(0, -1, 0);
/// <summary>
/// Represents the unit <see cref="Vector3DInt"/> pointing leftwards.
/// </summary>
public readonly static Vector3DInt Left = new(-1, 0, 0);
/// <summary>
/// Represents the unit <see cref="Vector3DInt"/> pointing rightwards.
/// </summary>
public readonly static Vector3DInt Right = new(1, 0, 0);
/// <summary>
/// Represents the unit <see cref="Vector3DInt"/> pointing forwards.
/// </summary>
public readonly static Vector3DInt Forward = new(0, 0, 1);
/// <summary>
/// Represents the unit <see cref="Vector3DInt"/> pointing backwards.
public readonly static Vector3DInt Backward = new(0, 0, -1);
/// <summary>
/// Represents the zero <see cref="Vector3DInt"/>.
/// </summary>
public readonly static Vector3DInt Zero = new(0, 0, 0);
/// <summary>
/// Represents the <see cref="Vector3DInt"/> with both components equal to 1.
/// </summary>
public readonly static Vector3DInt One = new(1, 1, 1);
public static Vector3DInt operator -(Vector3DInt vector) => new(0 - vector.X, 0 - vector.Y, 0 - vector.Z);
public static Vector3DInt operator +(Vector3DInt left, Vector3DInt right) => new(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
public static Vector3DInt operator -(Vector3DInt left, Vector3DInt right) => new(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
public static Vector3DInt operator *(Vector3DInt vector, int value) => new(vector.X * value, vector.Y * value, vector.Z * value);
public static Vector3DInt operator *(int value, Vector3DInt vector) => new(vector.X * value, vector.Y * value, vector.Z * value);
public static Vector3DInt operator /(Vector3DInt vector, int value) => new(vector.X / value, vector.Y / value, vector.Z / value);
public static bool operator ==(Vector3DInt left, Vector3DInt right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z;
public static bool operator !=(Vector3DInt left, Vector3DInt right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z;
public static implicit operator Vector3DInt(Vector3D vector) => new(vector.X.RoundToInt(), vector.Y.RoundToInt(), vector.Z.RoundToInt());
public static implicit operator Vector3DInt(Vector2DInt vector) => new(vector.X, vector.Y, 0);
/// <summary>
/// Calculates the length of the <see cref="Vector3DInt"/>.
/// </summary>
/// <param name="vector">The <see cref="Vector3DInt"/>.</param>
/// <returns>The length of the <see cref="Vector3DInt"/>.</returns>
public static float Length(Vector3DInt vector) => Math.Sqrt(LengthSquared(vector));
/// <summary>
/// Calculates the squared length of the <see cref="Vector3DInt"/>.
/// </summary>
/// <param name="vector">The <see cref="Vector3DInt"/>.</param>
/// <returns>The squared length of the <see cref="Vector3DInt"/>.</returns>
public static float LengthSquared(Vector3DInt vector) => vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z;
/// <summary>
/// Calculates the distance between two <see cref="Vector3DInt"/>s.
/// </summary>
/// <param name="from">The start <see cref="Vector3DInt"/>.</param>
/// <param name="to">The end <see cref="Vector3DInt"/>.</param>
/// <returns>The distance between the two <see cref="Vector3DInt"/>s.</returns>
public static float Distance(Vector3DInt from, Vector3DInt to) => Length(FromTo(from, to));
/// <summary>
/// Inverts the direction of the <see cref="Vector3DInt"/>.
/// </summary>
/// <param name="vector">The <see cref="Vector3DInt"/>.</param>
/// <returns>The inverted <see cref="Vector3DInt"/>.</returns>
public static Vector3DInt Invert(Vector3DInt vector) => -vector;
/// <summary>
/// Adds two <see cref="Vector3DInt"/>s.
/// </summary>
/// <param name="left">The first <see cref="Vector3DInt"/>.</param>
/// <param name="right">The second <see cref="Vector3DInt"/>.</param>
/// <returns>The sum of the two <see cref="Vector3DInt"/>s.</returns>
public static Vector3DInt Add(Vector3DInt left, Vector3DInt right) => left + right;
/// <summary>
/// Subtracts one <see cref="Vector3DInt"/> from another.
/// </summary>
/// <param name="left">The <see cref="Vector3DInt"/> to subtract from.</param>
/// <param name="right">The <see cref="Vector3DInt"/> to subtract.</param>
/// <returns>The result of subtracting the second <see cref="Vector3DInt"/> from the first.</returns>
public static Vector3DInt Subtract(Vector3DInt left, Vector3DInt right) => left - right;
/// <summary>
/// Multiplies a <see cref="Vector3DInt"/> by a scalar value.
/// </summary>
/// <param name="vector">The <see cref="Vector3DInt"/>.</param>
/// <param name="value">The scalar value.</param>
/// <returns>The result of multiplying the <see cref="Vector3DInt"/> by the scalar value.</returns>
public static Vector3DInt Multiply(Vector3DInt vector, int value) => vector * value;
/// <summary>
/// Divides a <see cref="Vector3DInt"/> by a scalar value.
/// </summary>
/// <param name="vector">The <see cref="Vector3DInt"/>.</param>
/// <param name="value">The scalar value.</param>
/// <returns>The result of dividing the <see cref="Vector3DInt"/> by the scalar value.</returns>
public static Vector3DInt Divide(Vector3DInt vector, int value) => vector / value;
/// <summary>
/// Calculates the absolute value of each component of the vector.
/// </summary>
/// <param name="vector">The <see cref="Vector3DInt"/>.</param>
/// <returns>The <see cref="Vector3DInt"/> with each component's absolute value.</returns>
public static Vector3DInt Abs(Vector3DInt vector) => new(Math.Abs(vector.X), Math.Abs(vector.Y), Math.Abs(vector.Z));
/// <summary>
/// Calculates the <see cref="Vector3DInt"/> from one point to another.
/// </summary>
/// <param name="from">The starting point.</param>
/// <param name="to">The ending point.</param>
/// <returns>The <see cref="Vector3DInt"/> from the starting point to the ending point.</returns>
public static Vector3DInt FromTo(Vector3DInt from, Vector3DInt to) => to - from;
/// <summary>
/// Scales a <see cref="Vector3DInt"/> by another <see cref="Vector3DInt"/> component-wise.
/// </summary>
/// <param name="vector">The <see cref="Vector3DInt"/> to scale.</param>
/// <param name="scale">The <see cref="Vector3DInt"/> containing the scaling factors for each component.</param>
/// <returns>The scaled <see cref="Vector3DInt"/>.</returns>
public static Vector3DInt Scale(Vector3DInt vector, Vector3DInt scale) => new(vector.X * scale.X, vector.Y * scale.Y, vector.Z * scale.Z);
/// <summary>
/// Returns the component-wise minimum of two <see cref="Vector3DInt"/>s.
/// </summary>
/// <param name="left">The first <see cref="Vector3DInt"/>.</param>
/// <param name="right">The second <see cref="Vector3DInt"/>.</param>
/// <returns>The <see cref="Vector3DInt"/> containing the minimum components from both input <see cref="Vector3DInt"/>s.</returns>
public static Vector3DInt Min(Vector3DInt left, Vector3DInt right) => new((left.X < right.X) ? left.X : right.X, (left.Y < right.Y) ? left.Y : right.Y, (left.Z < right.Z) ? left.Z : right.Z);
/// <summary>
/// Returns the component-wise maximum of two <see cref="Vector3DInt"/>s.
/// </summary>
/// <param name="left">The first <see cref="Vector3DInt"/>.</param>
/// <param name="right">The second <see cref="Vector3DInt"/>.</param>
/// <returns>The <see cref="Vector3DInt"/> containing the maximum components from both input <see cref="Vector3DInt"/>s.</returns>
public static Vector3DInt Max(Vector3DInt left, Vector3DInt right) => new((left.X > right.X) ? left.X : right.X, (left.Y > right.Y) ? left.Y : right.Y, (left.Z > right.Z) ? left.Z : right.Z);
/// <summary>
/// Clamps each component of a <see cref="Vector3DInt"/> between the corresponding component of two other <see cref="Vector3DInt"/>s.
/// </summary>
/// <param name="vector">The <see cref="Vector3DInt"/> to clamp.</param>
/// <param name="min">The <see cref="Vector3DInt"/> representing the minimum values for each component.</param>
/// <param name="max">The <see cref="Vector3DInt"/> representing the maximum values for each component.</param>
/// <returns>A <see cref="Vector3DInt"/> with each component clamped between the corresponding components of the min and max <see cref="Vector3DInt"/>s.</returns>
public static Vector3DInt Clamp(Vector3DInt vector, Vector3DInt min, Vector3DInt max) => new(Math.Clamp(vector.X, min.X, max.X), Math.Clamp(vector.Y, min.Y, max.Y), Math.Clamp(vector.Z, min.Z, max.Z));
/// <summary>
/// Performs linear interpolation between two <see cref="Vector3DInt"/>s.
/// </summary>
/// <param name="from">The starting <see cref="Vector3DInt"/> (t = 0).</param>
/// <param name="to">The ending <see cref="Vector3DInt"/> (t = 1).</param>
/// <param name="t">The interpolation parameter.</param>
/// <returns>The interpolated <see cref="Vector3DInt"/>.</returns>
public static Vector3DInt Lerp(Vector3DInt from, Vector3DInt to, int t) => from + FromTo(from, to) * t;
/// <summary>
/// Calculates the cross product of two <see cref="Vector3DInt"/>s.
/// </summary>
/// <param name="left">The first <see cref="Vector3DInt"/>.</param>
/// <param name="right">The second <see cref="Vector3DInt"/>.</param>
/// <returns>The cross product of the two <see cref="Vector3DInt"/>s.</returns>
public static Vector3DInt Cross(Vector3DInt left, Vector3DInt right) => new(left.Y * right.Z - left.Z * right.Y, left.Z * right.X - left.X * right.Z, left.X * right.Y - left.Y * right.X);
/// <summary>
/// Calculates the angle between two <see cref="Vector3DInt"/>s.
/// </summary>
/// <param name="left">The first <see cref="Vector3DInt"/>.</param>
/// <param name="right">The second <see cref="Vector3DInt"/>.</param>
/// <returns>The angle between the two <see cref="Vector3DInt"/>s in radians.</returns>
public static float Angle(Vector3DInt left, Vector3DInt right) => Math.Acos(Dot(left, right) / (Length(left) * Length(right)));
/// <summary>
/// Calculates the dot product of two <see cref="Vector3DInt"/>s.
/// </summary>
/// <param name="left">The first <see cref="Vector3DInt"/>.</param>
/// <param name="right">The second <see cref="Vector3DInt"/>.</param>
/// <returns>The dot product of the two <see cref="Vector3DInt"/>s.</returns>
public static int Dot(Vector3DInt left, Vector3DInt right) => left.X * right.X + left.Y * right.Y + left.Z * right.Z;
/// <summary>
/// Determines whether the specified object is equal to the current <see cref="Vector3DInt"/>.
/// </summary>
/// <param name="obj">The object to compare with the current <see cref="Vector3DInt"/>.</param>
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Vector3DInt"/>; otherwise, <see cref="false"/>.</returns>
public override bool Equals(object? obj) => obj is Vector3DInt vector3D && this == vector3D;
public bool Equals(Vector3DInt other) => this == other;
/// <summary>
/// Generates a hash code for the <see cref="Vector3DInt"/>.
/// </summary>
/// <returns>A hash code for the <see cref="Vector3DInt"/>.</returns>
public override int GetHashCode() => System.HashCode.Combine(X, Y, Z);
/// <summary>
/// Converts the <see cref="Vector3DInt"/> to its string representation.
/// </summary>
/// <returns>A string representation of the <see cref="Vector3DInt"/>.</returns>
public override string ToString() => $"{nameof(Vector3DInt)}({X}, {Y}, {Z})";
}
/// <summary>
/// Provides extension methods for <see cref="Vector3DInt"/> type.
/// </summary>
public static class Vector3DIntExtensions
{
/// <inheritdoc cref="Vector3DInt.Length(Vector3DInt)" />
public static float Length(this Vector3DInt vector) => Vector3DInt.Length(vector);
/// <inheritdoc cref="Vector3DInt.LengthSquared(Vector3DInt)" />
public static float LengthSquared(this Vector3DInt vector) => Vector3DInt.LengthSquared(vector);
/// <inheritdoc cref="Vector3DInt.Distance(Vector3DInt, Vector3DInt)" />
public static float Distance(this Vector3DInt from, Vector3DInt to) => Vector3DInt.Distance(from, to);
/// <inheritdoc cref="Vector3DInt.Invert(Vector3DInt)" />
public static Vector3DInt Invert(this Vector3DInt vector) => Vector3DInt.Invert(vector);
/// <inheritdoc cref="Vector3DInt.Add(Vector3DInt, Vector3DInt)" />
public static Vector3DInt Add(this Vector3DInt vector, Vector3DInt vectorToAdd) => Vector3DInt.Add(vector, vectorToAdd);
/// <inheritdoc cref="Vector3DInt.Subtract(Vector3DInt, Vector3DInt)" />
public static Vector3DInt Subtract(this Vector3DInt vector, Vector3DInt vectorToSubtract) => Vector3DInt.Subtract(vector, vectorToSubtract);
/// <inheritdoc cref="Vector3DInt.Multiply(Vector3DInt, int)" />
public static Vector3DInt Multiply(this Vector3DInt vector, int value) => Vector3DInt.Multiply(vector, value);
/// <inheritdoc cref="Vector3DInt.Divide(Vector3DInt, int)" />
public static Vector3DInt Divide(this Vector3DInt vector, int value) => Vector3DInt.Divide(vector, value);
/// <inheritdoc cref="Vector3DInt.Abs(Vector3DInt)" />
public static Vector3DInt Abs(this Vector3DInt vector) => Vector3DInt.Abs(vector);
/// <inheritdoc cref="Vector3DInt.FromTo(Vector3DInt, Vector3DInt)" />
public static Vector3DInt FromTo(this Vector3DInt from, Vector3DInt to) => Vector3DInt.FromTo(from, to);
/// <inheritdoc cref="Vector3DInt.Scale(Vector3DInt, Vector3DInt)" />
public static Vector3DInt Scale(this Vector3DInt vector, Vector3DInt scale) => Vector3DInt.Scale(vector, scale);
/// <inheritdoc cref="Vector3DInt.Min(Vector3DInt, Vector3DInt)" />
public static Vector3DInt Min(this Vector3DInt left, Vector3DInt right) => Vector3DInt.Min(left, right);
/// <inheritdoc cref="Vector3DInt.Max(Vector3DInt, Vector3DInt)" />
public static Vector3DInt Max(this Vector3DInt left, Vector3DInt right) => Vector3DInt.Max(left, right);
/// <inheritdoc cref="Vector3DInt.Clamp(Vector3DInt, Vector3DInt, Vector3DInt)" />
public static Vector3DInt Clamp(this Vector3DInt vector, Vector3DInt min, Vector3DInt max) => Vector3DInt.Clamp(vector, min, max);
/// <inheritdoc cref="Vector3DInt.Lerp(Vector3DInt, Vector3DInt, int)" />
public static Vector3DInt Lerp(this Vector3DInt from, Vector3DInt to, int t) => Vector3DInt.Lerp(from, to, t);
/// <inheritdoc cref="Vector3DInt.Cross(Vector3DInt, Vector3DInt)" />
public static Vector3DInt Cross(this Vector3DInt left, Vector3DInt right) => Vector3DInt.Cross(left, right);
/// <inheritdoc cref="Vector3DInt.Angle(Vector3DInt, Vector3DInt)" />
public static float AngleBetween(this Vector3DInt left, Vector3DInt right) => Vector3DInt.Angle(left, right);
/// <inheritdoc cref="Vector3DInt.Dot(Vector3DInt, Vector3DInt)" />
public static int Dot(this Vector3DInt left, Vector3DInt right) => Vector3DInt.Dot(left, right);
}

View File

@@ -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<IBehaviour> SortByDescendingPriority() => Comparer<IBehaviour>.Create((x, y) => y.Priority.CompareTo(x.Priority));
private static Comparer<int> SortByDescendingPriority() => Comparer<int>.Create((x, y) => y.CompareTo(x));
private static System.Func<IBehaviour, int> GetPriority() => (b) => b.Priority;
private readonly ActiveBehaviourCollectorSorted<IPreDraw> preDrawEntities = new() { SortBy = SortByDescendingPriority() };
private readonly ActiveBehaviourCollectorSorted<IDraw> drawEntities = new() { SortBy = SortByDescendingPriority() };
private readonly ActiveBehaviourCollectorSorted<IPostDraw> postDrawEntities = new() { SortBy = SortByDescendingPriority() };
private readonly ActiveBehaviourCollectorOrdered<int, IPreDraw> preDrawEntities = new(GetPriority(), SortByDescendingPriority());
private readonly ActiveBehaviourCollectorOrdered<int, IDraw> drawEntities = new(GetPriority(), SortByDescendingPriority());
private readonly ActiveBehaviourCollectorOrdered<int, IPostDraw> postDrawEntities = new(GetPriority(), SortByDescendingPriority());
private void OnPreDraw(IUniverse sender)
{

View File

@@ -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<IBehaviour> SortByAscendingPriority() => Comparer<IBehaviour>.Create((x, y) => x.Priority.CompareTo(y.Priority));
private static Comparer<int> SortByAscendingPriority() => Comparer<int>.Create((x, y) => x.CompareTo(y));
private static System.Func<IBehaviour, int> GetPriority() => (b) => b.Priority;
private readonly ActiveBehaviourCollectorSorted<IEnterUniverse> enterUniverses = new() { SortBy = SortByAscendingPriority() };
private readonly ActiveBehaviourCollectorSorted<IExitUniverse> exitUniverses = new() { SortBy = SortByAscendingPriority() };
private readonly ActiveBehaviourCollectorOrdered<int, IEnterUniverse> enterUniverses = new(GetPriority(), SortByAscendingPriority());
private readonly ActiveBehaviourCollectorOrdered<int, IExitUniverse> exitUniverses = new(GetPriority(), SortByAscendingPriority());
private readonly List<IEnterUniverse> toCallEnterUniverses = new(32);
private readonly List<IExitUniverse> toCallExitUniverses = new(32);

View File

@@ -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<IBehaviour> SortByAscendingPriority() => Comparer<IBehaviour>.Create((x, y) => x.Priority.CompareTo(y.Priority));
private static Comparer<int> SortByAscendingPriority() => Comparer<int>.Create((x, y) => x.CompareTo(y));
private static System.Func<IBehaviour, int> GetPriority() => (b) => b.Priority;
private readonly ActiveBehaviourCollectorSorted<IFirstFrameUpdate> firstFrameUpdates = new() { SortBy = SortByAscendingPriority() };
private readonly ActiveBehaviourCollectorOrdered<int, IFirstFrameUpdate> firstFrameUpdates = new(GetPriority(), SortByAscendingPriority());
private readonly ActiveBehaviourCollector<ILastFrameUpdate> lastFrameUpdates = new();
private readonly ActiveBehaviourCollectorSorted<IPreUpdate> preUpdateEntities = new() { SortBy = SortByAscendingPriority() };
private readonly ActiveBehaviourCollectorSorted<IUpdate> updateEntities = new() { SortBy = SortByAscendingPriority() };
private readonly ActiveBehaviourCollectorSorted<IPostUpdate> postUpdateEntities = new() { SortBy = SortByAscendingPriority() };
private readonly ActiveBehaviourCollectorOrdered<int, IPreUpdate> preUpdateEntities = new(GetPriority(), SortByAscendingPriority());
private readonly ActiveBehaviourCollectorOrdered<int, IUpdate> updateEntities = new(GetPriority(), SortByAscendingPriority());
private readonly ActiveBehaviourCollectorOrdered<int, IPostUpdate> postUpdateEntities = new(GetPriority(), SortByAscendingPriority());
private readonly List<IFirstFrameUpdate> toCallFirstFrameUpdates = new(32);

View File

@@ -22,7 +22,7 @@ public class Universe : BaseEntity, IUniverse
private readonly Event<IInitializable>.EventHandler delegateOnUniverseObjectFinalize = null!;
private readonly Event<IUniverseObject, IUniverseObject.ExitedUniverseArguments>.EventHandler delegateOnUniverseObjectExitedUniverse = null!;
private readonly List<IUniverseObject> _universeObjects = new(Constants.UNIVERSE_OBJECTS_SIZE_INITIAL);
private readonly FastList<IUniverseObject> _universeObjects = new(Constants.UNIVERSE_OBJECTS_SIZE_INITIAL);
private float _timeScale = 1f;
public Universe()
@@ -131,9 +131,10 @@ public class Universe : BaseEntity, IUniverse
UnscaledTime = engineTime;
Time = new(TimeSpan.FromTicks((long)(Time.TimeSinceStart.Ticks + engineTime.DeltaSpan.Ticks * TimeScale)), TimeSpan.FromTicks((long)(engineTime.DeltaSpan.Ticks * TimeScale)));
OnPreUpdate?.Invoke(this, new(Time));
OnUpdate?.Invoke(this, new(Time));
OnPostUpdate?.Invoke(this, new(Time));
IUniverse.UpdateArguments args = new(Time);
OnPreUpdate?.Invoke(this, args);
OnUpdate?.Invoke(this, args);
OnPostUpdate?.Invoke(this, args);
}
public void Draw()

View File

@@ -19,7 +19,7 @@ public class UniverseObject : BaseEntity, IUniverseObject
private IUniverse _universe = null!;
private IBehaviourController _behaviourController = null!;
private bool _isActive = false;
private readonly List<IUniverseObject> _children = [];
private readonly FastList<IUniverseObject> _children = [];
private IUniverseObject? _parent = null;
public IReadOnlyList<IUniverseObject> Children => _children;

View File

@@ -2,7 +2,7 @@ using System;
namespace Engine.Core;
public readonly struct UniverseTime(TimeSpan TimeSinceStart, TimeSpan TimeDelta)
public readonly record struct UniverseTime(TimeSpan TimeSinceStart, TimeSpan TimeDelta)
{
public readonly TimeSpan TimeSinceStart = TimeSinceStart;
public readonly TimeSpan DeltaSpan = TimeDelta;

View File

@@ -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<IBehaviour> SortByAscendingPriority() => Comparer<IBehaviour>.Create((x, y) => x.Priority.CompareTo(y.Priority));
private static Comparer<int> SortByAscendingPriority() => Comparer<int>.Create((x, y) => x.CompareTo(y));
private static System.Func<IBehaviour, int> GetPriority() => (b) => b.Priority;
private readonly ActiveBehaviourCollectorSorted<ILoadContent> loadContents = new() { SortBy = SortByAscendingPriority() };
private readonly ActiveBehaviourCollectorOrdered<int, ILoadContent> loadContents = new(GetPriority(), SortByAscendingPriority());
private readonly List<ILoadContent> toCallLoadContents = new(32);
private MonoGameWindowContainer monoGameWindowContainer = null!;

View File

@@ -6,12 +6,13 @@ namespace Engine.Integration.MonoGame;
public class SpriteBatcher : BehaviourBase, IFirstFrameUpdate, IDraw
{
private static Comparer<IBehaviour> SortByPriority() => Comparer<IBehaviour>.Create((x, y) => y.Priority.CompareTo(x.Priority));
private static Comparer<int> SortByPriority() => Comparer<int>.Create((x, y) => y.CompareTo(x));
private static System.Func<IBehaviour, int> GetPriority() => (b) => b.Priority;
private ISpriteBatch spriteBatch = null!;
private MonoGameCamera2D camera2D = null!;
private readonly ActiveBehaviourCollectorSorted<IDrawableSprite> drawableSprites = new() { SortBy = SortByPriority() };
private readonly ActiveBehaviourCollectorOrdered<int, IDrawableSprite> drawableSprites = new(GetPriority(), SortByPriority());
public void FirstActiveFrame()
{

View File

@@ -8,11 +8,13 @@ namespace Engine.Integration.MonoGame;
public class TriangleBatcher : BehaviourBase, ITriangleBatch, IFirstFrameUpdate, IDraw
{
private static Comparer<IBehaviour> SortByAscendingPriority() => Comparer<IBehaviour>.Create((x, y) => x.Priority.CompareTo(y.Priority));
private static Comparer<int> SortByAscendingPriority() => Comparer<int>.Create((x, y) => x.CompareTo(y));
private static System.Func<IBehaviour, int> GetPriority() => (b) => b.Priority;
private TriangleBatch triangleBatch = null!;
private MonoGameCamera2D camera2D = null!;
private readonly ActiveBehaviourCollectorSorted<IDrawableTriangle> drawableShapes = new() { SortBy = SortByAscendingPriority() };
private readonly ActiveBehaviourCollectorOrdered<int, IDrawableTriangle> drawableShapes = new(GetPriority(), SortByAscendingPriority());
public void FirstActiveFrame()
{

View File

@@ -21,6 +21,7 @@ public class TriangleBatch : ITriangleBatch
this.graphicsDevice = graphicsDevice;
basicEffect = new(graphicsDevice);
basicEffect.VertexColorEnabled = true;
vertexBuffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionColor), 1024, BufferUsage.WriteOnly);
}
public void Draw(Triangle triangle, ColorRGBA colorRGBA)
@@ -64,7 +65,6 @@ public class TriangleBatch : ITriangleBatch
graphicsDevice.RasterizerState = rasterizerState;
basicEffect.Projection = _projection;
basicEffect.View = _view;
vertexBuffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionColor), 1024, BufferUsage.WriteOnly);
vertexBuffer.SetData(vertices);
graphicsDevice.SetVertexBuffer(vertexBuffer);

View File

@@ -17,11 +17,12 @@ public class PhysicsEngine2D : Behaviour, IPreUpdate, IPhysicsEngine2D
protected readonly ICollisionResolver2D collisionResolver = null!;
protected readonly IRaycastResolver2D raycastResolver = null!;
private static Comparer<IBehaviour> SortByPriority() => Comparer<IBehaviour>.Create((x, y) => y.Priority.CompareTo(x.Priority));
protected ActiveBehaviourCollectorSorted<IPrePhysicsUpdate> physicsPreUpdateCollector = new() { SortBy = SortByPriority() };
protected ActiveBehaviourCollectorSorted<IPhysicsUpdate> physicsUpdateCollector = new() { SortBy = SortByPriority() };
protected ActiveBehaviourCollectorSorted<IPhysicsIteration> physicsIterationCollector = new() { SortBy = SortByPriority() };
protected ActiveBehaviourCollectorSorted<IPostPhysicsUpdate> physicsPostUpdateCollector = new() { SortBy = SortByPriority() };
private static Comparer<int> SortByPriority() => Comparer<int>.Create((x, y) => y.CompareTo(x));
private static System.Func<IBehaviour, int> GetPriority() => (b) => b.Priority;
protected ActiveBehaviourCollectorOrdered<int, IPrePhysicsUpdate> physicsPreUpdateCollector = new(GetPriority(), SortByPriority());
protected ActiveBehaviourCollectorOrdered<int, IPhysicsUpdate> physicsUpdateCollector = new(GetPriority(), SortByPriority());
protected ActiveBehaviourCollectorOrdered<int, IPhysicsIteration> physicsIterationCollector = new(GetPriority(), SortByPriority());
protected ActiveBehaviourCollectorOrdered<int, IPostPhysicsUpdate> physicsPostUpdateCollector = new(GetPriority(), SortByPriority());
protected BehaviourCollector<IRigidBody2D> rigidBodyCollector = new();
protected BehaviourCollector<ICollider2D> colliderCollector = new();

Submodule Engine.Serializers/YamlDotNet deleted from 62048d7abe