示例#1
0
        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();
            }
        }
示例#2
0
        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();
            }
        }