public static Route CalculateLineOfSight(this IRectangular from, IRectangular to, float increment) { Route ret = new Route(); IRectangular current = from; var currentDistance = current.CalculateDistanceTo(to); var firstDistance = currentDistance; while (currentDistance > increment) { #if DEBUG if (currentDistance > firstDistance) { throw new Exception("Bug, we got farther away"); } #endif current = Rectangular.Create(MoveTowards(current.Center(), to.Center(), increment), from); current = Rectangular.Create(current.Left - from.Width / 2, current.Top - from.Height / 2, from.Width, from.Height); ret.Steps.Add(current); var obstacles = SpaceTime.CurrentSpaceTime.Elements .Where(el => el != from && el != to && el.NumberOfPixelsThatOverlap(current) > 0); foreach (var obstacle in obstacles) { if (ret.Obstacles.Contains(obstacle) == false) { ret.Obstacles.Add(obstacle); } } currentDistance = current.CalculateDistanceTo(to); } return(ret); }
public static Route CalculateLineOfSight(IRectangular from, ILocation to, float increment) { Route ret = new Route(); IRectangular current = from; while (from.Center().CalculateDistanceTo(to) > increment) { current = Rectangular.Create(MoveTowards(current.Center(), to, increment), from); ret.Steps.Add(current.Center()); var obstacles = SpaceTime.CurrentSpaceTime.Elements .Where(el => el.NumberOfPixelsThatOverlap(current) > 0); foreach (var obstacle in obstacles) { if (ret.Obstacles.Contains(obstacle) == false) { ret.Obstacles.Add(obstacle); } } } return(ret); }
public override void Evaluate() { float dt = (float)Governor.Rate.TotalSeconds; if (dt == 0) { dt = (float)Time.CurrentTime.Increment.TotalSeconds; } float dx = SpeedX * dt; float dy = SpeedY * dt; if (dx == 0 && dy == 0) { return; } var hitPrediction = HitDetection.PredictHit(SpaceTime.CurrentSpaceTime, Element, HitDetectionTypes, dx, dy); if (hitPrediction.Type != HitType.None) { float angle; if (hitPrediction.ElementHit != null) { angle = Element.Center().CalculateAngleTo(hitPrediction.ElementHit.Center()); } else if (hitPrediction.Direction == Direction.Left) { angle = 180; } else if (hitPrediction.Direction == Direction.Right) { angle = 0; } else if (hitPrediction.Direction == Direction.Up) { angle = 270; } else if (hitPrediction.Direction == Direction.Down) { angle = 90; } else { throw new NotSupportedException($"Unsupported direction: {hitPrediction.Direction}"); } if (ImpactOccurred != null && haveMovedSinceLastHitDetection) { ImpactOccurred.Fire(new Impact() { Angle = angle, Bounds = hitPrediction.BoundsOfItemBeingHit, ElementHit = hitPrediction.ElementHit }); } haveMovedSinceLastHitDetection = false; var testArea = Rectangular.Create(Element.Left + dx, Element.Top + dy, Element.Width, Element.Height); if (hitPrediction.Direction == Direction.Down || hitPrediction.Direction == Direction.Up) { SpeedY = -SpeedY * Bounciness; SpeedX = SpeedX * ImpactFriction; } else if (hitPrediction.Direction == Direction.Left || hitPrediction.Direction == Direction.Right) { SpeedX = -SpeedX * Bounciness; SpeedY = SpeedY * ImpactFriction; } else { SpeedX = -SpeedX * Bounciness; SpeedY = -SpeedY * Bounciness; } } else { var oldLocation = Element.CopyBounds(); Element.MoveBy(dx, dy); this.Angle = oldLocation.Center().CalculateAngleTo(Element.Center()); haveMovedSinceLastHitDetection = true; } }
public static HitPrediction PredictHit(SpaceTime r, SpacialElement Target, List <Type> hitDetectionTypes, float dx, float dy) { HitPrediction prediction = new HitPrediction(); if (dx == 0 && dy == 0) { prediction.Direction = Direction.None; prediction.Type = HitType.None; return(prediction); } if (dy > 0 && Target.Bottom() + dy >= r.Height) { prediction.Direction = Direction.Down; prediction.Type = HitType.Boundary; prediction.BoundsOfItemBeingHit = Rectangular.Create(Target.Left + dx, r.Bounds.Height + dy, 1, 1); return(prediction); } else if (dx < 0 && Target.Left + dx <= 0) { prediction.Direction = Direction.Left; prediction.Type = HitType.Boundary; prediction.BoundsOfItemBeingHit = Rectangular.Create(-dx, Target.Top + dy, 1, 1); return(prediction); } else if (dy < 0 && Target.Top + dy <= 0) { prediction.Direction = Direction.Up; prediction.Type = HitType.Boundary; prediction.BoundsOfItemBeingHit = Rectangular.Create(Target.Left + dx, -dy, 1, 1); return(prediction); } else if (dx > 0 && Target.Right() + dx >= r.Width) { prediction.Direction = Direction.Right; prediction.Type = HitType.Boundary; prediction.BoundsOfItemBeingHit = Rectangular.Create(r.Width + dx, Target.Top + dy, 1, 1); return(prediction); } var testArea = Rectangular.Create(Target.Left + dx, Target.Top + dy, Target.Width, Target.Height); var match = (from t in r.Elements where t.IsOneOfThese(hitDetectionTypes) && Target != t && testArea.NumberOfPixelsThatOverlap(t) > 0 select t).OrderBy(t => t.Center().CalculateDistanceTo(Target.Center())); if (match.Count() == 0) { prediction.Direction = Direction.None; prediction.Type = HitType.None; } else { prediction.ElementHit = match.First(); prediction.Type = HitType.Element; prediction.Direction = testArea.GetHitDirection(match.First().Bounds); prediction.BoundsOfItemBeingHit = prediction.ElementHit.Bounds; } return(prediction); }
public static IRectangular CopyBounds(this IRectangular rectangular) => Rectangular.Create(rectangular.Left, rectangular.Top, rectangular.Width, rectangular.Height);