예제 #1
0
        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;
            }
        }
예제 #2
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();
            }
        }
예제 #3
0
        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;
            }
        }
예제 #4
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();
            }
        }