chore: Removed Physics Code
This commit is contained in:
parent
697e7c35b9
commit
8ea76f91f6
2
Engine
2
Engine
|
@ -1 +1 @@
|
||||||
Subproject commit d08495afbb7ca9f1afa2c8edcdaf0786bf095e9d
|
Subproject commit a9485475c7583a626801e7ae15550d34bd02f8dd
|
|
@ -1,19 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Abstract;
|
|
||||||
|
|
||||||
public interface ICollider2D : IBehaviour, IAssignableTransform
|
|
||||||
{
|
|
||||||
Action<ICollider2D, ICollider2D>? OnCollisionPreResolve { get; set; }
|
|
||||||
|
|
||||||
IRigidBody2D? RigidBody2D { get; }
|
|
||||||
|
|
||||||
IList<Vector2D> Vertices { get; }
|
|
||||||
|
|
||||||
bool CheckCollision(Vector2D point);
|
|
||||||
void Recalculate();
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace Syntriax.Engine.Physics2D.Abstract;
|
|
||||||
|
|
||||||
public interface ICollisionResolver2D
|
|
||||||
{
|
|
||||||
void ResolveCollision(ICollider2D colliderA, ICollider2D colliderB);
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
namespace Syntriax.Engine.Physics2D.Abstract;
|
|
||||||
|
|
||||||
public interface IPhysicsEngine2D
|
|
||||||
{
|
|
||||||
int IterationCount { get; set; }
|
|
||||||
|
|
||||||
void AddRigidBody(IRigidBody2D rigidBody);
|
|
||||||
void RemoveRigidBody(IRigidBody2D rigidBody);
|
|
||||||
|
|
||||||
void Step(float deltaTime);
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace Syntriax.Engine.Physics2D.Abstract;
|
|
||||||
|
|
||||||
public interface IPhysicsMaterial2D
|
|
||||||
{
|
|
||||||
float Friction { get; }
|
|
||||||
float Restitution { get; }
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
using Syntriax.Engine.Core;
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Abstract;
|
|
||||||
|
|
||||||
public interface IRigidBody2D : IBehaviour, IAssignableTransform
|
|
||||||
{
|
|
||||||
IPhysicsMaterial2D Material { get; set; }
|
|
||||||
|
|
||||||
Vector2D Velocity { get; set; }
|
|
||||||
float AngularVelocity { get; set; }
|
|
||||||
|
|
||||||
float Mass { get; set; }
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
using Syntriax.Engine.Physics2D.Abstract;
|
|
||||||
using Syntriax.Engine.Physics2D.Primitives;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D;
|
|
||||||
|
|
||||||
public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D
|
|
||||||
{
|
|
||||||
public AABB AABBLocal { get; set; } = null!;
|
|
||||||
public AABB AABBWorld { get; private set; } = null!;
|
|
||||||
|
|
||||||
private IRigidBody2D? _rigidBody2D = null;
|
|
||||||
private List<Vector2D> _vertices = new List<Vector2D>(4);
|
|
||||||
|
|
||||||
public IRigidBody2D? RigidBody2D
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_rigidBody2D is null)
|
|
||||||
BehaviourController.TryGetBehaviour(out _rigidBody2D);
|
|
||||||
|
|
||||||
return _rigidBody2D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Action<ICollider2D, ICollider2D>? OnCollisionPreResolve { get; set; } = null;
|
|
||||||
|
|
||||||
public Action<IAssignableTransform>? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; }
|
|
||||||
ITransform IAssignableTransform.Transform => Transform;
|
|
||||||
public bool Assign(ITransform transform) => GameObject.Assign(transform);
|
|
||||||
|
|
||||||
public IList<Vector2D> Vertices => _vertices;
|
|
||||||
|
|
||||||
public bool CheckCollision(Vector2D point)
|
|
||||||
{
|
|
||||||
return AABBWorld.Overlaps(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Recalculate()
|
|
||||||
{
|
|
||||||
AABBWorld = new AABB(
|
|
||||||
AABBLocal.LowerBoundary.Scale(Transform.Scale) + Transform.Position,
|
|
||||||
AABBLocal.UpperBoundary.Scale(Transform.Scale) + Transform.Position
|
|
||||||
);
|
|
||||||
|
|
||||||
Vertices.Clear();
|
|
||||||
Vertices.Add(AABBWorld.LowerBoundary);
|
|
||||||
Vertices.Add(new Vector2D(AABBWorld.LowerBoundary.X, AABBWorld.UpperBoundary.Y));
|
|
||||||
Vertices.Add(AABBWorld.UpperBoundary);
|
|
||||||
Vertices.Add(new Vector2D(AABBWorld.UpperBoundary.X, AABBWorld.LowerBoundary.Y));
|
|
||||||
}
|
|
||||||
public Collider2DAABBBehaviour(Vector2D lowerBoundary, Vector2D upperBoundary)
|
|
||||||
{
|
|
||||||
AABBLocal = new AABB(lowerBoundary, upperBoundary);
|
|
||||||
AABBWorld = new AABB(lowerBoundary, upperBoundary);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collider2DAABBBehaviour()
|
|
||||||
{
|
|
||||||
AABBLocal = new(Vector2D.Zero, Vector2D.Zero);
|
|
||||||
AABBWorld = new(Vector2D.Zero, Vector2D.Zero);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
using Microsoft.Xna.Framework;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D;
|
|
||||||
|
|
||||||
public record CollisionInformation
|
|
||||||
(
|
|
||||||
Vector2 Normal,
|
|
||||||
Vector2 ContactPosition
|
|
||||||
);
|
|
|
@ -1,75 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
using Syntriax.Engine.Physics2D.Abstract;
|
|
||||||
using Syntriax.Engine.Physics2D.Primitives;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D;
|
|
||||||
|
|
||||||
public class PhysicsEngine2D : IPhysicsEngine2D
|
|
||||||
{
|
|
||||||
private List<IRigidBody2D> rigidBodies = new List<IRigidBody2D>(32);
|
|
||||||
private List<ICollider2D> colliders = new List<ICollider2D>(64);
|
|
||||||
|
|
||||||
private int _iterationCount = 1;
|
|
||||||
|
|
||||||
|
|
||||||
public int IterationCount { get => _iterationCount; set => _iterationCount = value < 1 ? 1 : value; }
|
|
||||||
|
|
||||||
public void AddRigidBody(IRigidBody2D rigidBody)
|
|
||||||
{
|
|
||||||
if (rigidBodies.Contains(rigidBody))
|
|
||||||
return;
|
|
||||||
|
|
||||||
rigidBodies.Add(rigidBody);
|
|
||||||
|
|
||||||
foreach (var 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)
|
|
||||||
{
|
|
||||||
float intervalDeltaTime = deltaTime / IterationCount;
|
|
||||||
|
|
||||||
for (int iterationIndex = 0; iterationIndex < IterationCount; iterationIndex++)
|
|
||||||
{
|
|
||||||
foreach (var rigidBody in rigidBodies)
|
|
||||||
StepRigidBody(rigidBody, intervalDeltaTime);
|
|
||||||
|
|
||||||
foreach (var collider in colliders)
|
|
||||||
collider.Recalculate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime)
|
|
||||||
{
|
|
||||||
rigidBody.Transform.Position += rigidBody.Velocity * intervalDeltaTime;
|
|
||||||
rigidBody.Transform.Rotation += rigidBody.AngularVelocity * intervalDeltaTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnBehaviourAdded(IBehaviourController controller, IBehaviour behaviour)
|
|
||||||
{
|
|
||||||
if (behaviour is not ICollider2D collider2D)
|
|
||||||
return;
|
|
||||||
|
|
||||||
colliders.Add(collider2D);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnBehaviourRemoved(IBehaviourController controller, IBehaviour behaviour)
|
|
||||||
{
|
|
||||||
if (behaviour is not ICollider2D collider2D)
|
|
||||||
return;
|
|
||||||
|
|
||||||
colliders.Remove(collider2D);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
using Syntriax.Engine.Physics2D.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D;
|
|
||||||
|
|
||||||
public record PhysicsMaterial2D(float Friction, float Restitution) : IPhysicsMaterial2D { }
|
|
|
@ -1,6 +0,0 @@
|
||||||
namespace Syntriax.Engine.Physics2D;
|
|
||||||
|
|
||||||
public record PhysicsMaterial2DDefault : PhysicsMaterial2D
|
|
||||||
{
|
|
||||||
public PhysicsMaterial2DDefault() : base(.1f, .1f) { }
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Microsoft.Xna.Framework;
|
|
||||||
using Syntriax.Engine.Core;
|
|
||||||
using Syntriax.Engine.Physics2D.Primitives;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D;
|
|
||||||
|
|
||||||
public static class PhysicsMath
|
|
||||||
{
|
|
||||||
public static Vector2D Scale(this Vector2D original, Vector2D scale)
|
|
||||||
=> new Vector2D(original.X * scale.X, original.Y * scale.Y);
|
|
||||||
|
|
||||||
public static Triangle ToSuperTriangle(this IList<Vector2D> vertices)
|
|
||||||
{
|
|
||||||
float minX = float.MaxValue, minY = float.MaxValue;
|
|
||||||
float maxX = float.MinValue, maxY = float.MinValue;
|
|
||||||
|
|
||||||
foreach (Vector2D point in vertices)
|
|
||||||
{
|
|
||||||
minX = MathF.Min(minX, point.X);
|
|
||||||
minY = MathF.Min(minY, point.Y);
|
|
||||||
maxX = MathF.Max(maxX, point.X);
|
|
||||||
maxY = MathF.Max(maxY, point.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
float dx = maxX - minX;
|
|
||||||
float dy = maxY - minY;
|
|
||||||
float deltaMax = MathF.Max(dx, dy);
|
|
||||||
float midX = (minX + maxX) / 2;
|
|
||||||
float midY = (minY + maxY) / 2;
|
|
||||||
|
|
||||||
Vector2D p1 = new Vector2D((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax);
|
|
||||||
Vector2D p2 = new Vector2D((float)midX, (float)midY + 20 * (float)deltaMax);
|
|
||||||
Vector2D p3 = new Vector2D((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax);
|
|
||||||
|
|
||||||
return new Triangle(p1, p2, p3);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IList<Line> ToLines(this IList<Vector2D> vertices)
|
|
||||||
{
|
|
||||||
List<Line> lines = new List<Line>(vertices.Count - 1);
|
|
||||||
ToLines(vertices, lines);
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ToLines(this IList<Vector2D> vertices, IList<Line> lines)
|
|
||||||
{
|
|
||||||
lines.Clear();
|
|
||||||
for (int i = 0; i < vertices.Count - 1; i++)
|
|
||||||
lines.Add(new(vertices[i], vertices[i + 1]));
|
|
||||||
lines.Add(new(vertices[^1], vertices[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool LaysOn(this Vector2D point, Line line)
|
|
||||||
=> line.Resolve(point.X).ApproximatelyEquals(point);
|
|
||||||
|
|
||||||
|
|
||||||
// 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 Vector2 a, Vector2 b)
|
|
||||||
=> ApproximatelyEquals(a, b, float.Epsilon);
|
|
||||||
public static bool ApproximatelyEquals(this Vector2 a, Vector2 b, float epsilon)
|
|
||||||
=> ApproximatelyEquals(a.X, b.X, epsilon) && ApproximatelyEquals(a.Y, b.Y, 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,17 +0,0 @@
|
||||||
using Syntriax.Engine.Core;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
|
||||||
|
|
||||||
public record AABB(Vector2D LowerBoundary, Vector2D UpperBoundary)
|
|
||||||
{
|
|
||||||
public bool Overlaps(Vector2D point)
|
|
||||||
=> point.X >= LowerBoundary.X && point.X <= UpperBoundary.X &&
|
|
||||||
point.Y >= LowerBoundary.Y && point.Y <= UpperBoundary.Y;
|
|
||||||
|
|
||||||
public bool Overlaps(AABB other)
|
|
||||||
=> LowerBoundary.X <= other.UpperBoundary.X && UpperBoundary.X >= other.LowerBoundary.X &&
|
|
||||||
LowerBoundary.Y <= other.UpperBoundary.Y && UpperBoundary.Y >= other.LowerBoundary.Y;
|
|
||||||
|
|
||||||
public bool ApproximatelyEquals(AABB other)
|
|
||||||
=> LowerBoundary.ApproximatelyEquals(other.LowerBoundary) && UpperBoundary.ApproximatelyEquals(other.UpperBoundary);
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
using Syntriax.Engine.Core;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
|
||||||
|
|
||||||
public record Circle(Vector2D Position, float Radius)
|
|
||||||
{
|
|
||||||
public bool Intersects(Circle other)
|
|
||||||
{
|
|
||||||
float distanceSquared = (Position - other.Position).LengthSquared();
|
|
||||||
float radiusSumSquared = Radius * Radius + other.Radius * other.Radius;
|
|
||||||
|
|
||||||
return distanceSquared < radiusSumSquared;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Overlaps(Vector2D point) => (Position - point).LengthSquared() <= Radius * Radius;
|
|
||||||
public bool ApproximatelyEquals(Circle other)
|
|
||||||
=> Position.ApproximatelyEquals(other.Position) && Radius.ApproximatelyEquals(other.Radius);
|
|
||||||
}
|
|
|
@ -1,146 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
|
||||||
|
|
||||||
public record Line(Vector2D From, Vector2D To)
|
|
||||||
{
|
|
||||||
public Line Reversed => new(To, From);
|
|
||||||
public Vector2D Direction => Vector2D.Normalize(To - From);
|
|
||||||
public float Length => (From - To).Length();
|
|
||||||
public float LengthSquared => (From - To).LengthSquared();
|
|
||||||
|
|
||||||
public LineEquation LineEquation
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
Vector2D slopeVector = To - From;
|
|
||||||
float slope = slopeVector.Y / slopeVector.X;
|
|
||||||
|
|
||||||
float yOffset = From.Y - (slope * From.X);
|
|
||||||
|
|
||||||
return new LineEquation(slope, yOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Intersects(Vector2D point)
|
|
||||||
=> Resolve(point.X).ApproximatelyEquals(point);
|
|
||||||
|
|
||||||
public float GetT(Vector2D point)
|
|
||||||
{
|
|
||||||
float fromX = MathF.Abs(From.X);
|
|
||||||
float toX = MathF.Abs(To.X);
|
|
||||||
float pointX = MathF.Abs(point.X);
|
|
||||||
|
|
||||||
float min = MathF.Min(fromX, toX);
|
|
||||||
float max = MathF.Max(fromX, toX) - min;
|
|
||||||
|
|
||||||
pointX -= min;
|
|
||||||
|
|
||||||
float t = pointX / max;
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
// I don't even know, apparently whatever I wrote up there doesn't take into account of the direction of the line
|
|
||||||
// Which... I can see how, but I am also not sure how I can make it take into account. Or actually I'm for some reason
|
|
||||||
// too unmotivated to find a solution. Future me, find a better way if possible, please.
|
|
||||||
if (!Lerp(t).ApproximatelyEquals(point))
|
|
||||||
return 1f - t;
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Exist(List<Vector2D> vertices)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < vertices.Count - 1; i++)
|
|
||||||
{
|
|
||||||
Vector2D vertexCurrent = vertices[i];
|
|
||||||
Vector2D vertexNext = vertices[i];
|
|
||||||
if (From == vertexCurrent && To == vertexNext) return true;
|
|
||||||
if (From == vertexNext && To == vertexCurrent) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2D vertexFirst = vertices[0];
|
|
||||||
Vector2D vertexLast = vertices[^1];
|
|
||||||
if (From == vertexFirst && To == vertexLast) return true;
|
|
||||||
if (From == vertexLast && To == vertexFirst) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float IntersectionParameterT(Line other)
|
|
||||||
{
|
|
||||||
float numerator = (From.X - other.From.X) * (other.From.Y - other.To.Y) - (From.Y - other.From.Y) * (other.From.X - other.To.X);
|
|
||||||
float denominator = (From.X - To.X) * (other.From.Y - other.To.Y) - (From.Y - To.Y) * (other.From.X - other.To.X);
|
|
||||||
|
|
||||||
// Lines are parallel
|
|
||||||
if (denominator == 0)
|
|
||||||
return float.NaN;
|
|
||||||
|
|
||||||
return numerator / denominator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2D Lerp(float t)
|
|
||||||
=> new Vector2D(
|
|
||||||
From.X + (To.X - From.X) * t,
|
|
||||||
From.Y + (To.Y - From.Y) * t
|
|
||||||
);
|
|
||||||
|
|
||||||
public Vector2D Resolve(float x)
|
|
||||||
=> new Vector2D(x, LineEquation.Resolve(x));
|
|
||||||
|
|
||||||
public Vector2D ClosestPointTo(Vector2D point)
|
|
||||||
{
|
|
||||||
// Convert edge points to vectors
|
|
||||||
var edgeVector = new Vector2D(To.X - From.X, To.Y - From.Y);
|
|
||||||
var pointVector = new Vector2D(point.X - From.X, point.Y - From.Y);
|
|
||||||
|
|
||||||
// Calculate the projection of pointVector onto edgeVector
|
|
||||||
float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y);
|
|
||||||
|
|
||||||
// Clamp t to the range [0, 1] to ensure the closest point is on the edge
|
|
||||||
t = MathF.Max(0, MathF.Min(1, t));
|
|
||||||
|
|
||||||
// Calculate the closest point on the edge
|
|
||||||
float closestX = From.X + t * edgeVector.X;
|
|
||||||
float closestY = From.Y + t * edgeVector.Y;
|
|
||||||
|
|
||||||
return new Vector2D((float)closestX, (float)closestY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector2D IntersectionPoint(Line other)
|
|
||||||
=> Vector2D.Lerp(From, To, IntersectionParameterT(other));
|
|
||||||
|
|
||||||
public bool Intersects(Line other)
|
|
||||||
{
|
|
||||||
int o1 = PhysicsMath.Orientation(From, To, other.From);
|
|
||||||
int o2 = PhysicsMath.Orientation(From, To, other.To);
|
|
||||||
int o3 = PhysicsMath.Orientation(other.From, other.To, From);
|
|
||||||
int o4 = PhysicsMath.Orientation(other.From, other.To, To);
|
|
||||||
|
|
||||||
if (o1 != o2 && o3 != o4)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (o1 == 0 && PhysicsMath.OnSegment(From, other.From, To)) return true;
|
|
||||||
if (o2 == 0 && PhysicsMath.OnSegment(From, other.To, To)) return true;
|
|
||||||
if (o3 == 0 && PhysicsMath.OnSegment(other.From, From, other.To)) return true;
|
|
||||||
if (o4 == 0 && PhysicsMath.OnSegment(other.From, To, other.To)) return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Intersects(Line other, [NotNullWhen(returnValue: true)] out Vector2D? point)
|
|
||||||
{
|
|
||||||
point = null;
|
|
||||||
|
|
||||||
bool result = Intersects(other);
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
point = IntersectionPoint(other);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ApproximatelyEquals(Line other)
|
|
||||||
=> From.ApproximatelyEquals(other.From) && To.ApproximatelyEquals(other.To);
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
|
||||||
|
|
||||||
public record LineEquation(float Slope, float OffsetY)
|
|
||||||
{
|
|
||||||
public float Resolve(float x) => Slope * x + OffsetY; // y = mx + b
|
|
||||||
public bool ApproximatelyEquals(LineEquation other)
|
|
||||||
=> Slope.ApproximatelyEquals(other.Slope) && OffsetY.ApproximatelyEquals(other.OffsetY);
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
|
||||||
|
|
||||||
public static class Math
|
|
||||||
{
|
|
||||||
public const float RadianToDegree = 57.29577866666166f;
|
|
||||||
public const float DegreeToRadian = 0.01745329277777778f;
|
|
||||||
|
|
||||||
public static float Clamp(float value, float min, float max) => (value < min) ? min : (value > max) ? max : value;
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
|
||||||
|
|
||||||
public record Shape(IList<Vector2D> Vertices)
|
|
||||||
{
|
|
||||||
public Triangle SuperTriangle
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
float minX = float.MaxValue, minY = float.MaxValue;
|
|
||||||
float maxX = float.MinValue, maxY = float.MinValue;
|
|
||||||
|
|
||||||
foreach (Vector2D point in Vertices)
|
|
||||||
{
|
|
||||||
minX = MathF.Min(minX, point.X);
|
|
||||||
minY = MathF.Min(minY, point.Y);
|
|
||||||
maxX = MathF.Max(maxX, point.X);
|
|
||||||
maxY = MathF.Max(maxY, point.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
float dx = maxX - minX;
|
|
||||||
float dy = maxY - minY;
|
|
||||||
float deltaMax = MathF.Max(dx, dy);
|
|
||||||
float midX = (minX + maxX) / 2;
|
|
||||||
float midY = (minY + maxY) / 2;
|
|
||||||
|
|
||||||
Vector2D p1 = new Vector2D((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax);
|
|
||||||
Vector2D p2 = new Vector2D((float)midX, (float)midY + 20 * (float)deltaMax);
|
|
||||||
Vector2D p3 = new Vector2D((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax);
|
|
||||||
|
|
||||||
return new Triangle(p1, p2, p3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Line> Lines
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
List<Line> lines = new List<Line>(Vertices.Count - 1);
|
|
||||||
GetLinesNonAlloc(lines);
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GetLinesNonAlloc(IList<Line> lines)
|
|
||||||
{
|
|
||||||
lines.Clear();
|
|
||||||
for (int i = 0; i < Vertices.Count - 1; i++)
|
|
||||||
lines.Add(new(Vertices[i], Vertices[i + 1]));
|
|
||||||
lines.Add(new(Vertices[^1], Vertices[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ApproximatelyEquals(Shape other)
|
|
||||||
{
|
|
||||||
if (Vertices.Count != other.Vertices.Count)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (int i = 0; i < Vertices.Count; i++)
|
|
||||||
if (!Vertices[i].ApproximatelyEquals(other.Vertices[i]))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
|
||||||
|
|
||||||
public record Triangle(Vector2D A, Vector2D B, Vector2D C)
|
|
||||||
{
|
|
||||||
public float Area => MathF.Abs((
|
|
||||||
A.X * (B.Y - C.Y) +
|
|
||||||
B.X * (C.Y - A.Y) +
|
|
||||||
C.X * (A.Y - B.Y)
|
|
||||||
) * .5f);
|
|
||||||
|
|
||||||
public Circle CircumCircle
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
Vector2D midAB = (A + B) / 2;
|
|
||||||
Vector2D midBC = (B + C) / 2;
|
|
||||||
|
|
||||||
float slopeAB = (B.Y - A.Y) / (B.X - A.X);
|
|
||||||
float slopeBC = (C.Y - B.Y) / (C.X - B.X);
|
|
||||||
|
|
||||||
Vector2D center;
|
|
||||||
if (MathF.Abs(slopeAB - slopeBC) > float.Epsilon)
|
|
||||||
{
|
|
||||||
float x = (slopeAB * slopeBC * (A.Y - C.Y) + slopeBC * (A.X + B.X) - slopeAB * (B.X + C.X)) / (2 * (slopeBC - slopeAB));
|
|
||||||
float y = -(x - (A.X + B.X) / 2) / slopeAB + (A.Y + B.Y) / 2;
|
|
||||||
center = new Vector2D(x, y);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
center = (midAB + midBC) * .5f;
|
|
||||||
|
|
||||||
return new(center, Vector2D.Distance(center, A));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Overlaps(Vector2D point)
|
|
||||||
{
|
|
||||||
float originalTriangleArea = Area;
|
|
||||||
|
|
||||||
float pointTriangleArea1 = new Triangle(point, B, C).Area;
|
|
||||||
float pointTriangleArea2 = new Triangle(A, point, C).Area;
|
|
||||||
float pointTriangleArea3 = new Triangle(A, B, point).Area;
|
|
||||||
|
|
||||||
float pointTriangleAreasSum = pointTriangleArea1 + pointTriangleArea2 + pointTriangleArea3;
|
|
||||||
|
|
||||||
return originalTriangleArea.ApproximatelyEquals(pointTriangleAreasSum, float.Epsilon * 3f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ApproximatelyEquals(Triangle other)
|
|
||||||
=> A.ApproximatelyEquals(other.A) && B.ApproximatelyEquals(other.B) && C.ApproximatelyEquals(other.C);
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
|
||||||
using Syntriax.Engine.Core.Abstract;
|
|
||||||
using Syntriax.Engine.Physics2D.Abstract;
|
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D;
|
|
||||||
|
|
||||||
public class RigidBody2D : BehaviourOverride, IRigidBody2D
|
|
||||||
{
|
|
||||||
public Action<IAssignableTransform>? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; }
|
|
||||||
|
|
||||||
|
|
||||||
public IPhysicsMaterial2D Material { get; set; } = new PhysicsMaterial2DDefault();
|
|
||||||
|
|
||||||
public Vector2D Velocity { get; set; } = Vector2D.Zero;
|
|
||||||
public float AngularVelocity { get; set; } = 0f;
|
|
||||||
public float Mass { get; set; } = 0f;
|
|
||||||
|
|
||||||
ITransform IAssignableTransform.Transform => Transform;
|
|
||||||
|
|
||||||
|
|
||||||
public bool Assign(ITransform transform) => GameObject.Assign(transform);
|
|
||||||
}
|
|
Loading…
Reference in New Issue