Compare commits
6 Commits
dbd15cbbc2
...
perf/event
| Author | SHA1 | Date | |
|---|---|---|---|
| ce3cc895f4 | |||
| 76ad60fad3 | |||
| 1b123a3cc0 | |||
| 0d61735ae5 | |||
| b5140a94de | |||
| 846aa75dd5 |
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
||||
[submodule "Engine.Integration/YamlDotNet"]
|
||||
path = Engine.Integration/YamlDotNet
|
||||
url = https://github.com/Syntriax/YamlDotNet.git
|
||||
[submodule "Engine.Serializers/YamlDotNet"]
|
||||
path = Engine.Serializers/YamlDotNet
|
||||
url = git@github.com:Syntriax/YamlDotNet.git
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the class implementing it has Assignable fields that are necessary for the engine to work properly.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IBehaviourController"/> field.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IEntity"/> field.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IStateEnable"/> field.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IUniverse"/> field.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="IUniverseObject"/> field.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an entity which can be active or not.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a behaviour that any object in the engine that might use to interact with itself or other objects.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public interface IBehaviour2D : IBehaviour
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a collector for the class type of <typeparamref name="T"/>.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a controller for managing <see cref="IBehaviour"/>s. Connected to an <see cref="IUniverseObject"/>.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a 2D camera in the engine.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public interface ICoroutineYield
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a basic entity in the engine.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an entity that can be initialized and finalized. This information is useful for objects we know that are not in use and can be either recycled or dropped for garbage collection.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an entity with a name.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an entity with an enable state that can be toggled.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the transformation properties of an object such as position, scale, and rotation in 2D space.
|
||||
@@ -20,26 +20,6 @@ public interface ITransform2D : IBehaviour
|
||||
/// </summary>
|
||||
Event<ITransform2D, RotationChangedArguments> OnRotationChanged { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Vector2D"/> pointing upwards in world space.
|
||||
/// </summary>
|
||||
Vector2D Up { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Vector2D"/> pointing upwards in world space.
|
||||
/// </summary>
|
||||
Vector2D Down { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Vector2D"/> pointing upwards in world space.
|
||||
/// </summary>
|
||||
Vector2D Left { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Vector2D"/> pointing upwards in world space.
|
||||
/// </summary>
|
||||
Vector2D Right { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The world position of the <see cref="ITransform2D"/> in 2D space.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a universe responsible for managing <see cref="IUniverseObject"/>s.
|
||||
@@ -37,21 +37,11 @@ public interface IUniverse : IEntity, IEnumerable<IUniverseObject>
|
||||
/// </summary>
|
||||
Event<IUniverse> OnPostDraw { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when a <see cref="IUniverseObject"/> is about to be registered to the <see cref="IUniverse"/>.
|
||||
/// </summary>
|
||||
Event<IUniverse, UniverseObjectRegisteredArguments> OnPreUniverseObjectRegistered { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when a <see cref="IUniverseObject"/> is registered to the <see cref="IUniverse"/>.
|
||||
/// </summary>
|
||||
Event<IUniverse, UniverseObjectRegisteredArguments> OnUniverseObjectRegistered { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when a <see cref="IUniverseObject"/> is about to be unregistered from the <see cref="IUniverse"/>.
|
||||
/// </summary>
|
||||
Event<IUniverse, UniverseObjectUnRegisteredArguments> OnPreUniverseObjectUnRegistered { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when a <see cref="IUniverseObject"/> is unregistered from the <see cref="IUniverse"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an <see cref="IEntity"/> that can enter and exit a universe within the <see cref="IUniverse"/> system.
|
||||
/// This interface allows for tracking the object's presence in the universe and provides events
|
||||
/// for notifying when the see enters or exits the universe.
|
||||
/// </summary>
|
||||
public interface IUniverseObject : IEntity, IActive, INameable, IHasBehaviourController
|
||||
public interface IUniverseObject : IEntity, IActive, INameable, IHasBehaviourController, IEnumerable<IUniverseObject>
|
||||
{
|
||||
/// <summary>
|
||||
/// Event triggered when the <see cref="IUniverseObject"/> enters the universe.
|
||||
@@ -47,7 +47,7 @@ public interface IUniverseObject : IEntity, IActive, INameable, IHasBehaviourCon
|
||||
/// <summary>
|
||||
/// The parent <see cref="IUniverseObject"/> of the <see cref="IUniverseObject"/>.
|
||||
/// </summary>
|
||||
IUniverseObject? Parent { get; set; }
|
||||
IUniverseObject? Parent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IUniverseObject"/>s that have this <see cref="IUniverseObject"/> as their <see cref="Parent"/>.
|
||||
@@ -75,6 +75,12 @@ public interface IUniverseObject : IEntity, IActive, INameable, IHasBehaviourCon
|
||||
/// </returns>
|
||||
internal bool ExitUniverse();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the parent <see cref="IUniverseObject"/> of this <see cref="IUniverseObject"/>.
|
||||
/// </summary>
|
||||
/// <param name="universeObject">The parent <see cref="IUniverseObject"/> to set.</param>
|
||||
void SetParent(IUniverseObject? universeObject);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child <see cref="IUniverseObject"/> to this <see cref="IUniverseObject"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,29 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public abstract class ActiveBehaviourCollectorBase<T> : IBehaviourCollector<T> where T : class, IBehaviour
|
||||
public class ActiveBehaviourCollector<T> : IBehaviourCollector<T> where T : class, IBehaviour
|
||||
{
|
||||
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!;
|
||||
private readonly Event<IActive, IActive.ActiveChangedArguments>.EventHandler delegateOnBehaviourStateChanged = null!;
|
||||
private readonly Event<IUniverse, IUniverse.UniverseObjectRegisteredArguments>.EventHandler delegateOnUniverseObjectRegistered = null!;
|
||||
private readonly Event<IUniverse, IUniverse.UniverseObjectUnRegisteredArguments>.EventHandler delegateOnUniverseObjectUnregistered = null!;
|
||||
|
||||
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; }
|
||||
private readonly Event<IBehaviourController, IBehaviourController.BehaviourAddedArguments>.EventHandler cachedOnBehaviourAdded = null!;
|
||||
private readonly Event<IBehaviourController, IBehaviourController.BehaviourRemovedArguments>.EventHandler cachedOnBehaviourRemoved = null!;
|
||||
private readonly Event<IActive, IActive.ActiveChangedArguments>.EventHandler cachedOnBehaviourStateChanged = null!;
|
||||
private readonly Event<IUniverse, IUniverse.UniverseObjectRegisteredArguments>.EventHandler cachedOnUniverseObjectRegistered = null!;
|
||||
private readonly Event<IUniverse, IUniverse.UniverseObjectUnRegisteredArguments>.EventHandler cachedOnUniverseObjectUnregistered = null!;
|
||||
|
||||
private readonly List<T> monitoringBehaviours = new(32);
|
||||
protected readonly List<T> activeBehaviours = new(32);
|
||||
protected readonly Dictionary<IActive, T> monitoringActiveToBehaviour = new(32);
|
||||
|
||||
public abstract T this[Index index] { get; }
|
||||
public IUniverse Universe { get; private set; } = null!;
|
||||
|
||||
private void OnUniverseObjectRegistered(IUniverse manager, IUniverse.UniverseObjectRegisteredArguments arguments)
|
||||
{
|
||||
IUniverseObject universeObject = arguments.UniverseObjectRegistered;
|
||||
|
||||
universeObject.BehaviourController.OnBehaviourAdded.AddListener(cachedOnBehaviourAdded);
|
||||
universeObject.BehaviourController.OnBehaviourRemoved.AddListener(cachedOnBehaviourRemoved);
|
||||
|
||||
for (int i = 0; i < universeObject.BehaviourController.Count; i++)
|
||||
OnBehaviourAdded(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
|
||||
}
|
||||
|
||||
private void OnUniverseObjectUnregistered(IUniverse manager, IUniverse.UniverseObjectUnRegisteredArguments arguments)
|
||||
{
|
||||
IUniverseObject universeObject = arguments.UniverseObjectUnregistered;
|
||||
|
||||
universeObject.BehaviourController.OnBehaviourAdded.RemoveListener(cachedOnBehaviourAdded);
|
||||
universeObject.BehaviourController.OnBehaviourRemoved.RemoveListener(cachedOnBehaviourRemoved);
|
||||
|
||||
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 arguments)
|
||||
{
|
||||
if (arguments.BehaviourAdded is not T tBehaviour)
|
||||
return;
|
||||
|
||||
monitoringBehaviours.Add(tBehaviour);
|
||||
monitoringActiveToBehaviour.Add(tBehaviour, tBehaviour);
|
||||
tBehaviour.OnActiveChanged.AddListener(cachedOnBehaviourStateChanged);
|
||||
OnBehaviourStateChanged(tBehaviour, new(!tBehaviour.IsActive));
|
||||
}
|
||||
|
||||
private void OnBehaviourStateChanged(IActive sender, IActive.ActiveChangedArguments arguments)
|
||||
{
|
||||
T behaviour = monitoringActiveToBehaviour[sender];
|
||||
if (sender.IsActive)
|
||||
{
|
||||
activeBehaviours.Add(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 arguments)
|
||||
{
|
||||
if (arguments.BehaviourRemoved is not T tBehaviour)
|
||||
return;
|
||||
|
||||
if (!monitoringBehaviours.Remove(tBehaviour) || !monitoringActiveToBehaviour.Remove(tBehaviour))
|
||||
return;
|
||||
|
||||
tBehaviour.OnActiveChanged.RemoveListener(cachedOnBehaviourStateChanged);
|
||||
if (activeBehaviours.Remove(tBehaviour))
|
||||
{
|
||||
OnBehaviourRemove(tBehaviour);
|
||||
OnRemoved?.Invoke(this, new(tBehaviour));
|
||||
}
|
||||
}
|
||||
|
||||
public bool Assign(IUniverse universe)
|
||||
{
|
||||
if (Universe is not null)
|
||||
@@ -32,8 +97,8 @@ public abstract class ActiveBehaviourCollectorBase<T> : IBehaviourCollector<T> w
|
||||
foreach (IUniverseObject universeObject in universe.UniverseObjects)
|
||||
OnUniverseObjectRegistered(universe, new(universeObject));
|
||||
|
||||
universe.OnUniverseObjectRegistered.AddListener(delegateOnUniverseObjectRegistered);
|
||||
universe.OnUniverseObjectUnRegistered.AddListener(delegateOnUniverseObjectUnregistered);
|
||||
universe.OnUniverseObjectRegistered.AddListener(cachedOnUniverseObjectRegistered);
|
||||
universe.OnUniverseObjectUnRegistered.AddListener(cachedOnUniverseObjectUnregistered);
|
||||
|
||||
Universe = universe;
|
||||
OnUniverseAssigned?.Invoke(this);
|
||||
@@ -49,99 +114,23 @@ public abstract class ActiveBehaviourCollectorBase<T> : IBehaviourCollector<T> w
|
||||
foreach (IUniverseObject universeObject in Universe.UniverseObjects)
|
||||
OnUniverseObjectUnregistered(Universe, new(universeObject));
|
||||
|
||||
Universe.OnUniverseObjectRegistered.RemoveListener(delegateOnUniverseObjectRegistered);
|
||||
Universe.OnUniverseObjectUnRegistered.RemoveListener(delegateOnUniverseObjectUnregistered);
|
||||
Universe.OnUniverseObjectRegistered.RemoveListener(cachedOnUniverseObjectRegistered);
|
||||
Universe.OnUniverseObjectUnRegistered.RemoveListener(cachedOnUniverseObjectUnregistered);
|
||||
|
||||
Universe = null!;
|
||||
OnUnassigned?.Invoke(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void AddBehaviour(T behaviour);
|
||||
protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
|
||||
private void OnBehaviourAdded(IBehaviourController controller, IBehaviourController.BehaviourAddedArguments args)
|
||||
public int Count => activeBehaviours.Count;
|
||||
public T this[Index index] => activeBehaviours[index];
|
||||
|
||||
public ActiveBehaviourCollector()
|
||||
{
|
||||
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 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;
|
||||
delegateOnBehaviourStateChanged = OnBehaviourStateChanged;
|
||||
delegateOnUniverseObjectRegistered = OnUniverseObjectRegistered;
|
||||
delegateOnUniverseObjectUnregistered = OnUniverseObjectUnregistered;
|
||||
}
|
||||
|
||||
public ActiveBehaviourCollectorBase(IUniverse universe)
|
||||
{
|
||||
delegateOnBehaviourAdded = OnBehaviourAdded;
|
||||
delegateOnBehaviourRemoved = OnBehaviourRemoved;
|
||||
delegateOnBehaviourStateChanged = OnBehaviourStateChanged;
|
||||
delegateOnUniverseObjectRegistered = OnUniverseObjectRegistered;
|
||||
delegateOnUniverseObjectUnregistered = OnUniverseObjectUnregistered;
|
||||
|
||||
Assign(universe);
|
||||
cachedOnBehaviourAdded = OnBehaviourAdded;
|
||||
cachedOnBehaviourRemoved = OnBehaviourRemoved;
|
||||
cachedOnBehaviourStateChanged = OnBehaviourStateChanged;
|
||||
cachedOnUniverseObjectRegistered = OnUniverseObjectRegistered;
|
||||
cachedOnUniverseObjectUnregistered = OnUniverseObjectUnregistered;
|
||||
}
|
||||
}
|
||||
25
Engine.Core/ActiveBehaviourCollectorSorted.cs
Normal file
25
Engine.Core/ActiveBehaviourCollectorSorted.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public class ActiveBehaviourCollectorSorted<T> : ActiveBehaviourCollector<T> where T : class, IBehaviour
|
||||
{
|
||||
private Comparison<T>? _sortBy = null;
|
||||
public Comparison<T>? SortBy
|
||||
{
|
||||
get => _sortBy;
|
||||
set
|
||||
{
|
||||
_sortBy = value;
|
||||
|
||||
if (value is not null)
|
||||
activeBehaviours.Sort(value);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnBehaviourAdd(IBehaviour behaviour)
|
||||
{
|
||||
if (SortBy is not null)
|
||||
activeBehaviours.Sort(SortBy);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public abstract class BaseEntity : IEntity
|
||||
{
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public abstract class Behaviour : BehaviourBase
|
||||
public abstract class Behaviour : BehaviourBase, IFirstFrameUpdate,
|
||||
IPreUpdate, IUpdate, IPostUpdate,
|
||||
IPreDraw, IDraw, IPostDraw
|
||||
{
|
||||
private readonly Event<IUniverseObject, IUniverseObject.EnteredUniverseArguments>.EventHandler delegateEnteredUniverse = null!;
|
||||
private readonly Event<IUniverseObject, IUniverseObject.ExitedUniverseArguments>.EventHandler delegateExitedUniverse = null!;
|
||||
protected IUniverse Universe => BehaviourController.UniverseObject.Universe;
|
||||
protected IUniverseObject UniverseObject => BehaviourController.UniverseObject;
|
||||
|
||||
private readonly Event<IUniverseObject, IUniverseObject.EnteredUniverseArguments>.EventHandler cachedEnteredUniverse = null!;
|
||||
private readonly Event<IUniverseObject, IUniverseObject.ExitedUniverseArguments>.EventHandler cachedExitedUniverse = null!;
|
||||
|
||||
public Behaviour()
|
||||
{
|
||||
@@ -11,18 +16,18 @@ public abstract class Behaviour : BehaviourBase
|
||||
OnFinalized.AddListener(OnFinalize);
|
||||
OnUnassigned.AddListener(OnUnassign);
|
||||
|
||||
delegateEnteredUniverse = EnteredUniverse;
|
||||
delegateExitedUniverse = ExitedUniverse;
|
||||
cachedEnteredUniverse = EnteredUniverse;
|
||||
cachedExitedUniverse = ExitedUniverse;
|
||||
}
|
||||
|
||||
protected virtual void OnUnassign() { }
|
||||
protected void OnUnassign(IAssignable assignable) => OnUnassign();
|
||||
protected virtual void OnUnassign(IAssignable assignable) => OnUnassign();
|
||||
|
||||
protected virtual void OnInitialize() { }
|
||||
protected void OnInitialize(IInitializable _)
|
||||
protected virtual void OnInitialize(IInitializable _)
|
||||
{
|
||||
BehaviourController.UniverseObject.OnEnteredUniverse.AddListener(delegateEnteredUniverse);
|
||||
BehaviourController.UniverseObject.OnExitedUniverse.AddListener(delegateExitedUniverse);
|
||||
BehaviourController.UniverseObject.OnEnteredUniverse.AddListener(cachedEnteredUniverse);
|
||||
BehaviourController.UniverseObject.OnExitedUniverse.AddListener(cachedExitedUniverse);
|
||||
|
||||
OnInitialize();
|
||||
|
||||
@@ -31,10 +36,10 @@ public abstract class Behaviour : BehaviourBase
|
||||
}
|
||||
|
||||
protected virtual void OnFinalize() { }
|
||||
protected void OnFinalize(IInitializable _)
|
||||
protected virtual void OnFinalize(IInitializable _)
|
||||
{
|
||||
BehaviourController.UniverseObject.OnEnteredUniverse.RemoveListener(delegateEnteredUniverse);
|
||||
BehaviourController.UniverseObject.OnExitedUniverse.RemoveListener(delegateExitedUniverse);
|
||||
BehaviourController.UniverseObject.OnEnteredUniverse.RemoveListener(cachedEnteredUniverse);
|
||||
BehaviourController.UniverseObject.OnExitedUniverse.RemoveListener(cachedExitedUniverse);
|
||||
|
||||
OnFinalize();
|
||||
|
||||
@@ -42,9 +47,100 @@ public abstract class Behaviour : BehaviourBase
|
||||
ExitedUniverse(UniverseObject, new(Universe));
|
||||
}
|
||||
|
||||
protected virtual void OnFirstActiveFrame() { }
|
||||
void IFirstFrameUpdate.FirstActiveFrame()
|
||||
{
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
OnFirstActiveFrame();
|
||||
}
|
||||
|
||||
protected virtual void OnPreUpdatePreActiveCheck() { }
|
||||
protected virtual void OnPreUpdate() { }
|
||||
void IPreUpdate.PreUpdate()
|
||||
{
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
OnPreUpdatePreActiveCheck();
|
||||
|
||||
if (!IsActive)
|
||||
return;
|
||||
|
||||
OnPreUpdate();
|
||||
}
|
||||
|
||||
protected virtual void OnUpdatePreActiveCheck() { }
|
||||
protected virtual void OnUpdate() { }
|
||||
void IUpdate.Update()
|
||||
{
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
OnUpdatePreActiveCheck();
|
||||
|
||||
if (!IsActive)
|
||||
return;
|
||||
|
||||
OnUpdate();
|
||||
}
|
||||
|
||||
protected virtual void OnPostUpdatePreActiveCheck() { }
|
||||
protected virtual void OnPostUpdate() { }
|
||||
void IPostUpdate.PostUpdate()
|
||||
{
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
OnPostUpdatePreActiveCheck();
|
||||
|
||||
if (!StateEnable.Enabled)
|
||||
return;
|
||||
|
||||
OnPostUpdate();
|
||||
}
|
||||
|
||||
protected virtual void OnPreDrawPreActiveCheck() { }
|
||||
protected virtual void OnPreDraw() { }
|
||||
void IPreDraw.PreDraw()
|
||||
{
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
OnPreDrawPreActiveCheck();
|
||||
|
||||
if (!StateEnable.Enabled)
|
||||
return;
|
||||
|
||||
OnPreDraw();
|
||||
}
|
||||
|
||||
protected virtual void OnDrawPreActiveCheck() { }
|
||||
protected virtual void OnDraw() { }
|
||||
void IDraw.Draw()
|
||||
{
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
OnDrawPreActiveCheck();
|
||||
|
||||
if (!StateEnable.Enabled)
|
||||
return;
|
||||
|
||||
OnDraw();
|
||||
}
|
||||
|
||||
protected virtual void OnPostDrawPreActiveCheck() { }
|
||||
protected virtual void OnPostDraw() { }
|
||||
void IPostDraw.PostDraw()
|
||||
{
|
||||
Debug.Assert.AssertInitialized(this);
|
||||
|
||||
OnPostDrawPreActiveCheck();
|
||||
|
||||
if (!StateEnable.Enabled)
|
||||
return;
|
||||
|
||||
OnPostDraw();
|
||||
}
|
||||
|
||||
protected virtual void OnEnteredUniverse(IUniverse universe) { }
|
||||
protected void EnteredUniverse(IUniverseObject sender, IUniverseObject.EnteredUniverseArguments args) => OnEnteredUniverse(args.Universe);
|
||||
protected virtual void EnteredUniverse(IUniverseObject sender, IUniverseObject.EnteredUniverseArguments arguments) => OnEnteredUniverse(arguments.Universe);
|
||||
|
||||
protected virtual void OnExitedUniverse(IUniverse universe) { }
|
||||
protected void ExitedUniverse(IUniverseObject sender, IUniverseObject.ExitedUniverseArguments args) => OnExitedUniverse(args.Universe);
|
||||
protected virtual void ExitedUniverse(IUniverseObject sender, IUniverseObject.ExitedUniverseArguments arguments) => OnExitedUniverse(arguments.Universe);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public abstract class Behaviour2D : Behaviour, IBehaviour2D
|
||||
{
|
||||
public ITransform2D Transform { get; private set; } = null!;
|
||||
|
||||
protected override void OnInitialize() => Transform = BehaviourController.GetRequiredBehaviour<ITransform2D>();
|
||||
protected override void OnFinalize() => Transform = null!;
|
||||
protected sealed override void OnInitialize(IInitializable _)
|
||||
{
|
||||
Transform = BehaviourController.GetRequiredBehaviour<ITransform2D>();
|
||||
base.OnInitialize(_);
|
||||
}
|
||||
|
||||
protected sealed override void OnFinalize(IInitializable _)
|
||||
{
|
||||
Transform = null!;
|
||||
base.OnFinalize(_);
|
||||
}
|
||||
|
||||
protected sealed override void OnUnassign(IAssignable assignable) => base.OnUnassign(assignable);
|
||||
protected sealed override void EnteredUniverse(IUniverseObject sender, IUniverseObject.EnteredUniverseArguments arguments) => base.EnteredUniverse(sender, arguments);
|
||||
protected sealed override void ExitedUniverse(IUniverseObject sender, IUniverseObject.ExitedUniverseArguments arguments) => base.ExitedUniverse(sender, arguments);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
[System.Diagnostics.DebuggerDisplay("{GetType().Name, nq}, Priority: {Priority}, Initialized: {Initialized}")]
|
||||
public abstract class BehaviourBase : BaseEntity, IBehaviour
|
||||
@@ -7,12 +7,9 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
|
||||
public Event<IActive, IActive.ActiveChangedArguments> OnActiveChanged { get; } = new();
|
||||
public Event<IHasBehaviourController> OnBehaviourControllerAssigned { get; } = new();
|
||||
|
||||
private readonly Event<IHasUniverseObject>.EventHandler delegateOnUniverseObjectAssigned = null!;
|
||||
private readonly Event<IActive, IActive.ActiveChangedArguments>.EventHandler delegateOnUniverseObjectActiveChanged = null!;
|
||||
private readonly Event<IStateEnable, IStateEnable.EnabledChangedArguments>.EventHandler delegateOnStateEnabledChanged = null!;
|
||||
|
||||
public IUniverse Universe => BehaviourController.UniverseObject.Universe;
|
||||
public IUniverseObject UniverseObject => BehaviourController.UniverseObject;
|
||||
private readonly Event<IHasUniverseObject>.EventHandler cachedOnUniverseObjectAssigned = null!;
|
||||
private readonly Event<IActive, IActive.ActiveChangedArguments>.EventHandler cachedOnUniverseObjectActiveChanged = null!;
|
||||
private readonly Event<IStateEnable, IStateEnable.EnabledChangedArguments>.EventHandler cachedOnStateEnabledChanged = null!;
|
||||
|
||||
private IBehaviourController _behaviourController = null!;
|
||||
public IBehaviourController BehaviourController => _behaviourController;
|
||||
@@ -43,8 +40,7 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
|
||||
|
||||
_behaviourController = behaviourController;
|
||||
OnAssign(behaviourController);
|
||||
behaviourController.OnUniverseObjectAssigned.AddListener(delegateOnUniverseObjectAssigned);
|
||||
behaviourController.StateEnable.OnEnabledChanged.AddListener(delegateOnStateEnabledChanged);
|
||||
behaviourController.OnUniverseObjectAssigned.AddListener(cachedOnUniverseObjectAssigned);
|
||||
if (behaviourController.UniverseObject is not null)
|
||||
OnUniverseObjectAssigned(behaviourController);
|
||||
OnBehaviourControllerAssigned?.Invoke(this);
|
||||
@@ -53,7 +49,7 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
|
||||
|
||||
private void OnUniverseObjectAssigned(IHasUniverseObject sender)
|
||||
{
|
||||
sender.UniverseObject.OnActiveChanged.AddListener(delegateOnUniverseObjectActiveChanged);
|
||||
sender.UniverseObject.OnActiveChanged.AddListener(cachedOnUniverseObjectActiveChanged);
|
||||
UpdateActive();
|
||||
}
|
||||
|
||||
@@ -61,15 +57,14 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
|
||||
{
|
||||
base.OnAssign(stateEnable);
|
||||
|
||||
stateEnable.OnEnabledChanged.AddListener(delegateOnStateEnabledChanged);
|
||||
stateEnable.OnEnabledChanged.AddListener(cachedOnStateEnabledChanged);
|
||||
}
|
||||
|
||||
protected override void UnassignInternal()
|
||||
{
|
||||
BehaviourController.UniverseObject.OnActiveChanged.RemoveListener(delegateOnUniverseObjectActiveChanged);
|
||||
StateEnable.OnEnabledChanged.RemoveListener(delegateOnStateEnabledChanged);
|
||||
BehaviourController.OnUniverseObjectAssigned.RemoveListener(delegateOnUniverseObjectAssigned);
|
||||
BehaviourController.StateEnable.OnEnabledChanged.RemoveListener(delegateOnStateEnabledChanged);
|
||||
BehaviourController.UniverseObject.OnActiveChanged.RemoveListener(cachedOnUniverseObjectActiveChanged);
|
||||
StateEnable.OnEnabledChanged.RemoveListener(cachedOnStateEnabledChanged);
|
||||
BehaviourController.OnUniverseObjectAssigned.RemoveListener(cachedOnUniverseObjectAssigned);
|
||||
base.UnassignInternal();
|
||||
_behaviourController = null!;
|
||||
}
|
||||
@@ -78,17 +73,15 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
|
||||
{
|
||||
Debug.Assert.AssertBehaviourControllerAssigned(this);
|
||||
Debug.Assert.AssertStateEnableAssigned(this);
|
||||
|
||||
UpdateActive();
|
||||
}
|
||||
|
||||
private void OnStateEnabledChanged(IStateEnable sender, IStateEnable.EnabledChangedArguments args) => UpdateActive();
|
||||
private void OnUniverseObjectActiveChanged(IActive sender, IActive.ActiveChangedArguments args) => UpdateActive();
|
||||
private void OnStateEnabledChanged(IStateEnable sender, IStateEnable.EnabledChangedArguments arguments) => UpdateActive();
|
||||
private void OnUniverseObjectActiveChanged(IActive sender, IActive.ActiveChangedArguments arguments) => UpdateActive();
|
||||
|
||||
private void UpdateActive()
|
||||
{
|
||||
bool previousActive = IsActive;
|
||||
_isActive = StateEnable.Enabled && _behaviourController.StateEnable.Enabled && _behaviourController.UniverseObject.IsActive;
|
||||
_isActive = StateEnable.Enabled && _behaviourController.UniverseObject.IsActive;
|
||||
|
||||
if (previousActive != IsActive)
|
||||
OnActiveChanged?.Invoke(this, new(previousActive));
|
||||
@@ -96,8 +89,8 @@ public abstract class BehaviourBase : BaseEntity, IBehaviour
|
||||
|
||||
protected BehaviourBase()
|
||||
{
|
||||
delegateOnUniverseObjectAssigned = OnUniverseObjectAssigned;
|
||||
delegateOnUniverseObjectActiveChanged = OnUniverseObjectActiveChanged;
|
||||
delegateOnStateEnabledChanged = OnStateEnabledChanged;
|
||||
cachedOnUniverseObjectAssigned = OnUniverseObjectAssigned;
|
||||
cachedOnUniverseObjectActiveChanged = OnUniverseObjectActiveChanged;
|
||||
cachedOnStateEnabledChanged = OnStateEnabledChanged;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public abstract class BehaviourCollectorBase<T> : IBehaviourCollector<T> where T : class
|
||||
public class BehaviourCollector<T> : IBehaviourCollector<T> where T : class
|
||||
{
|
||||
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!;
|
||||
|
||||
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 cachedOnBehaviourAdded = null!;
|
||||
private readonly Event<IBehaviourController, IBehaviourController.BehaviourRemovedArguments>.EventHandler cachedOnBehaviourRemoved = null!;
|
||||
private readonly Event<IUniverse, IUniverse.UniverseObjectRegisteredArguments>.EventHandler cachedOnUniverseObjectRegistered = null!;
|
||||
private readonly Event<IUniverse, IUniverse.UniverseObjectUnRegisteredArguments>.EventHandler cachedOnUniverseObjectUnregistered = null!;
|
||||
|
||||
protected readonly List<T> behaviours = new(32);
|
||||
|
||||
public IUniverse Universe { get; private set; } = null!;
|
||||
|
||||
public abstract int Count { get; }
|
||||
private void OnUniverseObjectRegistered(IUniverse manager, IUniverse.UniverseObjectRegisteredArguments arguments)
|
||||
{
|
||||
IUniverseObject universeObject = arguments.UniverseObjectRegistered;
|
||||
|
||||
public abstract T this[Index index] { get; }
|
||||
universeObject.BehaviourController.OnBehaviourAdded.AddListener(cachedOnBehaviourAdded);
|
||||
universeObject.BehaviourController.OnBehaviourRemoved.AddListener(cachedOnBehaviourRemoved);
|
||||
|
||||
for (int i = 0; i < universeObject.BehaviourController.Count; i++)
|
||||
OnBehaviourAdded(universeObject.BehaviourController, new(universeObject.BehaviourController[i]));
|
||||
}
|
||||
|
||||
private void OnUniverseObjectUnregistered(IUniverse manager, IUniverse.UniverseObjectUnRegisteredArguments arguments)
|
||||
{
|
||||
IUniverseObject universeObject = arguments.UniverseObjectUnregistered;
|
||||
|
||||
universeObject.BehaviourController.OnBehaviourAdded.RemoveListener(cachedOnBehaviourAdded);
|
||||
universeObject.BehaviourController.OnBehaviourRemoved.RemoveListener(cachedOnBehaviourRemoved);
|
||||
|
||||
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 arguments)
|
||||
{
|
||||
if (arguments.BehaviourAdded is not T tBehaviour)
|
||||
return;
|
||||
|
||||
behaviours.Add(tBehaviour);
|
||||
OnBehaviourAdd(arguments.BehaviourAdded);
|
||||
OnCollected?.Invoke(this, new(tBehaviour));
|
||||
}
|
||||
|
||||
protected virtual void OnBehaviourRemove(IBehaviour behaviour) { }
|
||||
private void OnBehaviourRemoved(IBehaviourController controller, IBehaviourController.BehaviourRemovedArguments arguments)
|
||||
{
|
||||
if (arguments.BehaviourRemoved is not T tBehaviour)
|
||||
return;
|
||||
|
||||
if (!behaviours.Remove(tBehaviour))
|
||||
return;
|
||||
|
||||
OnBehaviourRemove(arguments.BehaviourRemoved);
|
||||
OnRemoved?.Invoke(this, new(tBehaviour));
|
||||
}
|
||||
|
||||
protected virtual void OnAssign(IUniverse universe) { }
|
||||
public bool Assign(IUniverse universe)
|
||||
{
|
||||
if (Universe is not null)
|
||||
@@ -28,8 +74,8 @@ public abstract class BehaviourCollectorBase<T> : IBehaviourCollector<T> where T
|
||||
foreach (IUniverseObject universeObject in universe.UniverseObjects)
|
||||
OnUniverseObjectRegistered(universe, new(universeObject));
|
||||
|
||||
universe.OnUniverseObjectRegistered.AddListener(delegateOnUniverseObjectRegistered);
|
||||
universe.OnPreUniverseObjectUnRegistered.AddListener(delegateOnUniverseObjectUnregistered);
|
||||
universe.OnUniverseObjectRegistered.AddListener(cachedOnUniverseObjectRegistered);
|
||||
universe.OnUniverseObjectUnRegistered.AddListener(cachedOnUniverseObjectUnregistered);
|
||||
|
||||
Universe = universe;
|
||||
OnAssign(universe);
|
||||
@@ -46,79 +92,22 @@ public abstract class BehaviourCollectorBase<T> : IBehaviourCollector<T> where T
|
||||
foreach (IUniverseObject universeObject in Universe.UniverseObjects)
|
||||
OnUniverseObjectUnregistered(Universe, new(universeObject));
|
||||
|
||||
Universe.OnUniverseObjectRegistered.RemoveListener(delegateOnUniverseObjectRegistered);
|
||||
Universe.OnPreUniverseObjectUnRegistered.RemoveListener(delegateOnUniverseObjectUnregistered);
|
||||
Universe.OnUniverseObjectRegistered.RemoveListener(cachedOnUniverseObjectRegistered);
|
||||
Universe.OnUniverseObjectUnRegistered.RemoveListener(cachedOnUniverseObjectUnregistered);
|
||||
|
||||
Universe = null!;
|
||||
OnUnassigned?.Invoke(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual void OnAssign(IUniverse universe) { }
|
||||
public int Count => behaviours.Count;
|
||||
public T this[Index index] => behaviours[index];
|
||||
|
||||
protected abstract void AddBehaviour(T behaviour);
|
||||
protected virtual void OnBehaviourAdd(IBehaviour behaviour) { }
|
||||
private void OnBehaviourAdded(IBehaviourController controller, IBehaviourController.BehaviourAddedArguments args)
|
||||
public BehaviourCollector()
|
||||
{
|
||||
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;
|
||||
delegateOnUniverseObjectRegistered = OnUniverseObjectRegistered;
|
||||
delegateOnUniverseObjectUnregistered = OnUniverseObjectUnregistered;
|
||||
}
|
||||
|
||||
public BehaviourCollectorBase(IUniverse universe)
|
||||
{
|
||||
delegateOnBehaviourAdded = OnBehaviourAdded;
|
||||
delegateOnBehaviourRemoved = OnBehaviourRemoved;
|
||||
delegateOnUniverseObjectRegistered = OnUniverseObjectRegistered;
|
||||
delegateOnUniverseObjectUnregistered = OnUniverseObjectUnregistered;
|
||||
|
||||
Assign(universe);
|
||||
cachedOnBehaviourAdded = OnBehaviourAdded;
|
||||
cachedOnBehaviourRemoved = OnBehaviourRemoved;
|
||||
cachedOnUniverseObjectRegistered = OnUniverseObjectRegistered;
|
||||
cachedOnUniverseObjectUnregistered = OnUniverseObjectUnregistered;
|
||||
}
|
||||
}
|
||||
25
Engine.Core/BehaviourCollectorSorted.cs
Normal file
25
Engine.Core/BehaviourCollectorSorted.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public class BehaviourCollectorSorted<T> : BehaviourCollector<T> where T : class
|
||||
{
|
||||
private Comparison<T>? _sortBy = null;
|
||||
public Comparison<T>? SortBy
|
||||
{
|
||||
get => _sortBy;
|
||||
set
|
||||
{
|
||||
_sortBy = value;
|
||||
|
||||
if (value is not null)
|
||||
behaviours.Sort(value);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnBehaviourAdd(IBehaviour behaviour)
|
||||
{
|
||||
if (SortBy is not null)
|
||||
behaviours.Sort(SortBy);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
[System.Diagnostics.DebuggerDisplay("Behaviour Count: {behaviours.Count}")]
|
||||
public class BehaviourController : BaseEntity, IBehaviourController
|
||||
@@ -10,7 +11,7 @@ public class BehaviourController : BaseEntity, IBehaviourController
|
||||
public Event<IBehaviourController, IBehaviourController.BehaviourRemovedArguments> OnBehaviourRemoved { get; } = new();
|
||||
public Event<IHasUniverseObject> OnUniverseObjectAssigned { get; } = new();
|
||||
|
||||
private readonly FastList<IBehaviour> behaviours = new(Constants.BEHAVIOURS_SIZE_INITIAL);
|
||||
private readonly List<IBehaviour> behaviours = new(Constants.BEHAVIOURS_SIZE_INITIAL);
|
||||
|
||||
private IUniverseObject _universeObject = null!;
|
||||
|
||||
@@ -26,7 +27,6 @@ public class BehaviourController : BaseEntity, IBehaviourController
|
||||
|
||||
if (IsInitialized)
|
||||
behaviour.Initialize();
|
||||
|
||||
behaviour.OnPriorityChanged.AddListener(OnPriorityChange);
|
||||
OnBehaviourAdded?.Invoke(this, new(behaviour));
|
||||
return behaviour;
|
||||
@@ -49,13 +49,17 @@ public class BehaviourController : BaseEntity, IBehaviourController
|
||||
|
||||
public IReadOnlyList<T> GetBehaviours<T>()
|
||||
{
|
||||
List<T> behaviours = [];
|
||||
|
||||
List<T>? behaviours = null;
|
||||
foreach (IBehaviour behaviourItem in this.behaviours)
|
||||
if (behaviourItem is T behaviour)
|
||||
behaviours.Add(behaviour);
|
||||
{
|
||||
if (behaviourItem is not T behaviour)
|
||||
continue;
|
||||
|
||||
return behaviours;
|
||||
behaviours ??= [];
|
||||
behaviours.Add(behaviour);
|
||||
}
|
||||
|
||||
return behaviours ?? Enumerable.Empty<T>().ToList();
|
||||
}
|
||||
|
||||
public void GetBehaviours<T>(IList<T> results)
|
||||
@@ -72,7 +76,7 @@ public class BehaviourController : BaseEntity, IBehaviourController
|
||||
|
||||
public void RemoveBehaviour<T>(bool removeAll = false) where T : class, IBehaviour
|
||||
{
|
||||
for (int i = behaviours.Count - 1; i >= 0; i--)
|
||||
for (int i = behaviours.Count; i >= 0; i--)
|
||||
{
|
||||
if (behaviours[i] is not T behaviour)
|
||||
continue;
|
||||
@@ -141,7 +145,7 @@ public class BehaviourController : BaseEntity, IBehaviourController
|
||||
behaviours.Add(behaviour);
|
||||
}
|
||||
|
||||
private void OnPriorityChange(IBehaviour sender, IBehaviour.PriorityChangedArguments args)
|
||||
private void OnPriorityChange(IBehaviour sender, IBehaviour.PriorityChangedArguments arguments)
|
||||
{
|
||||
behaviours.Remove(sender);
|
||||
InsertBehaviourByPriority(sender);
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
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);
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
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) { }
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public class CoroutineManager : Behaviour, IUpdate
|
||||
public class CoroutineManager : UniverseObject
|
||||
{
|
||||
private readonly List<IEnumerator> enumerators = [];
|
||||
|
||||
@@ -18,7 +18,17 @@ public class CoroutineManager : Behaviour, IUpdate
|
||||
enumerators.Remove(enumerator);
|
||||
}
|
||||
|
||||
void IUpdate.Update()
|
||||
protected override void OnEnteringUniverse(IUniverse universe)
|
||||
{
|
||||
universe.OnUpdate.AddListener(OnUpdate);
|
||||
}
|
||||
|
||||
protected override void OnExitingUniverse(IUniverse universe)
|
||||
{
|
||||
universe.OnUpdate.RemoveListener(OnUpdate);
|
||||
}
|
||||
|
||||
private void OnUpdate(IUniverse sender, IUniverse.UpdateArguments arguments)
|
||||
{
|
||||
for (int i = enumerators.Count - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -29,6 +39,4 @@ public class CoroutineManager : Behaviour, IUpdate
|
||||
enumerators.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
public CoroutineManager() => Priority = int.MinValue;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public class CoroutineYield(Func<bool> condition) : ICoroutineYield
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Engine.Core.Debug;
|
||||
namespace Syntriax.Engine.Core.Debug;
|
||||
|
||||
public static class Assert
|
||||
{
|
||||
@@ -10,21 +10,21 @@ public static class Assert
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void AssertBehaviourControllerAssigned(IHasBehaviourController assignable)
|
||||
=> System.Diagnostics.Debug.Assert(assignable.BehaviourController is not null, $"{assignable.GetType().Name} must be assigned an {nameof(IBehaviourController)}");
|
||||
=> System.Diagnostics.Debug.Assert(assignable.BehaviourController is not null, $"{assignable.GetType().Name} must be initialized");
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void AssertEntityAssigned(IHasEntity assignable)
|
||||
=> System.Diagnostics.Debug.Assert(assignable.Entity is not null, $"{assignable.GetType().Name} must be assigned an {nameof(IEntity)}");
|
||||
=> System.Diagnostics.Debug.Assert(assignable.Entity is not null, $"{assignable.GetType().Name} must be initialized");
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void AssertUniverseAssigned(IHasUniverse assignable)
|
||||
=> System.Diagnostics.Debug.Assert(assignable.Universe is not null, $"{assignable.GetType().Name} must be assigned an {nameof(IUniverse)}");
|
||||
=> System.Diagnostics.Debug.Assert(assignable.Universe is not null, $"{assignable.GetType().Name} must be initialized");
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void AssertUniverseObjectAssigned(IHasUniverseObject assignable)
|
||||
=> System.Diagnostics.Debug.Assert(assignable.UniverseObject is not null, $"{assignable.GetType().Name} must be assigned an {nameof(IUniverseObject)}");
|
||||
=> System.Diagnostics.Debug.Assert(assignable.UniverseObject is not null, $"{assignable.GetType().Name} must be initialized");
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void AssertStateEnableAssigned(IHasStateEnable assignable)
|
||||
=> System.Diagnostics.Debug.Assert(assignable.StateEnable is not null, $"{assignable.GetType().Name} must be assigned an {nameof(IStateEnable)}");
|
||||
=> System.Diagnostics.Debug.Assert(assignable.StateEnable is not null, $"{assignable.GetType().Name} must be initialized");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core.Debug;
|
||||
namespace Syntriax.Engine.Core.Debug;
|
||||
|
||||
public class ConsoleLogger : LoggerBase
|
||||
{
|
||||
|
||||
@@ -1,32 +1,20 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Engine.Core.Debug;
|
||||
namespace Syntriax.Engine.Core.Debug;
|
||||
|
||||
public class FileLogger : LoggerBase
|
||||
{
|
||||
public readonly string FilePath;
|
||||
|
||||
public FileLogger(string filePath)
|
||||
{
|
||||
FilePath = filePath;
|
||||
File.Open(filePath, FileMode.Create).Close();
|
||||
}
|
||||
|
||||
protected override void Write(string message)
|
||||
{
|
||||
File.AppendAllTextAsync(FilePath, $"{message}{Environment.NewLine}");
|
||||
}
|
||||
|
||||
public FileLogger(string filePath)
|
||||
{
|
||||
if (!filePath.EndsWith(".log"))
|
||||
filePath += ".log";
|
||||
|
||||
FilePath = filePath;
|
||||
|
||||
bool isRelativePath = Path.GetFullPath(filePath).CompareTo(filePath) != 0;
|
||||
|
||||
if (isRelativePath)
|
||||
FilePath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filePath));
|
||||
|
||||
if (Path.GetDirectoryName(FilePath) is string directoryPath)
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
|
||||
File.Open(FilePath, FileMode.Create).Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
namespace Engine.Core.Debug;
|
||||
namespace Syntriax.Engine.Core.Debug;
|
||||
|
||||
public interface ILogger
|
||||
{
|
||||
static ILogger Shared { get; set; } = new ConsoleLogger();
|
||||
|
||||
Level FilterLevel { get; set; }
|
||||
|
||||
void Log(string message, Level level = Level.Info, bool force = false);
|
||||
|
||||
enum Level
|
||||
{
|
||||
Trace,
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core.Debug;
|
||||
namespace Syntriax.Engine.Core.Debug;
|
||||
|
||||
public abstract class LoggerBase : ILogger
|
||||
{
|
||||
public ILogger.Level FilterLevel { get; set; } = ILogger.Level.Trace;
|
||||
public ILogger.Level FilterLevel { get; set; } = ILogger.Level.Info;
|
||||
|
||||
public void Log(string message, ILogger.Level level = ILogger.Level.Info, bool force = false)
|
||||
{
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace Engine.Core.Debug;
|
||||
|
||||
public class LoggerContainer : Behaviour, ILogger
|
||||
{
|
||||
public ILogger Logger { get; set; } = ILogger.Shared;
|
||||
|
||||
public ILogger.Level FilterLevel { get => Logger.FilterLevel; set => Logger.FilterLevel = value; }
|
||||
public void Log(string message, ILogger.Level level = ILogger.Level.Info, bool force = false) => Logger.Log(message, level, force);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Engine.Core.Debug;
|
||||
namespace Syntriax.Engine.Core.Debug;
|
||||
|
||||
public static class LoggerExtensions
|
||||
{
|
||||
@@ -16,21 +16,13 @@ public static class LoggerExtensions
|
||||
public static void LogError<T>(this ILogger logger, T caller, string message, bool force = false)
|
||||
{
|
||||
Log(logger, caller, message, ILogger.Level.Error, force);
|
||||
LogTrace(logger, caller, new StackTrace(), force);
|
||||
Log(logger, caller, $"{nameof(StackTrace)}:{Environment.NewLine}{new StackTrace()}");
|
||||
}
|
||||
|
||||
public static void LogException<T>(this ILogger logger, T caller, Exception exception, bool force = false)
|
||||
{
|
||||
Log(logger, caller, $"Exception of type {exception.GetType().Name} occured", ILogger.Level.Error, force);
|
||||
Log(logger, caller, $"Message: {exception.Message}", ILogger.Level.Error, force);
|
||||
Log(logger, caller, $"InnerException: {exception.InnerException}", ILogger.Level.Error, force);
|
||||
|
||||
// Not using LogTrace because exception.StackTrace is a type of string
|
||||
Log(logger, caller, $"{nameof(StackTrace)}:{Environment.NewLine}{exception.StackTrace}", ILogger.Level.Trace);
|
||||
}
|
||||
|
||||
public static void LogTrace<T>(this ILogger logger, T caller, StackTrace? stackTrace = null, bool force = false)
|
||||
{
|
||||
Log(logger, caller, $"{nameof(StackTrace)}:{Environment.NewLine}{stackTrace ?? new()}", ILogger.Level.Trace, force);
|
||||
Log(logger, caller, $"{nameof(StackTrace)}:{Environment.NewLine}{exception.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
namespace Engine.Core.Debug;
|
||||
|
||||
public class LoggerWrapper(ILogger firstLogger, ILogger secondLogger) : ILogger
|
||||
{
|
||||
private readonly ILogger firstLogger = firstLogger;
|
||||
private readonly ILogger secondLogger = secondLogger;
|
||||
|
||||
public ILogger.Level FilterLevel
|
||||
{
|
||||
get => firstLogger.FilterLevel;
|
||||
set
|
||||
{
|
||||
firstLogger.FilterLevel = value;
|
||||
secondLogger.FilterLevel = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Log(string message, ILogger.Level level = ILogger.Level.Info, bool force = false)
|
||||
{
|
||||
firstLogger.Log(message, level, force);
|
||||
secondLogger.Log(message, level, force);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Engine.Core.Debug;
|
||||
|
||||
public static class LoggerWrapperExtensions
|
||||
{
|
||||
public static ILogger WrapWith(this ILogger thisLogger, ILogger logger) => new LoggerWrapper(thisLogger, logger);
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Engine.Core.Debug;
|
||||
|
||||
public class RotatingFileLogger : ILogger
|
||||
{
|
||||
public readonly FileLogger FileLogger = null!;
|
||||
public readonly string Directory = string.Empty;
|
||||
public readonly int RotateLength = 3;
|
||||
|
||||
public RotatingFileLogger(string directory, string namePrefix, string nameSuffix = "", int rotateLength = 3)
|
||||
{
|
||||
RotateLength = rotateLength;
|
||||
|
||||
string fileName = Path.Combine(directory, namePrefix);
|
||||
if (!string.IsNullOrWhiteSpace(nameSuffix))
|
||||
fileName += $"_{nameSuffix}";
|
||||
|
||||
bool isRelativePath = Path.GetFullPath(fileName).CompareTo(fileName) != 0;
|
||||
|
||||
if (isRelativePath)
|
||||
fileName = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName));
|
||||
|
||||
if (File.Exists($"{fileName}.log"))
|
||||
RenameExistingLogs(fileName, RotateLength);
|
||||
|
||||
FileLogger = new(fileName);
|
||||
|
||||
Directory = Path.GetDirectoryName(fileName) ?? throw new("Unexpected error on getting directory of logger path");
|
||||
RotateLastLogs(Directory, namePrefix, RotateLength);
|
||||
}
|
||||
|
||||
private static void RenameExistingLogs(string filePath, int rotateLength)
|
||||
{
|
||||
for (int i = rotateLength - 1; i >= 0; i--)
|
||||
{
|
||||
string source = i == 0
|
||||
? $"{filePath}.log"
|
||||
: $"{filePath}_{i}.log";
|
||||
|
||||
string dest = $"{filePath}_{i + 1}.log";
|
||||
|
||||
if (!File.Exists(source))
|
||||
continue;
|
||||
|
||||
if (File.Exists(dest))
|
||||
File.Delete(dest);
|
||||
|
||||
File.Move(source, dest);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RotateLastLogs(string directory, string prefix, int rotateLength)
|
||||
{
|
||||
IOrderedEnumerable<string> logs = System.IO.Directory.GetFiles(directory, $"{prefix}*.log")
|
||||
.OrderBy(File.GetCreationTime);
|
||||
|
||||
foreach (string file in logs.Skip(rotateLength))
|
||||
try
|
||||
{
|
||||
ILogger.Shared.Log($"Removing log file located at \"{file}\" during rotation.");
|
||||
File.Delete(file);
|
||||
}
|
||||
catch (Exception e) { ILogger.Shared.LogException($"Failed to rotate log file at \"{file}\"", e); }
|
||||
}
|
||||
|
||||
public ILogger.Level FilterLevel { get => FileLogger.FilterLevel; set => FileLogger.FilterLevel = value; }
|
||||
public void Log(string message, ILogger.Level level = ILogger.Level.Info, bool force = false) => FileLogger.Log(message, level, force);
|
||||
}
|
||||
@@ -4,8 +4,7 @@
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>false</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Engine.Core</RootNamespace>
|
||||
<AssemblyName>Engine.Core</AssemblyName>
|
||||
<RootNamespace>Syntriax.Engine.Core</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core.Exceptions;
|
||||
namespace Syntriax.Engine.Core.Exceptions;
|
||||
|
||||
public class AssignFailedException(string? message) : Exception(message)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Engine.Core.Exceptions;
|
||||
namespace Syntriax.Engine.Core.Exceptions;
|
||||
|
||||
public class BehaviourNotFoundException(string? message) : NotFoundException(message);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core.Exceptions;
|
||||
namespace Syntriax.Engine.Core.Exceptions;
|
||||
|
||||
public class NotAssignedException(string? message) : Exception(message)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core.Exceptions;
|
||||
namespace Syntriax.Engine.Core.Exceptions;
|
||||
|
||||
public class NotFoundException(string? message) : Exception(message)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Engine.Core.Exceptions;
|
||||
namespace Syntriax.Engine.Core.Exceptions;
|
||||
|
||||
public class UniverseObjectNotFoundException(string? message) : NotFoundException(message);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using Engine.Core.Exceptions;
|
||||
using Syntriax.Engine.Core.Exceptions;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class BehaviourControllerExtensions
|
||||
{
|
||||
@@ -27,7 +27,7 @@ public static class BehaviourControllerExtensions
|
||||
/// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
|
||||
/// <returns>The <see cref="IBehaviour"/> of the specified type if found; otherwise, throws <see cref="BehaviourNotFoundException"/>.</returns>
|
||||
public static T GetRequiredBehaviour<T>(this IBehaviourController behaviourController) where T : class
|
||||
=> behaviourController.GetBehaviour<T>() ?? throw new BehaviourNotFoundException($"{behaviourController.UniverseObject?.Name ?? "NULL"}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName}");
|
||||
=> behaviourController.GetBehaviour<T>() ?? throw new BehaviourNotFoundException($"{behaviourController.UniverseObject.Name}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName}");
|
||||
|
||||
/// <summary>
|
||||
/// Gets an existing <see cref="IBehaviour"/> of the specified type, or adds and returns a new one if it doesn't exist.
|
||||
@@ -93,7 +93,7 @@ public static class BehaviourControllerExtensions
|
||||
/// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
|
||||
/// <returns>The <see cref="IBehaviour"/> of the specified type if found; otherwise, throws <see cref="BehaviourNotFoundException"/>.</returns>
|
||||
public static T GetRequiredBehaviourInParent<T>(this IBehaviourController behaviourController) where T : class
|
||||
=> behaviourController.GetBehaviourInParent<T>() ?? throw new BehaviourNotFoundException($"{behaviourController.UniverseObject?.Name ?? "NULL"}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName} on any parent");
|
||||
=> behaviourController.GetBehaviourInParent<T>() ?? throw new BehaviourNotFoundException($"{behaviourController.UniverseObject.Name}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName} on any parent");
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="IBehaviour"/>s of the specified type in it's <see cref="IUniverseObject"/>'s parents recursively and stores them in the provided list.
|
||||
@@ -140,7 +140,7 @@ public static class BehaviourControllerExtensions
|
||||
if (behaviourController.GetBehaviour<T>() is T localBehaviour)
|
||||
return localBehaviour;
|
||||
|
||||
foreach (IUniverseObject child in behaviourController.UniverseObject.Children)
|
||||
foreach (IUniverseObject child in behaviourController.UniverseObject)
|
||||
if (GetBehaviourInChildren<T>(child.BehaviourController) is T behaviour)
|
||||
return behaviour;
|
||||
|
||||
@@ -154,7 +154,7 @@ public static class BehaviourControllerExtensions
|
||||
/// <param name="behaviourController">The <see cref="IBehaviourController"/> to start searching from.</param>
|
||||
/// <returns>The <see cref="IBehaviour"/> of the specified type if found; otherwise, throws <see cref="BehaviourNotFoundException"/>.</returns>
|
||||
public static T GetRequiredBehaviourInChildren<T>(this IBehaviourController behaviourController) where T : class
|
||||
=> behaviourController.GetBehaviourInChildren<T>() ?? throw new BehaviourNotFoundException($"{behaviourController.UniverseObject?.Name ?? "NULL"}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName} on any children ");
|
||||
=> behaviourController.GetBehaviourInChildren<T>() ?? throw new BehaviourNotFoundException($"{behaviourController.UniverseObject.Name}'s {nameof(IBehaviourController)} does not contain any {typeof(T).FullName} on any children ");
|
||||
|
||||
/// <summary>
|
||||
/// Gets all <see cref="IBehaviour"/>s of the specified type in it's <see cref="IUniverseObject"/>'s children recursively and stores them in the provided list.
|
||||
@@ -176,7 +176,7 @@ public static class BehaviourControllerExtensions
|
||||
foreach (T behaviour in cache)
|
||||
behaviours.Add(behaviour);
|
||||
|
||||
foreach (IUniverseObject child in universeObject.Children)
|
||||
foreach (IUniverseObject child in universeObject)
|
||||
TraverseChildrenForBehaviour(child, behaviours, cache);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class EnumExtensions
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class FloatExtensions
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class TransformExtensions
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Engine.Core.Exceptions;
|
||||
using Syntriax.Engine.Core.Exceptions;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class UniverseExtensions
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using Engine.Core.Exceptions;
|
||||
using Syntriax.Engine.Core.Exceptions;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class UniverseObjectExtensions
|
||||
{
|
||||
@@ -12,7 +12,7 @@ public static class UniverseObjectExtensions
|
||||
if (!string.IsNullOrWhiteSpace(name))
|
||||
universeObject.Name = name;
|
||||
if (parent is not null)
|
||||
universeObject.Parent = parent;
|
||||
universeObject.SetParent(parent);
|
||||
return universeObject;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ public static class UniverseObjectExtensions
|
||||
/// <returns>The <see cref="IUniverseObject"/> of the specified type if found; otherwise, null.</returns>
|
||||
public static T? GetUniverseObjectInParent<T>(this IUniverseObject universeObject) where T : class
|
||||
{
|
||||
if (universeObject.Children.GetUniverseObject<T>() is T localUniverseObject)
|
||||
if (universeObject.GetUniverseObject<T>() is T localUniverseObject)
|
||||
return localUniverseObject;
|
||||
|
||||
IUniverseObject? parent = universeObject;
|
||||
@@ -129,10 +129,10 @@ public static class UniverseObjectExtensions
|
||||
/// <returns>The <see cref="IUniverseObject"/> of the specified type if found; otherwise, null.</returns>
|
||||
public static T? GetUniverseObjectInChildren<T>(this IUniverseObject universeObject) where T : class
|
||||
{
|
||||
if (universeObject.Children.GetUniverseObject<T>() is T localUniverseObject)
|
||||
if (universeObject.GetUniverseObject<T>() is T localUniverseObject)
|
||||
return localUniverseObject;
|
||||
|
||||
foreach (IUniverseObject child in universeObject.Children)
|
||||
foreach (IUniverseObject child in universeObject)
|
||||
if (GetUniverseObjectInChildren<T>(child) is T behaviour)
|
||||
return behaviour;
|
||||
|
||||
@@ -246,7 +246,7 @@ public static class UniverseObjectExtensions
|
||||
|
||||
foreach (IUniverseObject universeObject in universeObjects)
|
||||
{
|
||||
universeObject.Children.Find(cache);
|
||||
universeObject.Find(cache);
|
||||
foreach (T behaviour in cache)
|
||||
instances.Add(behaviour);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core.Factory.Abstract;
|
||||
namespace Syntriax.Engine.Core.Factory.Abstract;
|
||||
|
||||
public interface IFactory<TInterface> where TInterface : class
|
||||
{
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using Engine.Core.Exceptions;
|
||||
using Syntriax.Engine.Core.Exceptions;
|
||||
|
||||
namespace Engine.Core.Factory;
|
||||
namespace Syntriax.Engine.Core.Factory;
|
||||
|
||||
public class BehaviourControllerFactory
|
||||
{
|
||||
public static IBehaviourController Instantiate(IUniverseObject universeObject, IStateEnable? stateEnable = null)
|
||||
=> Instantiate<BehaviourController>(universeObject, stateEnable);
|
||||
public static IBehaviourController Instantiate(IUniverseObject universeObject)
|
||||
=> Instantiate<BehaviourController>(universeObject);
|
||||
|
||||
public static T Instantiate<T>(IUniverseObject universeObject, IStateEnable? stateEnable = null, params object?[]? args)
|
||||
public static T Instantiate<T>(IUniverseObject universeObject, params object?[]? args)
|
||||
where T : class, IBehaviourController
|
||||
{
|
||||
T behaviourController = TypeFactory.Get<T>(args);
|
||||
@@ -18,17 +18,6 @@ public class BehaviourControllerFactory
|
||||
if (!behaviourController.Assign(universeObject))
|
||||
throw AssignFailedException.From(behaviourController, universeObject);
|
||||
|
||||
if (stateEnable is not null)
|
||||
{
|
||||
if (!stateEnable.Assign(behaviourController))
|
||||
throw AssignFailedException.From(stateEnable, behaviourController);
|
||||
|
||||
if (!behaviourController.Assign(stateEnable))
|
||||
throw AssignFailedException.From(behaviourController, stateEnable);
|
||||
}
|
||||
else
|
||||
StateEnableFactory.Instantiate(behaviourController);
|
||||
|
||||
return behaviourController;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Engine.Core.Exceptions;
|
||||
using Syntriax.Engine.Core.Exceptions;
|
||||
|
||||
namespace Engine.Core.Factory;
|
||||
namespace Syntriax.Engine.Core.Factory;
|
||||
|
||||
public class BehaviourFactory
|
||||
{
|
||||
@@ -12,15 +12,12 @@ public class BehaviourFactory
|
||||
{
|
||||
T behaviour = TypeFactory.Get<T>(args);
|
||||
|
||||
if (stateEnable is not null)
|
||||
{
|
||||
stateEnable ??= TypeFactory.Get<StateEnable>();
|
||||
if (!stateEnable.Assign(behaviour))
|
||||
throw AssignFailedException.From(stateEnable, behaviour);
|
||||
|
||||
if (!behaviour.Assign(stateEnable))
|
||||
throw AssignFailedException.From(behaviour, stateEnable);
|
||||
}
|
||||
else
|
||||
StateEnableFactory.Instantiate(behaviour);
|
||||
|
||||
return behaviour;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using Engine.Core.Factory.Abstract;
|
||||
using Syntriax.Engine.Core.Factory.Abstract;
|
||||
|
||||
namespace Engine.Core.Factory;
|
||||
namespace Syntriax.Engine.Core.Factory;
|
||||
|
||||
public abstract class FactoryBase<TInterface> : IFactory<TInterface>
|
||||
where TInterface : class
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Engine.Core.Exceptions;
|
||||
using Syntriax.Engine.Core.Exceptions;
|
||||
|
||||
namespace Engine.Core.Factory;
|
||||
namespace Syntriax.Engine.Core.Factory;
|
||||
|
||||
public class StateEnableFactory
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core.Factory;
|
||||
namespace Syntriax.Engine.Core.Factory;
|
||||
|
||||
public class TransformFactory
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Engine.Core.Factory;
|
||||
namespace Syntriax.Engine.Core.Factory;
|
||||
|
||||
public static class TypeFactory
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Engine.Core.Exceptions;
|
||||
using Syntriax.Engine.Core.Exceptions;
|
||||
|
||||
namespace Engine.Core.Factory;
|
||||
namespace Syntriax.Engine.Core.Factory;
|
||||
|
||||
public class UniverseObjectFactory
|
||||
{
|
||||
@@ -18,25 +18,18 @@ public class UniverseObjectFactory
|
||||
{
|
||||
T universeObject = TypeFactory.Get<T>(args);
|
||||
|
||||
if (behaviourController is not null)
|
||||
{
|
||||
behaviourController ??= TypeFactory.Get<BehaviourController>();
|
||||
stateEnable ??= TypeFactory.Get<StateEnable>();
|
||||
|
||||
if (!behaviourController.Assign(universeObject))
|
||||
throw AssignFailedException.From(behaviourController, universeObject);
|
||||
if (!universeObject.Assign(behaviourController))
|
||||
throw AssignFailedException.From(universeObject, behaviourController);
|
||||
}
|
||||
else
|
||||
BehaviourControllerFactory.Instantiate(universeObject);
|
||||
|
||||
if (stateEnable is not null)
|
||||
{
|
||||
if (!stateEnable.Assign(universeObject))
|
||||
throw AssignFailedException.From(stateEnable, universeObject);
|
||||
|
||||
if (!universeObject.Assign(behaviourController))
|
||||
throw AssignFailedException.From(universeObject, behaviourController);
|
||||
if (!universeObject.Assign(stateEnable))
|
||||
throw AssignFailedException.From(universeObject, stateEnable);
|
||||
}
|
||||
else
|
||||
StateEnableFactory.Instantiate(universeObject);
|
||||
|
||||
return universeObject;
|
||||
}
|
||||
|
||||
18
Engine.Core/Helpers/DelegateExtensions.cs
Normal file
18
Engine.Core/Helpers/DelegateExtensions.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class DelegateExtensions
|
||||
{
|
||||
[Obsolete($"{nameof(InvokeSafe)} causes memory allocation, please use Invoke() instead.")]
|
||||
public static void InvokeSafe(this Delegate @delegate, params object?[] args)
|
||||
{
|
||||
foreach (Delegate invocation in Delegate.EnumerateInvocationList(@delegate))
|
||||
try { invocation.DynamicInvoke(args); }
|
||||
catch (Exception exception)
|
||||
{
|
||||
string methodCallRepresentation = $"{invocation.Method.DeclaringType?.FullName}.{invocation.Method.Name}({string.Join(", ", args)})";
|
||||
Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,506 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Engine.Core.Debug;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
namespace Engine.Core;
|
||||
|
||||
// TODO!: every reverse loop has a chance to have more than 1 unsubscription,
|
||||
// for (int i = listeners.Count - 1; i >= 0; i--)
|
||||
// can be replaced with
|
||||
// for (int i = listeners.Count - 1; i >= 0; i = Math.Min(i - 1, listeners.Count - 1))
|
||||
// but this would causes possible double calls on already called callbacks, find a better method.
|
||||
|
||||
/// <summary>
|
||||
/// Represents a simple event with no parameters.
|
||||
/// <para>Example usage:</para>
|
||||
/// <code>
|
||||
/// public class MyBehaviour : Behaviour, IUpdate
|
||||
/// {
|
||||
/// public readonly Event MyEvent = new();
|
||||
///
|
||||
/// public MyBehaviour()
|
||||
/// {
|
||||
/// MyEvent.AddListener(OnEventTriggered);
|
||||
/// MyEvent.AddOneTimeListener(OnEventTriggeredOneTime);
|
||||
/// }
|
||||
///
|
||||
/// public void Update()
|
||||
/// {
|
||||
/// MyEvent.Invoke();
|
||||
/// }
|
||||
///
|
||||
/// private void OnEventTriggered()
|
||||
/// {
|
||||
/// Console.WriteLine($"Event occurred!");
|
||||
/// }
|
||||
///
|
||||
/// private static void OnEventTriggeredOneTime()
|
||||
/// {
|
||||
/// Console.WriteLine($"Event called once!");
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// The output of the example code above would be:
|
||||
/// <code>
|
||||
/// Event occurred!
|
||||
/// Event called once!
|
||||
/// Event occurred!
|
||||
/// Event occurred!
|
||||
/// Event occurred!
|
||||
/// ...
|
||||
/// </code>
|
||||
/// </summary>
|
||||
public class Event
|
||||
public class Event<TSender>
|
||||
{
|
||||
// We use Ascending order because draw calls are running from last to first
|
||||
private static readonly Comparer<ListenerData> SortByAscendingPriority = Comparer<ListenerData>.Create((x, y) => x.Priority.CompareTo(y.Priority));
|
||||
private readonly List<EventHandler> listeners = new(8);
|
||||
|
||||
private ILogger _logger = ILogger.Shared;
|
||||
public ILogger Logger { get => _logger; set => _logger = value ?? ILogger.Shared; }
|
||||
|
||||
private readonly List<ListenerData> listeners = null!;
|
||||
private readonly List<ListenerData> onceListeners = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes the callback to be invoked whenever the event is triggered.
|
||||
/// </summary>
|
||||
/// <param name="listener">The callback to be called when the event is triggered.</param>
|
||||
/// <param name="priority">Priority of the callback.</param>
|
||||
public void AddListener(EventHandler listener, int priority = 0)
|
||||
public void AddListener(EventHandler listener) => listeners.Add(listener);
|
||||
public void RemoveListener(EventHandler listener) => listeners.Remove(listener);
|
||||
public void Clear() => listeners.Clear();
|
||||
public void Invoke(TSender argument)
|
||||
{
|
||||
ListenerData listenerData = new(listener, priority);
|
||||
|
||||
int insertIndex = listeners.BinarySearch(listenerData, SortByAscendingPriority);
|
||||
if (insertIndex < 0)
|
||||
insertIndex = ~insertIndex;
|
||||
|
||||
listeners.Insert(insertIndex, listenerData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes the callback to be invoked the next time the event is triggered. The callback will be called only once.
|
||||
/// </summary>
|
||||
/// <param name="listener">The callback to be called the next time the event is triggered.</param>
|
||||
/// <param name="priority">Priority of the callback.</param>
|
||||
public void AddOneTimeListener(EventHandler listener, int priority = 0)
|
||||
{
|
||||
ListenerData listenerData = new(listener, priority);
|
||||
|
||||
int insertIndex = onceListeners.BinarySearch(listenerData, SortByAscendingPriority);
|
||||
if (insertIndex < 0)
|
||||
insertIndex = ~insertIndex;
|
||||
|
||||
onceListeners.Insert(insertIndex, listenerData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes the callback that was previously registered by <see cref="AddListener(EventHandler)"/>.
|
||||
/// </summary>
|
||||
/// <param name="listener">The callback that was previously registered by <see cref="AddListener(EventHandler)"/></param>
|
||||
public void RemoveListener(EventHandler listener)
|
||||
{
|
||||
for (int i = listeners.Count - 1; i >= 0; i--)
|
||||
if (listeners[i].Callback == listener)
|
||||
{
|
||||
listeners.RemoveAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes the callback that was previously registered by <see cref="AddOneTimeListener(EventHandler)"/>.
|
||||
/// </summary>
|
||||
/// <param name="listener">The callback that was previously registered by <see cref="AddOneTimeListener(EventHandler)"/></param>
|
||||
public void RemoveOneTimeListener(EventHandler listener)
|
||||
{
|
||||
for (int i = 0; i < onceListeners.Count; i++)
|
||||
if (onceListeners[i].Callback == listener)
|
||||
{
|
||||
onceListeners.RemoveAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes all listeners that was previously registered by either <see cref="AddListener(EventHandler)"/> or <see cref="AddOneTimeListener(EventHandler)"/>.
|
||||
/// </summary>
|
||||
public void Clear() { listeners.Clear(); onceListeners.Clear(); }
|
||||
|
||||
/// <summary>
|
||||
/// Triggers the event.
|
||||
/// </summary>
|
||||
public void Invoke()
|
||||
{
|
||||
for (int i = listeners.Count - 1; i >= 0; i--)
|
||||
try { listeners[i].Callback.Invoke(); }
|
||||
for (int i = 0; i < listeners.Count; i++)
|
||||
try { listeners[i].Invoke(argument); }
|
||||
catch (Exception exception)
|
||||
{
|
||||
string methodCallRepresentation = $"{listeners[i].Callback.Method.DeclaringType?.FullName}.{listeners[i].Callback.Method.Name}()";
|
||||
EventHelpers.LogInvocationException(listeners[i].Callback.Target ?? this, Logger, exception, methodCallRepresentation);
|
||||
string methodCallRepresentation = $"{listeners[i].Method.DeclaringType?.FullName}.{listeners[i].Method.Name}({argument})";
|
||||
Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}");
|
||||
}
|
||||
|
||||
for (int i = onceListeners.Count - 1; i >= 0; i--)
|
||||
{
|
||||
try { onceListeners[i].Callback.Invoke(); }
|
||||
catch (Exception exception)
|
||||
{
|
||||
string methodCallRepresentation = $"{onceListeners[i].Callback.Method.DeclaringType?.FullName}.{onceListeners[i].Callback.Method.Name}()";
|
||||
EventHelpers.LogInvocationException(onceListeners[i].Callback.Target ?? this, Logger, exception, methodCallRepresentation);
|
||||
}
|
||||
onceListeners.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
public Event(int initialListenerCount = 4, int initialOnceListenerCount = 2)
|
||||
{
|
||||
listeners = new(initialListenerCount);
|
||||
onceListeners = new(initialOnceListenerCount);
|
||||
}
|
||||
|
||||
public Event()
|
||||
{
|
||||
listeners = new(4);
|
||||
onceListeners = new(2);
|
||||
}
|
||||
|
||||
public delegate void EventHandler();
|
||||
private record struct ListenerData(EventHandler Callback, int Priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an event with only sender parameters.
|
||||
/// <para>Example usage:</para>
|
||||
/// <code>
|
||||
/// public class MyBehaviour : Behaviour, IUpdate
|
||||
/// {
|
||||
/// public readonly Event<MyBehaviour> MyEvent = new();
|
||||
///
|
||||
/// public MyBehaviour()
|
||||
/// {
|
||||
/// MyEvent.AddListener(OnEventTriggered);
|
||||
/// MyEvent.AddOneTimeListener(OnEventTriggeredOneTime);
|
||||
/// }
|
||||
///
|
||||
/// public void Update()
|
||||
/// {
|
||||
/// MyEvent.Invoke(this);
|
||||
/// }
|
||||
///
|
||||
/// private void OnEventTriggered(MyBehaviour sender)
|
||||
/// {
|
||||
/// Console.WriteLine($"{sender.Id}'s event occurred!");
|
||||
/// }
|
||||
///
|
||||
/// private static void OnEventTriggeredOneTime(MyBehaviour sender)
|
||||
/// {
|
||||
/// Console.WriteLine($"{sender.Id}'s event called once!");
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// The output of the example code above would be:
|
||||
/// <code>
|
||||
/// [Id]'s event occurred!
|
||||
/// [Id]'s event called once!
|
||||
/// [Id]'s event occurred!
|
||||
/// [Id]'s event occurred!
|
||||
/// [Id]'s event occurred!
|
||||
/// ...
|
||||
/// </code>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TSender">Sender type</typeparam>
|
||||
public class Event<TSender> where TSender : class
|
||||
{
|
||||
// We use Ascending order because draw calls are running from last to first
|
||||
private static readonly Comparer<ListenerData> SortByAscendingPriority = Comparer<ListenerData>.Create((x, y) => x.Priority.CompareTo(y.Priority));
|
||||
|
||||
private ILogger _logger = ILogger.Shared;
|
||||
public ILogger Logger { get => _logger; set => _logger = value ?? ILogger.Shared; }
|
||||
|
||||
private readonly List<ListenerData> listeners = null!;
|
||||
private readonly List<ListenerData> onceListeners = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes the callback to be invoked whenever the event is triggered.
|
||||
/// </summary>
|
||||
/// <param name="listener">The callback to be called when the event is triggered.</param>
|
||||
/// <param name="priority">Priority of the callback.</param>
|
||||
public void AddListener(EventHandler listener, int priority = 0)
|
||||
{
|
||||
ListenerData listenerData = new(listener, priority);
|
||||
|
||||
int insertIndex = listeners.BinarySearch(listenerData, SortByAscendingPriority);
|
||||
if (insertIndex < 0)
|
||||
insertIndex = ~insertIndex;
|
||||
|
||||
listeners.Insert(insertIndex, listenerData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes the callback to be invoked the next time the event is triggered. The callback will be called only once.
|
||||
/// </summary>
|
||||
/// <param name="listener">The callback to be called the next time the event is triggered.</param>
|
||||
/// <param name="priority">Priority of the callback.</param>
|
||||
public void AddOneTimeListener(EventHandler listener, int priority = 0)
|
||||
{
|
||||
ListenerData listenerData = new(listener, priority);
|
||||
|
||||
int insertIndex = onceListeners.BinarySearch(listenerData, SortByAscendingPriority);
|
||||
if (insertIndex < 0)
|
||||
insertIndex = ~insertIndex;
|
||||
|
||||
onceListeners.Insert(insertIndex, listenerData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes the callback that was previously registered by <see cref="AddListener(EventHandler)"/>.
|
||||
/// </summary>
|
||||
/// <param name="listener">The callback that was previously registered by <see cref="AddListener(EventHandler)"/></param>
|
||||
public void RemoveListener(EventHandler listener)
|
||||
{
|
||||
for (int i = listeners.Count - 1; i >= 0; i--)
|
||||
if (listeners[i].Callback == listener)
|
||||
{
|
||||
listeners.RemoveAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes the callback that was previously registered by <see cref="AddOneTimeListener(EventHandler)"/>.
|
||||
/// </summary>
|
||||
/// <param name="listener">The callback that was previously registered by <see cref="AddOneTimeListener(EventHandler)"/></param>
|
||||
public void RemoveOneTimeListener(EventHandler listener)
|
||||
{
|
||||
for (int i = 0; i < onceListeners.Count; i++)
|
||||
if (onceListeners[i].Callback == listener)
|
||||
{
|
||||
onceListeners.RemoveAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes all listeners that was previously registered by either <see cref="AddListener(EventHandler)"/> or <see cref="AddOneTimeListener(EventHandler)"/>.
|
||||
/// </summary>
|
||||
public void Clear() { listeners.Clear(); onceListeners.Clear(); }
|
||||
|
||||
/// <summary>
|
||||
/// Triggers the event.
|
||||
/// </summary>
|
||||
/// <param name="sender">The caller that's triggering this event.</param>
|
||||
public void Invoke(TSender sender)
|
||||
{
|
||||
for (int i = listeners.Count - 1; i >= 0; i--)
|
||||
try { listeners[i].Callback.Invoke(sender); }
|
||||
catch (Exception exception)
|
||||
{
|
||||
string methodCallRepresentation = $"{listeners[i].Callback.Method.DeclaringType?.FullName}.{listeners[i].Callback.Method.Name}({sender})";
|
||||
EventHelpers.LogInvocationException(listeners[i].Callback.Target ?? sender, Logger, exception, methodCallRepresentation);
|
||||
}
|
||||
|
||||
for (int i = onceListeners.Count - 1; i >= 0; i--)
|
||||
{
|
||||
try { onceListeners[i].Callback.Invoke(sender); }
|
||||
catch (Exception exception)
|
||||
{
|
||||
string methodCallRepresentation = $"{onceListeners[i].Callback.Method.DeclaringType?.FullName}.{onceListeners[i].Callback.Method.Name}({sender})";
|
||||
EventHelpers.LogInvocationException(onceListeners[i].Callback.Target ?? sender, Logger, exception, methodCallRepresentation);
|
||||
}
|
||||
onceListeners.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
public Event(int initialListenerCount = 4, int initialOnceListenerCount = 2)
|
||||
{
|
||||
listeners = new(initialListenerCount);
|
||||
onceListeners = new(initialOnceListenerCount);
|
||||
}
|
||||
|
||||
public Event()
|
||||
{
|
||||
listeners = new(4);
|
||||
onceListeners = new(2);
|
||||
}
|
||||
|
||||
public delegate void EventHandler(TSender sender);
|
||||
private record struct ListenerData(EventHandler Callback, int Priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an event with sender and argument parameters.
|
||||
/// <para>Example usage:</para>
|
||||
/// <code>
|
||||
/// public class MyBehaviour : Behaviour, IUpdate
|
||||
/// {
|
||||
/// public readonly Event<MyBehaviour, MyArguments> MyEvent = new();
|
||||
///
|
||||
/// private int myInt = 0;
|
||||
/// private bool myBool = false;
|
||||
///
|
||||
/// public MyBehaviour()
|
||||
/// {
|
||||
/// MyEvent.AddOneTimeListener(OnEventTriggeredOneTime);
|
||||
/// MyEvent.AddListener(OnEventTriggered);
|
||||
/// }
|
||||
///
|
||||
/// public void Update()
|
||||
/// {
|
||||
/// MyEvent.Invoke(this, new MyArguments(myInt, myBool));
|
||||
/// myInt++;
|
||||
/// myBool = !myBool;
|
||||
/// }
|
||||
///
|
||||
/// private void OnEventTriggered(MyBehaviour sender, MyArguments args)
|
||||
/// {
|
||||
/// Console.WriteLine($"{sender.Id}'s event occurred with MyInt: {args.MyInt} and MyBool {args.MyBool}!");
|
||||
/// }
|
||||
///
|
||||
/// private static void OnEventTriggeredOneTime(MyBehaviour sender, MyArguments args)
|
||||
/// {
|
||||
/// Console.WriteLine($"{sender.Id}'s event called once with MyInt: {args.MyInt} and MyBool {args.MyBool}!");
|
||||
/// }
|
||||
///
|
||||
/// public readonly record struct MyArguments(int MyInt, bool MyBool);
|
||||
/// }
|
||||
/// </code>
|
||||
/// The output of the example code above would be:
|
||||
/// <code>
|
||||
/// [Id]'s event occurred with MyInt: 0 and MyBool False!
|
||||
/// [Id]'s event called once with MyInt: 0 and MyBool False!
|
||||
/// [Id]'s event occurred with MyInt: 1 and MyBool True!
|
||||
/// [Id]'s event occurred with MyInt: 2 and MyBool False!
|
||||
/// [Id]'s event occurred with MyInt: 3 and MyBool True!
|
||||
/// ...
|
||||
/// </code>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TSender">Sender type</typeparam>
|
||||
public class Event<TSender, TArguments> where TSender : class
|
||||
public class Event<TSender, TArguments>
|
||||
{
|
||||
// We use Ascending order because draw calls are running from last to first
|
||||
private static readonly Comparer<ListenerData> SortByAscendingPriority = Comparer<ListenerData>.Create((x, y) => x.Priority.CompareTo(y.Priority));
|
||||
private readonly List<EventHandler> listeners = new(8);
|
||||
|
||||
private ILogger _logger = ILogger.Shared;
|
||||
public ILogger Logger { get => _logger; set => _logger = value ?? ILogger.Shared; }
|
||||
|
||||
private readonly List<ListenerData> listeners = null!;
|
||||
private readonly List<ListenerData> onceListeners = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes the callback to be invoked whenever the event is triggered.
|
||||
/// </summary>
|
||||
/// <param name="listener">The callback to be called when the event is triggered.</param>
|
||||
/// <param name="priority">Priority of the callback.</param>
|
||||
public void AddListener(EventHandler listener, int priority = 0)
|
||||
public void AddListener(EventHandler listener) => listeners.Add(listener);
|
||||
public void RemoveListener(EventHandler listener) => listeners.Remove(listener);
|
||||
public void Clear() => listeners.Clear();
|
||||
public void Invoke(TSender sender, TArguments arguments)
|
||||
{
|
||||
ListenerData listenerData = new(listener, priority);
|
||||
|
||||
int insertIndex = listeners.BinarySearch(listenerData, SortByAscendingPriority);
|
||||
if (insertIndex < 0)
|
||||
insertIndex = ~insertIndex;
|
||||
|
||||
listeners.Insert(insertIndex, listenerData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes the callback to be invoked the next time the event is triggered. The callback will be called only once.
|
||||
/// </summary>
|
||||
/// <param name="listener">The callback to be called the next time the event is triggered.</param>
|
||||
/// <param name="priority">Priority of the callback.</param>
|
||||
public void AddOneTimeListener(EventHandler listener, int priority = 0)
|
||||
{
|
||||
ListenerData listenerData = new(listener, priority);
|
||||
|
||||
int insertIndex = onceListeners.BinarySearch(listenerData, SortByAscendingPriority);
|
||||
if (insertIndex < 0)
|
||||
insertIndex = ~insertIndex;
|
||||
|
||||
onceListeners.Insert(insertIndex, listenerData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes the callback that was previously registered by <see cref="AddListener(EventHandler)"/>.
|
||||
/// </summary>
|
||||
/// <param name="listener">The callback that was previously registered by <see cref="AddListener(EventHandler)"/></param>
|
||||
public void RemoveListener(EventHandler listener)
|
||||
{
|
||||
for (int i = listeners.Count - 1; i >= 0; i--)
|
||||
if (listeners[i].Callback == listener)
|
||||
{
|
||||
listeners.RemoveAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes the callback that was previously registered by <see cref="AddOneTimeListener(EventHandler)"/>.
|
||||
/// </summary>
|
||||
/// <param name="listener">The callback that was previously registered by <see cref="AddOneTimeListener(EventHandler)"/></param>
|
||||
public void RemoveOneTimeListener(EventHandler listener)
|
||||
{
|
||||
for (int i = 0; i < onceListeners.Count; i++)
|
||||
if (onceListeners[i].Callback == listener)
|
||||
{
|
||||
onceListeners.RemoveAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes all listeners that was previously registered by either <see cref="AddListener(EventHandler)"/> or <see cref="AddOneTimeListener(EventHandler)"/>.
|
||||
/// </summary>
|
||||
public void Clear() { listeners.Clear(); onceListeners.Clear(); }
|
||||
|
||||
/// <summary>
|
||||
/// Triggers the event.
|
||||
/// </summary>
|
||||
/// <param name="sender">The caller that's triggering this event.</param>
|
||||
/// <param name="args">The arguments provided for this event.</param>
|
||||
public void Invoke(TSender sender, TArguments args)
|
||||
{
|
||||
for (int i = listeners.Count - 1; i >= 0; i--)
|
||||
try { listeners[i].Callback.Invoke(sender, args); }
|
||||
for (int i = 0; i < listeners.Count; i++)
|
||||
try { listeners[i].Invoke(sender, arguments); }
|
||||
catch (Exception exception)
|
||||
{
|
||||
string methodCallRepresentation = $"{listeners[i].Callback.Method.DeclaringType?.FullName}.{listeners[i].Callback.Method.Name}({sender}, {args})";
|
||||
EventHelpers.LogInvocationException(listeners[i].Callback.Target ?? sender, Logger, exception, methodCallRepresentation);
|
||||
}
|
||||
|
||||
for (int i = onceListeners.Count - 1; i >= 0; i--)
|
||||
{
|
||||
try { onceListeners[i].Callback.Invoke(sender, args); }
|
||||
catch (Exception exception)
|
||||
{
|
||||
string methodCallRepresentation = $"{onceListeners[i].Callback.Method.DeclaringType?.FullName}.{onceListeners[i].Callback.Method.Name}({sender}, {args})";
|
||||
EventHelpers.LogInvocationException(onceListeners[i].Callback.Target ?? sender, Logger, exception, methodCallRepresentation);
|
||||
}
|
||||
onceListeners.RemoveAt(i);
|
||||
string methodCallRepresentation = $"{listeners[i].Method.DeclaringType?.FullName}.{listeners[i].Method.Name}({string.Join(", ", sender, arguments)})";
|
||||
Console.WriteLine($"Unexpected exception on invocation of method {methodCallRepresentation}:{Environment.NewLine}{exception.InnerException}");
|
||||
}
|
||||
}
|
||||
|
||||
public Event(int initialListenerCount = 4, int initialOnceListenerCount = 2)
|
||||
{
|
||||
listeners = new(initialListenerCount);
|
||||
onceListeners = new(initialOnceListenerCount);
|
||||
}
|
||||
|
||||
public Event()
|
||||
{
|
||||
listeners = new(4);
|
||||
onceListeners = new(2);
|
||||
}
|
||||
|
||||
public delegate void EventHandler(TSender sender, TArguments args);
|
||||
private record struct ListenerData(EventHandler Callback, int Priority);
|
||||
}
|
||||
|
||||
internal static class EventHelpers
|
||||
{
|
||||
public static void LogInvocationException(object sender, ILogger logger, Exception exception, string methodCallRepresentation)
|
||||
{
|
||||
logger.LogException(sender, exception);
|
||||
logger.LogError(sender, $"Unexpected exception on invocation of method {methodCallRepresentation}");
|
||||
}
|
||||
public delegate void EventHandler(TSender sender, TArguments arguments);
|
||||
}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Engine.Core;
|
||||
|
||||
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();
|
||||
|
||||
items[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(T item)
|
||||
{
|
||||
if (IsReadOnly)
|
||||
throw new System.Data.ReadOnlyException();
|
||||
|
||||
indexMap[item] = items.Count;
|
||||
items.Add(item);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
Remove(item, index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Remove(T item, int index)
|
||||
{
|
||||
int lastIndex = items.Count - 1;
|
||||
T lastItem = items[lastIndex];
|
||||
|
||||
items[index] = lastItem;
|
||||
indexMap[lastItem] = index;
|
||||
|
||||
items.RemoveAt(lastIndex);
|
||||
indexMap.Remove(item);
|
||||
}
|
||||
|
||||
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++)
|
||||
indexMap[items[i]] = i;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
public FastList() { }
|
||||
public FastList(int count) { items.Capacity = count; }
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Engine.Core;
|
||||
|
||||
public interface IPool<T>
|
||||
{
|
||||
Event<IPool<T>, T> OnRemoved { get; }
|
||||
Event<IPool<T>, T> OnReturned { get; }
|
||||
|
||||
T Get();
|
||||
void Return(T item);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Engine.Core;
|
||||
|
||||
public class ListPool<T> : IPool<List<T>>
|
||||
{
|
||||
public Event<IPool<List<T>>, List<T>> OnReturned { get; } = new();
|
||||
public Event<IPool<List<T>>, List<T>> OnRemoved { get; } = new();
|
||||
|
||||
private readonly Func<List<T>> generator = null!;
|
||||
private readonly Queue<List<T>> queue = new();
|
||||
|
||||
public List<T> Get()
|
||||
{
|
||||
if (!queue.TryDequeue(out List<T>? result))
|
||||
result = generator();
|
||||
|
||||
result.Clear();
|
||||
OnRemoved?.Invoke(this, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Return(List<T> list)
|
||||
{
|
||||
if (queue.Contains(list))
|
||||
return;
|
||||
|
||||
list.Clear();
|
||||
queue.Enqueue(list);
|
||||
OnReturned?.Invoke(this, list);
|
||||
}
|
||||
|
||||
public ListPool(int initialListCount = 1, int initialListCapacity = 32)
|
||||
{
|
||||
generator = () => new(initialListCapacity);
|
||||
for (int i = 0; i < initialListCount; i++)
|
||||
queue.Enqueue(generator());
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Engine.Core;
|
||||
|
||||
public class Pool<T> : IPool<T>
|
||||
{
|
||||
public Event<IPool<T>, T> OnRemoved { get; } = new();
|
||||
public Event<IPool<T>, T> OnReturned { get; } = new();
|
||||
|
||||
private readonly Func<T> generator = null!;
|
||||
private readonly Queue<T> queue = new();
|
||||
private readonly HashSet<T> queuedHashes = [];
|
||||
|
||||
public T Get()
|
||||
{
|
||||
if (!queue.TryDequeue(out T? result))
|
||||
result = generator();
|
||||
|
||||
queuedHashes.Remove(result);
|
||||
OnRemoved?.Invoke(this, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Return(T item)
|
||||
{
|
||||
if (queuedHashes.Contains(item))
|
||||
return;
|
||||
|
||||
queue.Enqueue(item);
|
||||
queuedHashes.Add(item);
|
||||
OnReturned?.Invoke(this, item);
|
||||
}
|
||||
|
||||
public Pool(Func<T> generator, int initialCapacity = 1)
|
||||
{
|
||||
this.generator = generator;
|
||||
for (int i = 0; i < initialCapacity; i++)
|
||||
queue.Enqueue(generator());
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public interface IProgressionTracker : IReadOnlyProgressionTracker
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public interface IReadOnlyProgressionTracker
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public class ProgressionTracker : IProgressionTracker
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public record struct ProgressiveTask<T>(IReadOnlyProgressionTracker ProgressionTracker, Task<T> Task)
|
||||
{
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class Math
|
||||
{
|
||||
/// <summary>
|
||||
/// The value of Pi (π).
|
||||
/// The value of Pi (π), a mathematical constant approximately equal to 3.14159.
|
||||
/// </summary>
|
||||
public const float Pi = 3.1415926535897932f;
|
||||
public const float PI = 3.1415926535897932f;
|
||||
|
||||
/// <summary>
|
||||
/// The value of Tau (τ), mathematical constant equal to 2π.
|
||||
/// The value of Tau (τ), a mathematical constant equal to 2π, approximately equal to 6.28319.
|
||||
/// </summary>
|
||||
public const float Tau = 2f * Pi;
|
||||
public const float Tau = 2f * PI;
|
||||
|
||||
/// <summary>
|
||||
/// The base of the natural logarithm.
|
||||
/// The base of the natural logarithm, approximately equal to 2.71828.
|
||||
/// </summary>
|
||||
public const float E = 2.718281828459045f;
|
||||
|
||||
/// <summary>
|
||||
/// The conversion factor from radians to degrees.
|
||||
/// </summary>
|
||||
public const float RadianToDegree = 180f / Pi;
|
||||
public const float RadianToDegree = 180f / PI;
|
||||
|
||||
/// <summary>
|
||||
/// The conversion factor from degrees to radians.
|
||||
/// </summary>
|
||||
public const float DegreeToRadian = Pi / 180f;
|
||||
public const float DegreeToRadian = PI / 180f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets one minus of given <see cref="T"/>.
|
||||
@@ -240,33 +240,21 @@ 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 the closest integer.
|
||||
/// Rounds a number to a specified number of fractional digits.
|
||||
/// </summary>
|
||||
/// <param name="x">The number to round.</param>
|
||||
/// <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);
|
||||
/// <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);
|
||||
|
||||
/// <summary>
|
||||
/// Rounds a number to the closest integer.
|
||||
/// Rounds a number to an 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>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);
|
||||
}
|
||||
/// <returns></returns>
|
||||
public static int RoundToInt(float x, RoundMode roundMode = RoundMode.Ceil) => (int)MathF.Round(x, 0, roundMode == RoundMode.Ceil ? MidpointRounding.ToPositiveInfinity : MidpointRounding.ToNegativeInfinity);
|
||||
public enum RoundMode { Ceil, Floor };
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class MathExtensions
|
||||
{
|
||||
@@ -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, Math.RoundMode mode) => Math.Round(x, mode);
|
||||
public static float Round(this float x, int digits, MidpointRounding mode) => Math.Round(x, digits, 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);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Engine.Core
|
||||
namespace Syntriax.Engine.Core
|
||||
{
|
||||
// This is pretty much so the assembly gets loaded automatically because
|
||||
// the builds include the assembly but sometimes doesn't link load it at startup.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an Axis-Aligned Bounding Box (AABB) in 2D space.
|
||||
@@ -12,7 +11,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) : IEquatable<AABB>
|
||||
public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary)
|
||||
{
|
||||
/// <summary>
|
||||
/// The lower boundary of the <see cref="AABB"/>.
|
||||
@@ -39,9 +38,6 @@ public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary) : IE
|
||||
/// </summary>
|
||||
public readonly Vector2D SizeHalf => Size * .5f;
|
||||
|
||||
public static bool operator ==(AABB left, AABB right) => left.UpperBoundary == right.UpperBoundary && left.LowerBoundary == right.LowerBoundary;
|
||||
public static bool operator !=(AABB left, AABB right) => left.UpperBoundary != right.UpperBoundary || left.LowerBoundary != right.LowerBoundary;
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AABB"/> from a collection of <see cref="Vector2D"/>s.
|
||||
/// </summary>
|
||||
@@ -67,6 +63,12 @@ public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary) : IE
|
||||
return new(lowerBoundary, upperBoundary);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="AABB"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="AABB"/>.</returns>
|
||||
public override string ToString() => $"{nameof(AABB)}({LowerBoundary}, {UpperBoundary})";
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="AABB"/>s are approximately equal.
|
||||
/// </summary>
|
||||
@@ -76,26 +78,6 @@ public readonly struct AABB(Vector2D lowerBoundary, Vector2D upperBoundary) : IE
|
||||
/// <returns><see cref="true"/> if the <see cref="AABB"/>s are approximately equal; otherwise, <see cref="false"/>.</returns>
|
||||
public static bool ApproximatelyEquals(AABB left, AABB right, float epsilon = float.Epsilon)
|
||||
=> left.LowerBoundary.ApproximatelyEquals(right.LowerBoundary, epsilon) && left.UpperBoundary.ApproximatelyEquals(right.UpperBoundary, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="AABB"/>.
|
||||
/// </summary>
|
||||
/// <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"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="AABB"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(LowerBoundary, UpperBoundary);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="AABB"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="AABB"/>.</returns>
|
||||
public override string ToString() => $"{nameof(AABB)}({LowerBoundary}, {UpperBoundary})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a 2D circle.
|
||||
@@ -12,7 +11,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) : IEquatable<Circle>
|
||||
public readonly struct Circle(Vector2D center, float radius)
|
||||
{
|
||||
/// <summary>
|
||||
/// The center of the circle.
|
||||
@@ -39,9 +38,6 @@ public readonly struct Circle(Vector2D center, float radius) : IEquatable<Circle
|
||||
/// </summary>
|
||||
public static readonly Circle UnitCircle = new(Vector2D.Zero, 1f);
|
||||
|
||||
public static bool operator ==(Circle left, Circle right) => left.Center == right.Center && left.Radius == right.Radius;
|
||||
public static bool operator !=(Circle left, Circle right) => left.Center != right.Center || left.Radius != right.Radius;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the center of the <see cref="Circle"/>.
|
||||
/// </summary>
|
||||
@@ -81,26 +77,6 @@ public readonly struct Circle(Vector2D center, float radius) : IEquatable<Circle
|
||||
/// <returns><see cref="true"/> if the <see cref="Circle"/>s are approximately equal; otherwise, <see cref="false"/>.</returns>
|
||||
public static bool ApproximatelyEquals(Circle left, Circle right, float epsilon = float.Epsilon)
|
||||
=> left.Center.ApproximatelyEquals(right.Center, epsilon) && left.Radius.ApproximatelyEquals(right.Radius, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="Circle"/>.
|
||||
/// </summary>
|
||||
/// <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"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Circle"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(Center, Radius);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Circle"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Circle"/>.</returns>
|
||||
public override string ToString() => $"{nameof(Circle)}({Center}, {Radius})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an HSV color.
|
||||
@@ -12,7 +10,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) : IEquatable<ColorHSV>
|
||||
public readonly struct ColorHSV(float hue, float saturation, float value)
|
||||
{
|
||||
/// <summary>
|
||||
/// The Hue value of the <see cref="ColorHSV"/>.
|
||||
@@ -29,19 +27,49 @@ public readonly struct ColorHSV(float hue, float saturation, float value) : IEqu
|
||||
/// </summary>
|
||||
public readonly float Value = value.Clamp(0f, 1f);
|
||||
|
||||
public static ColorHSV operator -(ColorHSV color) => new(color.Hue.OneMinus(), color.Saturation.OneMinus(), color.Value.OneMinus());
|
||||
public static ColorHSV operator +(ColorHSV left, ColorHSV right) => new(left.Hue + right.Hue, left.Saturation + right.Saturation, left.Value + right.Value);
|
||||
public static ColorHSV operator -(ColorHSV left, ColorHSV right) => new(left.Hue - right.Hue, left.Saturation - right.Saturation, left.Value - right.Value);
|
||||
public static ColorHSV operator *(ColorHSV left, ColorHSV right) => new(left.Hue * right.Hue, left.Saturation * right.Saturation, left.Value * right.Value);
|
||||
public static ColorHSV operator *(ColorHSV color, float value) => new(color.Hue * value, color.Saturation * value, color.Value * value);
|
||||
public static ColorHSV operator *(float value, ColorHSV color) => new(color.Hue * value, color.Saturation * value, color.Value * value);
|
||||
public static ColorHSV operator /(ColorHSV color, float value) => new(color.Hue / value, color.Saturation / value, color.Value / value);
|
||||
public static bool operator ==(ColorHSV left, ColorHSV right) => left.Hue == right.Hue && left.Saturation == right.Saturation && left.Value == right.Value;
|
||||
public static bool operator !=(ColorHSV left, ColorHSV right) => left.Hue != right.Hue || left.Saturation != right.Saturation || left.Value != right.Value;
|
||||
public static ColorHSV operator -(ColorHSV color) => new(color.Hue.OneMinus().Clamp(0f, 1f), color.Saturation.OneMinus().Clamp(0f, 1f), color.Value.OneMinus().Clamp(0f, 1f));
|
||||
public static ColorHSV operator +(ColorHSV left, ColorHSV right) => new((left.Hue + right.Hue).Clamp(0f, 1f), (left.Saturation + right.Saturation).Clamp(0f, 1f), (left.Value + right.Value).Clamp(0f, 1f));
|
||||
public static ColorHSV operator -(ColorHSV left, ColorHSV right) => new((left.Hue - right.Hue).Clamp(0f, 1f), (left.Saturation - right.Saturation).Clamp(0f, 1f), (left.Value - right.Value).Clamp(0f, 1f));
|
||||
public static ColorHSV operator *(ColorHSV left, ColorHSV right) => new((left.Hue * right.Hue).Clamp(0f, 1f), (left.Saturation * right.Saturation).Clamp(0f, 1f), (left.Value * right.Value).Clamp(0f, 1f));
|
||||
public static ColorHSV operator *(ColorHSV color, float value) => new((color.Hue * value).Clamp(0f, 1f), (color.Saturation * value).Clamp(0f, 1f), (color.Value * value).Clamp(0f, 1f));
|
||||
public static ColorHSV operator *(float value, ColorHSV color) => new((color.Hue * value).Clamp(0f, 1f), (color.Saturation * value).Clamp(0f, 1f), (color.Value * value).Clamp(0f, 1f));
|
||||
public static ColorHSV operator /(ColorHSV color, float value) => new((color.Hue / value).Clamp(0f, 1f), (color.Saturation / value).Clamp(0f, 1f), (color.Value / value).Clamp(0f, 1f));
|
||||
public static bool operator ==(ColorHSV left, ColorHSV right) => left.Hue.ApproximatelyEquals(right.Hue) && left.Saturation.ApproximatelyEquals(right.Saturation) && left.Value.ApproximatelyEquals(right.Value);
|
||||
public static bool operator !=(ColorHSV left, ColorHSV right) => !left.Hue.ApproximatelyEquals(right.Hue) || !left.Saturation.ApproximatelyEquals(right.Saturation) || !left.Value.ApproximatelyEquals(right.Value);
|
||||
|
||||
public static implicit operator ColorHSV(ColorHSVA hsva) => new(hsva.Hue, hsva.Saturation, hsva.Value);
|
||||
public static implicit operator ColorHSV(ColorRGBA rgba) => (ColorHSVA)rgba;
|
||||
public static implicit operator ColorHSV(ColorRGB rgb) => (ColorHSVA)rgb;
|
||||
public static implicit operator ColorHSV(ColorRGBA rgba) => (ColorRGB)rgba;
|
||||
public static implicit operator ColorHSV(ColorRGB rgb)
|
||||
{
|
||||
float hue;
|
||||
float saturation;
|
||||
float value;
|
||||
|
||||
float rd = rgb.R / 255f;
|
||||
float gd = rgb.G / 255f;
|
||||
float bd = rgb.B / 255f;
|
||||
|
||||
float max = Math.Max(rd, Math.Max(gd, bd));
|
||||
float min = Math.Min(rd, Math.Min(gd, bd));
|
||||
float delta = max - min;
|
||||
|
||||
if (delta.ApproximatelyEquals(0))
|
||||
hue = 0f;
|
||||
else if (max.ApproximatelyEquals(rd))
|
||||
hue = 60f * ((gd - bd) / delta % 6f);
|
||||
else if (max.ApproximatelyEquals(gd))
|
||||
hue = 60f * (((bd - rd) / delta) + 2f);
|
||||
else
|
||||
hue = 60f * (((rd - gd) / delta) + 4f);
|
||||
|
||||
if (hue < 0f)
|
||||
hue += 360f;
|
||||
|
||||
hue /= 360f;
|
||||
saturation = max.ApproximatelyEquals(0f) ? 0f : delta / max;
|
||||
value = max;
|
||||
|
||||
return new(hue, saturation, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inverts the given <see cref="ColorHSV"/>.
|
||||
@@ -82,6 +110,14 @@ public readonly struct ColorHSV(float hue, float saturation, float value) : IEqu
|
||||
/// <returns>The result of dividing the <see cref="ColorHSV"/> by the scalar value.</returns>
|
||||
public static ColorHSV Divide(ColorHSV color, float value) => color / value;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the <see cref="ColorHSV"/> from one point to another.
|
||||
/// </summary>
|
||||
/// <param name="from">The starting point.</param>
|
||||
/// <param name="to">The ending point.</param>
|
||||
/// <returns>The <see cref="ColorHSV"/> from the starting point to the ending point.</returns>
|
||||
public static ColorHSV FromTo(ColorHSV from, ColorHSV to) => to - from;
|
||||
|
||||
/// <summary>
|
||||
/// Performs linear interpolation between two <see cref="ColorHSV"/>s.
|
||||
/// </summary>
|
||||
@@ -89,14 +125,13 @@ public readonly struct ColorHSV(float hue, float saturation, float value) : IEqu
|
||||
/// <param name="to">The ending <see cref="ColorHSV"/> (t = 1).</param>
|
||||
/// <param name="t">The interpolation parameter.</param>
|
||||
/// <returns>The interpolated <see cref="ColorHSV"/>.</returns>
|
||||
public static ColorHSV Lerp(ColorHSV from, ColorHSV to, float t)
|
||||
{
|
||||
float hueDiff = to.Hue - from.Hue;
|
||||
float saturationDiff = to.Saturation - from.Saturation;
|
||||
float valueDiff = to.Value - from.Value;
|
||||
public static ColorHSV Lerp(ColorHSV from, ColorHSV to, float t) => from + FromTo(from, to) * t;
|
||||
|
||||
return from + new ColorHSV(hueDiff * t, saturationDiff * t, valueDiff * t);
|
||||
}
|
||||
/// <summary>
|
||||
/// Converts the <see cref="ColorHSV"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="ColorHSV"/>.</returns>
|
||||
public override string ToString() => $"{nameof(ColorHSV)}({Hue}, {Saturation}, {Value})";
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="ColorHSV"/>s are approximately equal within a specified epsilon range.
|
||||
@@ -113,20 +148,13 @@ public readonly struct ColorHSV(float hue, float saturation, float value) : IEqu
|
||||
/// </summary>
|
||||
/// <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;
|
||||
public override bool Equals(object? obj) => obj is ColorHSV objVec && Hue.Equals(objVec.Hue) && Saturation.Equals(objVec.Saturation) && Value.Equals(objVec.Value);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the <see cref="ColorHSV"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="ColorHSV"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(Hue, Saturation, Value);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="ColorHSV"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="ColorHSV"/>.</returns>
|
||||
public override string ToString() => $"{nameof(ColorHSV)}({Hue}, {Saturation}, {Value})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -146,6 +174,9 @@ public static class ColorHSVExtensions
|
||||
/// <inheritdoc cref="ColorHSV.Divide(ColorHSV, ColorHSV)" />
|
||||
public static ColorHSV Divide(this ColorHSV color, float value) => ColorHSV.Divide(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSV.FromTo(ColorHSV, ColorHSV)" />
|
||||
public static ColorHSV FromTo(this ColorHSV from, ColorHSV to) => ColorHSV.FromTo(from, to);
|
||||
|
||||
/// <inheritdoc cref="ColorHSV.Lerp(ColorHSV, ColorHSV, float)" />
|
||||
public static ColorHSV Lerp(this ColorHSV from, ColorHSV to, float t) => ColorHSV.Lerp(from, to, t);
|
||||
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an HSV color.
|
||||
/// </summary>
|
||||
/// <param name="hue">Hue of the <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="saturation">Saturation of the <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="value">Value of the <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="alpha">Alpha of the <see cref="ColorHSVA"/>.</param>
|
||||
/// <remarks>
|
||||
/// 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) : IEquatable<ColorHSVA>
|
||||
{
|
||||
/// <summary>
|
||||
/// The Hue value of the <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
public readonly float Hue = hue.Clamp(0f, 1f);
|
||||
|
||||
/// <summary>
|
||||
/// The Saturation value of the <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
public readonly float Saturation = saturation.Clamp(0f, 1f);
|
||||
|
||||
/// <summary>
|
||||
/// The Value value of the <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
public readonly float Value = value.Clamp(0f, 1f);
|
||||
|
||||
/// <summary>
|
||||
/// The Alpha value of the <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
public readonly float Alpha = alpha;
|
||||
|
||||
public static ColorHSVA operator -(ColorHSVA color) => new(color.Hue.OneMinus(), color.Saturation.OneMinus(), color.Value.OneMinus(), color.Alpha);
|
||||
public static ColorHSVA operator +(ColorHSVA left, ColorHSVA right) => new(left.Hue + right.Hue, left.Saturation + right.Saturation, left.Value + right.Value, left.Alpha + right.Alpha);
|
||||
public static ColorHSVA operator -(ColorHSVA left, ColorHSVA right) => new(left.Hue - right.Hue, left.Saturation - right.Saturation, left.Value - right.Value, left.Alpha - right.Alpha);
|
||||
public static ColorHSVA operator *(ColorHSVA left, ColorHSVA right) => new(left.Hue * right.Hue, left.Saturation * right.Saturation, left.Value * right.Value, left.Alpha * right.Alpha);
|
||||
public static ColorHSVA operator *(ColorHSVA color, float value) => new(color.Hue * value, color.Saturation * value, color.Value * value, color.Alpha * value);
|
||||
public static ColorHSVA operator *(float value, ColorHSVA color) => new(color.Hue * value, color.Saturation * value, color.Value * value, color.Alpha * value);
|
||||
public static ColorHSVA operator /(ColorHSVA color, float value) => new(color.Hue / value, color.Saturation / value, color.Value / value, color.Alpha / value);
|
||||
public static bool operator ==(ColorHSVA left, ColorHSVA right) => left.Hue == right.Hue && left.Saturation == right.Saturation && left.Value == right.Value;
|
||||
public static bool operator !=(ColorHSVA left, ColorHSVA right) => left.Hue != right.Hue || left.Saturation != right.Saturation || left.Value != right.Value;
|
||||
|
||||
public static implicit operator ColorHSVA(ColorHSV hsv) => new(hsv.Hue, hsv.Saturation, hsv.Value, 1f);
|
||||
public static implicit operator ColorHSVA(ColorRGB rgb) => (ColorRGBA)rgb;
|
||||
public static implicit operator ColorHSVA(ColorRGBA rgba)
|
||||
{
|
||||
float hue;
|
||||
float saturation;
|
||||
float value;
|
||||
|
||||
float rd = rgba.R / 255f;
|
||||
float gd = rgba.G / 255f;
|
||||
float bd = rgba.B / 255f;
|
||||
|
||||
float max = Math.Max(rd, Math.Max(gd, bd));
|
||||
float min = Math.Min(rd, Math.Min(gd, bd));
|
||||
float delta = max - min;
|
||||
|
||||
if (delta.ApproximatelyEquals(0))
|
||||
hue = 0f;
|
||||
else if (max.ApproximatelyEquals(rd))
|
||||
hue = 60f * ((gd - bd) / delta % 6f);
|
||||
else if (max.ApproximatelyEquals(gd))
|
||||
hue = 60f * (((bd - rd) / delta) + 2f);
|
||||
else
|
||||
hue = 60f * (((rd - gd) / delta) + 4f);
|
||||
|
||||
if (hue < 0f)
|
||||
hue += 360f;
|
||||
|
||||
hue /= 360f;
|
||||
saturation = max.ApproximatelyEquals(0f) ? 0f : delta / max;
|
||||
value = max;
|
||||
|
||||
return new(hue, saturation, value, rgba.A / 255f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inverts the given <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorHSVA"/>.</param>
|
||||
/// <returns>The inverted <see cref="ColorHSVA"/>.</returns>
|
||||
public static ColorHSVA Invert(ColorHSVA color) => -color;
|
||||
|
||||
/// <summary>
|
||||
/// Adds two <see cref="ColorHSVA"/>s.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="right">The second <see cref="ColorHSVA"/>.</param>
|
||||
/// <returns>The sum of the two <see cref="ColorHSVA"/>s.</returns>
|
||||
public static ColorHSVA Add(ColorHSVA left, ColorHSVA right) => left + right;
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts one <see cref="ColorHSVA"/> from another.
|
||||
/// </summary>
|
||||
/// <param name="left">The <see cref="ColorHSVA"/> to subtract from.</param>
|
||||
/// <param name="right">The <see cref="ColorHSVA"/> to subtract.</param>
|
||||
/// <returns>The result of subtracting the second <see cref="ColorHSVA"/> from the first.</returns>
|
||||
public static ColorHSVA Subtract(ColorHSVA left, ColorHSVA right) => left - right;
|
||||
|
||||
/// <summary>
|
||||
/// Multiplies a <see cref="ColorHSVA"/> by a scalar value.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="value">The scalar value.</param>
|
||||
/// <returns>The result of multiplying the <see cref="ColorHSVA"/> by the scalar value.</returns>
|
||||
public static ColorHSVA Multiply(ColorHSVA color, float value) => color * value;
|
||||
|
||||
/// <summary>
|
||||
/// Divides a <see cref="ColorHSVA"/> by a scalar value.
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="value">The scalar value.</param>
|
||||
/// <returns>The result of dividing the <see cref="ColorHSVA"/> by the scalar value.</returns>
|
||||
public static ColorHSVA Divide(ColorHSVA color, float value) => color / value;
|
||||
|
||||
/// <summary>
|
||||
/// Performs linear interpolation between two <see cref="ColorHSVA"/>s.
|
||||
/// </summary>
|
||||
/// <param name="from">The starting <see cref="ColorHSVA"/> (t = 0).</param>
|
||||
/// <param name="to">The ending <see cref="ColorHSVA"/> (t = 1).</param>
|
||||
/// <param name="t">The interpolation parameter.</param>
|
||||
/// <returns>The interpolated <see cref="ColorHSVA"/>.</returns>
|
||||
public static ColorHSVA Lerp(ColorHSVA from, ColorHSVA to, float t)
|
||||
{
|
||||
float hueDiff = to.Hue - from.Hue;
|
||||
float saturationDiff = to.Saturation - from.Saturation;
|
||||
float valueDiff = to.Value - from.Value;
|
||||
float alphaDiff = to.Alpha - from.Alpha;
|
||||
|
||||
return from + new ColorHSVA(hueDiff * t, saturationDiff * t, valueDiff * t, alphaDiff * t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="ColorHSVA"/>s are approximately equal within a specified epsilon range.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="right">The second <see cref="ColorHSVA"/>.</param>
|
||||
/// <param name="epsilon">The epsilon range.</param>
|
||||
/// <returns><see cref="true"/> if the <see cref="ColorHSVA"/>s are approximately equal; otherwise, <see cref="false"/>.</returns>
|
||||
public static bool ApproximatelyEquals(ColorHSVA left, ColorHSVA right, float epsilon = float.Epsilon)
|
||||
=> left.Hue.ApproximatelyEquals(right.Hue, epsilon) && left.Saturation.ApproximatelyEquals(right.Saturation, epsilon) && left.Value.ApproximatelyEquals(right.Value, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="ColorHSVA"/>.
|
||||
/// </summary>
|
||||
/// <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"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="ColorHSVA"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(Hue, Saturation, Value);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="ColorHSVA"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="ColorHSVA"/>.</returns>
|
||||
public override string ToString() => $"{nameof(ColorHSVA)}({Hue}, {Saturation}, {Value})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="ColorHSVA"/> type.
|
||||
/// </summary>
|
||||
public static class ColorHSVAExtensions
|
||||
{
|
||||
/// <inheritdoc cref="ColorHSVA.Add(ColorHSVA, ColorHSVA)" />
|
||||
public static ColorHSVA Add(this ColorHSVA color, ColorHSVA value) => ColorHSVA.Add(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSVA.Subtract(ColorHSVA, ColorHSVA)" />
|
||||
public static ColorHSVA Subtract(this ColorHSVA color, ColorHSVA value) => ColorHSVA.Subtract(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSVA.Multiply(ColorHSVA, ColorHSVA)" />
|
||||
public static ColorHSVA Multiply(this ColorHSVA color, float value) => ColorHSVA.Multiply(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSVA.Divide(ColorHSVA, ColorHSVA)" />
|
||||
public static ColorHSVA Divide(this ColorHSVA color, float value) => ColorHSVA.Divide(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorHSVA.Lerp(ColorHSVA, ColorHSVA, float)" />
|
||||
public static ColorHSVA Lerp(this ColorHSVA from, ColorHSVA to, float t) => ColorHSVA.Lerp(from, to, t);
|
||||
|
||||
/// <inheritdoc cref="ColorHSVA.ApproximatelyEquals(ColorHSVA, ColorHSVA, float) " />
|
||||
public static bool ApproximatelyEquals(this ColorHSVA left, ColorHSVA right, float epsilon = float.Epsilon) => ColorHSVA.ApproximatelyEquals(left, right, epsilon);
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an RGB color.
|
||||
@@ -12,7 +10,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) : IEquatable<ColorRGB>
|
||||
public readonly struct ColorRGB(byte r, byte g, byte b)
|
||||
{
|
||||
/// <summary>
|
||||
/// The Red value of the <see cref="ColorRGB"/>.
|
||||
@@ -40,8 +38,30 @@ public readonly struct ColorRGB(byte r, byte g, byte b) : IEquatable<ColorRGB>
|
||||
public static bool operator !=(ColorRGB left, ColorRGB right) => left.R != right.R || left.G != right.G || left.B != right.B;
|
||||
|
||||
public static implicit operator ColorRGB(ColorRGBA rgba) => new(rgba.R, rgba.G, rgba.B);
|
||||
public static implicit operator ColorRGB(ColorHSVA hsva) => (ColorRGBA)hsva;
|
||||
public static implicit operator ColorRGB(ColorHSV hsv) => (ColorRGBA)hsv;
|
||||
public static implicit operator ColorRGB(ColorHSV hsv)
|
||||
{
|
||||
float hue = hsv.Hue * 360f;
|
||||
float chroma = hsv.Value * hsv.Saturation;
|
||||
float x = chroma * (1f - Math.Abs(hue / 60f % 2f - 1f));
|
||||
float m = hsv.Value - chroma;
|
||||
|
||||
float r1 = 0f;
|
||||
float g1 = 0f;
|
||||
float b1 = 0f;
|
||||
|
||||
if (hue < 60) { r1 = chroma; g1 = x; b1 = 0; }
|
||||
else if (hue < 120) { r1 = x; g1 = chroma; b1 = 0; }
|
||||
else if (hue < 180) { r1 = 0; g1 = chroma; b1 = x; }
|
||||
else if (hue < 240) { r1 = 0; g1 = x; b1 = chroma; }
|
||||
else if (hue < 300) { r1 = x; g1 = 0; b1 = chroma; }
|
||||
else if (hue <= 360) { r1 = chroma; g1 = 0; b1 = x; }
|
||||
|
||||
byte r = (byte)Math.RoundToInt((r1 + m) * 255);
|
||||
byte g = (byte)Math.RoundToInt((g1 + m) * 255);
|
||||
byte b = (byte)Math.RoundToInt((b1 + m) * 255);
|
||||
|
||||
return new(r, g, b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inverts the given <see cref="ColorRGB"/>.
|
||||
@@ -82,6 +102,14 @@ public readonly struct ColorRGB(byte r, byte g, byte b) : IEquatable<ColorRGB>
|
||||
/// <returns>The result of dividing the <see cref="ColorRGB"/> by the scalar value.</returns>
|
||||
public static ColorRGB Divide(ColorRGB color, float value) => color / value;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the <see cref="ColorRGB"/> from one point to another.
|
||||
/// </summary>
|
||||
/// <param name="from">The starting point.</param>
|
||||
/// <param name="to">The ending point.</param>
|
||||
/// <returns>The <see cref="ColorRGB"/> from the starting point to the ending point.</returns>
|
||||
public static ColorRGB FromTo(ColorRGB from, ColorRGB to) => to - from;
|
||||
|
||||
/// <summary>
|
||||
/// Performs linear interpolation between two <see cref="ColorRGB"/>s.
|
||||
/// </summary>
|
||||
@@ -89,34 +117,26 @@ public readonly struct ColorRGB(byte r, byte g, byte b) : IEquatable<ColorRGB>
|
||||
/// <param name="to">The ending <see cref="ColorRGB"/> (t = 1).</param>
|
||||
/// <param name="t">The interpolation parameter.</param>
|
||||
/// <returns>The interpolated <see cref="ColorRGB"/>.</returns>
|
||||
public static ColorRGB Lerp(ColorRGB from, ColorRGB to, float t)
|
||||
{
|
||||
int redDiff = to.R - from.R;
|
||||
int greenDiff = to.G - from.G;
|
||||
int blueDiff = to.B - from.B;
|
||||
|
||||
return from + new ColorRGB((byte)(redDiff * t), (byte)(greenDiff * t), (byte)(blueDiff * t));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="ColorRGB"/>.
|
||||
/// </summary>
|
||||
/// <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"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="ColorRGB"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(R, G, B);
|
||||
public static ColorRGB Lerp(ColorRGB from, ColorRGB to, float t) => from + FromTo(from, to) * t;
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="ColorRGB"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="ColorRGB"/>.</returns>
|
||||
public override string ToString() => $"{nameof(ColorRGB)}({R}, {G}, {B})";
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="ColorRGB"/>.
|
||||
/// </summary>
|
||||
/// <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 objVec && R.Equals(objVec.R) && G.Equals(objVec.G) && B.Equals(objVec.B);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the <see cref="ColorRGB"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="ColorRGB"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(R, G, B);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -136,6 +156,9 @@ public static class ColorRGBExtensions
|
||||
/// <inheritdoc cref="ColorRGB.Divide(ColorRGB, ColorRGB)" />
|
||||
public static ColorRGB Divide(this ColorRGB color, float value) => ColorRGB.Divide(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorRGB.FromTo(ColorRGB, ColorRGB)" />
|
||||
public static ColorRGB FromTo(this ColorRGB from, ColorRGB to) => ColorRGB.FromTo(from, to);
|
||||
|
||||
/// <inheritdoc cref="ColorRGB.Lerp(ColorRGB, ColorRGB, float)" />
|
||||
public static ColorRGB Lerp(this ColorRGB from, ColorRGB to, float t) => ColorRGB.Lerp(from, to, t);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an RGBA color.
|
||||
@@ -13,7 +11,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) : IEquatable<ColorRGBA>
|
||||
public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255)
|
||||
{
|
||||
/// <summary>
|
||||
/// The Red value of the <see cref="ColorRGBA"/>.
|
||||
@@ -46,31 +44,7 @@ public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255) : IEquata
|
||||
public static bool operator !=(ColorRGBA left, ColorRGBA right) => left.R != right.R || left.G != right.G || left.B != right.B || left.A != right.A;
|
||||
|
||||
public static implicit operator ColorRGBA(ColorRGB rgb) => new(rgb.R, rgb.G, rgb.B, 255);
|
||||
public static implicit operator ColorRGBA(ColorHSV hsv) => (ColorHSVA)hsv;
|
||||
public static implicit operator ColorRGBA(ColorHSVA hsva)
|
||||
{
|
||||
float hue = hsva.Hue * 360f;
|
||||
float chroma = hsva.Value * hsva.Saturation;
|
||||
float x = chroma * (1f - Math.Abs(hue / 60f % 2f - 1f));
|
||||
float m = hsva.Value - chroma;
|
||||
|
||||
float r1 = 0f;
|
||||
float g1 = 0f;
|
||||
float b1 = 0f;
|
||||
|
||||
if (hue < 60) { r1 = chroma; g1 = x; b1 = 0; }
|
||||
else if (hue < 120) { r1 = x; g1 = chroma; b1 = 0; }
|
||||
else if (hue < 180) { r1 = 0; g1 = chroma; b1 = x; }
|
||||
else if (hue < 240) { r1 = 0; g1 = x; b1 = chroma; }
|
||||
else if (hue < 300) { r1 = x; g1 = 0; b1 = chroma; }
|
||||
else if (hue <= 360) { r1 = chroma; g1 = 0; b1 = x; }
|
||||
|
||||
byte r = (byte)Math.RoundToInt((r1 + m) * 255);
|
||||
byte g = (byte)Math.RoundToInt((g1 + m) * 255);
|
||||
byte b = (byte)Math.RoundToInt((b1 + m) * 255);
|
||||
|
||||
return new(r, g, b, (byte)(hsva.Alpha * 255));
|
||||
}
|
||||
public static implicit operator ColorRGBA(ColorHSV hsv) => (ColorRGB)hsv;
|
||||
|
||||
/// <summary>
|
||||
/// Inverts the given <see cref="ColorRGBA"/>.
|
||||
@@ -111,6 +85,14 @@ public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255) : IEquata
|
||||
/// <returns>The result of dividing the <see cref="ColorRGBA"/> by the scalar value.</returns>
|
||||
public static ColorRGBA Divide(ColorRGBA color, float value) => color / value;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the <see cref="ColorRGBA"/> from one point to another.
|
||||
/// </summary>
|
||||
/// <param name="from">The starting point.</param>
|
||||
/// <param name="to">The ending point.</param>
|
||||
/// <returns>The <see cref="ColorRGBA"/> from the starting point to the ending point.</returns>
|
||||
public static ColorRGBA FromTo(ColorRGBA from, ColorRGBA to) => to - from;
|
||||
|
||||
/// <summary>
|
||||
/// Performs linear interpolation between two <see cref="ColorRGBA"/>s.
|
||||
/// </summary>
|
||||
@@ -118,35 +100,26 @@ public readonly struct ColorRGBA(byte r, byte g, byte b, byte a = 255) : IEquata
|
||||
/// <param name="to">The ending <see cref="ColorRGBA"/> (t = 1).</param>
|
||||
/// <param name="t">The interpolation parameter.</param>
|
||||
/// <returns>The interpolated <see cref="ColorRGBA"/>.</returns>
|
||||
public static ColorRGBA Lerp(ColorRGBA from, ColorRGBA to, float t)
|
||||
{
|
||||
int redDiff = to.R - from.R;
|
||||
int greenDiff = to.G - from.G;
|
||||
int blueDiff = to.B - from.B;
|
||||
int alphaDiff = to.A - from.A;
|
||||
|
||||
return from + new ColorRGBA((byte)(redDiff * t), (byte)(greenDiff * t), (byte)(blueDiff * t), (byte)(alphaDiff * t));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="ColorRGBA"/>.
|
||||
/// </summary>
|
||||
/// <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"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="ColorRGBA"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(R, G, B, A);
|
||||
public static ColorRGBA Lerp(ColorRGBA from, ColorRGBA to, float t) => from + FromTo(from, to) * t;
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="ColorRGBA"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="ColorRGBA"/>.</returns>
|
||||
public override string ToString() => $"{nameof(ColorRGBA)}({R}, {G}, {B}, {A})";
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="ColorRGBA"/>.
|
||||
/// </summary>
|
||||
/// <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 objVec && R.Equals(objVec.R) && G.Equals(objVec.G) && B.Equals(objVec.B) && A.Equals(objVec.A);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the <see cref="ColorRGBA"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="ColorRGBA"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(R, G, B, A);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -166,6 +139,9 @@ public static class ColorRGBAExtensions
|
||||
/// <inheritdoc cref="ColorRGBA.Divide(ColorRGBA, ColorRGBA)" />
|
||||
public static ColorRGBA Divide(this ColorRGBA color, float value) => ColorRGBA.Divide(color, value);
|
||||
|
||||
/// <inheritdoc cref="ColorRGBA.FromTo(ColorRGBA, ColorRGBA)" />
|
||||
public static ColorRGBA FromTo(this ColorRGBA from, ColorRGBA to) => ColorRGBA.FromTo(from, to);
|
||||
|
||||
/// <inheritdoc cref="ColorRGBA.Lerp(ColorRGBA, ColorRGBA, float)" />
|
||||
public static ColorRGBA Lerp(this ColorRGBA from, ColorRGBA to, float t) => ColorRGBA.Lerp(from, to, t);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a 2D line segment defined by two endpoints.
|
||||
@@ -12,7 +11,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) : IEquatable<Line2D>
|
||||
public readonly struct Line2D(Vector2D from, Vector2D to)
|
||||
{
|
||||
/// <summary>
|
||||
/// The starting point of the <see cref="Line2D"/> segment.
|
||||
@@ -44,9 +43,6 @@ public readonly struct Line2D(Vector2D from, Vector2D to) : IEquatable<Line2D>
|
||||
/// </summary>
|
||||
public readonly float LengthSquared => From.FromTo(To).LengthSquared();
|
||||
|
||||
public static bool operator ==(Line2D left, Line2D right) => left.From == right.From && left.To == right.To;
|
||||
public static bool operator !=(Line2D left, Line2D right) => left.From != right.From || left.To != right.To;
|
||||
|
||||
/// <summary>
|
||||
/// The equation of the <see cref="Line2D"/> defined by this <see cref="Line2D"/> segment.
|
||||
/// </summary>
|
||||
@@ -171,14 +167,17 @@ public readonly struct Line2D(Vector2D from, Vector2D to) : IEquatable<Line2D>
|
||||
/// </summary>
|
||||
public static Vector2D ClosestPointTo(Line2D line, Vector2D point)
|
||||
{
|
||||
Vector2D lineRelativeVector = line.From.FromTo(line.To);
|
||||
Vector2D edgeVector = line.From.FromTo(line.To);
|
||||
Vector2D pointVector = point - line.From;
|
||||
|
||||
Vector2D lineDirection = lineRelativeVector.Normalized;
|
||||
Vector2D pointVector = line.From.FromTo(point);
|
||||
float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y);
|
||||
|
||||
float dot = lineDirection.Dot(pointVector).Clamp(0f, lineRelativeVector.Magnitude);
|
||||
t = Math.Max(0, Math.Min(1, t));
|
||||
|
||||
return lineDirection * dot;
|
||||
float closestX = line.From.X + t * edgeVector.X;
|
||||
float closestY = line.From.Y + t * edgeVector.Y;
|
||||
|
||||
return new Vector2D((float)closestX, (float)closestY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -190,26 +189,6 @@ public readonly struct Line2D(Vector2D from, Vector2D to) : IEquatable<Line2D>
|
||||
/// <returns><see cref="true"/> if the <see cref="Line2D"/>s are approximately equal; otherwise, <see cref="false"/>.</returns>
|
||||
public static bool ApproximatelyEquals(Line2D left, Line2D right, float epsilon = float.Epsilon)
|
||||
=> left.From.ApproximatelyEquals(right.From, epsilon) && left.To.ApproximatelyEquals(right.To, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="Line2D"/>.
|
||||
/// </summary>
|
||||
/// <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"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Line2D"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(From, To);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Line2D"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Line2D"/>.</returns>
|
||||
public override string ToString() => $"{nameof(Line2D)}({From}, {To})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -226,9 +205,6 @@ public static class Line2DExtensions
|
||||
/// <inheritdoc cref="Line2D.Intersects(Line2D, Vector2D)" />
|
||||
public static bool Intersects(this Line2D line, Vector2D point) => Line2D.Intersects(line, point);
|
||||
|
||||
/// <inheritdoc cref="Line2D.IntersectionPoint(Line2D, Line2D)" />
|
||||
public static Vector2D IntersectionPoint(this Line2D left, Line2D right) => Line2D.IntersectionPoint(left, right);
|
||||
|
||||
/// <inheritdoc cref="Line2D.GetT(Line2D, Vector2D)" />
|
||||
public static float GetT(this Line2D line, Vector2D point) => Line2D.GetT(line, point);
|
||||
|
||||
@@ -238,9 +214,6 @@ public static class Line2DExtensions
|
||||
/// <inheritdoc cref="Line2D.Intersects(Line2D, Line2D, out Vector2D?)" />
|
||||
public static bool Intersects(this Line2D left, Line2D right, [NotNullWhen(returnValue: true)] out Vector2D? point) => Line2D.Intersects(left, right, out point);
|
||||
|
||||
/// <inheritdoc cref="Line2D.ClosestPointTo(Line2D, Vector2D)" />
|
||||
public static Vector2D ClosestPointTo(this Line2D line, Vector2D point) => Line2D.ClosestPointTo(line, point);
|
||||
|
||||
/// <inheritdoc cref="Line2D.ApproximatelyEquals(Line2D, Line2D, float)" />
|
||||
public static bool ApproximatelyEquals(this Line2D left, Line2D right, float epsilon = float.Epsilon) => Line2D.ApproximatelyEquals(left, right, epsilon);
|
||||
}
|
||||
|
||||
@@ -1,72 +1,47 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a <see cref="Line2DEquation"/> in the form y = mx + b.
|
||||
/// Represents a line equation in the form y = mx + b.
|
||||
/// </summary>
|
||||
/// <param name="slope">The slope of the line.</param>
|
||||
/// <param name="offsetY">The Y intercept of the line.</param>
|
||||
/// <param name="offsetY">The y-intercept of the line.</param>
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of the <see cref="Line2DEquation"/> struct with the specified slope and Y intercept.
|
||||
/// 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) : IEquatable<Line2DEquation>
|
||||
public readonly struct Line2DEquation(float slope, float offsetY)
|
||||
{
|
||||
/// <summary>
|
||||
/// The slope of the <see cref="Line2DEquation"/>.
|
||||
/// The slope of the line equation.
|
||||
/// </summary>
|
||||
public readonly float Slope = slope;
|
||||
|
||||
/// <summary>
|
||||
/// The Y intercept of the <see cref="Line2DEquation"/>.
|
||||
/// The y-intercept of the line equation.
|
||||
/// </summary>
|
||||
public readonly float OffsetY = offsetY;
|
||||
|
||||
public static bool operator ==(Line2DEquation left, Line2DEquation right) => left.Slope == right.Slope && left.OffsetY == right.OffsetY;
|
||||
public static bool operator !=(Line2DEquation left, Line2DEquation right) => left.Slope != right.Slope || left.OffsetY != right.OffsetY;
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the Y coordinate for a given X coordinate using the <see cref="Line2DEquation"/>.
|
||||
/// Resolves the y-coordinate for a given x-coordinate using the line equation.
|
||||
/// </summary>
|
||||
/// <param name="lineEquation">The <see cref="Line2DEquation"/> to resolve.</param>
|
||||
/// <param name="x">The X coordinate for which to resolve the Y coordinate.</param>
|
||||
/// <returns>The Y coordinate resolved using the <see cref="Line2DEquation"/>.</returns>
|
||||
/// <param name="lineEquation">The line equation to resolve.</param>
|
||||
/// <param name="x">The x-coordinate for which to resolve the y-coordinate.</param>
|
||||
/// <returns>The y-coordinate resolved using the line equation.</returns>
|
||||
public static float Resolve(Line2DEquation lineEquation, float x) => lineEquation.Slope * x + lineEquation.OffsetY; // y = mx + b
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Line2DEquation"/> are approximately equal.
|
||||
/// Checks if two line equations are approximately equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="Line2DEquation"/> to compare.</param>
|
||||
/// <param name="right">The second <see cref="Line2DEquation"/> to compare.</param>
|
||||
/// <param name="left">The first line equation to compare.</param>
|
||||
/// <param name="right">The second line equation to compare.</param>
|
||||
/// <param name="epsilon">The epsilon range.</param>
|
||||
/// <returns>True if the <see cref="Line2DEquation"/> are approximately equal; otherwise, false.</returns>
|
||||
/// <returns>True if the line equations are approximately equal; otherwise, false.</returns>
|
||||
public static bool ApproximatelyEquals(Line2DEquation left, Line2DEquation right, float epsilon = float.Epsilon)
|
||||
=> left.Slope.ApproximatelyEquals(right.Slope, epsilon) && left.OffsetY.ApproximatelyEquals(right.OffsetY, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="Line2DEquation"/>.
|
||||
/// </summary>
|
||||
/// <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"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Line2DEquation"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(Slope, OffsetY);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Line2DEquation"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Line2DEquation"/>.</returns>
|
||||
public override string ToString() => $"{nameof(Line2DEquation)}({Slope}, {OffsetY})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for the <see cref="Line2DEquation"/> struct.
|
||||
/// Provides extension methods for the LineEquation struct.
|
||||
/// </summary>
|
||||
public static class Line2DEquationExtensions
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a range of values along a single axis.
|
||||
@@ -11,7 +9,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) : IEquatable<Projection1D>
|
||||
public readonly struct Projection1D(float min, float max)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the minimum value of the projection.
|
||||
@@ -23,9 +21,6 @@ public readonly struct Projection1D(float min, float max) : IEquatable<Projectio
|
||||
/// </summary>
|
||||
public readonly float Max = max;
|
||||
|
||||
public static bool operator ==(Projection1D left, Projection1D right) => left.Min == right.Min && left.Max == right.Max;
|
||||
public static bool operator !=(Projection1D left, Projection1D right) => left.Min != right.Min || left.Max != right.Max;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two projections overlap.
|
||||
/// </summary>
|
||||
@@ -75,36 +70,6 @@ public readonly struct Projection1D(float min, float max) : IEquatable<Projectio
|
||||
depth = 0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Projection1D"/>s are approximately equal within a specified epsilon range.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="Projection1D"/>.</param>
|
||||
/// <param name="right">The second <see cref="Projection1D"/>.</param>
|
||||
/// <param name="epsilon">The epsilon range.</param>
|
||||
/// <returns><see cref="true"/> if the <see cref="Projection1D"/>s are approximately equal; otherwise, <see cref="false"/>.</returns>
|
||||
public static bool ApproximatelyEquals(Projection1D left, Projection1D right, float epsilon = float.Epsilon)
|
||||
=> left.Min.ApproximatelyEquals(right.Min, epsilon) && left.Max.ApproximatelyEquals(right.Max, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="Projection1D"/>.
|
||||
/// </summary>
|
||||
/// <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"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Projection1D"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(Min, Max);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Projection1D"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Projection1D"/>.</returns>
|
||||
public override string ToString() => $"{nameof(Projection1D)}({Min}, {Max})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -117,7 +82,4 @@ public static class Projection1DExtensions
|
||||
|
||||
/// <inheritdoc cref="Projection1D.Overlaps(Projection1D, Projection1D, out float)" />
|
||||
public static bool Overlaps(this Projection1D left, Projection1D right, out float depth) => Projection1D.Overlaps(left, right, out depth);
|
||||
|
||||
/// <inheritdoc cref="Projection1D.ApproximatelyEquals(Projection1D, Projection1D, float)" />
|
||||
public static bool ApproximatelyEquals(this Projection1D left, Projection1D right, float epsilon = float.Epsilon) => Projection1D.ApproximatelyEquals(left, right, epsilon);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a 3D space rotation.
|
||||
@@ -13,7 +11,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) : IEquatable<Quaternion>
|
||||
public readonly struct Quaternion(float x, float y, float z, float w)
|
||||
{
|
||||
/// <summary>
|
||||
/// The X(i) imaginary of the <see cref="Quaternion"/>.
|
||||
@@ -284,25 +282,24 @@ public readonly struct Quaternion(float x, float y, float z, float w) : IEquatab
|
||||
public static bool ApproximatelyEquals(Quaternion left, Quaternion right, float epsilon = float.Epsilon)
|
||||
=> left.X.ApproximatelyEquals(right.X, epsilon) && left.Y.ApproximatelyEquals(right.Y, epsilon) && left.Z.ApproximatelyEquals(right.Z, epsilon) && left.W.ApproximatelyEquals(right.W, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Quaternion"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Quaternion"/>.</returns>
|
||||
public override string ToString() => $"{nameof(Quaternion)}({W}, {X}, {Y}, {Z})";
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="Quaternion"/>.
|
||||
/// </summary>
|
||||
/// <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;
|
||||
public override bool Equals(object? obj) => obj is Quaternion objVec && X.Equals(objVec.X) && Y.Equals(objVec.Y) && Z.Equals(objVec.Z) && W.Equals(objVec.W);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the <see cref="Quaternion"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Quaternion"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(W, X, Y, Z);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Quaternion"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Quaternion"/>.</returns>
|
||||
public override string ToString() => $"{nameof(Quaternion)}({W}, {X}, {Y}, {Z})";
|
||||
public override int GetHashCode() => System.HashCode.Combine(X, Y, Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an infinite ray in 2D space.
|
||||
/// </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) : IEquatable<Ray2D>
|
||||
{
|
||||
/// <summary>
|
||||
/// The starting point of the <see cref="Ray2D"/>.
|
||||
/// </summary>
|
||||
public readonly Vector2D Origin = Origin;
|
||||
|
||||
/// <summary>
|
||||
/// The direction in which the <see cref="Ray2D"/> points. Should be a normalized vector.
|
||||
/// </summary>
|
||||
public readonly Vector2D Direction = Direction;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="Ray2D"/> with the same origin but with the direction reversed.
|
||||
/// </summary>
|
||||
public readonly Ray2D Reversed => new(Origin, -Direction);
|
||||
|
||||
public static bool operator ==(Ray2D left, Ray2D right) => left.Origin == right.Origin && left.Direction == right.Direction;
|
||||
public static bool operator !=(Ray2D left, Ray2D right) => left.Origin != right.Origin || left.Direction != right.Direction;
|
||||
public static implicit operator Ray2D(Line2D line) => new(line.From, line.From.FromTo(line.To).Normalized);
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a <see cref="Line2D"/> from a <see cref="Ray2D"/>, extending from its origin in the <see cref="Ray2D"/>'s direction for a given distance.
|
||||
/// </summary>
|
||||
/// <param name="ray">The source <see cref="Ray2D"/>.</param>
|
||||
/// <param name="distance">The length of the line segment to create from the <see cref="Ray2D"/>.</param>
|
||||
/// <returns>A <see cref="Line2D"/> representing the segment of the <see cref="Ray2D"/>.</returns>
|
||||
public static Line2D GetLine(Ray2D ray, float distance)
|
||||
=> new(ray.Origin, ray.Origin + ray.Direction * distance);
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the point on the <see cref="Ray2D"/> at a specified distance from its origin.
|
||||
/// </summary>
|
||||
/// <param name="ray">The <see cref="Ray2D"/> to evaluate.</param>
|
||||
/// <param name="distanceFromOrigin">The distance from the origin along the <see cref="Ray2D"/>'s direction.</param>
|
||||
/// <returns>A <see cref="Vector2D"/> representing the point at the given distance on the <see cref="Ray2D"/>.</returns>
|
||||
public static Vector2D Evaluate(Ray2D ray, float distanceFromOrigin)
|
||||
=> ray.Origin + ray.Direction * distanceFromOrigin;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the closest point on the <see cref="Ray2D"/> to the specified point.
|
||||
/// </summary>
|
||||
public static Vector2D ClosestPointTo(Ray2D ray, Vector2D point)
|
||||
{
|
||||
Vector2D originToPoint = ray.Origin.FromTo(point);
|
||||
|
||||
float dot = ray.Direction.Dot(originToPoint);
|
||||
|
||||
return ray.Origin + ray.Direction * dot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Ray2D"/>s are approximately equal within a specified epsilon range.
|
||||
/// </summary>
|
||||
/// <param name="left">The first <see cref="Ray2D"/>.</param>
|
||||
/// <param name="right">The second <see cref="Ray2D"/>.</param>
|
||||
/// <param name="epsilon">The epsilon range.</param>
|
||||
/// <returns><see cref="true"/> if the <see cref="Ray2D"/>s are approximately equal; otherwise, <see cref="false"/>.</returns>
|
||||
public static bool ApproximatelyEquals(Ray2D left, Ray2D right, float epsilon = float.Epsilon)
|
||||
=> left.Origin.ApproximatelyEquals(right.Origin, epsilon) && left.Direction.ApproximatelyEquals(right.Direction, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="Ray2D"/>.
|
||||
/// </summary>
|
||||
/// <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"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Ray2D"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(Origin, Direction);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Ray2D"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Ray2D"/>.</returns>
|
||||
public override string ToString() => $"{nameof(Ray2D)}({Origin}, {Direction})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for the <see cref="Ray2D"/> struct.
|
||||
/// </summary>
|
||||
public static class Ray2DExtensions
|
||||
{
|
||||
/// <inheritdoc cref="Ray2D.GetLine(Ray2D, float) />
|
||||
public static Line2D ToLine(this Ray2D ray, float distance) => Ray2D.GetLine(ray, distance);
|
||||
|
||||
/// <inheritdoc cref="Ray2D.Evaluate(Ray2D, float) />
|
||||
public static Vector2D Evaluate(this Ray2D ray, float distanceFromOrigin) => Ray2D.Evaluate(ray, distanceFromOrigin);
|
||||
|
||||
/// <inheritdoc cref="Ray2D.ClosestPointTo(Ray2D, Vector2D) />
|
||||
public static Vector2D ClosestPointTo(this Ray2D ray, Vector2D point) => Ray2D.ClosestPointTo(ray, point);
|
||||
|
||||
/// <inheritdoc cref="Ray2D.ApproximatelyEquals(Ray2D, Ray2D, float)" />
|
||||
public static bool ApproximatelyEquals(this Ray2D left, Ray2D right, float epsilon = float.Epsilon) => Ray2D.ApproximatelyEquals(left, right, epsilon);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a shape defined by a collection of vertices.
|
||||
@@ -122,7 +122,7 @@ public class Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
triangles.Clear();
|
||||
|
||||
for (int i = 2; i < shape.Vertices.Count; i++)
|
||||
triangles.Add(new Triangle(shape[0], shape[i], shape[i - 1]));
|
||||
triangles.Add(new Triangle(shape[0], shape[i - 1], shape[i]));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -251,39 +251,13 @@ public class Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="Shape2D"/>.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare with the current <see cref="Shape2D"/>.</param>
|
||||
/// <returns><see cref="true"/> if the specified object is equal to the current <see cref="Shape2D"/>; otherwise, <see cref="false"/>.</returns>
|
||||
public override bool Equals(object? obj) => obj is Shape2D shape2D && _vertices.Equals(shape2D._vertices);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the <see cref="Shape2D"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Shape2D"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(Vertices);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Shape2D"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Shape2D"/>.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
System.Text.StringBuilder stringBuilder = new(Vertices[0].ToString());
|
||||
for (int i = 1; i < Vertices.Count; i++)
|
||||
{
|
||||
stringBuilder.Append(", ");
|
||||
stringBuilder.Append(Vertices[i].ToString());
|
||||
}
|
||||
return $"{nameof(Shape2D)}({stringBuilder})";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<Vector2D> GetEnumerator() => Vertices.GetEnumerator();
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => Vertices.GetEnumerator();
|
||||
|
||||
public readonly record struct ShapeUpdatedArguments(Shape2D shape2D);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -298,7 +272,7 @@ public static class Shape2DExtensions
|
||||
public static Triangle ToSuperTriangle(this Shape2D shape) => Shape2D.GetSuperTriangle(shape);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.TriangulateConvex(Shape2D, IList{Triangle})" />
|
||||
public static void ToTrianglesConvex(this Shape2D shape, IList<Triangle> triangles) => Shape2D.TriangulateConvex(shape, triangles);
|
||||
public static void ToTrianglesConvex(this Shape2D shape, IList<Triangle> lines) => Shape2D.TriangulateConvex(shape, lines);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.TriangulateConvex(Shape2D)" />
|
||||
public static List<Triangle> ToTrianglesConvex(this Shape2D shape) => Shape2D.TriangulateConvex(shape);
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.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) : IEquatable<Triangle>
|
||||
public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C)
|
||||
{
|
||||
public readonly Vector2D A { get; init; } = A;
|
||||
public readonly Vector2D B { get; init; } = B;
|
||||
public readonly Vector2D C { get; init; } = C;
|
||||
|
||||
public static bool operator ==(Triangle left, Triangle right) => left.A == right.A && left.B == right.B && left.C == right.C;
|
||||
public static bool operator !=(Triangle left, Triangle right) => left.A != right.A || left.B != right.B || left.C != right.C;
|
||||
|
||||
public readonly float Area
|
||||
=> .5f * Math.Abs(
|
||||
A.X * (B.Y - C.Y) +
|
||||
@@ -49,26 +44,6 @@ public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C) : IEquatable
|
||||
/// <returns><c>true</c> if the <see cref="Triangle"/>s are approximately equal; otherwise, <c>false</c>.</returns>
|
||||
public static bool ApproximatelyEquals(Triangle left, Triangle right, float epsilon = float.Epsilon)
|
||||
=> left.A.ApproximatelyEquals(right.A, epsilon) && left.B.ApproximatelyEquals(right.B, epsilon) && left.C.ApproximatelyEquals(right.C, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="Triangle"/>.
|
||||
/// </summary>
|
||||
/// <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"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Triangle"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(A, B, C);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Triangle"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Triangle"/>.</returns>
|
||||
public override string ToString() => $"{nameof(Triangle)}({A}, {B}, {C})";
|
||||
}
|
||||
|
||||
public static class TriangleExtensions
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a two-dimensional vector.
|
||||
@@ -11,7 +9,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) : IEquatable<Vector2D>
|
||||
public readonly struct Vector2D(float x, float y)
|
||||
{
|
||||
/// <summary>
|
||||
/// The X coordinate of the <see cref="Vector2D"/>.
|
||||
@@ -33,11 +31,6 @@ public readonly struct Vector2D(float x, float y) : IEquatable<Vector2D>
|
||||
/// </summary>
|
||||
public float MagnitudeSquared => LengthSquared(this);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="Vector2D"/> with the direction reversed.
|
||||
/// </summary>
|
||||
public readonly Vector2D Reversed => -this;
|
||||
|
||||
/// <summary>
|
||||
/// The normalized form of the <see cref="Vector2D"/> (a <see cref="Vector2D"/> with the same direction and a magnitude of 1).
|
||||
/// </summary>
|
||||
@@ -84,7 +77,6 @@ public readonly struct Vector2D(float x, float y) : IEquatable<Vector2D>
|
||||
|
||||
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);
|
||||
|
||||
@@ -305,25 +297,24 @@ public readonly struct Vector2D(float x, float y) : IEquatable<Vector2D>
|
||||
public static bool ApproximatelyEquals(Vector2D left, Vector2D right, float epsilon = float.Epsilon)
|
||||
=> left.X.ApproximatelyEquals(right.X, epsilon) && left.Y.ApproximatelyEquals(right.Y, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Vector2D"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Vector2D"/>.</returns>
|
||||
public override string ToString() => $"{nameof(Vector2D)}({X}, {Y})";
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="Vector2D"/>.
|
||||
/// </summary>
|
||||
/// <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;
|
||||
public override bool Equals(object? obj) => obj is Vector2D objVec && X.Equals(objVec.X) && Y.Equals(objVec.Y);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the <see cref="Vector2D"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Vector2D"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(X, Y);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Vector2D"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Vector2D"/>.</returns>
|
||||
public override string ToString() => $"{nameof(Vector2D)}({X}, {Y})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,306 +0,0 @@
|
||||
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);
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core;
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a three-dimensional vector.
|
||||
@@ -12,7 +10,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) : IEquatable<Vector3D>
|
||||
public readonly struct Vector3D(float x, float y, float z)
|
||||
{
|
||||
/// <summary>
|
||||
/// The X coordinate of the <see cref="Vector3D"/>.
|
||||
@@ -94,7 +92,6 @@ public readonly struct Vector3D(float x, float y, float z) : IEquatable<Vector3D
|
||||
|
||||
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);
|
||||
|
||||
@@ -274,25 +271,24 @@ public readonly struct Vector3D(float x, float y, float z) : IEquatable<Vector3D
|
||||
public static bool ApproximatelyEquals(Vector3D left, Vector3D right, float epsilon = float.Epsilon)
|
||||
=> left.X.ApproximatelyEquals(right.X, epsilon) && left.Y.ApproximatelyEquals(right.Y, epsilon) && left.Z.ApproximatelyEquals(right.Z, epsilon);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Vector3D"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Vector3D"/>.</returns>
|
||||
public override string ToString() => $"{nameof(Vector3D)}({X}, {Y}, {Z})";
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current <see cref="Vector3D"/>.
|
||||
/// </summary>
|
||||
/// <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;
|
||||
public override bool Equals(object? obj) => obj is Vector3D objVec && X.Equals(objVec.X) && Y.Equals(objVec.Y) && Z.Equals(objVec.Z);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a hash code for the <see cref="Vector3D"/>.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the <see cref="Vector3D"/>.</returns>
|
||||
public override int GetHashCode() => System.HashCode.Combine(X, Y, Z);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the <see cref="Vector3D"/> to its string representation.
|
||||
/// </summary>
|
||||
/// <returns>A string representation of the <see cref="Vector3D"/>.</returns>
|
||||
public override string ToString() => $"{nameof(Vector3D)}({X}, {Y}, {Z})";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,314 +0,0 @@
|
||||
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);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core.Serialization;
|
||||
namespace Syntriax.Engine.Core.Serialization;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Class)]
|
||||
public class IgnoreSerializationAttribute : Attribute;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core.Serialization;
|
||||
namespace Syntriax.Engine.Core.Serialization;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||
public class SerializeAllAttribute : Attribute;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Engine.Core.Serialization;
|
||||
namespace Syntriax.Engine.Core.Serialization;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class SerializeAttribute : Attribute;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user