multishape system
							parent
							
								
									b28196605e
								
							
						
					
					
						commit
						d23238bcfc
					
				|  | @ -1,10 +0,0 @@ | |||
| using System.Collections.Generic; | ||||
| using MoonTools.Core.Structs; | ||||
| 
 | ||||
| namespace MoonTools.Core.Bonk | ||||
| { | ||||
|     public interface IMultiShape2D : IHasAABB2D | ||||
|     { | ||||
|         IEnumerable<(IShape2D, Transform2D)> ShapeTransformPairs { get; } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,65 @@ | |||
| using System.Collections.Generic; | ||||
| using System.Collections.Immutable; | ||||
| using MoonTools.Core.Structs; | ||||
| 
 | ||||
| namespace MoonTools.Core.Bonk | ||||
| { | ||||
|     public struct MultiShape : IHasAABB2D | ||||
|     { | ||||
|         public ImmutableArray<(IShape2D, Transform2D)> ShapeTransformPairs { get; } | ||||
| 
 | ||||
|         public AABB AABB { get; } | ||||
| 
 | ||||
|         public MultiShape(ImmutableArray<(IShape2D, Transform2D)> shapeTransformPairs) | ||||
|         { | ||||
|             ShapeTransformPairs = shapeTransformPairs; | ||||
| 
 | ||||
|             AABB = AABBFromShapes(shapeTransformPairs); | ||||
|         } | ||||
| 
 | ||||
|         public AABB TransformedAABB(Transform2D transform) | ||||
|         { | ||||
|             return AABB.Transformed(AABB, transform); | ||||
|         } | ||||
| 
 | ||||
|         public IEnumerable<(IShape2D, Transform2D)> TransformedShapeTransforms(Transform2D transform) | ||||
|         { | ||||
|             foreach (var (shape, shapeTransform) in ShapeTransformPairs) | ||||
|             { | ||||
|                 yield return (shape, transform.Compose(shapeTransform)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static AABB AABBFromShapes(IEnumerable<(IShape2D, Transform2D)> shapeTransforms) | ||||
|         { | ||||
|             var minX = float.MaxValue; | ||||
|             var minY = float.MaxValue; | ||||
|             var maxX = float.MinValue; | ||||
|             var maxY = float.MinValue; | ||||
| 
 | ||||
|             foreach (var (shape, transform) in shapeTransforms) | ||||
|             { | ||||
|                 var aabb = shape.TransformedAABB(transform); | ||||
| 
 | ||||
|                 if (aabb.Min.X < minX) | ||||
|                 { | ||||
|                     minX = aabb.Min.X; | ||||
|                 } | ||||
|                 if (aabb.Min.Y < minY) | ||||
|                 { | ||||
|                     minY = aabb.Min.Y; | ||||
|                 } | ||||
|                 if (aabb.Max.X > maxX) | ||||
|                 { | ||||
|                     maxX = aabb.Max.X; | ||||
|                 } | ||||
|                 if (aabb.Max.Y > maxY) | ||||
|                 { | ||||
|                     maxY = aabb.Max.Y; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return new AABB(minX, minY, maxX, maxY); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,65 +0,0 @@ | |||
| using System.Collections.Generic; | ||||
| using System.Collections.Immutable; | ||||
| using MoonTools.Core.Structs; | ||||
| 
 | ||||
| namespace MoonTools.Core.Bonk | ||||
| { | ||||
|     public struct MultiRectangle : IMultiShape2D | ||||
|     { | ||||
|         private ImmutableArray<(Rectangle, Transform2D)> Rectangles { get; } | ||||
| 
 | ||||
|         public IEnumerable<(IShape2D, Transform2D)> ShapeTransformPairs | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 foreach (var rectangle in Rectangles) { yield return rectangle; } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public AABB AABB { get; } | ||||
| 
 | ||||
|         public MultiRectangle(ImmutableArray<(Rectangle, Transform2D)> rectangles) | ||||
|         { | ||||
|             Rectangles = rectangles; | ||||
| 
 | ||||
|             AABB = AABBFromRectangles(rectangles); | ||||
|         } | ||||
| 
 | ||||
|         public AABB TransformedAABB(Transform2D transform) | ||||
|         { | ||||
|             return AABB.Transformed(AABB, transform); | ||||
|         } | ||||
| 
 | ||||
|         private static AABB AABBFromRectangles(IEnumerable<(Rectangle, Transform2D)> rectangles) | ||||
|         { | ||||
|             var minX = float.MaxValue; | ||||
|             var minY = float.MaxValue; | ||||
|             var maxX = float.MinValue; | ||||
|             var maxY = float.MinValue; | ||||
| 
 | ||||
|             foreach (var (rectangle, transform) in rectangles) | ||||
|             { | ||||
|                 var transformedAABB = rectangle.TransformedAABB(transform); | ||||
| 
 | ||||
|                 if (transformedAABB.Min.X < minX) | ||||
|                 { | ||||
|                     minX = transformedAABB.Min.X; | ||||
|                 } | ||||
|                 if (transformedAABB.Min.Y < minY) | ||||
|                 { | ||||
|                     minY = transformedAABB.Min.Y; | ||||
|                 } | ||||
|                 if (transformedAABB.Max.X > maxX) | ||||
|                 { | ||||
|                     maxX = transformedAABB.Max.X; | ||||
|                 } | ||||
|                 if (transformedAABB.Max.Y > maxY) | ||||
|                 { | ||||
|                     maxY = transformedAABB.Max.Y; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return new AABB(minX, minY, maxX, maxY); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -14,6 +14,30 @@ namespace MoonTools.Core.Bonk | |||
|         /// <summary> | ||||
|         /// Tests if two shape-transform pairs are overlapping. Automatically detects fast-path optimizations. | ||||
|         /// </summary> | ||||
|         public static bool TestCollision(IHasAABB2D hasBoundingBoxA, Transform2D transformA, IHasAABB2D hasBoundingBoxB, Transform2D transformB) | ||||
|         { | ||||
|             if (hasBoundingBoxA is MultiShape && hasBoundingBoxB is MultiShape) | ||||
|             { | ||||
|                 return TestCollision((MultiShape)hasBoundingBoxA, transformA, (MultiShape)hasBoundingBoxB, transformB); | ||||
|             } | ||||
|             else if (hasBoundingBoxA is MultiShape && hasBoundingBoxB is IShape2D) | ||||
|             { | ||||
|                 return TestCollision((MultiShape)hasBoundingBoxA, transformA, (IShape2D)hasBoundingBoxB, transformB); | ||||
|             } | ||||
|             else if (hasBoundingBoxA is IShape2D && hasBoundingBoxB is MultiShape) | ||||
|             { | ||||
|                 return TestCollision((IShape2D)hasBoundingBoxA, transformA, (MultiShape)hasBoundingBoxB, transformB); | ||||
|             } | ||||
|             else if (hasBoundingBoxA is IShape2D && hasBoundingBoxB is IShape2D) | ||||
|             { | ||||
|                 return TestCollision((IShape2D)hasBoundingBoxA, transformA, (IShape2D)hasBoundingBoxB, transformB); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 throw new System.ArgumentException("Collision testing requires MultiShapes or IShape2Ds."); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public static bool TestCollision(IShape2D shapeA, Transform2D transformA, IShape2D shapeB, Transform2D transformB) | ||||
|         { | ||||
|             if (shapeA is Rectangle rectangleA && shapeB is Rectangle rectangleB && transformA.Rotation == 0 && transformB.Rotation == 0) | ||||
|  | @ -44,7 +68,7 @@ namespace MoonTools.Core.Bonk | |||
|         /// <param name="shape"></param> | ||||
|         /// <param name="shapeTransform"></param> | ||||
|         /// <returns></returns> | ||||
|         public static bool TestCollision(IMultiShape2D multiShape, Transform2D multiShapeTransform, IShape2D shape, Transform2D shapeTransform) | ||||
|         public static bool TestCollision(MultiShape multiShape, Transform2D multiShapeTransform, IShape2D shape, Transform2D shapeTransform) | ||||
|         { | ||||
|             foreach (var (otherShape, otherTransform) in multiShape.ShapeTransformPairs) | ||||
|             { | ||||
|  | @ -62,7 +86,7 @@ namespace MoonTools.Core.Bonk | |||
|         /// <param name="shape"></param> | ||||
|         /// <param name="shapeTransform"></param> | ||||
|         /// <returns></returns> | ||||
|         public static bool TestCollision(IShape2D shape, Transform2D shapeTransform, IMultiShape2D multiShape, Transform2D multiShapeTransform) | ||||
|         public static bool TestCollision(IShape2D shape, Transform2D shapeTransform, MultiShape multiShape, Transform2D multiShapeTransform) | ||||
|         { | ||||
|             foreach (var (otherShape, otherTransform) in multiShape.ShapeTransformPairs) | ||||
|             { | ||||
|  | @ -80,7 +104,7 @@ namespace MoonTools.Core.Bonk | |||
|         /// <param name="multiShapeB"></param> | ||||
|         /// <param name="transformB"></param> | ||||
|         /// <returns></returns> | ||||
|         public static bool TestCollision(IMultiShape2D multiShapeA, Transform2D transformA, IMultiShape2D multiShapeB, Transform2D transformB) | ||||
|         public static bool TestCollision(MultiShape multiShapeA, Transform2D transformA, MultiShape multiShapeB, Transform2D transformB) | ||||
|         { | ||||
|             foreach (var (shapeA, shapeTransformA) in multiShapeA.ShapeTransformPairs) | ||||
|             { | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ using MoonTools.Core.Structs; | |||
| 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. | ||||
|     /// A rectangle is a shape defined by a width and height. The origin is the center of the rectangle. | ||||
|     /// </summary> | ||||
|     public struct Rectangle : IShape2D, IEquatable<Rectangle> | ||||
|     { | ||||
|  |  | |||
|  | @ -366,11 +366,11 @@ namespace Tests | |||
|         [Test] | ||||
|         public void RotatedRectanglesOverlapping() | ||||
|         { | ||||
|             var rectangleA = new Rectangle(3, 3); | ||||
|             var transformA = new Transform2D(new Vector2(-1, 0), -90f); | ||||
|             var rectangleA = new Rectangle(3, 6); | ||||
|             var transformA = new Transform2D(new Vector2(4f, 0), (float)System.Math.PI / 2); | ||||
| 
 | ||||
|             var rectangleB = new Rectangle(2, 2); | ||||
|             var transformB = new Transform2D(new Vector2(1, 0)); | ||||
|             var transformB = new Transform2D(new Vector2(0, 0)); | ||||
| 
 | ||||
|             NarrowPhase.TestCollision(rectangleA, transformA, rectangleB, transformB).Should().BeTrue(); | ||||
|         } | ||||
|  | @ -426,8 +426,8 @@ namespace Tests | |||
|         [Test] | ||||
|         public void MultiRectanglesOverlapping() | ||||
|         { | ||||
|             var multiRectangleA = new MultiRectangle( | ||||
|                 ImmutableArray.Create( | ||||
|             var multiRectangleA = new MultiShape( | ||||
|                 ImmutableArray.Create<(IShape2D, Transform2D)>( | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(-5, 0))), | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(-5, 1))), | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(-5, 2))) | ||||
|  | @ -435,8 +435,8 @@ namespace Tests | |||
|             ); | ||||
|             var transformA = new Transform2D(new Position2D(5, 0)); | ||||
| 
 | ||||
|             var multiRectangleB = new MultiRectangle( | ||||
|                 ImmutableArray.Create( | ||||
|             var multiRectangleB = new MultiShape( | ||||
|                 ImmutableArray.Create<(IShape2D, Transform2D)>( | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(4, -1))), | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(4, 0))), | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(4, 1))) | ||||
|  | @ -450,8 +450,8 @@ namespace Tests | |||
|         [Test] | ||||
|         public void MultiRectanglesNotOverlapping() | ||||
|         { | ||||
|             var multiRectangleA = new MultiRectangle( | ||||
|                 ImmutableArray.Create( | ||||
|             var multiRectangleA = new MultiShape( | ||||
|                 ImmutableArray.Create<(IShape2D, Transform2D)>( | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(-5, 0))), | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(-5, 1))), | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(-5, 2))) | ||||
|  | @ -459,8 +459,8 @@ namespace Tests | |||
|             ); | ||||
|             var transformA = new Transform2D(new Position2D(5, 0)); | ||||
| 
 | ||||
|             var multiRectangleB = new MultiRectangle( | ||||
|                 ImmutableArray.Create( | ||||
|             var multiRectangleB = new MultiShape( | ||||
|                 ImmutableArray.Create<(IShape2D, Transform2D)>( | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(4, -1))), | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(4, 0))), | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(4, 1))) | ||||
|  |  | |||
|  | @ -38,8 +38,8 @@ namespace Tests | |||
|             var point = new Point(); | ||||
|             var pointTransform = new Transform2D(new Position2D(8, 8)); | ||||
| 
 | ||||
|             var multiRectangle = new MultiRectangle( | ||||
|                 ImmutableArray.Create( | ||||
|             var multiRectangle = new MultiShape( | ||||
|                 ImmutableArray.Create<(IShape2D, Transform2D)>( | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(-2, -2))), | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(-2, -1))), | ||||
|                     (new Rectangle(4, 1), new Transform2D(new Position2D(-2, 0))) | ||||
|  | @ -70,6 +70,7 @@ namespace Tests | |||
|             spatialHash.Retrieve(6, line, lineTransform).Should().Contain((4, circleA, circleATransform)).And.Contain((2, rectC, rectCTransform)); | ||||
| 
 | ||||
|             spatialHash.Retrieve(8, multiRectangle, multiRectangleTransform).Should().Contain((1, rectB, rectBTransform)); | ||||
|             spatialHash.Retrieve(8, multiRectangle, multiRectangleTransform).Should().NotContain((0, rectA, rectATransform)); | ||||
|         } | ||||
| 
 | ||||
|         [Test] | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue