diff --git a/Bonk/Bonk.csproj b/Bonk/Bonk.csproj index ee8b234..66762f5 100644 --- a/Bonk/Bonk.csproj +++ b/Bonk/Bonk.csproj @@ -17,6 +17,6 @@ - + \ No newline at end of file diff --git a/Bonk/NarrowPhase/EPA2D.cs b/Bonk/NarrowPhase/EPA2D.cs index 791c9a9..d14ca1b 100644 --- a/Bonk/NarrowPhase/EPA2D.cs +++ b/Bonk/NarrowPhase/EPA2D.cs @@ -4,9 +4,10 @@ * https://blog.hamaluik.ca/posts/building-a-collision-engine-part-2-2d-penetration-vectors/ */ -using Collections.Pooled; using MoonTools.Core.Structs; using System; +using System.Collections.Immutable; +using System.Linq; using System.Numerics; namespace MoonTools.Core.Bonk @@ -26,12 +27,7 @@ namespace MoonTools.Core.Bonk /// public static Vector2 Intersect(IShape2D shapeA, Transform2D Transform2DA, IShape2D shapeB, Transform2D Transform2DB, Simplex2D simplex) { - var simplexVertices = new PooledList(36, ClearMode.Always); - - foreach (var vertex in simplex.Vertices) - { - simplexVertices.Add(vertex); - } + var simplexVertices = simplex.Vertices.Select(vertex => vertex.ToVector2()).ToImmutableArray(); var e0 = (simplexVertices[1].X - simplexVertices[0].X) * (simplexVertices[1].Y + simplexVertices[0].Y); var e1 = (simplexVertices[2].X - simplexVertices[1].X) * (simplexVertices[2].Y + simplexVertices[1].Y); @@ -55,25 +51,23 @@ namespace MoonTools.Core.Bonk } else { - simplexVertices.Insert(edge.index, support); + simplexVertices = simplexVertices.Insert(edge.index, support); } } - simplexVertices.Dispose(); - return intersection; } - private static Edge FindClosestEdge(PolygonWinding winding, PooledList simplexVertices) + private static Edge FindClosestEdge(PolygonWinding winding, ImmutableArray simplexVertices) { var closestDistance = float.PositiveInfinity; var closestNormal = Vector2.Zero; var closestIndex = 0; - for (int i = 0; i < simplexVertices.Count; i++) + for (int i = 0; i < simplexVertices.Length; i++) { var j = i + 1; - if (j >= simplexVertices.Count) { j = 0; } + if (j >= simplexVertices.Length) { j = 0; } Vector2 edge = simplexVertices[j] - simplexVertices[i]; Vector2 norm; diff --git a/Bonk/Shapes/Line.cs b/Bonk/Shapes/Line.cs index 72f1362..10dd4a1 100644 --- a/Bonk/Shapes/Line.cs +++ b/Bonk/Shapes/Line.cs @@ -13,7 +13,7 @@ namespace MoonTools.Core.Bonk private Position2D v0; private Position2D v1; - private IEnumerable vertices + private IEnumerable Vertices { get { @@ -39,7 +39,7 @@ namespace MoonTools.Core.Bonk public AABB AABB(Transform2D Transform2D) { - return Bonk.AABB.FromTransformedVertices(vertices, Transform2D); + return Bonk.AABB.FromTransformedVertices(Vertices, Transform2D); } public override bool Equals(object obj) @@ -67,7 +67,7 @@ namespace MoonTools.Core.Bonk var hashCode = -851829407; hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(v0); hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(v1); - hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(vertices); + hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(Vertices); return hashCode; } diff --git a/Bonk/Shapes/Polygon.cs b/Bonk/Shapes/Polygon.cs index 44ecf93..0e10f48 100644 --- a/Bonk/Shapes/Polygon.cs +++ b/Bonk/Shapes/Polygon.cs @@ -1,26 +1,32 @@ using System.Linq; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Numerics; -using Collections.Pooled; using MoonTools.Core.Structs; using MoreLinq; namespace MoonTools.Core.Bonk { /// - /// A Shape defined by an arbitrary collection of vertices. WARNING: Polygon must use an Array internally and therefore will create GC pressure. + /// A Shape defined by an arbitrary collection of vertices. + /// NOTE: A Polygon must have more than 2 vertices and should not have duplicate vertices. /// public struct Polygon : IShape2D, IEquatable { - private PooledSet vertices; + private ImmutableArray vertices; public IEnumerable Vertices { get { return vertices == null ? Enumerable.Empty() : vertices; } } // vertices are local to the origin public Polygon(params Position2D[] vertices) { - this.vertices = new PooledSet(vertices, ClearMode.Always); + this.vertices = ImmutableArray.Create(vertices); + } + + public Polygon(ImmutableArray vertices) + { + this.vertices = vertices; } public Vector2 Support(Vector2 direction, Transform2D transform) @@ -47,7 +53,19 @@ namespace MoonTools.Core.Bonk { if (other is Polygon otherPolygon) { - return vertices.SetEquals(otherPolygon.vertices); + var q = from a in vertices + join b in otherPolygon.vertices on a equals b + select a; + + return vertices.Length == otherPolygon.vertices.Length && q.Count() == vertices.Length; + } + else if (other is Rectangle rectangle) + { + var q = from a in vertices + join b in rectangle.Vertices on a equals b + select a; + + return vertices.Length == 4 && q.Count() == vertices.Length; } return false; @@ -55,10 +73,7 @@ namespace MoonTools.Core.Bonk public override int GetHashCode() { - var hashCode = -1404792980; - hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(vertices); - hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(Vertices); - return hashCode; + return HashCode.Combine(vertices, Vertices); } public static bool operator ==(Polygon a, Polygon b) @@ -70,5 +85,15 @@ namespace MoonTools.Core.Bonk { return !(a == b); } + + public static bool operator ==(Polygon a, Rectangle b) + { + return a.Equals(b); + } + + public static bool operator !=(Polygon a, Rectangle b) + { + return !(a == b); + } } } diff --git a/Bonk/Shapes/Rectangle.cs b/Bonk/Shapes/Rectangle.cs index c1b46c6..9e5a001 100644 --- a/Bonk/Shapes/Rectangle.cs +++ b/Bonk/Shapes/Rectangle.cs @@ -17,7 +17,7 @@ namespace MoonTools.Core.Bonk public int MaxX { get; } public int MaxY { get; } - private IEnumerable vertices + public IEnumerable Vertices { get { @@ -38,12 +38,12 @@ namespace MoonTools.Core.Bonk public Vector2 Support(Vector2 direction, Transform2D transform) { - return vertices.Select(vertex => Vector2.Transform(vertex, transform.TransformMatrix)).MaxBy(transformed => Vector2.Dot(transformed, direction)).First(); + return Vertices.Select(vertex => Vector2.Transform(vertex, transform.TransformMatrix)).MaxBy(transformed => Vector2.Dot(transformed, direction)).First(); } public AABB AABB(Transform2D Transform2D) { - return Bonk.AABB.FromTransformedVertices(vertices, Transform2D); + return Bonk.AABB.FromTransformedVertices(Vertices, Transform2D); } public override bool Equals(object obj) @@ -76,7 +76,7 @@ namespace MoonTools.Core.Bonk hashCode = hashCode * -1521134295 + MinY.GetHashCode(); hashCode = hashCode * -1521134295 + MaxX.GetHashCode(); hashCode = hashCode * -1521134295 + MaxY.GetHashCode(); - hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(vertices); + hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(Vertices); return hashCode; } diff --git a/Test/Equality.cs b/Test/Equality.cs index fc6b6ef..e5921fd 100644 --- a/Test/Equality.cs +++ b/Test/Equality.cs @@ -253,6 +253,66 @@ namespace Tests (a != b).Should().BeTrue(); } + + [Test] + public void PolygonRectangleEqual() + { + var a = new Polygon( + new Position2D(1, 1), + new Position2D(1, -1), + new Position2D(-1, -1), + new Position2D(-1, 1) + ); + + var b = new Rectangle(-1, -1, 1, 1); + + a.Should().BeEquivalentTo(b); + } + + [Test] + public void PolygonRectangleNotEqual() + { + var a = new Polygon( + new Position2D(2, 1), + new Position2D(1, -1), + new Position2D(-1, -1), + new Position2D(-2, 1) + ); + + var b = new Rectangle(-1, -1, 1, 1); + + a.Should().NotBeEquivalentTo(b); + } + + [Test] + public void PolygonRectangleEqualOperator() + { + var a = new Polygon( + new Position2D(1, 1), + new Position2D(1, -1), + new Position2D(-1, -1), + new Position2D(-1, 1) + ); + + var b = new Rectangle(-1, -1, 1, 1); + + (a == b).Should().BeTrue(); + } + + [Test] + public void PolygonRectangleNotEqualOperator() + { + var a = new Polygon( + new Position2D(2, 1), + new Position2D(1, -1), + new Position2D(-1, -1), + new Position2D(-2, 1) + ); + + var b = new Rectangle(-1, -1, 1, 1); + + (a != b).Should().BeTrue(); + } } public class SimplexTests