diff --git a/.gitignore b/.gitignore
index 5ed3d3e..f768bd5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 bin/
 obj/
-.vscode
\ No newline at end of file
+.vscode
+.vs
diff --git a/Bonk/AABB.cs b/Bonk/AABB.cs
index 246e1b1..1f47466 100644
--- a/Bonk/AABB.cs
+++ b/Bonk/AABB.cs
@@ -1,3 +1,4 @@
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Numerics;
@@ -8,7 +9,7 @@ namespace MoonTools.Core.Bonk
     /// <summary>
     /// Axis-aligned bounding box.
     /// </summary>
-    public struct AABB
+    public struct AABB : IEquatable<AABB>
     {
         public float MinX { get; private set; }
         public float MinY { get; private set; }
@@ -31,6 +32,24 @@ namespace MoonTools.Core.Bonk
             };
         }
 
+        public override bool Equals(object obj)
+        {
+            return obj is AABB aabb && Equals(aabb);
+        }
+
+        public bool Equals(AABB other)
+        {
+            return MinX == other.MinX &&
+                   MinY == other.MinY &&
+                   MaxX == other.MaxX &&
+                   MaxY == other.MaxY;
+        }
+
+        public override int GetHashCode()
+        {
+            return HashCode.Combine(MinX, MinY, MaxX, MaxY);
+        }
+
         public AABB(float minX, float minY, float maxX, float maxY)
         {
             MinX = minX;
@@ -38,5 +57,15 @@ namespace MoonTools.Core.Bonk
             MaxX = maxX;
             MaxY = maxY;
         }
+
+        public static bool operator ==(AABB left, AABB right)
+        {
+            return left.Equals(right);
+        }
+
+        public static bool operator !=(AABB left, AABB right)
+        {
+            return !(left == right);
+        }
     }
 }
\ No newline at end of file
diff --git a/Bonk/Bonk.csproj b/Bonk/Bonk.csproj
index a8a2d64..17f86a7 100644
--- a/Bonk/Bonk.csproj
+++ b/Bonk/Bonk.csproj
@@ -15,8 +15,12 @@
     <PackageProjectUrl>https://github.com/MoonsideGames/MoonTools.Core.Bonk</PackageProjectUrl>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="MoonTools.Core.Structs" Version="2.0.0"/>
-    <PackageReference Include="morelinq" Version="3.2.0"/>
-    <PackageReference Include="System.Collections.Immutable" Version="1.6.0"/>
+    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="MoonTools.Core.Structs" Version="2.0.0" />
+    <PackageReference Include="morelinq" Version="3.2.0" />
+    <PackageReference Include="System.Collections.Immutable" Version="1.6.0" />
   </ItemGroup>
 </Project>
diff --git a/Bonk/BroadPhase/SpatialHash.cs b/Bonk/BroadPhase/SpatialHash.cs
index f29edd8..f87b53f 100644
--- a/Bonk/BroadPhase/SpatialHash.cs
+++ b/Bonk/BroadPhase/SpatialHash.cs
@@ -31,7 +31,7 @@ namespace MoonTools.Core.Bonk
         /// <param name="id">A unique ID for the shape-transform pair.</param>
         /// <param name="shape"></param>
         /// <param name="transform2D"></param>
-        public void Insert(T id, IShape2D shape, Transform2D transform2D)
+        public void Insert<TShape2D>(T id, TShape2D shape, Transform2D transform2D) where TShape2D : struct, IShape2D
         {
             var box = shape.AABB(transform2D);
             var minHash = Hash(box.MinX, box.MinY);
@@ -60,7 +60,7 @@ namespace MoonTools.Core.Bonk
         /// <summary>
         /// Retrieves all the potential collisions of a shape-transform pair. Excludes any shape-transforms with the given ID.
         /// </summary>
-        public IEnumerable<(T, IShape2D, Transform2D)> Retrieve(T id, IShape2D shape, Transform2D transform2D)
+        public IEnumerable<(T, IShape2D, Transform2D)> Retrieve<TShape2D>(T id, TShape2D shape, Transform2D transform2D) where TShape2D : struct, IShape2D
         {
             var box = shape.AABB(transform2D);
             var minHash = Hash(box.MinX, box.MinY);
diff --git a/Bonk/MinkowskiDifference.cs b/Bonk/MinkowskiDifference.cs
index dce2e03..89d7c0d 100644
--- a/Bonk/MinkowskiDifference.cs
+++ b/Bonk/MinkowskiDifference.cs
@@ -1,5 +1,4 @@
 using System;
-using System.Collections.Generic;
 using System.Numerics;
 using MoonTools.Core.Structs;
 
@@ -10,51 +9,41 @@ namespace MoonTools.Core.Bonk
     /// </summary>
     public struct MinkowskiDifference : IEquatable<MinkowskiDifference>
     {
-        private IShape2D shapeA;
-        private Transform2D transformA;
-        private IShape2D shapeB;
-        private Transform2D transformB;
+        private IShape2D ShapeA { get; }
+        private Transform2D TransformA { get; }
+        private IShape2D ShapeB { get; }
+        private Transform2D TransformB { get; }
 
         public MinkowskiDifference(IShape2D shapeA, Transform2D transformA, IShape2D shapeB, Transform2D transformB)
         {
-            this.shapeA = shapeA;
-            this.transformA = transformA;
-            this.shapeB = shapeB;
-            this.transformB = transformB;
+            ShapeA = shapeA;
+            TransformA = transformA;
+            ShapeB = shapeB;
+            TransformB = transformB;
         }
 
         public Vector2 Support(Vector2 direction)
         {
-            return shapeA.Support(direction, transformA) - shapeB.Support(-direction, transformB);
+            return ShapeA.Support(direction, TransformA) - ShapeB.Support(-direction, TransformB);
         }
 
         public override bool Equals(object other)
         {
-            if (other is MinkowskiDifference otherMinkowskiDifference)
-            {
-                return Equals(otherMinkowskiDifference);
-            }
-
-            return false;
+            return other is MinkowskiDifference minkowskiDifference && Equals(minkowskiDifference);
         }
 
         public bool Equals(MinkowskiDifference other)
         {
             return
-                shapeA == other.shapeA &&
-                transformA == other.transformA &&
-                shapeB == other.shapeB &&
-                transformB == other.transformB;
+                ShapeA == other.ShapeA &&
+                TransformA == other.TransformA &&
+                ShapeB == other.ShapeB &&
+                TransformB == other.TransformB;
         }
 
         public override int GetHashCode()
         {
-            var hashCode = 974363698;
-            hashCode = hashCode * -1521134295 + EqualityComparer<IShape2D>.Default.GetHashCode(shapeA);
-            hashCode = hashCode * -1521134295 + EqualityComparer<Transform2D>.Default.GetHashCode(transformA);
-            hashCode = hashCode * -1521134295 + EqualityComparer<IShape2D>.Default.GetHashCode(shapeB);
-            hashCode = hashCode * -1521134295 + EqualityComparer<Transform2D>.Default.GetHashCode(transformB);
-            return hashCode;
+            return HashCode.Combine(ShapeA, TransformA, ShapeB, TransformB);
         }
 
         public static bool operator ==(MinkowskiDifference a, MinkowskiDifference b)
diff --git a/Bonk/NarrowPhase/EPA2D.cs b/Bonk/NarrowPhase/EPA2D.cs
index d14ca1b..5bb5715 100644
--- a/Bonk/NarrowPhase/EPA2D.cs
+++ b/Bonk/NarrowPhase/EPA2D.cs
@@ -12,7 +12,7 @@ using System.Numerics;
 
 namespace MoonTools.Core.Bonk
 {
-    enum PolygonWinding
+    internal enum PolygonWinding
     {
         Clockwise,
         CounterClockwise
@@ -24,8 +24,7 @@ namespace MoonTools.Core.Bonk
         /// Returns a minimum separating vector in the direction from A to B.
         /// </summary>
         /// <param name="simplex">A simplex returned by the GJK algorithm.</param>
-        /// <returns></returns>
-        public static Vector2 Intersect(IShape2D shapeA, Transform2D Transform2DA, IShape2D shapeB, Transform2D Transform2DB, Simplex2D simplex)
+        public static Vector2 Intersect<TShapeA, TShapeB>(TShapeA shapeA, Transform2D Transform2DA, TShapeB shapeB, Transform2D Transform2DB, Simplex2D simplex) where TShapeA : struct, IShape2D where TShapeB : struct, IShape2D
         {
             var simplexVertices = simplex.Vertices.Select(vertex => vertex.ToVector2()).ToImmutableArray();
 
diff --git a/Bonk/Shapes/Circle.cs b/Bonk/Shapes/Circle.cs
index 465a5f8..6b2a93b 100644
--- a/Bonk/Shapes/Circle.cs
+++ b/Bonk/Shapes/Circle.cs
@@ -7,9 +7,9 @@ namespace MoonTools.Core.Bonk
     /// <summary>
     /// A Circle is a shape defined by a radius.
     /// </summary>
-    public struct Circle : IShape2D, IEquatable<IShape2D>
+    public struct Circle : IShape2D, IEquatable<Circle>
     {
-        public int Radius { get; private set; }
+        public int Radius { get; }
 
         public Circle(int radius)
         {
@@ -24,36 +24,31 @@ namespace MoonTools.Core.Bonk
         public AABB AABB(Transform2D transform2D)
         {
             return new AABB(
-                transform2D.Position.X - Radius * transform2D.Scale.X,
-                transform2D.Position.Y - Radius * transform2D.Scale.Y,
-                transform2D.Position.X + Radius * transform2D.Scale.X,
-                transform2D.Position.Y + Radius * transform2D.Scale.Y
+                transform2D.Position.X - (Radius * transform2D.Scale.X),
+                transform2D.Position.Y - (Radius * transform2D.Scale.Y),
+                transform2D.Position.X + (Radius * transform2D.Scale.X),
+                transform2D.Position.Y + (Radius * transform2D.Scale.Y)
             );
         }
 
         public override bool Equals(object obj)
         {
-            if (obj is Circle other)
-            {
-                return Equals(other);
-            }
-
-            return false;
+            return obj is IShape2D other && Equals(other);
         }
 
         public bool Equals(IShape2D other)
         {
-            if (other is Circle circle)
-            {
-                return Radius == circle.Radius;
-            }
+            return other is Circle circle && Equals(circle);
+        }
 
-            return false;
+        public bool Equals(Circle other)
+        {
+            return Radius == other.Radius;
         }
 
         public override int GetHashCode()
         {
-            return 598075851 + Radius.GetHashCode();
+            return HashCode.Combine(Radius);
         }
 
         public static bool operator ==(Circle a, Circle b)
diff --git a/Bonk/Shapes/Line.cs b/Bonk/Shapes/Line.cs
index 8556b07..6e9f3eb 100644
--- a/Bonk/Shapes/Line.cs
+++ b/Bonk/Shapes/Line.cs
@@ -8,7 +8,7 @@ namespace MoonTools.Core.Bonk
     /// <summary>
     /// A line is a shape defined by exactly two points in space.
     /// </summary>
-    public struct Line : IShape2D, IEquatable<IShape2D>
+    public struct Line : IShape2D, IEquatable<Line>
     {
         private Position2D v0;
         private Position2D v1;
@@ -18,7 +18,7 @@ namespace MoonTools.Core.Bonk
             get
             {
                 yield return v0;
-                yield return v0;
+                yield return v1;
             }
         }
 
@@ -44,31 +44,22 @@ namespace MoonTools.Core.Bonk
 
         public override bool Equals(object obj)
         {
-            if (obj is IShape2D other)
-            {
-                return Equals(other);
-            }
-
-            return false;
+            return obj is IShape2D other && Equals(other);
         }
 
         public bool Equals(IShape2D other)
         {
-            if (other is Line otherLine)
-            {
-                return (v0 == otherLine.v0 && v1 == otherLine.v1) || (v1 == otherLine.v0 && v0 == otherLine.v1);
-            }
+            return other is Line otherLine && Equals(otherLine);
+        }
 
-            return false;
+        public bool Equals(Line other)
+        {
+            return (v0 == other.v0 && v1 == other.v1) || (v1 == other.v0 && v0 == other.v1);
         }
 
         public override int GetHashCode()
         {
-            var hashCode = -851829407;
-            hashCode = hashCode * -1521134295 + EqualityComparer<Position2D>.Default.GetHashCode(v0);
-            hashCode = hashCode * -1521134295 + EqualityComparer<Position2D>.Default.GetHashCode(v1);
-            hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(Vertices);
-            return hashCode;
+            return HashCode.Combine(v0, v1);
         }
 
         public static bool operator ==(Line a, Line b)
diff --git a/Bonk/Shapes/Point.cs b/Bonk/Shapes/Point.cs
index 7daba13..c1fbc0b 100644
--- a/Bonk/Shapes/Point.cs
+++ b/Bonk/Shapes/Point.cs
@@ -5,7 +5,7 @@ using MoonTools.Core.Structs;
 
 namespace MoonTools.Core.Bonk
 {
-    public struct Point : IShape2D, IEquatable<IShape2D>
+    public struct Point : IShape2D, IEquatable<Point>
     {
         private Position2D position;
 
@@ -31,22 +31,17 @@ namespace MoonTools.Core.Bonk
 
         public override bool Equals(object obj)
         {
-            if (obj is IShape2D other)
-            {
-                return Equals(other);
-            }
-
-            return false;
+            return obj is IShape2D other && Equals(other);
         }
 
         public bool Equals(IShape2D other)
         {
-            if (other is Point otherPoint)
-            {
-                return position == otherPoint.position;
-            }
+            return other is Point otherPoint && Equals(otherPoint);
+        }
 
-            return false;
+        public bool Equals(Point other)
+        {
+            return position == other.position;
         }
 
         public override int GetHashCode()
diff --git a/Bonk/Shapes/Polygon.cs b/Bonk/Shapes/Polygon.cs
index 877f8c0..504dcc1 100644
--- a/Bonk/Shapes/Polygon.cs
+++ b/Bonk/Shapes/Polygon.cs
@@ -12,16 +12,18 @@ namespace MoonTools.Core.Bonk
     /// A Shape defined by an arbitrary collection of vertices.
     /// NOTE: A Polygon must have more than 2 vertices, be convex, and should not have duplicate vertices.
     /// </summary>
-    public struct Polygon : IShape2D, IEquatable<IShape2D>
+    public struct Polygon : IShape2D, IEquatable<Polygon>
     {
         private ImmutableArray<Position2D> vertices;
 
-        public IEnumerable<Position2D> Vertices { get { return vertices == null ? Enumerable.Empty<Position2D>() : vertices; } }
+        public IEnumerable<Position2D> Vertices { get { return vertices; } }
+
+        public int VertexCount {  get { return vertices.Length; } }
 
         // vertices are local to the origin
-        public Polygon(params Position2D[] vertices) // TODO: remove this, params is bad because it allocates an array
+        public Polygon(IEnumerable<Position2D> vertices) // TODO: remove this, params is bad because it allocates an array
         {
-            this.vertices = ImmutableArray.Create<Position2D>(vertices);
+            this.vertices = vertices.ToImmutableArray();
         }
 
         public Polygon(ImmutableArray<Position2D> vertices)
@@ -41,39 +43,31 @@ namespace MoonTools.Core.Bonk
 
         public override bool Equals(object obj)
         {
-            if (obj is IShape2D other)
-            {
-                return Equals(other);
-            }
-
-            return false;
+            return obj is IShape2D other && Equals(other);
         }
 
         public bool Equals(IShape2D other)
         {
-            if (other is Polygon otherPolygon)
-            {
-                var q = from a in vertices
-                        join b in otherPolygon.vertices on a equals b
-                        select a;
+            return (other is Polygon otherPolygon && Equals(otherPolygon)) || (other is Rectangle rectangle && Equals(rectangle));
+        }
 
-                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;
+        public bool Equals(Polygon other)
+        {
+            var q = from a in vertices
+                    join b in other.Vertices on a equals b
+                    select a;
 
-                return vertices.Length == 4 && q.Count() == vertices.Length;
-            }
+            return vertices.Length == other.VertexCount && q.Count() == vertices.Length;
+        }
 
-            return false;
+        public bool Equals(Rectangle rectangle)
+        {
+            return RectanglePolygonComparison.Equals(this, rectangle);
         }
 
         public override int GetHashCode()
         {
-            return HashCode.Combine(vertices, Vertices);
+            return HashCode.Combine(Vertices);
         }
 
         public static bool operator ==(Polygon a, Polygon b)
diff --git a/Bonk/Shapes/Rectangle.cs b/Bonk/Shapes/Rectangle.cs
index 9e5a001..2e04491 100644
--- a/Bonk/Shapes/Rectangle.cs
+++ b/Bonk/Shapes/Rectangle.cs
@@ -10,7 +10,7 @@ namespace MoonTools.Core.Bonk
     /// <summary>
     /// A rectangle is a shape defined by a minimum and maximum X value and a minimum and maximum Y value.
     /// </summary>
-    public struct Rectangle : IShape2D, IEquatable<IShape2D>
+    public struct Rectangle : IShape2D, IEquatable<Rectangle>
     {
         public int MinX { get; }
         public int MinY { get; }
@@ -48,36 +48,30 @@ namespace MoonTools.Core.Bonk
 
         public override bool Equals(object obj)
         {
-            if (obj is IShape2D other)
-            {
-                return Equals(other);
-            }
-
-            return false;
+            return obj is IShape2D other && Equals(other);
         }
 
         public bool Equals(IShape2D other)
         {
-            if (other is Rectangle rectangle)
-            {
-                return MinX == rectangle.MinX &&
-                    MinY == rectangle.MinY &&
-                    MaxX == rectangle.MaxX &&
-                    MaxY == rectangle.MaxY;
-            }
+            return (other is Rectangle rectangle && Equals(rectangle)) || (other is Polygon polygon && Equals(polygon));
+        }
 
-            return false;
+        public bool Equals(Rectangle other)
+        {
+            return MinX == other.MinX &&
+                MinY == other.MinY &&
+                MaxX == other.MaxX &&
+                MaxY == other.MaxY;
+        }
+
+        public bool Equals(Polygon other)
+        {
+            return RectanglePolygonComparison.Equals(other, this);
         }
 
         public override int GetHashCode()
         {
-            var hashCode = -1260800952;
-            hashCode = hashCode * -1521134295 + MinX.GetHashCode();
-            hashCode = hashCode * -1521134295 + MinY.GetHashCode();
-            hashCode = hashCode * -1521134295 + MaxX.GetHashCode();
-            hashCode = hashCode * -1521134295 + MaxY.GetHashCode();
-            hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(Vertices);
-            return hashCode;
+            return HashCode.Combine(MinX, MinY, MaxX, MaxY);
         }
 
         public static bool operator ==(Rectangle a, Rectangle b)
diff --git a/Bonk/Shapes/RectanglePolygonComparison.cs b/Bonk/Shapes/RectanglePolygonComparison.cs
new file mode 100644
index 0000000..34c7ef3
--- /dev/null
+++ b/Bonk/Shapes/RectanglePolygonComparison.cs
@@ -0,0 +1,16 @@
+using System.Linq;
+
+namespace MoonTools.Core.Bonk
+{
+    internal static class RectanglePolygonComparison
+    {
+        public static bool Equals(Polygon polygon, Rectangle rectangle)
+        {
+            var q = from a in polygon.Vertices
+                    join b in rectangle.Vertices on a equals b
+                    select a;
+
+            return polygon.VertexCount == 4 && q.Count() == 4;
+        }
+    }
+}
diff --git a/Bonk/Shapes/Simplex.cs b/Bonk/Shapes/Simplex.cs
index f8e6ad5..680f488 100644
--- a/Bonk/Shapes/Simplex.cs
+++ b/Bonk/Shapes/Simplex.cs
@@ -3,17 +3,18 @@ using System.Collections.Generic;
 using System.Numerics;
 using MoonTools.Core.Structs;
 using MoreLinq;
+using System;
 
 namespace MoonTools.Core.Bonk
 {
     /// <summary>
     /// A simplex is a shape with up to n - 2 vertices in the nth dimension.
     /// </summary>
-    public struct Simplex2D : IShape2D
+    public struct Simplex2D : IShape2D, IEquatable<Simplex2D>
     {
-        Vector2 a;
-        Vector2? b;
-        Vector2? c;
+        private Vector2 a;
+        private Vector2? b;
+        private Vector2? c;
 
         public Vector2 A => a;
         public Vector2? B => b;
@@ -28,15 +29,15 @@ namespace MoonTools.Core.Bonk
         public Simplex2D(Vector2 a)
         {
             this.a = a;
-            this.b = null;
-            this.c = null;
+            b = null;
+            c = null;
         }
 
         public Simplex2D(Vector2 a, Vector2 b)
         {
             this.a = a;
             this.b = b;
-            this.c = null;
+            c = null;
         }
 
         public Simplex2D(Vector2 a, Vector2 b, Vector2 c)
@@ -73,36 +74,26 @@ namespace MoonTools.Core.Bonk
 
         public override bool Equals(object obj)
         {
-            if (obj is IShape2D other)
-            {
-                return Equals(other);
-            }
-
-            return false;
+            return obj is IShape2D other && Equals(other);
         }
 
         public bool Equals(IShape2D other)
         {
-            if (other is Simplex2D otherSimplex)
-            {
-                if (Count != otherSimplex.Count) { return false; }
-                return Vertices.Intersect(otherSimplex.Vertices).Count() == Count;
-            }
+            return other is Simplex2D otherSimplex && Equals(otherSimplex);
+        }
 
-            return false;
+        public bool Equals(Simplex2D other)
+        {
+            var q = from a in Vertices
+                    join b in other.Vertices on a equals b
+                    select a;
+
+            return Count == other.Count && q.Count() == Count;
         }
 
         public override int GetHashCode()
         {
-            var hashCode = -495772172;
-            hashCode = hashCode * -1521134295 + EqualityComparer<Vector2>.Default.GetHashCode(a);
-            hashCode = hashCode * -1521134295 + EqualityComparer<Vector2?>.Default.GetHashCode(b);
-            hashCode = hashCode * -1521134295 + EqualityComparer<Vector2?>.Default.GetHashCode(c);
-            hashCode = hashCode * -1521134295 + ZeroSimplex.GetHashCode();
-            hashCode = hashCode * -1521134295 + OneSimplex.GetHashCode();
-            hashCode = hashCode * -1521134295 + TwoSimplex.GetHashCode();
-            hashCode = hashCode * -1521134295 + EqualityComparer<IEnumerable<Position2D>>.Default.GetHashCode(Vertices);
-            return hashCode;
+            return HashCode.Combine(Vertices);
         }
 
         public static bool operator ==(Simplex2D a, Simplex2D b)
diff --git a/Test/EPA2DTest.cs b/Test/EPA2DTest.cs
index cf26e71..468b057 100644
--- a/Test/EPA2DTest.cs
+++ b/Test/EPA2DTest.cs
@@ -27,7 +27,7 @@ namespace Tests
             intersection.X.Should().Be(1f);
             intersection.Y.Should().Be(0);
 
-            var movedTransform = new Transform2D(transformA.Position - intersection * 1.01f); // move a tiny bit past
+            var movedTransform = new Transform2D(transformA.Position - (intersection * 1.01f)); // move a tiny bit past
 
             GJK2D.TestCollision(squareA, movedTransform, squareB, transformB).Should().BeFalse();
         }
@@ -46,13 +46,13 @@ namespace Tests
 
             var intersection = EPA2D.Intersect(circleA, transformA, circleB, transformB, simplex);
 
-            var ix = circleA.Radius * (float)Math.Cos(Math.PI / 4) - (circleB.Radius * (float)Math.Cos(5 * Math.PI / 4) + transformB.Position.X);
-            var iy = circleA.Radius * (float)Math.Sin(Math.PI / 4) - (circleB.Radius * (float)Math.Sin(5 * Math.PI / 4) + transformB.Position.Y);
+            var ix = (circleA.Radius * (float)Math.Cos(Math.PI / 4)) - ((circleB.Radius * (float)Math.Cos(5 * Math.PI / 4)) + transformB.Position.X);
+            var iy = (circleA.Radius * (float)Math.Sin(Math.PI / 4)) - ((circleB.Radius * (float)Math.Sin(5 * Math.PI / 4)) + transformB.Position.Y);
 
             intersection.X.Should().BeApproximately(ix, 0.01f);
             intersection.Y.Should().BeApproximately(iy, 0.01f);
 
-            var movedTransform = new Transform2D(transformA.Position - intersection * 1.01f); // move a tiny bit past
+            var movedTransform = new Transform2D(transformA.Position - (intersection * 1.01f)); // move a tiny bit past
 
             GJK2D.TestCollision(circleA, movedTransform, circleB, transformB).Should().BeFalse();
         }
@@ -71,7 +71,7 @@ namespace Tests
 
             var intersection = EPA2D.Intersect(line, transformA, square, transformB, simplex);
 
-            var movedTransform = new Transform2D(transformA.Position - intersection * 1.01f); // move a tiny bit past
+            var movedTransform = new Transform2D(transformA.Position - (intersection * 1.01f)); // move a tiny bit past
 
             GJK2D.TestCollision(line, movedTransform, square, transformB).Should().BeFalse();
         }
diff --git a/Test/Equality.cs b/Test/Equality.cs
index 07979a0..75af6ff 100644
--- a/Test/Equality.cs
+++ b/Test/Equality.cs
@@ -4,10 +4,11 @@ using FluentAssertions;
 using MoonTools.Core.Bonk;
 using MoonTools.Core.Structs;
 using System.Numerics;
+using System.Collections.Immutable;
 
 namespace Tests
 {
-    public class EqualityTests
+    public static class EqualityTests
     {
         public class PointTests
         {
@@ -148,8 +149,8 @@ namespace Tests
             [Test]
             public void RectangleEqual()
             {
-                var a = new MoonTools.Core.Bonk.Rectangle(0, 0, 3, 3);
-                var b = new MoonTools.Core.Bonk.Rectangle(0, 0, 3, 3);
+                var a = new Rectangle(0, 0, 3, 3);
+                var b = new Rectangle(0, 0, 3, 3);
 
                 a.Equals(b).Should().BeTrue();
             }
@@ -157,8 +158,8 @@ namespace Tests
             [Test]
             public void RectangleEqualOperator()
             {
-                var a = new MoonTools.Core.Bonk.Rectangle(0, 0, 3, 3);
-                var b = new MoonTools.Core.Bonk.Rectangle(0, 0, 3, 3);
+                var a = new Rectangle(0, 0, 3, 3);
+                var b = new Rectangle(0, 0, 3, 3);
 
                 (a == b).Should().BeTrue();
             }
@@ -166,8 +167,8 @@ namespace Tests
             [Test]
             public void RectangleNotEqual()
             {
-                var a = new MoonTools.Core.Bonk.Rectangle(0, 0, 3, 3);
-                var b = new MoonTools.Core.Bonk.Rectangle(-1, -1, 5, 5);
+                var a = new Rectangle(0, 0, 3, 3);
+                var b = new Rectangle(-1, -1, 5, 5);
 
                 a.Equals(b).Should().BeFalse();
             }
@@ -175,8 +176,8 @@ namespace Tests
             [Test]
             public void RectangleNotEqualOperator()
             {
-                var a = new MoonTools.Core.Bonk.Rectangle(0, 0, 3, 3);
-                var b = new MoonTools.Core.Bonk.Rectangle(-1, -1, 5, 5);
+                var a = new Rectangle(0, 0, 3, 3);
+                var b = new Rectangle(-1, -1, 5, 5);
 
                 (a != b).Should().BeTrue();
             }
@@ -187,17 +188,17 @@ namespace Tests
             [Test]
             public void PolygonEqual()
             {
-                var a = new Polygon(
+                var a = new Polygon(ImmutableArray.Create(
                     new Position2D(0, 1),
                     new Position2D(1, 2),
                     new Position2D(-1, -1)
-                );
+                ));
 
-                var b = new Polygon(
+                var b = new Polygon(ImmutableArray.Create(
                     new Position2D(0, 1),
                     new Position2D(1, 2),
                     new Position2D(-1, -1)
-                );
+                ));
 
                 a.Equals(b).Should().BeTrue();
             }
@@ -205,17 +206,17 @@ namespace Tests
             [Test]
             public void PolygonEqualOperator()
             {
-                var a = new Polygon(
+                var a = new Polygon(ImmutableArray.Create(
                     new Position2D(0, 1),
                     new Position2D(1, 2),
                     new Position2D(-1, -1)
-                );
+                ));
 
-                var b = new Polygon(
+                var b = new Polygon(ImmutableArray.Create(
                     new Position2D(0, 1),
                     new Position2D(1, 2),
                     new Position2D(-1, -1)
-                );
+                ));
 
                 (a == b).Should().BeTrue();
             }
@@ -223,17 +224,17 @@ namespace Tests
             [Test]
             public void PolygonDifferentOrderEqual()
             {
-                var a = new Polygon(
+                var a = new Polygon(ImmutableArray.Create(
                     new Position2D(0, 1),
                     new Position2D(1, 2),
                     new Position2D(-1, -1)
-                );
+                ));
 
-                var b = new Polygon(
+                var b = new Polygon(ImmutableArray.Create(
                     new Position2D(1, 2),
                     new Position2D(-1, -1),
                     new Position2D(0, 1)
-                );
+                ));
 
                 a.Equals(b).Should().BeTrue();
             }
@@ -241,17 +242,17 @@ namespace Tests
             [Test]
             public void PolygonDifferentOrderEqualOperator()
             {
-                var a = new Polygon(
+                var a = new Polygon(ImmutableArray.Create(
                     new Position2D(0, 1),
                     new Position2D(1, 2),
                     new Position2D(-1, -1)
-                );
+                ));
 
-                var b = new Polygon(
+                var b = new Polygon(ImmutableArray.Create(
                     new Position2D(1, 2),
                     new Position2D(-1, -1),
                     new Position2D(0, 1)
-                );
+                ));
 
                 (a == b).Should().BeTrue();
             }
@@ -259,17 +260,17 @@ namespace Tests
             [Test]
             public void PolygonNotEqual()
             {
-                var a = new Polygon(
+                var a = new Polygon(ImmutableArray.Create(
                     new Position2D(0, 1),
                     new Position2D(1, 2),
                     new Position2D(-1, -1)
-                );
+                ));
 
-                var b = new Polygon(
+                var b = new Polygon(ImmutableArray.Create(
                     new Position2D(1, 0),
                     new Position2D(2, 1),
                     new Position2D(-1, -1)
-                );
+                ));
 
                 a.Equals(b).Should().BeFalse();
             }
@@ -277,17 +278,17 @@ namespace Tests
             [Test]
             public void PolygonNotEqualOperator()
             {
-                var a = new Polygon(
+                var a = new Polygon(ImmutableArray.Create(
                     new Position2D(0, 1),
                     new Position2D(1, 2),
                     new Position2D(-1, -1)
-                );
+                ));
 
-                var b = new Polygon(
+                var b = new Polygon(ImmutableArray.Create(
                     new Position2D(1, 0),
                     new Position2D(2, 1),
                     new Position2D(-1, -1)
-                );
+                ));
 
                 (a != b).Should().BeTrue();
             }
@@ -295,12 +296,12 @@ namespace Tests
             [Test]
             public void PolygonRectangleEqual()
             {
-                var a = new Polygon(
+                var a = new Polygon(ImmutableArray.Create(
                     new Position2D(1, 1),
                     new Position2D(1, -1),
                     new Position2D(-1, -1),
                     new Position2D(-1, 1)
-                );
+                ));
 
                 var b = new Rectangle(-1, -1, 1, 1);
 
@@ -310,12 +311,12 @@ namespace Tests
             [Test]
             public void PolygonRectangleNotEqual()
             {
-                var a = new Polygon(
+                var a = new Polygon(ImmutableArray.Create(
                     new Position2D(2, 1),
                     new Position2D(1, -1),
                     new Position2D(-1, -1),
                     new Position2D(-2, 1)
-                );
+                ));
 
                 var b = new Rectangle(-1, -1, 1, 1);
 
@@ -325,12 +326,12 @@ namespace Tests
             [Test]
             public void PolygonRectangleEqualOperator()
             {
-                var a = new Polygon(
+                var a = new Polygon(ImmutableArray.Create(
                     new Position2D(1, 1),
                     new Position2D(1, -1),
                     new Position2D(-1, -1),
                     new Position2D(-1, 1)
-                );
+                ));
 
                 var b = new Rectangle(-1, -1, 1, 1);
 
@@ -340,12 +341,12 @@ namespace Tests
             [Test]
             public void PolygonRectangleNotEqualOperator()
             {
-                var a = new Polygon(
+                var a = new Polygon(ImmutableArray.Create(
                     new Position2D(2, 1),
                     new Position2D(1, -1),
                     new Position2D(-1, -1),
                     new Position2D(-2, 1)
-                );
+                ));
 
                 var b = new Rectangle(-1, -1, 1, 1);
 
@@ -515,5 +516,26 @@ namespace Tests
                 (simplexC == simplexD).Should().BeFalse();
             }
         }
+
+        public class AABBTests
+        {
+            [Test]
+            public void Equal()
+            {
+                var aabb = new AABB(0, 0, 3, 3);
+                var other = new AABB(0, 0, 3, 3);
+
+                (aabb == other).Should().BeTrue();
+            }
+
+            [Test]
+            public void NotEqual()
+            {
+                var aabb = new AABB(0, 0, 3, 3);
+                var other = new AABB(0, 0, 6, 6);
+
+                (aabb != other).Should().BeTrue();
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/Test/GJK2DTest.cs b/Test/GJK2DTest.cs
index 9fe83d5..a962495 100644
--- a/Test/GJK2DTest.cs
+++ b/Test/GJK2DTest.cs
@@ -3,6 +3,7 @@ using MoonTools.Core.Bonk;
 using MoonTools.Core.Structs;
 using System.Numerics;
 using FluentAssertions;
+using System.Collections.Immutable;
 
 namespace Tests
 {
@@ -15,7 +16,7 @@ namespace Tests
             var pointTransform = new Transform2D(new Position2D(4, 4));
             var line = new Line(new Position2D(-2, -2), new Position2D(2, 2));
 
-            GJK2D.TestCollision(point, Transform2D.DefaultTransform, line, Transform2D.DefaultTransform).Should().BeTrue();
+            GJK2D.TestCollision(point, pointTransform, line, Transform2D.DefaultTransform).Should().BeTrue();
         }
 
         [Test]
@@ -71,12 +72,12 @@ namespace Tests
         public void PointPolygonOverlapping()
         {
             var point = new Point(1, 1);
-            var polygon = new Polygon(
+            var polygon = new Polygon(ImmutableArray.Create(
                 new Position2D(-2, -2),
                 new Position2D(-3, 2),
                 new Position2D(3, 2),
                 new Position2D(3, -2)
-            );
+            ));
 
             GJK2D.TestCollision(point, Transform2D.DefaultTransform, polygon, Transform2D.DefaultTransform).Should().BeTrue();
         }
@@ -85,12 +86,12 @@ namespace Tests
         public void PointPolygonNotOverlapping()
         {
             var point = new Point(5, 5);
-            var polygon = new Polygon(
+            var polygon = new Polygon(ImmutableArray.Create(
                 new Position2D(-2, -2),
                 new Position2D(-3, 2),
                 new Position2D(3, 2),
                 new Position2D(3, -2)
-            );
+            ));
 
             GJK2D.TestCollision(point, Transform2D.DefaultTransform, polygon, Transform2D.DefaultTransform).Should().BeFalse();
         }
@@ -182,17 +183,17 @@ namespace Tests
         [Test]
         public void PolygonPolygonOverlapping()
         {
-            var shapeA = new Polygon(
+            var shapeA = new Polygon(ImmutableArray.Create(
                 new Position2D(-1, 1), new Position2D(1, 1),
                 new Position2D(-1, -1), new Position2D(1, -1)
-            );
+            ));
 
             var transformA = Transform2D.DefaultTransform;
 
-            var shapeB = new Polygon(
+            var shapeB = new Polygon(ImmutableArray.Create(
                 new Position2D(-1, 1), new Position2D(1, 1),
                 new Position2D(-1, -1), new Position2D(1, -1)
-            );
+            ));
 
             var transformB = new Transform2D(new Vector2(0.5f, 0.5f));
 
@@ -202,17 +203,17 @@ namespace Tests
         [Test]
         public void ScaledPolygonsOverlapping()
         {
-            var shapeA = new Polygon(
+            var shapeA = new Polygon(ImmutableArray.Create(
                 new Position2D(-1, 1), new Position2D(1, 1),
                 new Position2D(-1, -1), new Position2D(1, -1)
-            );
+            ));
 
             var transformA = Transform2D.DefaultTransform;
 
-            var shapeB = new Polygon(
+            var shapeB = new Polygon(ImmutableArray.Create(
                 new Position2D(-1, 1), new Position2D(1, 1),
                 new Position2D(-1, -1), new Position2D(1, -1)
-            );
+            ));
 
             var transformB = new Transform2D(new Vector2(3f, 0f), 0f, new Vector2(3f, 3f));
 
@@ -222,17 +223,17 @@ namespace Tests
         [Test]
         public void PolygonPolygonNotOverlapping()
         {
-            var shapeA = new Polygon(
+            var shapeA = new Polygon(ImmutableArray.Create(
                 new Position2D(-1, 1), new Position2D(1, 1),
                 new Position2D(-1, -1), new Position2D(1, -1)
-            );
+            ));
 
             var transformA = Transform2D.DefaultTransform;
 
-            var shapeB = new Polygon(
+            var shapeB = new Polygon(ImmutableArray.Create(
                 new Position2D(-1, 1), new Position2D(1, 1),
                 new Position2D(-1, -1), new Position2D(1, -1)
-            );
+            ));
 
             var transformB = new Transform2D(new Vector2(5, 0));
 
@@ -242,17 +243,17 @@ namespace Tests
         [Test]
         public void ScaledPolygonsNotOverlapping()
         {
-            var shapeA = new Polygon(
+            var shapeA = new Polygon(ImmutableArray.Create(
                 new Position2D(-1, 1), new Position2D(1, 1),
                 new Position2D(-1, -1), new Position2D(1, -1)
-            );
+            ));
 
             var transformA = Transform2D.DefaultTransform;
 
-            var shapeB = new Polygon(
+            var shapeB = new Polygon(ImmutableArray.Create(
                 new Position2D(-2, 2), new Position2D(2, 2),
                 new Position2D(-2, -2), new Position2D(2, -2)
-            );
+            ));
 
             var transformB = new Transform2D(new Vector2(3f, 0), 0f, new Vector2(0.5f, 0.5f));
 
@@ -266,10 +267,10 @@ namespace Tests
 
             var transformA = Transform2D.DefaultTransform;
 
-            var polygon = new Polygon(
+            var polygon = new Polygon(ImmutableArray.Create(
                 new Position2D(-1, -1), new Position2D(1, -1),
                 new Position2D(1, 1), new Position2D(-1, 1)
-            );
+            ));
 
             var transformB = Transform2D.DefaultTransform;
 
@@ -283,10 +284,10 @@ namespace Tests
 
             var transformA = Transform2D.DefaultTransform;
 
-            var polygon = new Polygon(
+            var polygon = new Polygon(ImmutableArray.Create(
                 new Position2D(-1, -1), new Position2D(1, -1),
                 new Position2D(1, 1), new Position2D(-1, 1)
-            );
+            ));
 
             var transformB = Transform2D.DefaultTransform;
 
@@ -321,10 +322,10 @@ namespace Tests
             var circle = new Circle(1);
             var transformA = new Transform2D(new Vector2(0.25f, 0));
 
-            var square = new Polygon(
+            var square = new Polygon(ImmutableArray.Create(
                 new Position2D(-1, -1), new Position2D(1, -1),
                 new Position2D(1, 1), new Position2D(-1, 1)
-            );
+            ));
 
             var transformB = Transform2D.DefaultTransform;
 
@@ -337,10 +338,10 @@ namespace Tests
             var circle = new Circle(1);
             var circleTransform = new Transform2D(new Vector2(5, 0));
 
-            var square = new Polygon(
+            var square = new Polygon(ImmutableArray.Create(
                 new Position2D(-1, -1), new Position2D(1, -1),
                 new Position2D(1, 1), new Position2D(-1, 1)
-            );
+            ));
             var squareTransform = Transform2D.DefaultTransform;
 
             GJK2D.TestCollision(circle, circleTransform, square, squareTransform).Should().BeFalse();