fixing sweep test
							parent
							
								
									9777429d07
								
							
						
					
					
						commit
						354912d674
					
				|  | @ -73,7 +73,38 @@ namespace MoonTools.Core.Bonk | |||
|                         foreach (var t in hashDictionary[key]) | ||||
|                         { | ||||
|                             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); | ||||
|                             } | ||||
|  |  | |||
|  | @ -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) | ||||
|         { | ||||
|             var minX = float.MaxValue; | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ namespace MoonTools.Core.Bonk | |||
|     public static class SweepTest | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Performs a sweep test on rectangles. | ||||
|         /// Performs a sweep test on rectangles. Returns the position 1 pixel before overlap occurs. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="T"></typeparam> | ||||
|         /// <param name="spatialHash">A spatial hash.</param> | ||||
|  | @ -27,67 +27,88 @@ namespace MoonTools.Core.Bonk | |||
| 
 | ||||
|             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); | ||||
|                     float xInvEntry, yInvEntry; | ||||
|                     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; | ||||
|                 } | ||||
| 
 | ||||
|                     if (ray.X > 0) | ||||
|                     { | ||||
|                         xInvEntry = shapeTransform.Position.X - (transform.Position.X + transformedAABB.Width); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         xInvEntry = (shapeTransform.Position.X + otherTransformedAABB.Width) - transform.Position.X; | ||||
|                     } | ||||
|                 float xInvEntry, yInvEntry; | ||||
| 
 | ||||
|                     if (ray.Y > 0) | ||||
|                     { | ||||
|                         yInvEntry = shapeTransform.Position.Y - (transform.Position.Y + transformedAABB.Height); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         yInvEntry = (shapeTransform.Position.Y + otherTransformedAABB.Height) - shapeTransform.Position.Y; | ||||
|                     } | ||||
|                 if (ray.X > 0) | ||||
|                 { | ||||
|                     xInvEntry = otherTransformedAABB.Left - (transformedAABB.Right); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     xInvEntry = (otherTransformedAABB.Right) - transformedAABB.Left; | ||||
|                 } | ||||
| 
 | ||||
|                     float xEntry, yEntry; | ||||
|                 if (ray.Y > 0) | ||||
|                 { | ||||
|                     yInvEntry = otherTransformedAABB.Top - (transformedAABB.Bottom); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     yInvEntry = (otherTransformedAABB.Bottom) - transformedAABB.Top; | ||||
|                 } | ||||
| 
 | ||||
|                     if (ray.X == 0) | ||||
|                     { | ||||
|                         xEntry = float.MinValue; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         xEntry = xInvEntry / ray.X; | ||||
|                     } | ||||
|                 float xEntry, yEntry; | ||||
| 
 | ||||
|                     if (ray.Y == 0) | ||||
|                     { | ||||
|                         yEntry = float.MinValue; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         yEntry = yInvEntry / ray.Y; | ||||
|                     } | ||||
|                 if (ray.X == 0) | ||||
|                 { | ||||
|                     xEntry = float.MinValue; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     xEntry = xInvEntry / ray.X; | ||||
|                 } | ||||
| 
 | ||||
|                     var entryTime = Math.Max(xEntry, yEntry); | ||||
|                 if (ray.Y == 0) | ||||
|                 { | ||||
|                     yEntry = float.MinValue; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     yEntry = yInvEntry / ray.Y; | ||||
|                 } | ||||
| 
 | ||||
|                     if (entryTime > 0 && entryTime < 1) | ||||
|                 var entryTime = Math.Max(xEntry, yEntry); | ||||
| 
 | ||||
|                 if (entryTime >= 0 && entryTime <= 1) | ||||
|                 { | ||||
|                     if (entryTime < shortestDistance) | ||||
|                     { | ||||
|                         if (entryTime < shortestDistance) | ||||
|                         { | ||||
|                             shortestDistance = entryTime; | ||||
|                             nearestID = id; | ||||
|                             nearestRectangle = rectangle; | ||||
|                             nearestTransform = shapeTransform; | ||||
|                         } | ||||
|                         shortestDistance = entryTime; | ||||
|                         nearestID = id; | ||||
|                         nearestRectangle = otherRectangle; | ||||
|                         nearestTransform = shapeTransform; | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|             } | ||||
| 
 | ||||
|             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 | ||||
|             { | ||||
|  |  | |||
|  | @ -20,15 +20,23 @@ namespace Tests | |||
|             var farthestRectangle = new Rectangle(4, 4); | ||||
|             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); | ||||
|             spatialHash.Insert(1, otherRectangle, otherTransform); | ||||
|             spatialHash.Insert(2, farthestRectangle, farthestTransform); | ||||
|             spatialHash.Insert(3, downRectangle, downTransform); | ||||
| 
 | ||||
|             SweepTest.Rectangle(spatialHash, rectangle, transform, new Vector2(12, 0)).Should().Be( | ||||
|                 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(0, 20)).Should().Be( | ||||
|                 new SweepResult<int, Rectangle>(true, new Vector2(0, 16), 3, downRectangle, downTransform) | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue