public static IRectangularF GetLineOfSightObstruction(this IRectangularF from, IRectangularF to, IEnumerable <IRectangularF> obstacles) { var prediction = PredictHit(new HitDetectionOptions() { MovingObject = from, Angle = from.Center().CalculateAngleTo(to.Center()), Obstacles = obstacles.Union(new IRectangularF[] { to }), Visibility = 3 * from.Center().CalculateDistanceTo(to.Center()), Mode = CastingMode.Rough, }); if (prediction.Type == HitType.None) { return(SpaceTime.CurrentSpaceTime?.Bounds); } else { if (to is IHaveMassBounds && prediction.ObstacleHit is SpacialElement && (to as IHaveMassBounds).IsPartOfMass(prediction.ObstacleHit as SpacialElement)) { return(null); } if (prediction.ObstacleHit is SpacialElement && (to is IHaveMassBounds) && (to as IHaveMassBounds).IsPartOfMass((SpacialElement)prediction.ObstacleHit)) { return(null); } else { return(prediction.ObstacleHit == to ? null : prediction.ObstacleHit); } } }
private static List <IRectangularF> GetLineOfSight(this IRectangularF from, IRectangularF to, List <IRectangularF> obstacles, float increment = .5f) { IRectangularF current = from; var currentDistance = current.CalculateDistanceTo(to); var a = current.Center().CalculateAngleTo(to.Center()); var path = new List <IRectangularF>(); while (currentDistance > increment) { current = RectangularF.Create(MoveTowards(current.Center(), a, increment), current); current = RectangularF.Create(current.Left - current.Width / 2, current.Top - current.Height / 2, current.Width, current.Height); foreach (var obstacle in obstacles) { if (obstacle == to || obstacle == from) { continue; } else if (obstacle.OverlapPercentage(current) > 0) { return(null); } } path.Add(current); currentDistance = current.CalculateDistanceTo(to); } return(path); }
public static IRectangularF Shrink(this IRectangularF rect, float percentage) { var center = rect.Center(); var newW = rect.Width * (1 - percentage); var newH = rect.Height * (1 - percentage); return(RectangularF.Create(center.Left - newW / 2, center.Top - newH / 2, newW, newH)); }
public static float LineOfSightVisibility(this IRectangularF from, float angle, IEnumerable <IRectangularF> obstacles, float range, float increment = .5f) { for (var d = increment; d < range; d += increment) { var testLocation = from.Center().MoveTowards(angle, d); var testRect = RectangularF.Create(testLocation.Left - from.Width / 2, testLocation.Top - from.Height / 2, from.Width, from.Height); if (obstacles.Where(o => o.Touches(testRect)).Any() || SpaceTime.CurrentSpaceTime.Bounds.Contains(testRect) == false) { return(d); } } return(range); }
public static float CalculateAngleTo(this IRectangularF from, IRectangularF to) => CalculateAngleTo(from.Center(), to.Center());
private async Task ExecuteAsync() { while (this.Lifetime.IsExpired == false) { await Time.CurrentTime.YieldAsync(); if (this.Lifetime.IsExpired) { return; } if (MovementTakeover != null) { await MovementTakeover(); continue; } float dt = (float)Time.CurrentTime.Increment.TotalSeconds; if (dt == 0) { dt = (float)Time.CurrentTime.Increment.TotalSeconds; } float d = Speed * dt; if (d == 0) { OnVelocityEnforced?.Fire(); continue; } HitPrediction hitPrediction = null; IRectangularF bounds = null; if (HitDetectionDisabled == false) { var obstacles = GetObstacles(); bounds = BoundsTransform != null?BoundsTransform() : Element; hitPrediction = HitDetection.PredictHit(new HitDetectionOptions() { MovingObject = bounds, Obstacles = obstacles, Angle = Angle, Visibility = d, Mode = CastingMode.Precise, }); LastPrediction = hitPrediction; } if (hitPrediction != null && hitPrediction.Type != HitType.None) { var dx = BoundsTransform != null ? bounds.Left - Element.Left : 0; var dy = BoundsTransform != null ? bounds.Top - Element.Top : 0; var proposedBounds = BoundsTransform != null?BoundsTransform() : Element; var distanceToObstacleHit = proposedBounds.CalculateDistanceTo(hitPrediction.ObstacleHit); if (distanceToObstacleHit > .5f) { proposedBounds = proposedBounds.MoveTowards(Angle, distanceToObstacleHit - .5f, false); Element.MoveTo(proposedBounds.Left - dx, proposedBounds.Top - dy); haveMovedSinceLastHitDetection = true; } float angle = bounds.Center().CalculateAngleTo(hitPrediction.ObstacleHit.Center()); if (haveMovedSinceLastHitDetection) { LastImpact = new Impact() { Angle = angle, MovingObject = Element, ObstacleHit = hitPrediction.ObstacleHit, HitType = hitPrediction.Type, }; if (hitPrediction.ObstacleHit is SpacialElement) { Velocity.For(hitPrediction.ObstacleHit as SpacialElement)?.ImpactOccurred.Fire(new Impact() { Angle = angle.GetOppositeAngle(), MovingObject = hitPrediction.ObstacleHit as SpacialElement, ObstacleHit = Element, HitType = hitPrediction.Type, }); } ImpactOccurred?.Fire(LastImpact); GlobalImpactOccurred.Fire(LastImpact); haveMovedSinceLastHitDetection = false; Element.SizeOrPositionChanged.Fire(); } if (Bounce) { var side = Geometry.GetSideGivenEdgeIndex(hitPrediction.EdgeIndex); if (side == Side.Top || side == Side.Bottom) { Angle = 0.AddToAngle(-Angle); } else { Angle = 180.AddToAngle(-Angle); } } else { Stop(); } } else { var newLocation = Element.MoveTowards(Angle, d); Element.MoveTo(newLocation.Left, newLocation.Top); haveMovedSinceLastHitDetection = true; } OnVelocityEnforced?.Fire(); } }