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(); } }
private async Task ExecuteAsync() { while (this.Lifetime.IsExpired == false) { if (MovementTakeover != null) { await MovementTakeover(); continue; } float dt = (float)Governor.Rate.TotalSeconds; if (dt == 0) { dt = (float)Time.CurrentTime.Increment.TotalSeconds; } float d = Speed * dt; if (d == 0) { OnVelocityEnforced?.Fire(); await Time.CurrentTime.YieldAsync(); continue; } var obstacles = GetObstacles(); if (obstacles.Where(o => o.Touches(Element)).Any()) { Element.NudgeFree(); } var hitPrediction = HitDetection.PredictHit(new HitDetectionOptions() { MovingObject = Element is IHaveMassBounds ? (Element as IHaveMassBounds).MassBounds : Element, Obstacles = obstacles, Angle = Angle, Visibility = d, }); LastPrediction = hitPrediction; if (hitPrediction.Type != HitType.None) { if (hitPrediction.LKG != null && Element.TopLeft().Equals(hitPrediction.LKG) == false) { Element.MoveTo(hitPrediction.LKG.Left, hitPrediction.LKG.Top); haveMovedSinceLastHitDetection = true; } float angle = Element.Center().CalculateAngleTo(hitPrediction.ObstacleHit.Center()); if (haveMovedSinceLastHitDetection) { LastImpact = new Impact() { Angle = angle, MovingObject = Element, ObstacleHit = hitPrediction.ObstacleHit, HitType = hitPrediction.Type, }; ImpactOccurred?.Fire(LastImpact); GlobalImpactOccurred.Fire(LastImpact); haveMovedSinceLastHitDetection = false; Element.SizeOrPositionChanged.Fire(); } Stop(); } else { var newLocation = Element.MoveTowards(Angle, d); Element.MoveTo(newLocation.Left, newLocation.Top); haveMovedSinceLastHitDetection = true; } OnVelocityEnforced?.Fire(); await Time.CurrentTime.YieldAsync(); } }