fixing sweep test
							parent
							
								
									9777429d07
								
							
						
					
					
						commit
						354912d674
					
				|  | @ -73,7 +73,38 @@ namespace MoonTools.Core.Bonk | ||||||
|                         foreach (var t in hashDictionary[key]) |                         foreach (var t in hashDictionary[key]) | ||||||
|                         { |                         { | ||||||
|                             var (otherShape, otherTransform) = IDLookup[t]; |                             var (otherShape, otherTransform) = IDLookup[t]; | ||||||
|                             if (!id.Equals(t) && AABB.TestOverlap(shape.TransformedAABB(transform2D), otherShape.TransformedAABB(otherTransform))) |                             if (!id.Equals(t) && AABB.TestOverlap(box, otherShape.TransformedAABB(otherTransform))) | ||||||
|  |                             { | ||||||
|  |                                 yield return (t, otherShape, otherTransform); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Retrieves objects based on a pre-transformed AABB. | ||||||
|  |         /// </summary> | ||||||
|  |         /// <param name="aabb">A transformed AABB.</param> | ||||||
|  |         /// <returns></returns> | ||||||
|  |         public IEnumerable<(T, IHasAABB2D, Transform2D)> Retrieve(AABB aabb) | ||||||
|  |         { | ||||||
|  |             var minHash = Hash(aabb.Min); | ||||||
|  |             var maxHash = Hash(aabb.Max); | ||||||
|  | 
 | ||||||
|  |             for (var i = minHash.Item1; i <= maxHash.Item1; i++) | ||||||
|  |             { | ||||||
|  |                 for (var j = minHash.Item2; j <= maxHash.Item2; j++) | ||||||
|  |                 { | ||||||
|  |                     var key = MakeLong(i, j); | ||||||
|  |                     if (hashDictionary.ContainsKey(key)) | ||||||
|  |                     { | ||||||
|  |                         foreach (var t in hashDictionary[key]) | ||||||
|  |                         { | ||||||
|  |                             var (otherShape, otherTransform) = IDLookup[t]; | ||||||
|  |                             if (AABB.TestOverlap(aabb, otherShape.TransformedAABB(otherTransform))) | ||||||
|                             { |                             { | ||||||
|                                 yield return (t, otherShape, otherTransform); |                                 yield return (t, otherShape, otherTransform); | ||||||
|                             } |                             } | ||||||
|  |  | ||||||
|  | @ -30,6 +30,16 @@ namespace MoonTools.Core.Bonk | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         public bool IsSingleShape<T>() where T : struct, IShape2D | ||||||
|  |         { | ||||||
|  |             return ShapeTransformPairs.Length == 1 && ShapeTransformPairs[0].Item1 is T; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public (T, Transform2D) ShapeTransformPair<T>() where T : struct, IShape2D | ||||||
|  |         { | ||||||
|  |             return ((T, Transform2D))ShapeTransformPairs[0]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         private static AABB AABBFromShapes(IEnumerable<(IShape2D, Transform2D)> shapeTransforms) |         private static AABB AABBFromShapes(IEnumerable<(IShape2D, Transform2D)> shapeTransforms) | ||||||
|         { |         { | ||||||
|             var minX = float.MaxValue; |             var minX = float.MaxValue; | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ namespace MoonTools.Core.Bonk | ||||||
|     public static class SweepTest |     public static class SweepTest | ||||||
|     { |     { | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Performs a sweep test on rectangles. |         /// Performs a sweep test on rectangles. Returns the position 1 pixel before overlap occurs. | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <typeparam name="T"></typeparam> |         /// <typeparam name="T"></typeparam> | ||||||
|         /// <param name="spatialHash">A spatial hash.</param> |         /// <param name="spatialHash">A spatial hash.</param> | ||||||
|  | @ -27,27 +27,45 @@ namespace MoonTools.Core.Bonk | ||||||
| 
 | 
 | ||||||
|             foreach (var (id, shape, shapeTransform) in spatialHash.Retrieve(sweepBox)) |             foreach (var (id, shape, shapeTransform) in spatialHash.Retrieve(sweepBox)) | ||||||
|             { |             { | ||||||
|                 if (shape is Rectangle otherRectangle) |                 Rectangle otherRectangle; | ||||||
|  |                 Transform2D otherTransform; | ||||||
|  |                 AABB otherTransformedAABB; | ||||||
|  |                 if (shape is Rectangle) | ||||||
|                 { |                 { | ||||||
|                     var otherTransformedAABB = otherRectangle.TransformedAABB(shapeTransform); |                     otherRectangle = (Rectangle)shape; | ||||||
|  |                     otherTransformedAABB = shape.TransformedAABB(shapeTransform); | ||||||
|  |                     otherTransform = shapeTransform; | ||||||
|  |                 } | ||||||
|  |                 else if (shape is MultiShape multiShape && multiShape.IsSingleShape<Rectangle>()) | ||||||
|  |                 { | ||||||
|  |                     Transform2D rectangleOffset; | ||||||
|  |                     (otherRectangle, rectangleOffset) = multiShape.ShapeTransformPair<Rectangle>(); | ||||||
|  |                     otherTransform = shapeTransform.Compose(rectangleOffset); | ||||||
|  |                     otherTransformedAABB = shape.TransformedAABB(otherTransform); | ||||||
|  |                 } | ||||||
|  |                 else | ||||||
|  |                 { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 float xInvEntry, yInvEntry; |                 float xInvEntry, yInvEntry; | ||||||
| 
 | 
 | ||||||
|                 if (ray.X > 0) |                 if (ray.X > 0) | ||||||
|                 { |                 { | ||||||
|                         xInvEntry = shapeTransform.Position.X - (transform.Position.X + transformedAABB.Width); |                     xInvEntry = otherTransformedAABB.Left - (transformedAABB.Right); | ||||||
|                 } |                 } | ||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                         xInvEntry = (shapeTransform.Position.X + otherTransformedAABB.Width) - transform.Position.X; |                     xInvEntry = (otherTransformedAABB.Right) - transformedAABB.Left; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (ray.Y > 0) |                 if (ray.Y > 0) | ||||||
|                 { |                 { | ||||||
|                         yInvEntry = shapeTransform.Position.Y - (transform.Position.Y + transformedAABB.Height); |                     yInvEntry = otherTransformedAABB.Top - (transformedAABB.Bottom); | ||||||
|                 } |                 } | ||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                         yInvEntry = (shapeTransform.Position.Y + otherTransformedAABB.Height) - shapeTransform.Position.Y; |                     yInvEntry = (otherTransformedAABB.Bottom) - transformedAABB.Top; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 float xEntry, yEntry; |                 float xEntry, yEntry; | ||||||
|  | @ -72,22 +90,25 @@ namespace MoonTools.Core.Bonk | ||||||
| 
 | 
 | ||||||
|                 var entryTime = Math.Max(xEntry, yEntry); |                 var entryTime = Math.Max(xEntry, yEntry); | ||||||
| 
 | 
 | ||||||
|                     if (entryTime > 0 && entryTime < 1) |                 if (entryTime >= 0 && entryTime <= 1) | ||||||
|                 { |                 { | ||||||
|                     if (entryTime < shortestDistance) |                     if (entryTime < shortestDistance) | ||||||
|                     { |                     { | ||||||
|                         shortestDistance = entryTime; |                         shortestDistance = entryTime; | ||||||
|                         nearestID = id; |                         nearestID = id; | ||||||
|                             nearestRectangle = rectangle; |                         nearestRectangle = otherRectangle; | ||||||
|                         nearestTransform = shapeTransform; |                         nearestTransform = shapeTransform; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 } |                  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (nearestRectangle.HasValue) |             if (nearestRectangle.HasValue) | ||||||
|             { |             { | ||||||
|                 return new SweepResult<T, Rectangle>(true, ray * shortestDistance, nearestID, nearestRectangle.Value, nearestTransform.Value); |                 var overlapPosition = ray * shortestDistance; | ||||||
|  |                 var correctionX = ray.X > 0 ? -1 : 1; | ||||||
|  |                 var correctionY = ray.Y > 0 ? -1 : 1; | ||||||
|  |                 return new SweepResult<T, Rectangle>(true, new Position2D((int)overlapPosition.X + correctionX, (int)overlapPosition.Y + correctionY), nearestID, nearestRectangle.Value, nearestTransform.Value); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|  |  | ||||||
|  | @ -20,15 +20,23 @@ namespace Tests | ||||||
|             var farthestRectangle = new Rectangle(4, 4); |             var farthestRectangle = new Rectangle(4, 4); | ||||||
|             var farthestTransform = new Transform2D(new Position2D(12, 0)); |             var farthestTransform = new Transform2D(new Position2D(12, 0)); | ||||||
| 
 | 
 | ||||||
|  |             var downRectangle = new Rectangle(12, 4); | ||||||
|  |             var downTransform = new Transform2D(new Position2D(-6, 20)); | ||||||
|  | 
 | ||||||
|             var spatialHash = new SpatialHash<int>(16); |             var spatialHash = new SpatialHash<int>(16); | ||||||
|             spatialHash.Insert(1, otherRectangle, otherTransform); |             spatialHash.Insert(1, otherRectangle, otherTransform); | ||||||
|             spatialHash.Insert(2, farthestRectangle, farthestTransform); |             spatialHash.Insert(2, farthestRectangle, farthestTransform); | ||||||
|  |             spatialHash.Insert(3, downRectangle, downTransform); | ||||||
| 
 | 
 | ||||||
|             SweepTest.Rectangle(spatialHash, rectangle, transform, new Vector2(12, 0)).Should().Be( |             SweepTest.Rectangle(spatialHash, rectangle, transform, new Vector2(12, 0)).Should().Be( | ||||||
|                 new SweepResult<int, Rectangle>(true, new Vector2(8, 0), 1, otherRectangle, otherTransform) |                 new SweepResult<int, Rectangle>(true, new Vector2(8, 0), 1, otherRectangle, otherTransform) | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|             SweepTest.Rectangle(spatialHash, rectangle, transform, new Vector2(-12, 0)).Hit.Should().BeFalse(); |             SweepTest.Rectangle(spatialHash, rectangle, transform, new Vector2(-12, 0)).Hit.Should().BeFalse(); | ||||||
|  | 
 | ||||||
|  |             SweepTest.Rectangle(spatialHash, rectangle, transform, new Vector2(0, 20)).Should().Be( | ||||||
|  |                 new SweepResult<int, Rectangle>(true, new Vector2(0, 16), 3, downRectangle, downTransform) | ||||||
|  |             ); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue