Compare commits
16 Commits
e5732f0ac5
...
3428fcc6ca
Author | SHA1 | Date | |
---|---|---|---|
3428fcc6ca | |||
528649659d | |||
da67f4559b | |||
08b31d9db1 | |||
326bcfca61 | |||
bfab35c27e | |||
468615e4cb | |||
56b46b93eb | |||
0c3bf48d2c | |||
77e1949f59 | |||
fbf9bd5832 | |||
d40183db65 | |||
a60f79f12b | |||
4bf618251f | |||
b3d404bb6b | |||
87bf47eefd |
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
using Syntriax.Engine.Core.Abstract;
|
||||
|
||||
@@ -55,17 +56,17 @@ public class BehaviourController : IBehaviourController
|
||||
|
||||
public IList<T> GetBehaviours<T>()
|
||||
{
|
||||
IList<T> behaviours = new List<T>();
|
||||
List<T>? behaviours = null;
|
||||
foreach (var behaviourItem in this.behaviours)
|
||||
{
|
||||
if (behaviourItem is not T behaviour)
|
||||
continue;
|
||||
|
||||
behaviours ??= new List<T>();
|
||||
behaviours ??= [];
|
||||
behaviours.Add(behaviour);
|
||||
}
|
||||
|
||||
return behaviours;
|
||||
return behaviours ?? Enumerable.Empty<T>().ToList();
|
||||
}
|
||||
|
||||
public void RemoveBehaviour<T>(bool removeAll = false) where T : class, IBehaviour
|
||||
|
9
Engine.Core/Extensions/Abstract/TransformExtensions.cs
Normal file
9
Engine.Core/Extensions/Abstract/TransformExtensions.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Syntriax.Engine.Core.Abstract;
|
||||
|
||||
public static class TransformExtensions
|
||||
{
|
||||
public static Vector2D TransformVector2D(this ITransform transform, Vector2D vector)
|
||||
=> vector.Scale(transform.Scale)
|
||||
.Rotate(transform.Rotation * Math.DegreeToRadian)
|
||||
.Add(transform.Position);
|
||||
}
|
22
Engine.Core/Extensions/FloatExtensions.cs
Normal file
22
Engine.Core/Extensions/FloatExtensions.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class FloatExtensions
|
||||
{
|
||||
public static bool ApproximatelyEquals(this float a, float b)
|
||||
=> ApproximatelyEquals(a, b, float.Epsilon);
|
||||
public static bool ApproximatelyEquals(this float a, float b, float epsilon)
|
||||
{
|
||||
if (a == b)
|
||||
return true;
|
||||
|
||||
const float floatNormal = (1 << 23) * float.Epsilon;
|
||||
float absA = Math.Abs(a);
|
||||
float absB = Math.Abs(b);
|
||||
float diff = Math.Abs(a - b);
|
||||
|
||||
if (a == 0.0f || b == 0.0f || diff < floatNormal)
|
||||
return diff < (epsilon * floatNormal);
|
||||
|
||||
return diff / Math.Min(absA + absB, float.MaxValue) < epsilon;
|
||||
}
|
||||
}
|
@@ -13,6 +13,7 @@ public static class Vector2DExtensions
|
||||
public static Vector2D Multiply(this Vector2D vector, float value) => Vector2D.Multiply(vector, value);
|
||||
public static Vector2D Subdivide(this Vector2D vector, float value) => Vector2D.Subdivide(vector, value);
|
||||
|
||||
public static Vector2D Abs(this Vector2D vector) => Vector2D.Abs(vector);
|
||||
public static Vector2D Reflect(this Vector2D vector, Vector2D normal) => Vector2D.Reflect(vector, normal);
|
||||
public static Vector2D Normalize(this Vector2D vector) => Vector2D.Normalize(vector);
|
||||
public static Vector2D FromTo(this Vector2D from, Vector2D to) => Vector2D.FromTo(from, to);
|
||||
@@ -27,4 +28,7 @@ public static class Vector2DExtensions
|
||||
public static float Cross(this Vector2D left, Vector2D right) => Vector2D.Cross(left, right);
|
||||
public static float AngleBetween(this Vector2D left, Vector2D right) => Vector2D.Angle(left, right);
|
||||
public static float Dot(this Vector2D left, Vector2D right) => Vector2D.Dot(left, right);
|
||||
|
||||
|
||||
public static bool ApproximatelyEquals(this Vector2D left, Vector2D right, float epsilon = float.Epsilon) => Vector2D.ApproximatelyEquals(left, right, epsilon);
|
||||
}
|
||||
|
32
Engine.Core/Math.cs
Normal file
32
Engine.Core/Math.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace Syntriax.Engine.Core;
|
||||
|
||||
public static class Math
|
||||
{
|
||||
public const float RadianToDegree = 180f / PI;
|
||||
public const float DegreeToRadian = PI / 180f;
|
||||
|
||||
public const float E = 2.718281828459045f;
|
||||
public const float PI = 3.1415926535897932f;
|
||||
public const float Tau = 2f * PI;
|
||||
|
||||
public static float Abs(float x) => MathF.Abs(x);
|
||||
public static float Acos(float x) => MathF.Acos(x);
|
||||
public static float Asin(float x) => MathF.Asin(x);
|
||||
public static float Atan2(float y, float x) => MathF.Atan2(y, x);
|
||||
public static float Atanh(float x) => MathF.Atanh(x);
|
||||
public static float Clamp(float x, float min, float max) => (x < min) ? min : (x > max) ? max : x;
|
||||
public static float Ceiling(float x) => MathF.Ceiling(x);
|
||||
public static float CopySign(float x, float y) => MathF.CopySign(x, y);
|
||||
public static float Floor(float x) => MathF.Floor(x);
|
||||
public static float IEEERemainder(float x, float y) => MathF.IEEERemainder(x, y);
|
||||
public static float Log(float x, float y) => MathF.Log(x, y);
|
||||
public static float Max(float x, float y) => MathF.Max(x, y);
|
||||
public static float MaxMagnitude(float x, float y) => MathF.MaxMagnitude(x, y);
|
||||
public static float Min(float x, float y) => MathF.Min(x, y);
|
||||
public static float MinMagnitude(float x, float y) => MathF.MinMagnitude(x, y);
|
||||
public static float Pow(float x, float y) => MathF.Pow(x, y);
|
||||
public static float Round(float x, int digits, MidpointRounding mode) => MathF.Round(x, digits, mode);
|
||||
public static float Truncate(float x) => MathF.Truncate(x);
|
||||
}
|
@@ -34,6 +34,7 @@ public record Vector2D(float X, float Y)
|
||||
public static Vector2D Multiply(Vector2D vector, float value) => vector * value;
|
||||
public static Vector2D Subdivide(Vector2D vector, float value) => vector / value;
|
||||
|
||||
public static Vector2D Abs(Vector2D vector) => new(Math.Abs(vector.X), Math.Abs(vector.Y));
|
||||
public static Vector2D Normalize(Vector2D vector) => vector / Length(vector);
|
||||
public static Vector2D Reflect(Vector2D vector, Vector2D normal) => vector - 2f * Dot(vector, normal) * normal;
|
||||
public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from;
|
||||
@@ -49,5 +50,25 @@ public record Vector2D(float X, float Y)
|
||||
public static float Angle(Vector2D left, Vector2D right) => MathF.Acos(Dot(left, right) / (Length(left) * Length(right)));
|
||||
public static float Dot(Vector2D left, Vector2D right) => left.X * right.X + left.Y * right.Y;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the Orientation of 3 <see cref="Vector2D"/>s
|
||||
/// </summary>
|
||||
/// <returns>0 -> Collinear, 1 -> Clockwise, 2 -> Counterclockwise</returns>
|
||||
public static int Orientation(Vector2D left, Vector2D middle, Vector2D right)
|
||||
{
|
||||
Vector2D leftToMiddle = left.FromTo(middle);
|
||||
Vector2D middleToRight = middle.FromTo(right);
|
||||
|
||||
float value = leftToMiddle.Y * middleToRight.X -
|
||||
leftToMiddle.X * middleToRight.Y;
|
||||
|
||||
if (value > 0) return 1;
|
||||
if (value < 0) return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static bool ApproximatelyEquals(Vector2D left, Vector2D right, float epsilon = float.Epsilon)
|
||||
=> left.X.ApproximatelyEquals(right.X, epsilon) && left.Y.ApproximatelyEquals(right.Y, epsilon);
|
||||
|
||||
public override string ToString() => $"{nameof(Vector2D)}({X}, {Y})";
|
||||
}
|
||||
|
@@ -8,9 +8,6 @@ namespace Engine.Physics2D;
|
||||
|
||||
public static partial class Physics2D
|
||||
{
|
||||
public const float RadianToDegree = 57.29577866666166f;
|
||||
public const float DegreeToRadian = 0.01745329277777778f;
|
||||
|
||||
public static bool Overlaps(this Circle left, Circle right)
|
||||
{
|
||||
float distanceSquared = left.Position.FromTo(right.Position).LengthSquared();
|
||||
|
@@ -1,67 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
using Syntriax.Engine.Physics2D.Primitives;
|
||||
|
||||
namespace Syntriax.Engine.Physics2D;
|
||||
|
||||
public static class PhysicsMath
|
||||
{
|
||||
|
||||
|
||||
// Given three collinear points p, q, r, the function checks if
|
||||
// point q lies on line segment 'pr'
|
||||
public static bool OnSegment(Vector2D p, Vector2D q, Vector2D r)
|
||||
{
|
||||
if (q.X <= MathF.Max(p.X, r.X) && q.X >= MathF.Min(p.X, r.X) &&
|
||||
q.Y <= MathF.Max(p.Y, r.Y) && q.Y >= MathF.Min(p.Y, r.Y))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// To find orientation of ordered triplet (p, q, r).
|
||||
// The function returns following values
|
||||
// 0 --> p, q and r are collinear
|
||||
// 1 --> Clockwise
|
||||
// 2 --> Counterclockwise
|
||||
public static int Orientation(Vector2D p, Vector2D q, Vector2D r)
|
||||
{
|
||||
// See https://www.geeksforgeeks.org/orientation-3-ordered-points/
|
||||
// for details of below formula.
|
||||
float val = (q.Y - p.Y) * (r.X - q.X) -
|
||||
(q.X - p.X) * (r.Y - q.Y);
|
||||
|
||||
if (val == 0) return 0; // collinear
|
||||
|
||||
return (val > 0) ? 1 : 2; // clock or counterclock wise
|
||||
}
|
||||
|
||||
public static float IntersectionParameterT(Vector2D p0, Vector2D p1, Vector2D q0, Vector2D q1)
|
||||
=> ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) /
|
||||
((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y));
|
||||
|
||||
|
||||
public static bool ApproximatelyEquals(this float a, float b)
|
||||
=> ApproximatelyEquals(a, b, float.Epsilon);
|
||||
public static bool ApproximatelyEquals(this Vector2D a, Vector2D b)
|
||||
=> ApproximatelyEquals(a, b, float.Epsilon);
|
||||
public static bool ApproximatelyEquals(this Vector2D a, Vector2D b, float epsilon)
|
||||
=> ApproximatelyEquals(a.X, b.X, epsilon) && ApproximatelyEquals(a.Y, b.Y, epsilon);
|
||||
public static bool ApproximatelyEquals(this float a, float b, float epsilon)
|
||||
{
|
||||
if (a == b)
|
||||
return true;
|
||||
|
||||
const float floatNormal = (1 << 23) * float.Epsilon;
|
||||
float absA = MathF.Abs(a);
|
||||
float absB = MathF.Abs(b);
|
||||
float diff = MathF.Abs(a - b);
|
||||
|
||||
if (a == 0.0f || b == 0.0f || diff < floatNormal)
|
||||
return diff < (epsilon * floatNormal);
|
||||
|
||||
return diff / MathF.Min(absA + absB, float.MaxValue) < epsilon;
|
||||
}
|
||||
}
|
@@ -1,14 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
||||
|
||||
public record AABB(Vector2D LowerBoundary, Vector2D UpperBoundary)
|
||||
{
|
||||
public Vector2D Center => (LowerBoundary + UpperBoundary) * .5f;
|
||||
public Vector2D Size => LowerBoundary.FromTo(UpperBoundary).Abs();
|
||||
public Vector2D SizeHalf => Size * .5f;
|
||||
|
||||
public static AABB FromVectors(IEnumerable<Vector2D> vectors)
|
||||
{
|
||||
int counter = 0;
|
||||
|
||||
Vector2D lowerBoundary = new(float.MaxValue, float.MaxValue);
|
||||
Vector2D upperBoundary = new(float.MinValue, float.MinValue);
|
||||
|
||||
foreach (Vector2D vector in vectors)
|
||||
{
|
||||
lowerBoundary = Vector2D.Min(lowerBoundary, vector);
|
||||
upperBoundary = Vector2D.Max(upperBoundary, vector);
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (counter < 2)
|
||||
throw new System.ArgumentException($"Parameter {nameof(vectors)} must have at least 2 items.");
|
||||
|
||||
return new(lowerBoundary, upperBoundary);
|
||||
}
|
||||
|
||||
public static bool ApproximatelyEquals(AABB left, AABB right)
|
||||
=> left.LowerBoundary.ApproximatelyEquals(right.LowerBoundary) && left.UpperBoundary.ApproximatelyEquals(right.UpperBoundary);
|
||||
}
|
||||
|
||||
public static class AABBExtensions
|
||||
{
|
||||
public static AABB ToAABB(this IEnumerable<Vector2D> vectors) => AABB.FromVectors(vectors);
|
||||
|
||||
public static bool ApproximatelyEquals(this AABB left, AABB right) => AABB.ApproximatelyEquals(left, right);
|
||||
}
|
||||
|
@@ -107,18 +107,27 @@ public record Line(Vector2D From, Vector2D To)
|
||||
|
||||
public static bool Intersects(Line left, Line right)
|
||||
{
|
||||
int o1 = PhysicsMath.Orientation(left.From, left.To, right.From);
|
||||
int o2 = PhysicsMath.Orientation(left.From, left.To, right.To);
|
||||
int o3 = PhysicsMath.Orientation(right.From, right.To, left.From);
|
||||
int o4 = PhysicsMath.Orientation(right.From, right.To, left.To);
|
||||
int o1 = Vector2D.Orientation(left.From, left.To, right.From);
|
||||
int o2 = Vector2D.Orientation(left.From, left.To, right.To);
|
||||
int o3 = Vector2D.Orientation(right.From, right.To, left.From);
|
||||
int o4 = Vector2D.Orientation(right.From, right.To, left.To);
|
||||
|
||||
if (o1 != o2 && o3 != o4)
|
||||
return true;
|
||||
|
||||
if (o1 == 0 && PhysicsMath.OnSegment(left.From, right.From, left.To)) return true;
|
||||
if (o2 == 0 && PhysicsMath.OnSegment(left.From, right.To, left.To)) return true;
|
||||
if (o3 == 0 && PhysicsMath.OnSegment(right.From, left.From, right.To)) return true;
|
||||
if (o4 == 0 && PhysicsMath.OnSegment(right.From, left.To, right.To)) return true;
|
||||
if (o1 == 0 && OnSegment(left, right.From)) return true;
|
||||
if (o2 == 0 && OnSegment(left, right.To)) return true;
|
||||
if (o3 == 0 && OnSegment(right, left.From)) return true;
|
||||
if (o4 == 0 && OnSegment(right, left.To)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool OnSegment(Line line, Vector2D point)
|
||||
{
|
||||
if (point.X <= MathF.Max(line.From.X, line.To.X) && point.X >= MathF.Min(line.From.X, line.To.X) &&
|
||||
point.Y <= MathF.Max(line.From.Y, line.To.Y) && point.Y >= MathF.Min(line.From.Y, line.To.Y))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -1,3 +1,5 @@
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
||||
|
||||
public record LineEquation(float Slope, float OffsetY)
|
||||
|
@@ -1,11 +1,12 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Syntriax.Engine.Core;
|
||||
|
||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
||||
|
||||
public record Shape(IList<Vector2D> Vertices)
|
||||
public record Shape(IList<Vector2D> Vertices) : IEnumerable<Vector2D>
|
||||
{
|
||||
public Vector2D this[Index index] => Vertices[index];
|
||||
|
||||
@@ -61,6 +62,9 @@ public record Shape(IList<Vector2D> Vertices)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerator<Vector2D> GetEnumerator() => Vertices.GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => Vertices.GetEnumerator();
|
||||
}
|
||||
|
||||
public static class ShapeExtensions
|
||||
|
Reference in New Issue
Block a user