Compare commits
29 Commits
main
...
developmen
Author | SHA1 | Date | |
---|---|---|---|
bfbcfdce4f | |||
80202d4a07 | |||
2be99d2142 | |||
4081693d32 | |||
193d23c877 | |||
c135035d5b | |||
fabc485689 | |||
48710b0a7f | |||
bf34e52dc8 | |||
e3845a2f5c | |||
26a80452bc | |||
2535a1d6ec | |||
3a385900fb | |||
b94bbc8ed7 | |||
3f7a646bf0 | |||
f119a23d2b | |||
61488aa0e5 | |||
66b46e3d36 | |||
1ee07b41f8 | |||
6f425776cc | |||
98c9dde98a | |||
04d325f38b | |||
901585d4bb | |||
33a452a62e | |||
906edf096e | |||
d1129c95df | |||
40f483974d | |||
4b856420f9 | |||
7f93d95f6b |
@ -8,14 +8,19 @@ namespace Syntriax.Engine.Core.Abstract;
|
||||
public interface IGameManager : IEntity, IEnumerable<IHierarchyObject>
|
||||
{
|
||||
/// <summary>
|
||||
/// Event triggered when <see cref="Update(double)"/> is called on the <see cref="IGameManager"/>.
|
||||
/// Event triggered when <see cref="Update(EngineTime)"/> is about to be called called on the <see cref="IGameManager"/>.
|
||||
/// </summary>
|
||||
event UpdateEventHandler? OnPreUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when <see cref="Update(EngineTime)"/> is called on the <see cref="IGameManager"/>.
|
||||
/// </summary>
|
||||
event UpdateEventHandler? OnUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when <see cref="PreDraw"/> is called on the <see cref="IGameManager"/>.
|
||||
/// </summary>
|
||||
event PreDawEventHandler? OnPreDraw;
|
||||
event PreDrawEventHandler? OnPreDraw;
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when a <see cref="IHierarchyObject"/> is registered to the <see cref="IGameManager"/>.
|
||||
@ -27,11 +32,21 @@ public interface IGameManager : IEntity, IEnumerable<IHierarchyObject>
|
||||
/// </summary>
|
||||
event HierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered;
|
||||
|
||||
/// <summary>
|
||||
/// Current time scale the <see cref="IGameManager"/> operates on.
|
||||
/// </summary>
|
||||
float TimeScale { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains time data related to this <see cref="IGameManager"/>.
|
||||
/// </summary>
|
||||
EngineTime Time { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Contains unscaled time data related to this <see cref="IGameManager"/>.
|
||||
/// </summary>
|
||||
EngineTime UnscaledTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a read-only list of <see cref="IHierarchyObject"/>s managed by the <see cref="IGameManager"/>.
|
||||
/// </summary>
|
||||
@ -69,7 +84,7 @@ public interface IGameManager : IEntity, IEnumerable<IHierarchyObject>
|
||||
void PreDraw();
|
||||
|
||||
delegate void UpdateEventHandler(IGameManager sender, EngineTime engineTime);
|
||||
delegate void PreDawEventHandler(IGameManager sender);
|
||||
delegate void PreDrawEventHandler(IGameManager sender);
|
||||
|
||||
delegate void HierarchyObjectRegisteredEventHandler(IGameManager sender, IHierarchyObject hierarchyObjectRegistered);
|
||||
delegate void HierarchyObjectUnRegisteredEventHandler(IGameManager sender, IHierarchyObject hierarchyObjectUnregistered);
|
||||
|
@ -6,7 +6,18 @@ namespace Syntriax.Engine.Core;
|
||||
|
||||
public class ActiveBehaviourCollectorSorted<T> : ActiveBehaviourCollector<T> where T : class, IBehaviour
|
||||
{
|
||||
public Comparison<T>? SortBy { get; set; } = null;
|
||||
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)
|
||||
{
|
||||
@ -15,5 +26,5 @@ public class ActiveBehaviourCollectorSorted<T> : ActiveBehaviourCollector<T> whe
|
||||
}
|
||||
|
||||
public ActiveBehaviourCollectorSorted() { }
|
||||
public ActiveBehaviourCollectorSorted(IGameManager gameManager) : base(gameManager) { }
|
||||
public ActiveBehaviourCollectorSorted(IGameManager gameManager, Comparison<T> sortBy) : base(gameManager) => SortBy = sortBy;
|
||||
}
|
||||
|
@ -6,7 +6,18 @@ namespace Syntriax.Engine.Core;
|
||||
|
||||
public class BehaviourCollectorSorted<T> : BehaviourCollector<T> where T : class
|
||||
{
|
||||
public Comparison<T>? SortBy { get; set; } = null;
|
||||
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)
|
||||
{
|
||||
@ -15,5 +26,5 @@ public class BehaviourCollectorSorted<T> : BehaviourCollector<T> where T : class
|
||||
}
|
||||
|
||||
public BehaviourCollectorSorted() { }
|
||||
public BehaviourCollectorSorted(IGameManager gameManager) : base(gameManager) { }
|
||||
public BehaviourCollectorSorted(IGameManager gameManager, Comparison<T> sortBy) : base(gameManager) => SortBy = sortBy;
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
namespace Syntriax.Engine.Core.Abstract;
|
||||
|
||||
public static class TransformExtensions
|
||||
{
|
||||
public static Vector2D TransformVector2D(this ITransform2D transform, Vector2D vector)
|
||||
=> vector.Scale(transform.Scale)
|
||||
.Rotate(transform.Rotation * Math.DegreeToRadian)
|
||||
.Add(transform.Position);
|
||||
}
|
@ -54,7 +54,7 @@ public static class BehaviourControllerExtensions
|
||||
|
||||
while (controller is not null)
|
||||
{
|
||||
if (behaviourController.GetBehaviour<T>() is T behaviour)
|
||||
if (controller.GetBehaviour<T>() is T behaviour)
|
||||
return behaviour;
|
||||
|
||||
controller = controller.HierarchyObject.Parent?.BehaviourController;
|
||||
|
@ -7,9 +7,12 @@ namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class HierarchyObjectExtensions
|
||||
{
|
||||
public static IHierarchyObject SetHierarchyObject(this IHierarchyObject hierarchyObject, string name)
|
||||
public static T SetHierarchyObject<T>(this T hierarchyObject, string? name = "", IHierarchyObject? parent = null) where T : IHierarchyObject
|
||||
{
|
||||
hierarchyObject.Name = name;
|
||||
if (!string.IsNullOrWhiteSpace(name))
|
||||
hierarchyObject.Name = name;
|
||||
if (parent is not null)
|
||||
hierarchyObject.SetParent(parent);
|
||||
return hierarchyObject;
|
||||
}
|
||||
|
||||
|
@ -5,9 +5,11 @@ namespace Syntriax.Engine.Core.Factory;
|
||||
|
||||
public class HierarchyObjectFactory
|
||||
{
|
||||
public static IHierarchyObject Instantiate() => Instantiate<HierarchyObject>();
|
||||
public static T Instantiate<T>(params object?[]? args) where T : class, IHierarchyObject
|
||||
=> Instantiate<T>(behaviourController: null, stateEnable: null, args);
|
||||
|
||||
public static IHierarchyObject Instantiate(IBehaviourController? behaviourController = null, IStateEnable? stateEnable = null) => Instantiate<HierarchyObject>(behaviourController, stateEnable);
|
||||
public static T Instantiate<T>(
|
||||
IBehaviourController? behaviourController = null,
|
||||
IStateEnable? stateEnable = null,
|
||||
|
@ -10,13 +10,15 @@ namespace Syntriax.Engine.Core;
|
||||
[System.Diagnostics.DebuggerDisplay("HierarchyObject Count: {_hierarchyObjects.Count}")]
|
||||
public class GameManager : BaseEntity, IGameManager
|
||||
{
|
||||
public event IGameManager.UpdateEventHandler? OnPreUpdate = null;
|
||||
public event IGameManager.UpdateEventHandler? OnUpdate = null;
|
||||
public event IGameManager.PreDawEventHandler? OnPreDraw = null;
|
||||
public event IGameManager.PreDrawEventHandler? OnPreDraw = null;
|
||||
|
||||
public event IGameManager.HierarchyObjectRegisteredEventHandler? OnHierarchyObjectRegistered = null;
|
||||
public event IGameManager.HierarchyObjectUnRegisteredEventHandler? OnHierarchyObjectUnRegistered = null;
|
||||
|
||||
private readonly List<IHierarchyObject> _hierarchyObjects = new(Constants.GAME_OBJECTS_SIZE_INITIAL);
|
||||
private float _timeScale = 1f;
|
||||
|
||||
public IReadOnlyList<IHierarchyObject> HierarchyObjects => _hierarchyObjects;
|
||||
|
||||
@ -36,6 +38,12 @@ public class GameManager : BaseEntity, IGameManager
|
||||
}
|
||||
|
||||
public EngineTime Time { get; private set; } = new();
|
||||
public EngineTime UnscaledTime { get; private set; } = new();
|
||||
public float TimeScale
|
||||
{
|
||||
get => _timeScale;
|
||||
set => _timeScale = value.Max(0f);
|
||||
}
|
||||
|
||||
public void Register(IHierarchyObject hierarchyObject)
|
||||
{
|
||||
@ -48,8 +56,8 @@ public class GameManager : BaseEntity, IGameManager
|
||||
if (!hierarchyObject.Initialize())
|
||||
throw new Exception($"{hierarchyObject.Name} can't be initialized");
|
||||
|
||||
foreach (IHierarchyObject child in hierarchyObject.Children)
|
||||
Register(child);
|
||||
for (int i = 0; i < hierarchyObject.Children.Count; i++)
|
||||
Register(hierarchyObject.Children[i]);
|
||||
|
||||
_hierarchyObjects.Add(hierarchyObject);
|
||||
|
||||
@ -67,6 +75,12 @@ public class GameManager : BaseEntity, IGameManager
|
||||
}
|
||||
|
||||
public void Remove(IHierarchyObject hierarchyObject)
|
||||
{
|
||||
hierarchyObject.SetParent(null);
|
||||
RemoveIncursive(hierarchyObject);
|
||||
}
|
||||
|
||||
private void RemoveIncursive(IHierarchyObject hierarchyObject)
|
||||
{
|
||||
if (!_hierarchyObjects.Contains(hierarchyObject))
|
||||
throw new Exception($"{nameof(IHierarchyObject)} named {hierarchyObject.Name} is not registered to the {nameof(GameManager)}.");
|
||||
@ -74,8 +88,8 @@ public class GameManager : BaseEntity, IGameManager
|
||||
hierarchyObject.OnFinalized -= OnHierarchyObjectFinalize;
|
||||
hierarchyObject.OnExitedHierarchy -= OnHierarchyObjectExitedHierarchy;
|
||||
|
||||
foreach (IHierarchyObject child in hierarchyObject.Children)
|
||||
Remove(child);
|
||||
for (int i = hierarchyObject.Children.Count - 1; i >= 0; i--)
|
||||
Remove(hierarchyObject.Children[i]);
|
||||
|
||||
_hierarchyObjects.Remove(hierarchyObject);
|
||||
|
||||
@ -106,12 +120,15 @@ public class GameManager : BaseEntity, IGameManager
|
||||
|
||||
public void Update(EngineTime engineTime)
|
||||
{
|
||||
Time = engineTime;
|
||||
UnscaledTime = engineTime;
|
||||
Time = new(TimeSpan.FromTicks((long)(Time.TimeSinceStart.Ticks + engineTime.DeltaSpan.Ticks * TimeScale)), TimeSpan.FromTicks((long)(engineTime.DeltaSpan.Ticks * TimeScale)));
|
||||
|
||||
OnPreUpdate?.Invoke(this, Time);
|
||||
|
||||
for (int i = 0; i < HierarchyObjects.Count; i++)
|
||||
HierarchyObjects[i].BehaviourController.Update();
|
||||
|
||||
OnUpdate?.Invoke(this, engineTime);
|
||||
OnUpdate?.Invoke(this, Time);
|
||||
}
|
||||
|
||||
public void PreDraw()
|
||||
|
@ -62,15 +62,18 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
|
||||
if (!IsInHierarchy || _gameManager is not IGameManager gameManager)
|
||||
return false;
|
||||
|
||||
_gameManager = null!;
|
||||
OnExitingHierarchy(gameManager);
|
||||
_gameManager = null!;
|
||||
OnExitedHierarchy?.Invoke(this, gameManager);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetParent(IHierarchyObject? parent)
|
||||
{
|
||||
if (parent == this || Parent == parent)
|
||||
if (parent == this)
|
||||
throw new Exceptions.AssignException($"{Name} can not parent itself");
|
||||
|
||||
if (Parent == parent)
|
||||
return;
|
||||
|
||||
IHierarchyObject? previousParent = Parent;
|
||||
@ -84,6 +87,9 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
|
||||
|
||||
if (parent is not null)
|
||||
{
|
||||
if (parent.IsInHierarchy && !IsInHierarchy)
|
||||
parent.GameManager.Register(this);
|
||||
|
||||
parent.AddChild(this);
|
||||
parent.OnActiveChanged += OnParentActiveChanged;
|
||||
}
|
||||
@ -102,13 +108,13 @@ public class HierarchyObject : BaseEntity, IHierarchyObject
|
||||
OnChildrenAdded?.Invoke(this, parent);
|
||||
}
|
||||
|
||||
public void RemoveChild(IHierarchyObject parent)
|
||||
public void RemoveChild(IHierarchyObject child)
|
||||
{
|
||||
if (!_children.Remove(parent))
|
||||
if (!_children.Remove(child))
|
||||
return;
|
||||
|
||||
parent.SetParent(null);
|
||||
OnChildrenRemoved?.Invoke(this, parent);
|
||||
child.SetParent(null);
|
||||
OnChildrenRemoved?.Invoke(this, child);
|
||||
}
|
||||
|
||||
protected virtual void OnAssign(IBehaviourController behaviourController) { }
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
using Syntriax.Engine.Core.Abstract;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
@ -66,8 +67,8 @@ public readonly struct Circle(Vector2D center, float radius)
|
||||
/// <summary>
|
||||
/// Transforms the <see cref="Circle"/> by the specified <see cref="ITransform2D"/>.
|
||||
/// </summary>
|
||||
public static Circle TransformCircle(ITransform2D transform, Circle circle)
|
||||
=> new(transform.TransformVector2D(circle.Center), circle.Radius * (transform.Scale.Magnitude / Vector2D.One.Magnitude));
|
||||
public static Circle Transform(ITransform2D transform, Circle circle)
|
||||
=> new(transform.Transform(circle.Center), circle.Radius * (transform.Scale.Magnitude / Vector2D.One.Magnitude));
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Circle"/>s are approximately equal.
|
||||
@ -97,8 +98,11 @@ public static class CircleExtensions
|
||||
/// <inheritdoc cref="Circle.Project(Circle, Vector2D)" />
|
||||
public static Projection1D ToProjection(this Circle circle, Vector2D projectionVector) => Circle.Project(circle, projectionVector);
|
||||
|
||||
/// <inheritdoc cref="Circle.TransformCircle(ITransform2D, Circle)" />
|
||||
public static Circle TransformCircle(this ITransform2D transform, Circle circle) => Circle.TransformCircle(transform, circle);
|
||||
/// <inheritdoc cref="Circle.Transform(ITransform2D, Circle)" />
|
||||
public static Circle Transform(this ITransform2D transform, Circle circle) => Circle.Transform(transform, circle);
|
||||
|
||||
/// <inheritdoc cref="Circle.Transform(ITransform2D, Circle)" />
|
||||
public static Circle Transform(this Circle circle, ITransform2D transform) => Circle.Transform(transform, circle);
|
||||
|
||||
/// <inheritdoc cref="Circle.ApproximatelyEquals(Circle, Circle, float)" />
|
||||
public static bool ApproximatelyEquals(this Circle left, Circle right, float epsilon = float.Epsilon) => Circle.ApproximatelyEquals(left, right, epsilon);
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Syntriax.Engine.Core.Abstract;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
@ -9,20 +10,20 @@ namespace Syntriax.Engine.Core;
|
||||
/// </summary>
|
||||
/// <param name="vertices">The vertices of the shape.</param>
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of the <see cref="Shape2D"/> struct with the specified vertices.
|
||||
/// Initializes a new instance of a <see cref="Shape2D"/> struct with the specified vertices.
|
||||
/// </remarks>
|
||||
[System.Diagnostics.DebuggerDisplay("Vertices Count: {Vertices.Count}")]
|
||||
public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
{
|
||||
public static readonly Shape2D Triangle = CreateNgon(3, Vector2D.Up);
|
||||
public static readonly Shape2D Box = CreateNgon(4, Vector2D.One);
|
||||
public static readonly Shape2D Square = CreateNgon(4, Vector2D.One);
|
||||
public static readonly Shape2D Pentagon = CreateNgon(5, Vector2D.Up);
|
||||
public static readonly Shape2D Hexagon = CreateNgon(6, Vector2D.Right);
|
||||
|
||||
private readonly List<Vector2D> _verticesList = vertices;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the vertices of the shape.
|
||||
/// Gets the vertices of the <see cref="Shape2D"/>.
|
||||
/// </summary>
|
||||
public IReadOnlyList<Vector2D> Vertices => _verticesList;
|
||||
|
||||
@ -34,10 +35,10 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
public Vector2D this[System.Index index] => Vertices[index];
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of the current shape.
|
||||
/// Returns a copy of the current <see cref="Shape2D"/>.
|
||||
/// </summary>
|
||||
/// <param name="shape">The shape to copy.</param>
|
||||
/// <returns>A copy of the input shape.</returns>
|
||||
/// <param name="shape">The <see cref="Shape2D"/> to copy.</param>
|
||||
/// <returns>A copy of the input <see cref="Shape2D"/>.</returns>
|
||||
public static Shape2D CreateCopy(Shape2D shape) => new(new List<Vector2D>(shape.Vertices));
|
||||
|
||||
/// <summary>
|
||||
@ -69,10 +70,10 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the super triangle that encloses the given shape.
|
||||
/// Gets the super triangle that encloses the given <see cref="Shape2D"/>.
|
||||
/// </summary>
|
||||
/// <param name="shape">The shape to enclose.</param>
|
||||
/// <returns>The super triangle that encloses the given shape.</returns>
|
||||
/// <param name="shape">The <see cref="Shape2D"/> to enclose.</param>
|
||||
/// <returns>The super triangle that encloses the given <see cref="Shape2D"/>.</returns>
|
||||
public static Triangle GetSuperTriangle(Shape2D shape)
|
||||
{
|
||||
float minX = float.MaxValue, minY = float.MaxValue;
|
||||
@ -100,10 +101,35 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the lines that form the edges of the shape.
|
||||
/// Triangulates the given convex <see cref="Shape2D"/>.
|
||||
/// </summary>
|
||||
/// <param name="shape">The shape to get lines from.</param>
|
||||
/// <param name="lines">The list to populate with lines.</param>
|
||||
/// <param name="shape">The <see cref="Shape2D"/> to triangulate.</param>
|
||||
/// <param name="triangles">The list to populate with triangles.</param>
|
||||
public static void TriangulateConvex(Shape2D shape, IList<Triangle> triangles)
|
||||
{
|
||||
triangles.Clear();
|
||||
|
||||
for (int i = 2; i < shape.Vertices.Count; i++)
|
||||
triangles.Add(new Triangle(shape[0], shape[i - 1], shape[i]));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulates the given convex <see cref="Shape2D"/>.
|
||||
/// </summary>
|
||||
/// <param name="shape">The <see cref="Shape2D"/> to triangulate.</param>
|
||||
/// <returns>A list of <see cref="Triangle"/>s that makes up the given convex <see cref="Shape2D"/>.</returns>
|
||||
public static List<Triangle> TriangulateConvex(Shape2D shape)
|
||||
{
|
||||
List<Triangle> triangles = new(shape.Vertices.Count - 2);
|
||||
TriangulateConvex(shape, triangles);
|
||||
return triangles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Line2D"/>s that form the edges of the <see cref="Shape2D"/>.
|
||||
/// </summary>
|
||||
/// <param name="shape">The <see cref="Shape2D"/> to get <see cref="Line2D"/>s from.</param>
|
||||
/// <param name="lines">The list to populate with <see cref="Line2D"/>.</sparam>
|
||||
public static void GetLines(Shape2D shape, IList<Line2D> lines)
|
||||
{
|
||||
lines.Clear();
|
||||
@ -113,10 +139,10 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of lines that form the edges of the shape.
|
||||
/// Gets a list of <see cref="Line2D"/>s that form the edges of the <see cref="Shape2D"/>.
|
||||
/// </summary>
|
||||
/// <param name="shape">The shape to get lines from.</param>
|
||||
/// <returns>A list of lines that form the edges of the shape.</returns>
|
||||
/// <param name="shape">The shape to get <see cref="Line2D"/>s from.</param>
|
||||
/// <returns>A list of <see cref="Line2D"/>s that form the edges of the <see cref="Shape2D"/>.</returns>
|
||||
public static List<Line2D> GetLines(Shape2D shape)
|
||||
{
|
||||
List<Line2D> lines = new(shape.Vertices.Count - 1);
|
||||
@ -125,7 +151,7 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projects the shape onto a vector.
|
||||
/// Projects the <see cref="Shape2D"/> onto a 1D plane.
|
||||
/// </summary>
|
||||
/// <param name="shape">The shape to project.</param>
|
||||
/// <param name="projectionVector">The vector to project onto.</param>
|
||||
@ -140,11 +166,11 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projects the shape onto a vector.
|
||||
/// Projects the <see cref="Shape2D"/> onto a vector.
|
||||
/// </summary>
|
||||
/// <param name="shape">The shape to project.</param>
|
||||
/// <param name="shape">The <see cref="Shape2D"/> to project.</param>
|
||||
/// <param name="projectionVector">The vector to project onto.</param>
|
||||
/// <returns>The projection of the shape onto the vector.</returns>
|
||||
/// <returns>The projection of the <see cref="Shape2D"/> onto the vector.</returns>
|
||||
public static Projection1D Project(Shape2D shape, Vector2D projectionVector)
|
||||
{
|
||||
float min = float.MaxValue;
|
||||
@ -161,44 +187,44 @@ public readonly struct Shape2D(List<Vector2D> vertices) : IEnumerable<Vector2D>
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms the shape using the specified transform.
|
||||
/// Transforms the <see cref="Shape2D"/> using the specified <see cref="ITransform2D"/>.
|
||||
/// </summary>
|
||||
/// <param name="shape">The shape to transform.</param>
|
||||
/// <param name="transform">The transform to apply.</param>
|
||||
/// <returns>The transformed shape.</returns>
|
||||
public static Shape2D TransformShape(Shape2D shape, ITransform2D transform)
|
||||
/// <param name="shape">The <see cref="Shape2D"/> to transform.</param>
|
||||
/// <param name="transform">The <see cref="ITransform2D"/> to apply.</param>
|
||||
/// <returns>The transformed <see cref="Shape2D"/>.</returns>
|
||||
public static Shape2D Transform(Shape2D shape, ITransform2D transform)
|
||||
{
|
||||
List<Vector2D> vertices = new(shape.Vertices.Count);
|
||||
|
||||
int count = shape.Vertices.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
vertices.Add(transform.TransformVector2D(shape[i]));
|
||||
vertices.Add(transform.Transform(shape[i]));
|
||||
|
||||
return new Shape2D(vertices);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms the shape using the specified transform.
|
||||
/// Transforms the <see cref="Shape2D"/> using the specified <see cref="ITransform2D"/>.
|
||||
/// </summary>
|
||||
/// <param name="from">The shape to transform.</param>
|
||||
/// <param name="transform">The transform to apply.</param>
|
||||
/// <param name="to">The transformed shape.</param>
|
||||
public static void TransformShape(Shape2D from, ITransform2D transform, ref Shape2D to)
|
||||
/// <param name="from">The <see cref="Shape2D"/> to transform.</param>
|
||||
/// <param name="transform">The <see cref="ITransform2D"/> to apply.</param>
|
||||
/// <param name="to">The transformed <see cref="Shape2D"/>.</param>
|
||||
public static void Transform(Shape2D from, ITransform2D transform, ref Shape2D to)
|
||||
{
|
||||
to._verticesList.Clear();
|
||||
|
||||
int count = from._verticesList.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
to._verticesList.Add(transform.TransformVector2D(from[i]));
|
||||
to._verticesList.Add(transform.Transform(from[i]));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether two shapes are approximately equal.
|
||||
/// Determines whether two <see cref="Shape2D"/>s are approximately equal.
|
||||
/// </summary>
|
||||
/// <param name="left">The first shape to compare.</param>
|
||||
/// <param name="right">The second shape to compare.</param>
|
||||
/// <param name="left">The first <see cref="Shape2D"/> to compare.</param>
|
||||
/// <param name="right">The second <see cref="Shape2D"/> to compare.</param>
|
||||
/// <param name="epsilon">The epsilon range.</param>
|
||||
/// <returns><c>true</c> if the shapes are approximately equal; otherwise, <c>false</c>.</returns>
|
||||
/// <returns><c>true</c> if the <see cref="Shape2D"/>s are approximately equal; otherwise, <c>false</c>.</returns>
|
||||
public static bool ApproximatelyEquals(Shape2D left, Shape2D right, float epsilon = float.Epsilon)
|
||||
{
|
||||
if (left.Vertices.Count != right.Vertices.Count)
|
||||
@ -229,6 +255,12 @@ public static class Shape2DExtensions
|
||||
/// <inheritdoc cref="Shape2D.GetSuperTriangle(Shape2D)" />
|
||||
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> lines) => Shape2D.TriangulateConvex(shape, lines);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.TriangulateConvex(Shape2D)" />
|
||||
public static List<Triangle> ToTrianglesConvex(this Shape2D shape) => Shape2D.TriangulateConvex(shape);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.GetLines(Shape2D, IList{Line2D})" />
|
||||
public static void ToLines(this Shape2D shape, IList<Line2D> lines) => Shape2D.GetLines(shape, lines);
|
||||
|
||||
@ -241,11 +273,17 @@ public static class Shape2DExtensions
|
||||
/// <inheritdoc cref="Shape2D.Project(Shape2D, Vector2D)" />
|
||||
public static Projection1D ToProjection(this Shape2D shape, Vector2D projectionVector) => Shape2D.Project(shape, projectionVector);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.TransformShape(Shape2D, ITransform2D)" />
|
||||
public static Shape2D TransformShape(this ITransform2D transform, Shape2D shape) => Shape2D.TransformShape(shape, transform);
|
||||
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D)" />
|
||||
public static Shape2D Transform(this ITransform2D transform, Shape2D shape) => Shape2D.Transform(shape, transform);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.TransformShape(Shape2D, ITransform2D, Shape2D)" />
|
||||
public static void TransformShape(this ITransform2D transform, Shape2D from, ref Shape2D to) => Shape2D.TransformShape(from, transform, ref to);
|
||||
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D, Shape2D)" />
|
||||
public static void Transform(this ITransform2D transform, Shape2D from, ref Shape2D to) => Shape2D.Transform(from, transform, ref to);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D)" />
|
||||
public static Shape2D Transform(this Shape2D shape, ITransform2D transform) => Shape2D.Transform(shape, transform);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.Transform(Shape2D, ITransform2D, ref Shape2D)" />
|
||||
public static void Transform(this Shape2D from, ITransform2D transform, ref Shape2D to) => Shape2D.Transform(from, transform, ref to);
|
||||
|
||||
/// <inheritdoc cref="Shape2D.ApproximatelyEquals(Shape2D, Shape2D, float)" />
|
||||
public static bool ApproximatelyEquals(this Shape2D left, Shape2D right, float epsilon = float.Epsilon) => Shape2D.ApproximatelyEquals(left, right, epsilon);
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Syntriax.Engine.Core.Abstract;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
@ -278,6 +279,17 @@ public readonly struct Vector2D(float x, float y)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms the <see cref="Vector2D"/> using the specified <see cref="ITransform2D"/>.
|
||||
/// </summary>
|
||||
/// <param name="vector">The <see cref="Vector2D"/> to transform.</param>
|
||||
/// <param name="transform">The <see cref="ITransform2D"/> to apply.</param>
|
||||
/// <returns>The transformed <see cref="Vector2D"/>.</returns>
|
||||
public static Vector2D Transform(Vector2D vector, ITransform2D transform)
|
||||
=> vector.Scale(transform.Scale)
|
||||
.Rotate(transform.Rotation * Math.DegreeToRadian)
|
||||
.Add(transform.Position);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if two <see cref="Vector2D"/>s are approximately equal within a specified epsilon range.
|
||||
/// </summary>
|
||||
@ -379,6 +391,12 @@ public static class Vector2DExtensions
|
||||
/// <inheritdoc cref="Vector2D.Dot(Vector2D, Vector2D)" />
|
||||
public static float Dot(this Vector2D left, Vector2D right) => Vector2D.Dot(left, right);
|
||||
|
||||
/// <inheritdoc cref="Vector2D.Transform(Vector2D, ITransform2D)" />
|
||||
public static Vector2D Transform(this Vector2D vector, ITransform2D transform) => Vector2D.Transform(vector, transform);
|
||||
|
||||
/// <inheritdoc cref="Vector2D.Transform(Vector2D, ITransform2D)" />
|
||||
public static Vector2D Transform(this ITransform2D transform, Vector2D vector) => Vector2D.Transform(vector, transform);
|
||||
|
||||
/// <inheritdoc cref="Vector2D.ApproximatelyEquals(Vector2D, Vector2D, float) " />
|
||||
public static bool ApproximatelyEquals(this Vector2D left, Vector2D right, float epsilon = float.Epsilon) => Vector2D.ApproximatelyEquals(left, right, epsilon);
|
||||
}
|
||||
|
@ -92,10 +92,13 @@ public class Transform2D : Behaviour, ITransform2D
|
||||
return;
|
||||
|
||||
Vector2D previousScale = _scale;
|
||||
Vector2D previousPosition = _position;
|
||||
_localScale = value;
|
||||
|
||||
UpdateScale();
|
||||
UpdatePosition();
|
||||
OnScaleChanged?.Invoke(this, previousScale);
|
||||
OnPositionChanged?.Invoke(this, previousPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,13 +123,9 @@ public class Transform2D : Behaviour, ITransform2D
|
||||
if (parentTransform is null)
|
||||
return;
|
||||
|
||||
float previousRotation = Rotation;
|
||||
|
||||
UpdatePosition();
|
||||
UpdateRotation();
|
||||
|
||||
OnPositionChanged?.Invoke(this, previousPosition);
|
||||
OnRotationChanged?.Invoke(this, previousRotation);
|
||||
}
|
||||
|
||||
private void RecalculateScale(ITransform2D _, Vector2D previousScale)
|
||||
@ -134,9 +133,13 @@ public class Transform2D : Behaviour, ITransform2D
|
||||
if (parentTransform is null)
|
||||
return;
|
||||
|
||||
Vector2D previousPosition = _position;
|
||||
|
||||
UpdateScale();
|
||||
UpdatePosition();
|
||||
|
||||
OnScaleChanged?.Invoke(this, previousScale);
|
||||
OnPositionChanged?.Invoke(this, previousPosition);
|
||||
}
|
||||
|
||||
private void RecalculateRotation(ITransform2D _, float previousRotation)
|
||||
@ -146,11 +149,11 @@ public class Transform2D : Behaviour, ITransform2D
|
||||
|
||||
Vector2D previousPosition = Position;
|
||||
|
||||
UpdatePosition();
|
||||
UpdateRotation();
|
||||
UpdatePosition();
|
||||
|
||||
OnPositionChanged?.Invoke(this, previousPosition);
|
||||
OnRotationChanged?.Invoke(this, previousRotation);
|
||||
OnPositionChanged?.Invoke(this, previousPosition);
|
||||
}
|
||||
|
||||
private void UpdateLocalPosition()
|
||||
@ -203,32 +206,31 @@ public class Transform2D : Behaviour, ITransform2D
|
||||
|
||||
protected override void InitializeInternal()
|
||||
{
|
||||
UpdateParent(BehaviourController.HierarchyObject.Parent);
|
||||
BehaviourController.HierarchyObject.OnParentChanged += OnParentChanged;
|
||||
UpdateReferences(HierarchyObject.Parent);
|
||||
HierarchyObject.OnParentChanged += OnParentChanged;
|
||||
}
|
||||
|
||||
protected override void FinalizeInternal()
|
||||
{
|
||||
BehaviourController.HierarchyObject.OnParentChanged -= OnParentChanged;
|
||||
HierarchyObject.OnParentChanged -= OnParentChanged;
|
||||
}
|
||||
|
||||
private void UpdateParent(IHierarchyObject? parent)
|
||||
private void UpdateReferences(IHierarchyObject? parent)
|
||||
{
|
||||
ITransform2D? previousParent = parentTransform;
|
||||
if (previousParent is not null)
|
||||
{
|
||||
previousParent.BehaviourController.HierarchyObject.RemoveChild(HierarchyObject);
|
||||
previousParent.OnPositionChanged -= RecalculatePosition;
|
||||
previousParent.OnScaleChanged -= RecalculateScale;
|
||||
previousParent.OnRotationChanged -= RecalculateRotation;
|
||||
previousParent.BehaviourController.HierarchyObject.OnParentChanged -= OnParentChanged;
|
||||
previousParent.BehaviourController.OnBehaviourAdded -= LookForTransform2D;
|
||||
}
|
||||
|
||||
parentTransform = parent?.BehaviourController.GetBehaviour<ITransform2D>();
|
||||
|
||||
if (parentTransform is not null)
|
||||
{
|
||||
parentTransform.BehaviourController.HierarchyObject.AddChild(HierarchyObject);
|
||||
parentTransform.OnPositionChanged += RecalculatePosition;
|
||||
parentTransform.OnScaleChanged += RecalculateScale;
|
||||
parentTransform.OnRotationChanged += RecalculateRotation;
|
||||
@ -238,6 +240,8 @@ public class Transform2D : Behaviour, ITransform2D
|
||||
UpdateScale();
|
||||
UpdateRotation();
|
||||
}
|
||||
else if (HierarchyObject.Parent is not null)
|
||||
HierarchyObject.Parent.BehaviourController.OnBehaviourAdded += LookForTransform2D;
|
||||
|
||||
UpdateLocalPosition();
|
||||
UpdateLocalScale();
|
||||
@ -248,8 +252,16 @@ public class Transform2D : Behaviour, ITransform2D
|
||||
OnRotationChanged?.Invoke(this, Rotation);
|
||||
}
|
||||
|
||||
private void LookForTransform2D(IBehaviourController sender, IBehaviour behaviourAdded)
|
||||
{
|
||||
if (behaviourAdded is not ITransform2D transform2D)
|
||||
return;
|
||||
|
||||
UpdateReferences(HierarchyObject.Parent);
|
||||
}
|
||||
|
||||
private void OnParentChanged(IHierarchyObject sender, IHierarchyObject? previousParent, IHierarchyObject? newParent)
|
||||
{
|
||||
UpdateParent(newParent);
|
||||
UpdateReferences(newParent);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ public abstract class Collider2DBehaviourBase : Behaviour2D, ICollider2D
|
||||
public event ICollider2D.CollisionResolvedEventHandler? OnCollisionResolved = null;
|
||||
public event ICollider2D.TriggeredEventHandler? OnTriggered = null;
|
||||
|
||||
protected bool NeedsRecalculation { get; private set; } = true;
|
||||
protected bool NeedsRecalculation { get; set; } = true;
|
||||
protected IRigidBody2D? _rigidBody2D = null;
|
||||
|
||||
public IRigidBody2D? RigidBody2D => _rigidBody2D;
|
||||
|
@ -5,10 +5,20 @@ namespace Syntriax.Engine.Physics2D;
|
||||
|
||||
public class Collider2DCircleBehaviour : Collider2DBehaviourBase, ICircleCollider2D
|
||||
{
|
||||
public Circle CircleWorld { get; protected set; } = Circle.UnitCircle;
|
||||
public Circle CircleLocal { get; set; } = Circle.UnitCircle;
|
||||
private Circle _circleLocal = Circle.UnitCircle;
|
||||
|
||||
public override void CalculateCollider() => CircleWorld = Transform.TransformCircle(CircleLocal);
|
||||
public Circle CircleWorld { get; protected set; } = Circle.UnitCircle;
|
||||
public Circle CircleLocal
|
||||
{
|
||||
get => _circleLocal;
|
||||
set
|
||||
{
|
||||
_circleLocal = value;
|
||||
NeedsRecalculation = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void CalculateCollider() => CircleWorld = Transform.Transform(_circleLocal);
|
||||
|
||||
public Collider2DCircleBehaviour() { }
|
||||
public Collider2DCircleBehaviour(Circle circle) => CircleLocal = circle;
|
||||
|
@ -6,12 +6,24 @@ namespace Syntriax.Engine.Physics2D;
|
||||
public class Collider2DShapeBehaviour : Collider2DBehaviourBase, IShapeCollider2D
|
||||
{
|
||||
public Shape2D ShapeWorld { get => _shapeWorld; protected set => _shapeWorld = value; }
|
||||
public Shape2D ShapeLocal { get; set; } = Shape2D.Box;
|
||||
public Shape2D ShapeLocal
|
||||
{
|
||||
get => _shapeLocal;
|
||||
set
|
||||
{
|
||||
_shapeLocal = value;
|
||||
NeedsRecalculation = true;
|
||||
}
|
||||
}
|
||||
|
||||
private Shape2D _shapeWorld = Shape2D.Box.CreateCopy();
|
||||
private Shape2D _shapeWorld = Shape2D.Square.CreateCopy();
|
||||
private Shape2D _shapeLocal = Shape2D.Square;
|
||||
|
||||
public override void CalculateCollider() => Transform.TransformShape(ShapeLocal, ref _shapeWorld);
|
||||
public override void CalculateCollider() => Transform.Transform(ShapeLocal, ref _shapeWorld);
|
||||
|
||||
public Collider2DShapeBehaviour() { }
|
||||
public Collider2DShapeBehaviour(Shape2D shape) => ShapeLocal = shape;
|
||||
public Collider2DShapeBehaviour(Shape2D shape)
|
||||
{
|
||||
ShapeLocal = shape;
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
using Syntriax.Engine.Core.Abstract;
|
||||
using Syntriax.Engine.Physics2D.Abstract;
|
||||
|
||||
namespace Syntriax.Engine.Physics2D;
|
||||
|
||||
public class PhysicsEngine2D : IPhysicsEngine2D
|
||||
public class PhysicsEngine2D : HierarchyObject, IPhysicsEngine2D
|
||||
{
|
||||
public event IPhysicsEngine2D.PhysicsIterationEventHandler? OnPhysicsIteration = null;
|
||||
public event IPhysicsEngine2D.PhysicsStepEventHandler? OnPhysicsStep = null;
|
||||
|
||||
private readonly List<IRigidBody2D> rigidBodies = new(32);
|
||||
private readonly List<ICollider2D> colliders = new(64);
|
||||
private float physicsTicker = 0f;
|
||||
private int _iterationPerStep = 1;
|
||||
private float _iterationPeriod = 1f / 60f;
|
||||
|
||||
private int _iterationCount = 1;
|
||||
protected readonly ICollisionDetector2D collisionDetector = null!;
|
||||
protected readonly ICollisionResolver2D collisionResolver = null!;
|
||||
|
||||
private readonly ICollisionDetector2D collisionDetector = null!;
|
||||
private readonly ICollisionResolver2D collisionResolver = null!;
|
||||
protected BehaviourCollector<IRigidBody2D> rigidBodyCollector = new();
|
||||
protected BehaviourCollector<ICollider2D> colliderCollector = new();
|
||||
protected BehaviourCollector<IPhysicsUpdate> physicsUpdateCollector = new();
|
||||
|
||||
public int IterationPerStep { get => _iterationCount; set => _iterationCount = value < 1 ? 1 : value; }
|
||||
|
||||
public void AddRigidBody(IRigidBody2D rigidBody)
|
||||
{
|
||||
if (rigidBodies.Contains(rigidBody))
|
||||
return;
|
||||
|
||||
rigidBodies.Add(rigidBody);
|
||||
|
||||
foreach (ICollider2D collider2D in rigidBody.BehaviourController.GetBehaviours<ICollider2D>())
|
||||
colliders.Add(collider2D);
|
||||
|
||||
rigidBody.BehaviourController.OnBehaviourAdded += OnBehaviourAdded;
|
||||
rigidBody.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved;
|
||||
}
|
||||
|
||||
public void RemoveRigidBody(IRigidBody2D rigidBody)
|
||||
{
|
||||
rigidBodies.Remove(rigidBody);
|
||||
}
|
||||
public int IterationPerStep { get => _iterationPerStep; set => _iterationPerStep = value < 1 ? 1 : value; }
|
||||
public float IterationPeriod { get => _iterationPeriod; set => _iterationPeriod = value.Max(0.0001f); }
|
||||
|
||||
public void Step(float deltaTime)
|
||||
{
|
||||
@ -46,23 +30,23 @@ public class PhysicsEngine2D : IPhysicsEngine2D
|
||||
for (int iterationIndex = 0; iterationIndex < IterationPerStep; iterationIndex++)
|
||||
{
|
||||
// Can Parallel
|
||||
for (int i = 0; i < rigidBodies.Count; i++)
|
||||
StepRigidBody(rigidBodies[i], intervalDeltaTime);
|
||||
foreach (IRigidBody2D rigidBody in rigidBodyCollector)
|
||||
StepRigidBody(rigidBody, intervalDeltaTime);
|
||||
|
||||
// Can Parallel
|
||||
foreach (ICollider2D collider in colliders)
|
||||
foreach (ICollider2D collider in colliderCollector)
|
||||
collider.Recalculate();
|
||||
|
||||
// Can Parallel
|
||||
for (int x = 0; x < colliders.Count; x++)
|
||||
for (int x = 0; x < colliderCollector.Behaviours.Count; x++)
|
||||
{
|
||||
ICollider2D? colliderX = colliders[x];
|
||||
ICollider2D? colliderX = colliderCollector.Behaviours[x];
|
||||
if (!colliderX.IsActive)
|
||||
return;
|
||||
|
||||
for (int y = x + 1; y < colliders.Count; y++)
|
||||
for (int y = x + 1; y < colliderCollector.Behaviours.Count; y++)
|
||||
{
|
||||
ICollider2D? colliderY = colliders[y];
|
||||
ICollider2D? colliderY = colliderCollector.Behaviours[y];
|
||||
|
||||
if (!colliderY.IsActive)
|
||||
return;
|
||||
@ -87,7 +71,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D
|
||||
}
|
||||
else if (colliderY.IsTrigger)
|
||||
{
|
||||
colliderY.Trigger(colliderY);
|
||||
colliderY.Trigger(colliderX);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -106,8 +90,13 @@ public class PhysicsEngine2D : IPhysicsEngine2D
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OnPhysicsIteration?.Invoke(this, intervalDeltaTime);
|
||||
}
|
||||
|
||||
foreach (IPhysicsUpdate physicsUpdate in physicsUpdateCollector)
|
||||
physicsUpdate.PhysicsUpdate(deltaTime);
|
||||
|
||||
OnPhysicsStep?.Invoke(this, deltaTime);
|
||||
}
|
||||
|
||||
@ -120,20 +109,33 @@ public class PhysicsEngine2D : IPhysicsEngine2D
|
||||
rigidBody.Transform.Rotation += rigidBody.AngularVelocity * intervalDeltaTime;
|
||||
}
|
||||
|
||||
private void OnBehaviourAdded(IBehaviourController controller, IBehaviour behaviour)
|
||||
protected override void OnEnteringHierarchy(IGameManager gameManager)
|
||||
{
|
||||
if (behaviour is not ICollider2D collider2D)
|
||||
return;
|
||||
physicsUpdateCollector.Assign(gameManager);
|
||||
colliderCollector.Assign(gameManager);
|
||||
rigidBodyCollector.Assign(gameManager);
|
||||
|
||||
colliders.Add(collider2D);
|
||||
gameManager.OnPreUpdate += OnEnginePreUpdate;
|
||||
}
|
||||
|
||||
private void OnBehaviourRemoved(IBehaviourController controller, IBehaviour behaviour)
|
||||
protected override void OnExitingHierarchy(IGameManager gameManager)
|
||||
{
|
||||
if (behaviour is not ICollider2D collider2D)
|
||||
return;
|
||||
physicsUpdateCollector.Unassign();
|
||||
colliderCollector.Unassign();
|
||||
rigidBodyCollector.Unassign();
|
||||
|
||||
colliders.Remove(collider2D);
|
||||
gameManager.OnPreUpdate -= OnEnginePreUpdate;
|
||||
}
|
||||
|
||||
private void OnEnginePreUpdate(IGameManager sender, EngineTime engineTime)
|
||||
{
|
||||
physicsTicker += engineTime.DeltaTime;
|
||||
|
||||
while (physicsTicker >= IterationPeriod)
|
||||
{
|
||||
physicsTicker -= IterationPeriod;
|
||||
Step(IterationPeriod);
|
||||
}
|
||||
}
|
||||
|
||||
public PhysicsEngine2D()
|
||||
|
@ -1,24 +1,43 @@
|
||||
using Syntriax.Engine.Core;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Syntriax.Engine.Core.Abstract;
|
||||
using Syntriax.Engine.Physics2D.Abstract;
|
||||
|
||||
namespace Syntriax.Engine.Physics2D;
|
||||
|
||||
public class PhysicsEngine2DCollector : HierarchyObject, IPhysicsEngine2D
|
||||
public class PhysicsEngine2DStandalone : IPhysicsEngine2D
|
||||
{
|
||||
public event IPhysicsEngine2D.PhysicsIterationEventHandler? OnPhysicsIteration = null;
|
||||
public event IPhysicsEngine2D.PhysicsStepEventHandler? OnPhysicsStep = null;
|
||||
|
||||
private int _iterationPerStep = 1;
|
||||
private readonly List<IRigidBody2D> rigidBodies = new(32);
|
||||
private readonly List<ICollider2D> colliders = new(64);
|
||||
|
||||
protected readonly ICollisionDetector2D collisionDetector = null!;
|
||||
protected readonly ICollisionResolver2D collisionResolver = null!;
|
||||
private int _iterationCount = 1;
|
||||
|
||||
protected BehaviourCollector<IRigidBody2D> rigidBodyCollector = new();
|
||||
protected BehaviourCollector<ICollider2D> colliderCollector = new();
|
||||
protected BehaviourCollector<IPhysicsUpdate> physicsUpdateCollector = new();
|
||||
private readonly ICollisionDetector2D collisionDetector = null!;
|
||||
private readonly ICollisionResolver2D collisionResolver = null!;
|
||||
|
||||
public int IterationPerStep { get => _iterationPerStep; set => _iterationPerStep = value < 1 ? 1 : value; }
|
||||
public int IterationPerStep { get => _iterationCount; set => _iterationCount = value < 1 ? 1 : value; }
|
||||
|
||||
public void AddRigidBody(IRigidBody2D rigidBody)
|
||||
{
|
||||
if (rigidBodies.Contains(rigidBody))
|
||||
return;
|
||||
|
||||
rigidBodies.Add(rigidBody);
|
||||
|
||||
foreach (ICollider2D collider2D in rigidBody.BehaviourController.GetBehaviours<ICollider2D>())
|
||||
colliders.Add(collider2D);
|
||||
|
||||
rigidBody.BehaviourController.OnBehaviourAdded += OnBehaviourAdded;
|
||||
rigidBody.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved;
|
||||
}
|
||||
|
||||
public void RemoveRigidBody(IRigidBody2D rigidBody)
|
||||
{
|
||||
rigidBodies.Remove(rigidBody);
|
||||
}
|
||||
|
||||
public void Step(float deltaTime)
|
||||
{
|
||||
@ -27,23 +46,23 @@ public class PhysicsEngine2DCollector : HierarchyObject, IPhysicsEngine2D
|
||||
for (int iterationIndex = 0; iterationIndex < IterationPerStep; iterationIndex++)
|
||||
{
|
||||
// Can Parallel
|
||||
foreach (IRigidBody2D rigidBody in rigidBodyCollector)
|
||||
StepRigidBody(rigidBody, intervalDeltaTime);
|
||||
for (int i = 0; i < rigidBodies.Count; i++)
|
||||
StepRigidBody(rigidBodies[i], intervalDeltaTime);
|
||||
|
||||
// Can Parallel
|
||||
foreach (ICollider2D collider in colliderCollector)
|
||||
foreach (ICollider2D collider in colliders)
|
||||
collider.Recalculate();
|
||||
|
||||
// Can Parallel
|
||||
for (int x = 0; x < colliderCollector.Behaviours.Count; x++)
|
||||
for (int x = 0; x < colliders.Count; x++)
|
||||
{
|
||||
ICollider2D? colliderX = colliderCollector.Behaviours[x];
|
||||
ICollider2D? colliderX = colliders[x];
|
||||
if (!colliderX.IsActive)
|
||||
return;
|
||||
|
||||
for (int y = x + 1; y < colliderCollector.Behaviours.Count; y++)
|
||||
for (int y = x + 1; y < colliders.Count; y++)
|
||||
{
|
||||
ICollider2D? colliderY = colliderCollector.Behaviours[y];
|
||||
ICollider2D? colliderY = colliders[y];
|
||||
|
||||
if (!colliderY.IsActive)
|
||||
return;
|
||||
@ -68,7 +87,7 @@ public class PhysicsEngine2DCollector : HierarchyObject, IPhysicsEngine2D
|
||||
}
|
||||
else if (colliderY.IsTrigger)
|
||||
{
|
||||
colliderY.Trigger(colliderY);
|
||||
colliderY.Trigger(colliderX);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -87,13 +106,8 @@ public class PhysicsEngine2DCollector : HierarchyObject, IPhysicsEngine2D
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OnPhysicsIteration?.Invoke(this, intervalDeltaTime);
|
||||
}
|
||||
|
||||
foreach (IPhysicsUpdate physicsUpdate in physicsUpdateCollector)
|
||||
physicsUpdate.PhysicsUpdate(deltaTime);
|
||||
|
||||
OnPhysicsStep?.Invoke(this, deltaTime);
|
||||
}
|
||||
|
||||
@ -105,27 +119,30 @@ public class PhysicsEngine2DCollector : HierarchyObject, IPhysicsEngine2D
|
||||
rigidBody.Transform.Position += rigidBody.Velocity * intervalDeltaTime;
|
||||
rigidBody.Transform.Rotation += rigidBody.AngularVelocity * intervalDeltaTime;
|
||||
}
|
||||
protected override void OnEnteringHierarchy(IGameManager gameManager)
|
||||
|
||||
private void OnBehaviourAdded(IBehaviourController controller, IBehaviour behaviour)
|
||||
{
|
||||
physicsUpdateCollector.Assign(gameManager);
|
||||
colliderCollector.Assign(gameManager);
|
||||
rigidBodyCollector.Assign(gameManager);
|
||||
if (behaviour is not ICollider2D collider2D)
|
||||
return;
|
||||
|
||||
colliders.Add(collider2D);
|
||||
}
|
||||
|
||||
protected override void OnExitingHierarchy(IGameManager gameManager)
|
||||
private void OnBehaviourRemoved(IBehaviourController controller, IBehaviour behaviour)
|
||||
{
|
||||
physicsUpdateCollector.Unassign();
|
||||
colliderCollector.Unassign();
|
||||
rigidBodyCollector.Unassign();
|
||||
if (behaviour is not ICollider2D collider2D)
|
||||
return;
|
||||
|
||||
colliders.Remove(collider2D);
|
||||
}
|
||||
|
||||
public PhysicsEngine2DCollector()
|
||||
public PhysicsEngine2DStandalone()
|
||||
{
|
||||
collisionDetector = new CollisionDetector2D();
|
||||
collisionResolver = new CollisionResolver2D();
|
||||
}
|
||||
|
||||
public PhysicsEngine2DCollector(ICollisionDetector2D collisionDetector, ICollisionResolver2D collisionResolver)
|
||||
public PhysicsEngine2DStandalone(ICollisionDetector2D collisionDetector, ICollisionResolver2D collisionResolver)
|
||||
{
|
||||
this.collisionDetector = collisionDetector;
|
||||
this.collisionResolver = collisionResolver;
|
@ -2,9 +2,9 @@ namespace Syntriax.Engine.Systems.Time;
|
||||
|
||||
public interface IStopwatch : IReadOnlyStopwatch
|
||||
{
|
||||
void StopwatchStart();
|
||||
void StopwatchStop();
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
void StopwatchPause();
|
||||
void StopwatchResume();
|
||||
void Pause();
|
||||
void Resume();
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ public interface ITicker : IStopwatch
|
||||
event TickerTickEventHandler? OnTick;
|
||||
|
||||
int TickCounter { get; }
|
||||
double TickPeriod { get; set; }
|
||||
double Period { get; set; }
|
||||
|
||||
delegate void TickerTickEventHandler(ITicker sender);
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ namespace Syntriax.Engine.Systems.Time;
|
||||
|
||||
public interface ITimer : IReadOnlyTimer
|
||||
{
|
||||
void TimerStart(double time);
|
||||
void TimerStop();
|
||||
void Start(double time);
|
||||
void Stop();
|
||||
|
||||
void TimerPause();
|
||||
void TimerResume();
|
||||
void Pause();
|
||||
void Resume();
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ public class StopwatchBehaviour : Behaviour, IStopwatch
|
||||
private bool shouldBeTicking = false;
|
||||
private bool hasStartedTickingBefore = false;
|
||||
|
||||
public virtual void StopwatchStart()
|
||||
public virtual void Start()
|
||||
{
|
||||
Time = 0f;
|
||||
|
||||
@ -28,7 +28,7 @@ public class StopwatchBehaviour : Behaviour, IStopwatch
|
||||
StartStopwatch();
|
||||
}
|
||||
|
||||
public virtual void StopwatchStop()
|
||||
public virtual void Stop()
|
||||
{
|
||||
if (!shouldBeTicking)
|
||||
return;
|
||||
@ -56,7 +56,7 @@ public class StopwatchBehaviour : Behaviour, IStopwatch
|
||||
return;
|
||||
|
||||
if (hasStartedTickingBefore)
|
||||
StopwatchResume();
|
||||
Resume();
|
||||
else
|
||||
StartStopwatch();
|
||||
}
|
||||
@ -66,16 +66,16 @@ public class StopwatchBehaviour : Behaviour, IStopwatch
|
||||
if (!shouldBeTicking || State is not TimerState.Ticking)
|
||||
return;
|
||||
|
||||
StopwatchPause();
|
||||
Pause();
|
||||
}
|
||||
|
||||
public virtual void StopwatchPause()
|
||||
public virtual void Pause()
|
||||
{
|
||||
State = TimerState.Paused;
|
||||
OnPaused?.Invoke(this);
|
||||
}
|
||||
|
||||
public virtual void StopwatchResume()
|
||||
public virtual void Resume()
|
||||
{
|
||||
State = TimerState.Ticking;
|
||||
OnResumed?.Invoke(this);
|
||||
|
@ -4,28 +4,28 @@ public class TickerBehaviour : StopwatchBehaviour, ITicker
|
||||
{
|
||||
public event ITicker.TickerTickEventHandler? OnTick = null;
|
||||
|
||||
public double TickPeriod { get; set; } = 1f;
|
||||
public double Period { get; set; } = 1f;
|
||||
public int TickCounter { get; private set; } = 0;
|
||||
|
||||
private double nextTick = 0f;
|
||||
|
||||
public override void StopwatchStart()
|
||||
public override void Start()
|
||||
{
|
||||
TickCounter = 0;
|
||||
base.StopwatchStart();
|
||||
nextTick = Time + TickPeriod;
|
||||
base.Start();
|
||||
nextTick = Time + Period;
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
base.OnUpdate();
|
||||
|
||||
if (Time < nextTick)
|
||||
return;
|
||||
|
||||
nextTick += TickPeriod;
|
||||
TickCounter++;
|
||||
OnTick?.Invoke(this);
|
||||
while (Time > nextTick)
|
||||
{
|
||||
nextTick += Period;
|
||||
TickCounter++;
|
||||
OnTick?.Invoke(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnFinalize()
|
||||
|
@ -31,7 +31,7 @@ public class TimerBehaviour : Behaviour, ITimer
|
||||
private bool shouldBeTicking = false;
|
||||
private bool hasStartedTickingBefore = false;
|
||||
|
||||
public virtual void TimerStart(double time)
|
||||
public virtual void Start(double time)
|
||||
{
|
||||
StartTime = time;
|
||||
Remaining = time;
|
||||
@ -43,7 +43,7 @@ public class TimerBehaviour : Behaviour, ITimer
|
||||
StartTimer();
|
||||
}
|
||||
|
||||
public virtual void TimerStop()
|
||||
public virtual void Stop()
|
||||
{
|
||||
if (!shouldBeTicking)
|
||||
return;
|
||||
@ -65,7 +65,7 @@ public class TimerBehaviour : Behaviour, ITimer
|
||||
OnDelta?.Invoke(this, delta);
|
||||
|
||||
if (Remaining <= .0f)
|
||||
TimerStop();
|
||||
Stop();
|
||||
}
|
||||
|
||||
protected override void OnEnteredHierarchy(IGameManager gameManager)
|
||||
@ -74,7 +74,7 @@ public class TimerBehaviour : Behaviour, ITimer
|
||||
return;
|
||||
|
||||
if (hasStartedTickingBefore)
|
||||
TimerResume();
|
||||
Resume();
|
||||
else
|
||||
StartTimer();
|
||||
}
|
||||
@ -84,16 +84,16 @@ public class TimerBehaviour : Behaviour, ITimer
|
||||
if (!shouldBeTicking || State is not TimerState.Ticking)
|
||||
return;
|
||||
|
||||
TimerPause();
|
||||
Pause();
|
||||
}
|
||||
|
||||
public virtual void TimerPause()
|
||||
public virtual void Pause()
|
||||
{
|
||||
State = TimerState.Paused;
|
||||
OnPaused?.Invoke(this);
|
||||
}
|
||||
|
||||
public virtual void TimerResume()
|
||||
public virtual void Resume()
|
||||
{
|
||||
State = TimerState.Ticking;
|
||||
OnResumed?.Invoke(this);
|
||||
|
@ -7,66 +7,66 @@ internal static class EaseConstants
|
||||
internal const float c1 = 1.70158f;
|
||||
internal const float c2 = c1 * 1.525f;
|
||||
internal const float c3 = c1 + 1f;
|
||||
internal const float c4 = 2f * Core.Math.PI / 3;
|
||||
internal const float c4 = 2f * Core.Math.PI / 3f;
|
||||
internal const float c5 = 2f * Core.Math.PI / 4.5f;
|
||||
}
|
||||
|
||||
public readonly struct EaseLinear : IEasing { public readonly float Evaluate(float value) => value; }
|
||||
public readonly struct EaseLinear : IEasing { public readonly float Evaluate(float x) => x; }
|
||||
|
||||
public readonly struct EaseInQuad : IEasing { public readonly float Evaluate(float value) => value * value; }
|
||||
public readonly struct EaseOutQuad : IEasing { public readonly float Evaluate(float value) => 1f - (1f - value) * (1f - value); }
|
||||
public readonly struct EaseInOutQuad : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? 2f * value * value : 1f - Core.Math.Pow(-2f * value + 2f, 2f) * .5f; }
|
||||
public readonly struct EaseInQuad : IEasing { public readonly float Evaluate(float x) => x * x; }
|
||||
public readonly struct EaseOutQuad : IEasing { public readonly float Evaluate(float x) => 1f - (1f - x) * (1f - x); }
|
||||
public readonly struct EaseInOutQuad : IEasing { public readonly float Evaluate(float x) => x < .5f ? 2f * x * x : 1f - Core.Math.Pow(-2f * x + 2f, 2f) * .5f; }
|
||||
|
||||
public readonly struct EaseInCubic : IEasing { public readonly float Evaluate(float value) => value * value * value; }
|
||||
public readonly struct EaseOutCubic : IEasing { public readonly float Evaluate(float value) => 1f - Core.Math.Pow(1f - value, 3); }
|
||||
public readonly struct EaseInOutCubic : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? 4f * value * value * value : 1f - Core.Math.Pow(-2f * value + 2f, 3) * .5f; }
|
||||
public readonly struct EaseInCubic : IEasing { public readonly float Evaluate(float x) => x * x * x; }
|
||||
public readonly struct EaseOutCubic : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Pow(1f - x, 3f); }
|
||||
public readonly struct EaseInOutCubic : IEasing { public readonly float Evaluate(float x) => x < .5f ? 4f * x * x * x : 1f - Core.Math.Pow(-2f * x + 2f, 3f) * .5f; }
|
||||
|
||||
public readonly struct EaseInQuart : IEasing { public readonly float Evaluate(float value) => value * value * value * value; }
|
||||
public readonly struct EaseOutQuart : IEasing { public readonly float Evaluate(float value) => 1f - Core.Math.Pow(1f - value, 4f); }
|
||||
public readonly struct EaseInOutQuart : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? 8 * value * value * value * value : 1f - Core.Math.Pow(-2f * value + 2f, 4f) * .5f; }
|
||||
public readonly struct EaseInQuart : IEasing { public readonly float Evaluate(float x) => x * x * x * x; }
|
||||
public readonly struct EaseOutQuart : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Pow(1f - x, 4f); }
|
||||
public readonly struct EaseInOutQuart : IEasing { public readonly float Evaluate(float x) => x < .5f ? 8f * x * x * x * x : 1f - Core.Math.Pow(-2f * x + 2f, 4f) * .5f; }
|
||||
|
||||
public readonly struct EaseInQuint : IEasing { public readonly float Evaluate(float value) => value * value * value * value * value; }
|
||||
public readonly struct EaseOutQuint : IEasing { public readonly float Evaluate(float value) => 1f - Core.Math.Pow(1f - value, 5); }
|
||||
public readonly struct EaseInOutQuint : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? 16 * value * value * value * value * value : 1f - Core.Math.Pow(-2f * value + 2f, 5) * .5f; }
|
||||
public readonly struct EaseInQuint : IEasing { public readonly float Evaluate(float x) => x * x * x * x * x; }
|
||||
public readonly struct EaseOutQuint : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Pow(1f - x, 5f); }
|
||||
public readonly struct EaseInOutQuint : IEasing { public readonly float Evaluate(float x) => x < .5f ? 16f * x * x * x * x * x : 1f - Core.Math.Pow(-2f * x + 2f, 5f) * .5f; }
|
||||
|
||||
public readonly struct EaseInSine : IEasing { public readonly float Evaluate(float value) => 1f - Core.Math.Cos(value * Core.Math.PI * .5f); }
|
||||
public readonly struct EaseOutSine : IEasing { public readonly float Evaluate(float value) => Core.Math.Sin(value * Core.Math.PI * .5f); }
|
||||
public readonly struct EaseInOutSine : IEasing { public readonly float Evaluate(float value) => -(Core.Math.Cos(Core.Math.PI * value) - 1f) * .5f; }
|
||||
public readonly struct EaseInSine : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Cos(x * Core.Math.PI * .5f); }
|
||||
public readonly struct EaseOutSine : IEasing { public readonly float Evaluate(float x) => Core.Math.Sin(x * Core.Math.PI * .5f); }
|
||||
public readonly struct EaseInOutSine : IEasing { public readonly float Evaluate(float x) => -(Core.Math.Cos(Core.Math.PI * x) - 1f) * .5f; }
|
||||
|
||||
public readonly struct EaseInExpo : IEasing { public readonly float Evaluate(float value) => value == 0 ? 0 : Core.Math.Pow(2f, 10f * value - 10f); }
|
||||
public readonly struct EaseOutExpo : IEasing { public readonly float Evaluate(float value) => value == 1f ? 1f : 1f - Core.Math.Pow(2f, -10f * value); }
|
||||
public readonly struct EaseInOutExpo : IEasing { public readonly float Evaluate(float value) => value == 0 ? 0 : value == 1f ? 1f : value < 0.5f ? Core.Math.Pow(2f, 20 * value - 10f) * .5f : (2f - Core.Math.Pow(2f, -20 * value + 10f)) * .5f; }
|
||||
public readonly struct EaseInExpo : IEasing { public readonly float Evaluate(float x) => x == 0f ? 0f : Core.Math.Pow(2f, 10f * x - 10f); }
|
||||
public readonly struct EaseOutExpo : IEasing { public readonly float Evaluate(float x) => x == 1f ? 1f : 1f - Core.Math.Pow(2f, -10f * x); }
|
||||
public readonly struct EaseInOutExpo : IEasing { public readonly float Evaluate(float x) => x == 0f ? 0f : x == 1f ? 1f : x < .5f ? Core.Math.Pow(2f, 20f * x - 10f) * .5f : (2f - Core.Math.Pow(2f, -20f * x + 10f)) * .5f; }
|
||||
|
||||
public readonly struct EaseInCirc : IEasing { public readonly float Evaluate(float value) => 1f - Core.Math.Sqrt(1f - Core.Math.Pow(value, 2f)); }
|
||||
public readonly struct EaseOutCirc : IEasing { public readonly float Evaluate(float value) => Core.Math.Sqrt(1f - Core.Math.Pow(value - 1f, 2f)); }
|
||||
public readonly struct EaseInOutCirc : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? (1f - Core.Math.Sqrt(1f - Core.Math.Pow(2f * value, 2f))) * .5f : (Core.Math.Sqrt(1f - Core.Math.Pow(-2f * value + 2f, 2f)) + 1f) * .5f; }
|
||||
public readonly struct EaseInCirc : IEasing { public readonly float Evaluate(float x) => 1f - Core.Math.Sqrt(1f - Core.Math.Pow(x, 2f)); }
|
||||
public readonly struct EaseOutCirc : IEasing { public readonly float Evaluate(float x) => Core.Math.Sqrt(1f - Core.Math.Pow(x - 1f, 2f)); }
|
||||
public readonly struct EaseInOutCirc : IEasing { public readonly float Evaluate(float x) => x < .5f ? (1f - Core.Math.Sqrt(1f - Core.Math.Pow(2f * x, 2f))) * .5f : (Core.Math.Sqrt(1f - Core.Math.Pow(-2f * x + 2f, 2f)) + 1f) * .5f; }
|
||||
|
||||
public readonly struct EaseInBack : IEasing { public readonly float Evaluate(float value) => EaseConstants.c3 * value * value * value - EaseConstants.c1 * value * value; }
|
||||
public readonly struct EaseOutBack : IEasing { public readonly float Evaluate(float value) => 1f + EaseConstants.c3 * Core.Math.Pow(value - 1f, 3) + EaseConstants.c1 * Core.Math.Pow(value - 1f, 2f); }
|
||||
public readonly struct EaseInOutBack : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? Core.Math.Pow(2f * value, 2f) * ((EaseConstants.c2 + 1f) * 2f * value - EaseConstants.c2) * .5f : (Core.Math.Pow(2f * value - 2f, 2f) * ((EaseConstants.c2 + 1f) * (value * 2f - 2f) + EaseConstants.c2) + 2f) * .5f; }
|
||||
public readonly struct EaseInBack : IEasing { public readonly float Evaluate(float x) => EaseConstants.c3 * x * x * x - EaseConstants.c1 * x * x; }
|
||||
public readonly struct EaseOutBack : IEasing { public readonly float Evaluate(float x) => 1f + EaseConstants.c3 * Core.Math.Pow(x - 1f, 3f) + EaseConstants.c1 * Core.Math.Pow(x - 1f, 2f); }
|
||||
public readonly struct EaseInOutBack : IEasing { public readonly float Evaluate(float x) => x < .5f ? Core.Math.Pow(2f * x, 2f) * ((EaseConstants.c2 + 1f) * 2f * x - EaseConstants.c2) * .5f : (Core.Math.Pow(2f * x - 2f, 2f) * ((EaseConstants.c2 + 1f) * (x * 2f - 2f) + EaseConstants.c2) + 2f) * .5f; }
|
||||
|
||||
public readonly struct EaseInElastic : IEasing { public readonly float Evaluate(float value) => value == 0 ? 0 : value == 1f ? 1f : -Core.Math.Pow(2f, 10f * value - 10f) * Core.Math.Sin((value * 10f - 10.75f) * EaseConstants.c4); }
|
||||
public readonly struct EaseOutElastic : IEasing { public readonly float Evaluate(float value) => value == 0 ? 0 : value == 1f ? 1f : Core.Math.Pow(2f, -10f * value) * Core.Math.Sin((value * 10f - 0.75f) * EaseConstants.c4) + 1f; }
|
||||
public readonly struct EaseInOutElastic : IEasing { public readonly float Evaluate(float value) => value == 0 ? 0 : value == 1f ? 1f : value < 0.5f ? -(Core.Math.Pow(2f, 20 * value - 10f) * Core.Math.Sin((20 * value - 11.125f) * EaseConstants.c5)) * .5f : Core.Math.Pow(2f, -20 * value + 10f) * Core.Math.Sin((20 * value - 11.125f) * EaseConstants.c5) * .5f + 1f; }
|
||||
public readonly struct EaseInElastic : IEasing { public readonly float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : -Core.Math.Pow(2f, 10f * x - 10f) * Core.Math.Sin((x * 10f - 10.75f) * EaseConstants.c4); }
|
||||
public readonly struct EaseOutElastic : IEasing { public readonly float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : Core.Math.Pow(2f, -10f * x) * Core.Math.Sin((x * 10f - .75f) * EaseConstants.c4) + 1f; }
|
||||
public readonly struct EaseInOutElastic : IEasing { public readonly float Evaluate(float x) => x == 0 ? 0 : x == 1f ? 1f : x < .5f ? -(Core.Math.Pow(2f, 20f * x - 10f) * Core.Math.Sin((20f * x - 11.125f) * EaseConstants.c5)) * .5f : Core.Math.Pow(2f, -20f * x + 10f) * Core.Math.Sin((20f * x - 11.125f) * EaseConstants.c5) * .5f + 1f; }
|
||||
|
||||
public readonly struct EaseInBounce : IEasing { public readonly float Evaluate(float value) => 1f - new EaseOutBounce().Evaluate(1f - value); }
|
||||
public readonly struct EaseInBounce : IEasing { public readonly float Evaluate(float x) => 1f - new EaseOutBounce().Evaluate(1f - x); }
|
||||
public readonly struct EaseOutBounce : IEasing
|
||||
{
|
||||
public readonly float Evaluate(float value)
|
||||
public readonly float Evaluate(float x)
|
||||
{
|
||||
const float n1 = 7.5625f;
|
||||
const float d1 = 2.75f;
|
||||
|
||||
if (value < 1 / d1)
|
||||
return n1 * value * value;
|
||||
if (x < 1f / d1)
|
||||
return n1 * x * x;
|
||||
|
||||
if (value < 2 / d1)
|
||||
return n1 * (value -= 1.5f / d1) * value + 0.75f;
|
||||
if (x < 2f / d1)
|
||||
return n1 * (x -= 1.5f / d1) * x + .75f;
|
||||
|
||||
if (value < 2.5 / d1)
|
||||
return n1 * (value -= 2.25f / d1) * value + 0.9375f;
|
||||
if (x < 2.5f / d1)
|
||||
return n1 * (x -= 2.25f / d1) * x + .9375f;
|
||||
|
||||
return n1 * (value -= 2.625f / d1) * value + 0.984375f;
|
||||
return n1 * (x -= 2.625f / d1) * x + .984375f;
|
||||
}
|
||||
}
|
||||
public readonly struct EaseInOutBounce : IEasing { public readonly float Evaluate(float value) => value < 0.5f ? (1f - new EaseOutBounce().Evaluate(1f - 2f * value)) * .5f : (1f + new EaseOutBounce().Evaluate(2f * value - 1f)) * .5f; }
|
||||
public readonly struct EaseInOutBounce : IEasing { public readonly float Evaluate(float x) => x < .5f ? (1f - new EaseOutBounce().Evaluate(1f - 2f * x)) * .5f : (1f + new EaseOutBounce().Evaluate(2f * x - 1f)) * .5f; }
|
||||
|
@ -2,6 +2,6 @@ namespace Syntriax.Engine.Systems.Tween;
|
||||
|
||||
public interface IEasing
|
||||
{
|
||||
float Evaluate(float value);
|
||||
float Evaluate(float x);
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
# Work In Progress
|
||||
|
||||
This engine is still in development but the implemented features include:
|
||||
This engine is still in development so there **WILL** be breaking changes, but the implemented features include:
|
||||
|
||||
- Modular Systems
|
||||
- Behaviour System
|
||||
- 2D Physics Engine(**Not Fully Completed, but usable**)
|
||||
- Rigid Body Simulations
|
||||
- Collision Detection (Convex Shape & Circle)
|
||||
- Collision Resolution (**Not Fully Completed**)
|
||||
- Rigid Body Simulations
|
||||
- Collision Detection (Convex Shape & Circle)
|
||||
- Collision Resolution (**Not Fully Completed**)
|
||||
- Vector2D, AABB, Circle, Line, LineEquation, Projection & Shape Data Types
|
||||
- General Math
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user