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; } }
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(); } }
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; var obstacles = GetObstacles().ToList(); if (dx == 0 && dy == 0) { return; } var effectiveExclusions = HitDetectionExclusionTypes.Count > 0 || HitDetectionExclusions.Count == 0 ? new List <IRectangularF>(this.HitDetectionExclusions.Union(SpaceTime.CurrentSpaceTime.Elements.Where(e => HitDetectionExclusionTypes.Contains(e.GetType())))) : null; var hitPrediction = HitDetection.PredictHit(new HitDetectionOptions() { Bounds = SpaceTime.CurrentSpaceTime.Bounds, MovingObject = Element, Exclusions = effectiveExclusions, Obstacles = obstacles.As <IRectangularF>().ToList(), Dx = dx, Dy = dy, }); if (hitPrediction.Type != HitType.None) { float angle = Element.Center().CalculateAngleTo(hitPrediction.ObstacleHit.Center()); if (haveMovedSinceLastHitDetection) { ImpactOccurred?.Fire(new Impact() { Angle = angle, MovingObject = Element, ObstacleHit = hitPrediction.ObstacleHit, HitType = hitPrediction.Type, }); haveMovedSinceLastHitDetection = false; var testArea = RectangularF.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; } Element.SizeOrPositionChanged.Fire(); } } else { var oldLocation = Element.CopyBounds(); Element.MoveBy(dx, dy); isSettingAnglePrivately = true; this.Angle = oldLocation.Center().CalculateAngleTo(Element.Center()); isSettingAnglePrivately = false; haveMovedSinceLastHitDetection = true; } }
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(); } }