diff --git a/Engine.Core/EngineTime.cs b/Engine.Core/EngineTime.cs index 107748c..c9d5f87 100644 --- a/Engine.Core/EngineTime.cs +++ b/Engine.Core/EngineTime.cs @@ -2,8 +2,8 @@ using System; namespace Syntriax.Engine.Core; -public record EngineTime -( - TimeSpan Total, - TimeSpan Elapsed -); +public readonly struct EngineTime(TimeSpan Total, TimeSpan Elapsed) +{ + public readonly TimeSpan Total { get; init; } = Total; + public readonly TimeSpan Elapsed { get; init; } = Elapsed; +} diff --git a/Engine.Core/Vector2D.cs b/Engine.Core/Vector2D.cs index 4051c54..1f23e9a 100644 --- a/Engine.Core/Vector2D.cs +++ b/Engine.Core/Vector2D.cs @@ -3,11 +3,14 @@ using System; namespace Syntriax.Engine.Core; [System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized}")] -public record Vector2D(float X, float Y) +public readonly struct Vector2D(float X, float Y) { - public float Magnitude => Length(this); - public float MagnitudeSquared => LengthSquared(this); - public Vector2D Normalized => Normalize(this); + public readonly float X { get; init; } = X; + public readonly float Y { get; init; } = Y; + + public readonly float Magnitude => Length(this); + public readonly float MagnitudeSquared => LengthSquared(this); + public readonly Vector2D Normalized => Normalize(this); public readonly static Vector2D Up = new(0f, 1f); public readonly static Vector2D Down = new(0f, -1f); @@ -22,6 +25,8 @@ public record Vector2D(float X, float Y) public static Vector2D operator *(Vector2D vector, float value) => new(vector.X * value, vector.Y * value); public static Vector2D operator *(float value, Vector2D vector) => new(vector.X * value, vector.Y * value); public static Vector2D operator /(Vector2D vector, float value) => new(vector.X / value, vector.Y / value); + public static bool operator ==(Vector2D left, Vector2D right) => left.X == right.X && left.Y == right.Y; + public static bool operator !=(Vector2D left, Vector2D right) => left.X != right.X || left.Y != right.Y; public static float Length(Vector2D vector) => MathF.Sqrt(LengthSquared(vector)); public static float LengthSquared(Vector2D vector) => vector.X * vector.X + vector.Y * vector.Y; @@ -72,4 +77,7 @@ public record Vector2D(float X, float Y) => left.X.ApproximatelyEquals(right.X, epsilon) && left.Y.ApproximatelyEquals(right.Y, epsilon); public override string ToString() => $"{nameof(Vector2D)}({X}, {Y})"; + + public override bool Equals(object? obj) => obj is Vector2D objVec && X.Equals(objVec.X) && Y.Equals(objVec.Y); + public override int GetHashCode() => HashCode.Combine(X, Y); } diff --git a/Engine.Physics2D/CollisionDetectionInformation.cs b/Engine.Physics2D/CollisionDetectionInformation.cs index 3274bf9..ccf4ce2 100644 --- a/Engine.Physics2D/CollisionDetectionInformation.cs +++ b/Engine.Physics2D/CollisionDetectionInformation.cs @@ -3,10 +3,16 @@ using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; -public record CollisionDetectionInformation +public readonly struct CollisionDetectionInformation ( ICollider2D Left, ICollider2D Right, Vector2D Normal, float Penetration -); +) +{ + public ICollider2D Left { get; init; } = Left; + public ICollider2D Right { get; init; } = Right; + public Vector2D Normal { get; init; } = Normal; + public float Penetration { get; init; } = Penetration; +} diff --git a/Engine.Physics2D/CollisionDetector.cs b/Engine.Physics2D/CollisionDetector.cs index 74da3bb..32b0e4b 100644 --- a/Engine.Physics2D/CollisionDetector.cs +++ b/Engine.Physics2D/CollisionDetector.cs @@ -1,5 +1,3 @@ -using System.Diagnostics.CodeAnalysis; - using Syntriax.Engine.Core; using Syntriax.Engine.Physics2D.Abstract; using Syntriax.Engine.Physics2D.Primitives; @@ -8,7 +6,7 @@ namespace Syntriax.Engine.Physics2D; public class CollisionDetector : ICollisionDetector { - public bool TryDetect(T1 left, T2 right, [NotNullWhen(true)] out CollisionDetectionInformation? collisionInformation) + public bool TryDetect(T1 left, T2 right, out CollisionDetectionInformation collisionInformation) where T1 : ICollider2D where T2 : ICollider2D { @@ -31,18 +29,18 @@ public class CollisionDetector : ICollisionDetector return false; } - private static bool DetectCircleShape(ICircleCollider2D circleCollider, IShapeCollider2D shapeCollider, out CollisionDetectionInformation? collisionInformation) + private static bool DetectCircleShape(ICircleCollider2D circleCollider, IShapeCollider2D shapeCollider, out CollisionDetectionInformation collisionInformation) { return DetectShapeCircle(shapeCollider, circleCollider, out collisionInformation); } - private static bool DetectShapeShape(IShapeCollider2D left, IShapeCollider2D right, out CollisionDetectionInformation? collisionInformation) + private static bool DetectShapeShape(IShapeCollider2D left, IShapeCollider2D right, out CollisionDetectionInformation collisionInformation) { collisionInformation = default; return DetectShapeShapeOneWay(left, right, ref collisionInformation) && DetectShapeShapeOneWay(right, left, ref collisionInformation); } - private static bool DetectShapeShapeOneWay(IShapeCollider2D left, IShapeCollider2D right, ref CollisionDetectionInformation? collisionInformation) + private static bool DetectShapeShapeOneWay(IShapeCollider2D left, IShapeCollider2D right, ref CollisionDetectionInformation collisionInformation) { var vertices = left.ShapeWorld.Vertices; int count = vertices.Count; @@ -57,14 +55,14 @@ public class CollisionDetector : ICollisionDetector if (!leftProjection.Overlaps(rightProjection, out float depth)) return false; - if (collisionInformation == default || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth)) + if (collisionInformation.Left is null || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth)) collisionInformation = new(left, right, projectionVector, depth); } return true; } - private static bool DetectShapeCircle(IShapeCollider2D shapeCollider, ICircleCollider2D circleCollider, out CollisionDetectionInformation? collisionInformation) + private static bool DetectShapeCircle(IShapeCollider2D shapeCollider, ICircleCollider2D circleCollider, out CollisionDetectionInformation collisionInformation) { collisionInformation = default; @@ -77,7 +75,7 @@ public class CollisionDetector : ICollisionDetector if (!shapeProjection.Overlaps(circleProjection, out float depth)) return false; - if (collisionInformation == default || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth)) + if (Math.Abs(collisionInformation.Penetration) > Math.Abs(depth)) collisionInformation = new(shapeCollider, circleCollider, shapeToCircleProjectionVector, depth); } @@ -94,14 +92,14 @@ public class CollisionDetector : ICollisionDetector if (!shapeProjection.Overlaps(circleProjection, out float depth)) return false; - if (collisionInformation == default || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth)) + if (collisionInformation.Left is null || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth)) collisionInformation = new(shapeCollider, circleCollider, projectionVector, depth); } return true; } - private static bool DetectCircleCircle(ICircleCollider2D left, ICircleCollider2D right, out CollisionDetectionInformation? collisionInformation) + private static bool DetectCircleCircle(ICircleCollider2D left, ICircleCollider2D right, out CollisionDetectionInformation collisionInformation) { collisionInformation = default; @@ -118,7 +116,7 @@ public class CollisionDetector : ICollisionDetector return collision; } - // private static bool DetectCircleCircle(ICircleCollider2D left, ICircleCollider2D right, out CollisionDetectionInformation? collisionInformation) + // private static bool DetectCircleCircle(ICircleCollider2D left, ICircleCollider2D right, out CollisionDetectionInformation collisionInformation) // { // collisionInformation = default; diff --git a/Engine.Physics2D/ICollisionDetector.cs b/Engine.Physics2D/ICollisionDetector.cs index 460e5bb..11b9db1 100644 --- a/Engine.Physics2D/ICollisionDetector.cs +++ b/Engine.Physics2D/ICollisionDetector.cs @@ -1,10 +1,8 @@ -using System.Diagnostics.CodeAnalysis; - using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; public interface ICollisionDetector { - bool TryDetect(T1 left, T2 right, [NotNullWhen(returnValue: true)] out CollisionDetectionInformation? collisionInformation) where T1 : ICollider2D where T2 : ICollider2D; + bool TryDetect(T1 left, T2 right, out CollisionDetectionInformation collisionInformation) where T1 : ICollider2D where T2 : ICollider2D; } diff --git a/Engine.Physics2D/PhysicsEngine2D.cs b/Engine.Physics2D/PhysicsEngine2D.cs index 0624fac..a471e1d 100644 --- a/Engine.Physics2D/PhysicsEngine2D.cs +++ b/Engine.Physics2D/PhysicsEngine2D.cs @@ -60,7 +60,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D if (colliderX.RigidBody2D == colliderY.RigidBody2D) continue; - if (collisionDetector.TryDetect(colliderX, colliderY, out CollisionDetectionInformation? information)) + if (collisionDetector.TryDetect(colliderX, colliderY, out CollisionDetectionInformation information)) { Vector2D displacementVector = .5f * information.Normal * information.Penetration; information.Left.Transform.Position -= displacementVector; diff --git a/Engine.Physics2D/PhysicsMaterial2D.cs b/Engine.Physics2D/PhysicsMaterial2D.cs index 878691a..23e462e 100644 --- a/Engine.Physics2D/PhysicsMaterial2D.cs +++ b/Engine.Physics2D/PhysicsMaterial2D.cs @@ -2,4 +2,8 @@ using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; -public record PhysicsMaterial2D(float Friction, float Restitution) : IPhysicsMaterial2D { } +public readonly struct PhysicsMaterial2D(float Friction, float Restitution) : IPhysicsMaterial2D +{ + public readonly float Friction { get; init; } = Friction; + public readonly float Restitution { get; init; } = Restitution; +} diff --git a/Engine.Physics2D/PhysicsMaterial2DDefault.cs b/Engine.Physics2D/PhysicsMaterial2DDefault.cs index 61b4367..41d1709 100644 --- a/Engine.Physics2D/PhysicsMaterial2DDefault.cs +++ b/Engine.Physics2D/PhysicsMaterial2DDefault.cs @@ -1,6 +1,10 @@ +using Syntriax.Engine.Physics2D.Abstract; + namespace Syntriax.Engine.Physics2D; -public record PhysicsMaterial2DDefault : PhysicsMaterial2D +public readonly struct PhysicsMaterial2DDefault : IPhysicsMaterial2D { - public PhysicsMaterial2DDefault() : base(.1f, .1f) { } + public readonly float Friction => .1f; + + public readonly float Restitution => .1f; } diff --git a/Engine.Physics2D/Primitives/AABB.cs b/Engine.Physics2D/Primitives/AABB.cs index 5da1cc1..b102087 100644 --- a/Engine.Physics2D/Primitives/AABB.cs +++ b/Engine.Physics2D/Primitives/AABB.cs @@ -4,11 +4,14 @@ using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Primitives; -public record AABB(Vector2D LowerBoundary, Vector2D UpperBoundary) +public readonly struct AABB(Vector2D LowerBoundary, Vector2D UpperBoundary) { - public Vector2D Center => (LowerBoundary + UpperBoundary) * .5f; - public Vector2D Size => LowerBoundary.FromTo(UpperBoundary).Abs(); - public Vector2D SizeHalf => Size * .5f; + public readonly Vector2D LowerBoundary { get; init; } = LowerBoundary; + public readonly Vector2D UpperBoundary { get; init; } = UpperBoundary; + + public readonly Vector2D Center => (LowerBoundary + UpperBoundary) * .5f; + public readonly Vector2D Size => LowerBoundary.FromTo(UpperBoundary).Abs(); + public readonly Vector2D SizeHalf => Size * .5f; public static AABB FromVectors(IEnumerable vectors) { diff --git a/Engine.Physics2D/Primitives/Circle.cs b/Engine.Physics2D/Primitives/Circle.cs index 071dce2..4b8e20b 100644 --- a/Engine.Physics2D/Primitives/Circle.cs +++ b/Engine.Physics2D/Primitives/Circle.cs @@ -3,10 +3,13 @@ using Syntriax.Engine.Core.Abstract; namespace Syntriax.Engine.Physics2D.Primitives; -public record Circle(Vector2D Center, float Radius) +public readonly struct Circle(Vector2D Center, float Radius) { - public float RadiusSquared => Radius * Radius; - public float Diameter => 2f * Radius; + public readonly Vector2D Center { get; init; } = Center; + public readonly float Radius { get; init; } = Radius; + + public readonly float RadiusSquared => Radius * Radius; + public readonly float Diameter => 2f * Radius; public static Circle SetCenter(Circle circle, Vector2D center) => new(center, circle.Radius); public static Circle SetRadius(Circle circle, float radius) => new(circle.Center, radius); diff --git a/Engine.Physics2D/Primitives/Line.cs b/Engine.Physics2D/Primitives/Line.cs index 85a981e..bcb8e0d 100644 --- a/Engine.Physics2D/Primitives/Line.cs +++ b/Engine.Physics2D/Primitives/Line.cs @@ -6,12 +6,15 @@ using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Primitives; -public record Line(Vector2D From, Vector2D To) +public readonly struct Line(Vector2D From, Vector2D To) { - public Line Reversed => new(To, From); - public Vector2D Direction => From.FromTo(To).Normalize(); - public float Length => From.FromTo(To).Length(); - public float LengthSquared => From.FromTo(To).LengthSquared(); + public readonly Vector2D From { get; init; } = From; + public readonly Vector2D To { get; init; } = To; + + public readonly Line Reversed => new(To, From); + public readonly Vector2D Direction => From.FromTo(To).Normalize(); + public readonly float Length => From.FromTo(To).Length(); + public readonly float LengthSquared => From.FromTo(To).LengthSquared(); public static LineEquation GetLineEquation(Line line) { diff --git a/Engine.Physics2D/Primitives/LineEquation.cs b/Engine.Physics2D/Primitives/LineEquation.cs index 06ff657..a36b25e 100644 --- a/Engine.Physics2D/Primitives/LineEquation.cs +++ b/Engine.Physics2D/Primitives/LineEquation.cs @@ -2,8 +2,11 @@ using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Primitives; -public record LineEquation(float Slope, float OffsetY) +public readonly struct LineEquation(float Slope, float OffsetY) { + public readonly float Slope { get; init; } = Slope; + public readonly float OffsetY { get; init; } = OffsetY; + public static float Resolve(LineEquation lineEquation, float x) => lineEquation.Slope * x + lineEquation.OffsetY; // y = mx + b public static bool ApproximatelyEquals(LineEquation left, LineEquation right) diff --git a/Engine.Physics2D/Primitives/Projection.cs b/Engine.Physics2D/Primitives/Projection.cs index 153c4c4..9f76f4a 100644 --- a/Engine.Physics2D/Primitives/Projection.cs +++ b/Engine.Physics2D/Primitives/Projection.cs @@ -1,7 +1,10 @@ namespace Syntriax.Engine.Physics2D.Primitives; -public record Projection(float Min, float Max) +public readonly struct Projection(float Min, float Max) { + public readonly float Min { get; init; } = Min; + public readonly float Max { get; init; } = Max; + public static bool Overlaps(Projection left, Projection right) => Overlaps(left, right, out var _); public static bool Overlaps(Projection left, Projection right, out float depth) { diff --git a/Engine.Physics2D/Primitives/Shape.cs b/Engine.Physics2D/Primitives/Shape.cs index 74b6142..240b25e 100644 --- a/Engine.Physics2D/Primitives/Shape.cs +++ b/Engine.Physics2D/Primitives/Shape.cs @@ -6,13 +6,15 @@ using Syntriax.Engine.Core.Abstract; namespace Syntriax.Engine.Physics2D.Primitives; -public record Shape(IList Vertices) : IEnumerable +public readonly struct Shape(IList Vertices) : IEnumerable { public static readonly Shape Triangle = CreateNgon(3, Vector2D.Up); public static readonly Shape Box = CreateNgon(4, Vector2D.One); public static readonly Shape Pentagon = CreateNgon(5, Vector2D.Up); public static readonly Shape Hexagon = CreateNgon(6, Vector2D.Right); + public readonly IList Vertices { get; init; } = Vertices; + public Vector2D this[System.Index index] => Vertices[index]; @@ -89,9 +91,9 @@ public record Shape(IList Vertices) : IEnumerable float min = float.MaxValue; float max = float.MinValue; - foreach (var vertex in shape) + for (int i = 0; i < shape.Vertices.Count; i++) { - float projectedLength = projectionVector.Dot(vertex); + float projectedLength = projectionVector.Dot(shape.Vertices[i]); min = Math.Min(projectedLength, min); max = Math.Max(projectedLength, max); } diff --git a/Engine.Physics2D/Primitives/Triangle.cs b/Engine.Physics2D/Primitives/Triangle.cs index 8ab76ec..06099f4 100644 --- a/Engine.Physics2D/Primitives/Triangle.cs +++ b/Engine.Physics2D/Primitives/Triangle.cs @@ -4,9 +4,13 @@ using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Primitives; -public record Triangle(Vector2D A, Vector2D B, Vector2D C) +public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C) { - public float Area + public readonly Vector2D A { get; init; } = A; + public readonly Vector2D B { get; init; } = B; + public readonly Vector2D C { get; init; } = C; + + public readonly float Area => .5f * MathF.Abs( A.X * (B.Y - C.Y) + B.X * (C.Y - A.Y) +