private static bool IsIncluded(HitDetectionOptions options, IRectangularF obj) { if (options.Exclusions == null) { return(true); } else { return(options.Exclusions.Contains(obj) == false); } }
public static HitPrediction PredictHit(HitDetectionOptions options) { HitPrediction prediction = new HitPrediction(); var left = Math.Min(options.MovingObject.Left, options.MovingObject.Left + options.Dx); var top = Math.Min(options.MovingObject.Top, options.MovingObject.Top + options.Dy); var right = Math.Max(options.MovingObject.Left + options.MovingObject.Width, options.MovingObject.Left + options.MovingObject.Width + options.Dx); var bottom = Math.Max(options.MovingObject.Top + options.MovingObject.Height, options.MovingObject.Top + options.MovingObject.Height + options.Dy); var relevantArea = RectangularF.Create(left, top, right - left, bottom - top); var effectiveObstacles = options.Obstacles.Where(o => o.Touches(relevantArea)).ToList(); if (options.Dx == 0 && options.Dy == 0) { prediction.Direction = Direction.None; prediction.Type = HitType.None; return(prediction); } var endPoint = RectangularF.Create(options.MovingObject.Left + options.Dx, options.MovingObject.Top + options.Dy, options.MovingObject.Width, options.MovingObject.Height); var angle = options.MovingObject.CalculateAngleTo(endPoint); var d = endPoint.CalculateDistanceTo(options.MovingObject); for (var dPrime = options.Precision; dPrime < d; dPrime += options.Precision) { var testLocation = options.MovingObject.Center().MoveTowards(angle, dPrime); var testArea = RectangularF.Create(testLocation.Left - options.MovingObject.Width / 2, testLocation.Top - options.MovingObject.Height / 2, options.MovingObject.Width, options.MovingObject.Height); var obstacleHit = effectiveObstacles.Where(o => IsIncluded(options, o) && o.Touches(testArea) == true).FirstOrDefault(); if (obstacleHit != null) { return(new HitPrediction() { Type = HitType.Obstacle, ObstacleHit = obstacleHit }); } } var obstacleHitFinal = effectiveObstacles.Where(o => IsIncluded(options, o) && o.Touches(endPoint) == true).FirstOrDefault(); if (obstacleHitFinal != null) { return(new HitPrediction() { Type = HitType.Obstacle, ObstacleHit = obstacleHitFinal }); } prediction.Type = HitType.None; return(prediction); }
public static ICollider GetLineOfSightObstruction(this ICollider from, ICollider to, IEnumerable <ICollider> obstacles, CastingMode castingMode = CastingMode.Rough) { var options = new HitDetectionOptions(from, obstacles.Union(new[] { to })); options.Mode = castingMode; options.Angle = options.MovingObject.CalculateAngleTo(to.Bounds); options.Visibility = 3 * options.MovingObject.CalculateDistanceTo(to.Bounds); var prediction = PredictHit(options); if (prediction.Type == HitType.None) { return(null); } else { var obstacleHit = prediction.ColliderHit; return(obstacleHit == to ? null : obstacleHit); } }
public static HitPrediction PredictHit(HitDetectionOptions options) { return(PredictHit(options.MovingObject, options.Obstacles.ToArray(), options.Angle, options.Colliders, options.Visibility, options.Mode, options.EdgesHitOutput, options.ObstacleBufferLength)); }
public static HitPrediction PredictHit(HitDetectionOptions options) { HitPrediction prediction = new HitPrediction(); prediction.LKG = options.MovingObject.CopyBounds().TopLeft(); prediction.MovingObjectPosition = options.MovingObject.CopyBounds(); prediction.Visibility = options.Visibility; if (options.Visibility == 0) { prediction.Direction = Direction.None; prediction.Type = HitType.None; return(prediction); } var mov = options.MovingObject; List <Edge> rays; if (options.Mode == CastingMode.Precise) { rays = new List <Edge>() { new Edge() { From = mov.TopLeft(), To = mov.TopLeft().MoveTowards(options.Angle, options.Visibility, normalized: false) }, new Edge() { From = mov.TopRight(), To = mov.TopRight().MoveTowards(options.Angle, options.Visibility, normalized: false) }, new Edge() { From = mov.BottomLeft(), To = mov.BottomLeft().MoveTowards(options.Angle, options.Visibility, normalized: false) }, new Edge() { From = mov.BottomRight(), To = mov.BottomRight().MoveTowards(options.Angle, options.Visibility, normalized: false) }, }; var granularity = .5f; for (var x = mov.Left + granularity; x < mov.Left + mov.Width; x += granularity) { var top = LocationF.Create(x, mov.Top); var bot = LocationF.Create(x, mov.Bottom()); rays.Add(new Edge() { From = top, To = top.MoveTowards(options.Angle, options.Visibility, normalized: false) }); rays.Add(new Edge() { From = bot, To = bot.MoveTowards(options.Angle, options.Visibility, normalized: false) }); } for (var y = mov.Top + granularity; y < mov.Top + mov.Height; y += granularity) { var left = LocationF.Create(mov.Left, y); var right = LocationF.Create(mov.Right(), y); rays.Add(new Edge() { From = left, To = left.MoveTowards(options.Angle, options.Visibility, normalized: false) }); rays.Add(new Edge() { From = right, To = right.MoveTowards(options.Angle, options.Visibility, normalized: false) }); } } else if (options.Mode == CastingMode.Rough) { var center = options.MovingObject.Center(); rays = new List <Edge>() { new Edge() { From = mov.TopLeft(), To = mov.TopLeft().MoveTowards(options.Angle, options.Visibility, normalized: false) }, new Edge() { From = mov.TopRight(), To = mov.TopRight().MoveTowards(options.Angle, options.Visibility, normalized: false) }, new Edge() { From = mov.BottomLeft(), To = mov.BottomLeft().MoveTowards(options.Angle, options.Visibility, normalized: false) }, new Edge() { From = mov.BottomRight(), To = mov.BottomRight().MoveTowards(options.Angle, options.Visibility, normalized: false) }, new Edge() { From = center, To = center.MoveTowards(options.Angle, options.Visibility, normalized: false) } }; } else if (options.Mode == CastingMode.SingleRay) { var center = options.MovingObject.Center(); rays = new List <Edge>() { new Edge() { From = center, To = center.MoveTowards(options.Angle, options.Visibility, normalized: false) } }; } else { throw new NotSupportedException("Unknown mide: " + options.Mode); } var closestIntersectionDistance = float.MaxValue; IRectangularF closestIntersectingElement = null; var closestEdgeIndex = -1; var effectiveObstacles = options.Obstacles.ToArray(); for (var i = 0; i < effectiveObstacles.Length; i++) { var obstacle = effectiveObstacles[i]; for (var j = 0; j < obstacle.Edges.Length; j++) { var edge = obstacle.Edges[j]; for (var k = 0; k < rays.Count; k++) { var ray = rays[k]; var intersection = FindIntersectionPoint(ray, edge); if (intersection != null) { var d = ray.From.CalculateDistanceTo(intersection); if (d < closestIntersectionDistance && d <= options.Visibility) { closestIntersectionDistance = d; closestIntersectingElement = obstacle; closestEdgeIndex = j; } } } } } if (closestIntersectingElement != null) { prediction.ObstacleHit = closestIntersectingElement; prediction.LKGD = closestIntersectionDistance - .1f; prediction.LKG = options.MovingObject.MoveTowards(options.Angle, prediction.LKGD, normalized: false).TopLeft(); prediction.Type = HitType.Obstacle; prediction.EdgeIndex = closestEdgeIndex; } return(prediction); }
public static HitPrediction PredictHit(HitDetectionOptions options) { HitPrediction prediction = new HitPrediction(); prediction.MovingObjectPosition = options.MovingObject.CopyBounds(); prediction.Visibility = options.Visibility; if (options.Visibility == 0) { prediction.Direction = Direction.None; prediction.Type = HitType.None; return(prediction); } var effectiveObstacles = options.Obstacles.Where(o => o.CalculateDistanceTo(options.MovingObject) <= options.Visibility + options.Precision).ToList(); var endPoint = options.MovingObject.MoveTowards(options.Angle, options.Visibility); ILocationF lkg = null; for (var dPrime = options.Precision; dPrime < options.Visibility; dPrime += options.Precision) { var testArea = options.MovingObject.MoveTowards(options.Angle, dPrime); prediction.Path.Add(testArea); var obstacleHit = effectiveObstacles.Where(o => { var simpleTest = o.Touches(testArea) == true; if (simpleTest == false) { return(false); } if (o.Touches(options.MovingObject)) { var overlapBefore = options.MovingObject.NumberOfPixelsThatOverlap(o); var overlapAfter = testArea.NumberOfPixelsThatOverlap(o); if (overlapAfter < overlapBefore) { return(false); } else { return(true); } } else { return(true); } }).FirstOrDefault(); if (obstacleHit != null) { prediction.Type = HitType.Obstacle; prediction.ObstacleHit = obstacleHit; prediction.LKG = lkg; return(prediction); } else { lkg = testArea.TopLeft(); } } var obstacleHitFinal = effectiveObstacles.Where(o => o.Touches(endPoint) == true).FirstOrDefault(); if (obstacleHitFinal != null) { prediction.Type = HitType.Obstacle; prediction.ObstacleHit = obstacleHitFinal; prediction.LKG = lkg; return(prediction); } prediction.Type = HitType.None; return(prediction); }