示例#1
0
        public static HitPrediction PredictHit(Scene r, Thing Target, List <Type> hitDetectionTypes, float dx, float dy)
        {
            HitPrediction prediction = new HitPrediction();

            if (Target.Bottom + dy >= r.Bounds.Size.H)
            {
                prediction.Direction            = Direction.Down;
                prediction.Type                 = HitType.Boundary;
                prediction.BoundsOfItemBeingHit = new Rectangle(Target.Left + dx, r.Bounds.Size.H + dy, 1, 1);
                return(prediction);
            }
            else if (Target.Left + dx <= 0)
            {
                prediction.Direction            = Direction.Left;
                prediction.Type                 = HitType.Boundary;
                prediction.BoundsOfItemBeingHit = new Rectangle(-dx, Target.Top + dy, 1, 1);
                return(prediction);
            }
            else if (Target.Top + dy <= 0)
            {
                prediction.Direction            = Direction.Up;
                prediction.Type                 = HitType.Boundary;
                prediction.BoundsOfItemBeingHit = new Rectangle(Target.Left + dx, -dy, 1, 1);
                return(prediction);
            }
            else if (Target.Right + dx >= r.Bounds.Size.W)
            {
                prediction.Direction            = Direction.Right;
                prediction.Type                 = HitType.Boundary;
                prediction.BoundsOfItemBeingHit = new Rectangle(r.Bounds.Size.W + dx, Target.Top + dy, 1, 1);
                return(prediction);
            }

            var testArea = new Rectangle(Target.Left + dx, Target.Top + dy, Target.Bounds.Size.W, Target.Bounds.Size.H);

            var match = (from t in r.Things
                         where
                         IsOneOfThese(t, hitDetectionTypes) &&
                         Target != t &&
                         testArea.Hits(t.Bounds)
                         select t).OrderBy(t => t.Bounds.Location.CalculateDistanceTo(Target.Bounds.Location));


            if (match.Count() == 0)
            {
                prediction.Direction = Direction.None;
                prediction.Type      = HitType.None;
            }
            else
            {
                prediction.ThingHit             = match.First();
                prediction.Type                 = HitType.Thing;
                prediction.Direction            = testArea.GetHitDirection(match.First().Bounds);
                prediction.BoundsOfItemBeingHit = prediction.ThingHit.Bounds;
            }

            return(prediction);
        }
示例#2
0
        public static HitPrediction PredictHit(HitDetectionOptions options)
        {
            HitPrediction prediction = new HitPrediction();

            var left         = Math.Min(options.MovingObject.Left, options.MovingObject.Left + options.Dx);
            var top          = Math.Min(options.MovingObject.Top, options.MovingObject.Top + options.Dy);
            var right        = Math.Max(options.MovingObject.Left + options.MovingObject.Width, options.MovingObject.Left + options.MovingObject.Width + options.Dx);
            var bottom       = Math.Max(options.MovingObject.Top + options.MovingObject.Height, options.MovingObject.Top + options.MovingObject.Height + options.Dy);
            var relevantArea = RectangularF.Create(left, top, right - left, bottom - top);

            var effectiveObstacles = options.Obstacles.Where(o => o.Touches(relevantArea)).ToList();

            if (options.Dx == 0 && options.Dy == 0)
            {
                prediction.Direction = Direction.None;
                prediction.Type      = HitType.None;
                return(prediction);
            }

            var endPoint = RectangularF.Create(options.MovingObject.Left + options.Dx, options.MovingObject.Top + options.Dy, options.MovingObject.Width, options.MovingObject.Height);
            var angle    = options.MovingObject.CalculateAngleTo(endPoint);
            var d        = endPoint.CalculateDistanceTo(options.MovingObject);

            for (var dPrime = options.Precision; dPrime < d; dPrime += options.Precision)
            {
                var testLocation = options.MovingObject.Center().MoveTowards(angle, dPrime);
                var testArea     = RectangularF.Create(testLocation.Left - options.MovingObject.Width / 2, testLocation.Top - options.MovingObject.Height / 2, options.MovingObject.Width, options.MovingObject.Height);
                var obstacleHit  = effectiveObstacles.Where(o => IsIncluded(options, o) && o.Touches(testArea) == true).FirstOrDefault();

                if (obstacleHit != null)
                {
                    return(new HitPrediction()
                    {
                        Type = HitType.Obstacle,
                        ObstacleHit = obstacleHit
                    });
                }
            }

            var obstacleHitFinal = effectiveObstacles.Where(o => IsIncluded(options, o) && o.Touches(endPoint) == true).FirstOrDefault();

            if (obstacleHitFinal != null)
            {
                return(new HitPrediction()
                {
                    Type = HitType.Obstacle,
                    ObstacleHit = obstacleHitFinal
                });
            }

            prediction.Type = HitType.None;
            return(prediction);
        }
示例#3
0
        public static HitPrediction PredictHit(SpaceTime r, SpacialElement Target, List <Type> hitDetectionTypes, List <SpacialElement> hitDetectionExclusions, float dx, float dy)
        {
            if (Math.Abs(dx) <= 1 && Math.Abs(dy) <= 1)
            {
                return(PredictHitInternal(r, Target, hitDetectionTypes, hitDetectionExclusions, dx, dy));
            }

            HitPrediction latestResult = null;

            for (var i = 1; i <= 10; i++)
            {
                var dxP = Approach(0, dx, dx / 10 * i);
                var dyP = Approach(0, dy, dy / 10 * i);
                latestResult = PredictHitInternal(r, Target, hitDetectionTypes, hitDetectionExclusions, dxP, dyP);
                if (latestResult.Type != HitType.None)
                {
                    return(latestResult);
                }
            }

            return(latestResult);
        }
示例#4
0
        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);
        }
示例#5
0
        public static HitPrediction PredictHit(HitDetectionOptions options)
        {
            HitPrediction prediction = new HitPrediction();

            prediction.LKG = options.MovingObject.CopyBounds().TopLeft();
            prediction.MovingObjectPosition = options.MovingObject.CopyBounds();
            prediction.Visibility           = options.Visibility;
            if (options.Visibility == 0)
            {
                prediction.Direction = Direction.None;
                prediction.Type      = HitType.None;
                return(prediction);
            }


            var mov = options.MovingObject;

            List <Edge> rays;

            if (options.Mode == CastingMode.Precise)
            {
                rays = new List <Edge>()
                {
                    new Edge()
                    {
                        From = mov.TopLeft(), To = mov.TopLeft().MoveTowards(options.Angle, options.Visibility, normalized: false)
                    },
                    new Edge()
                    {
                        From = mov.TopRight(), To = mov.TopRight().MoveTowards(options.Angle, options.Visibility, normalized: false)
                    },
                    new Edge()
                    {
                        From = mov.BottomLeft(), To = mov.BottomLeft().MoveTowards(options.Angle, options.Visibility, normalized: false)
                    },
                    new Edge()
                    {
                        From = mov.BottomRight(), To = mov.BottomRight().MoveTowards(options.Angle, options.Visibility, normalized: false)
                    },
                };

                var granularity = .5f;

                for (var x = mov.Left + granularity; x < mov.Left + mov.Width; x += granularity)
                {
                    var top = LocationF.Create(x, mov.Top);
                    var bot = LocationF.Create(x, mov.Bottom());

                    rays.Add(new Edge()
                    {
                        From = top, To = top.MoveTowards(options.Angle, options.Visibility, normalized: false)
                    });
                    rays.Add(new Edge()
                    {
                        From = bot, To = bot.MoveTowards(options.Angle, options.Visibility, normalized: false)
                    });
                }

                for (var y = mov.Top + granularity; y < mov.Top + mov.Height; y += granularity)
                {
                    var left  = LocationF.Create(mov.Left, y);
                    var right = LocationF.Create(mov.Right(), y);

                    rays.Add(new Edge()
                    {
                        From = left, To = left.MoveTowards(options.Angle, options.Visibility, normalized: false)
                    });
                    rays.Add(new Edge()
                    {
                        From = right, To = right.MoveTowards(options.Angle, options.Visibility, normalized: false)
                    });
                }
            }
            else if (options.Mode == CastingMode.Rough)
            {
                var center = options.MovingObject.Center();
                rays = new List <Edge>()
                {
                    new Edge()
                    {
                        From = mov.TopLeft(), To = mov.TopLeft().MoveTowards(options.Angle, options.Visibility, normalized: false)
                    },
                    new Edge()
                    {
                        From = mov.TopRight(), To = mov.TopRight().MoveTowards(options.Angle, options.Visibility, normalized: false)
                    },
                    new Edge()
                    {
                        From = mov.BottomLeft(), To = mov.BottomLeft().MoveTowards(options.Angle, options.Visibility, normalized: false)
                    },
                    new Edge()
                    {
                        From = mov.BottomRight(), To = mov.BottomRight().MoveTowards(options.Angle, options.Visibility, normalized: false)
                    },
                    new Edge()
                    {
                        From = center, To = center.MoveTowards(options.Angle, options.Visibility, normalized: false)
                    }
                };
            }
            else if (options.Mode == CastingMode.SingleRay)
            {
                var center = options.MovingObject.Center();
                rays = new List <Edge>()
                {
                    new Edge()
                    {
                        From = center, To = center.MoveTowards(options.Angle, options.Visibility, normalized: false)
                    }
                };
            }
            else
            {
                throw new NotSupportedException("Unknown mide: " + options.Mode);
            }

            var           closestIntersectionDistance = float.MaxValue;
            IRectangularF closestIntersectingElement  = null;
            var           closestEdgeIndex            = -1;
            var           effectiveObstacles          = options.Obstacles.ToArray();

            for (var i = 0; i < effectiveObstacles.Length; i++)
            {
                var obstacle = effectiveObstacles[i];
                for (var j = 0; j < obstacle.Edges.Length; j++)
                {
                    var edge = obstacle.Edges[j];
                    for (var k = 0; k < rays.Count; k++)
                    {
                        var ray          = rays[k];
                        var intersection = FindIntersectionPoint(ray, edge);
                        if (intersection != null)
                        {
                            var d = ray.From.CalculateDistanceTo(intersection);
                            if (d < closestIntersectionDistance && d <= options.Visibility)
                            {
                                closestIntersectionDistance = d;
                                closestIntersectingElement  = obstacle;
                                closestEdgeIndex            = j;
                            }
                        }
                    }
                }
            }

            if (closestIntersectingElement != null)
            {
                prediction.ObstacleHit = closestIntersectingElement;
                prediction.LKGD        = closestIntersectionDistance - .1f;
                prediction.LKG         = options.MovingObject.MoveTowards(options.Angle, prediction.LKGD, normalized: false).TopLeft();
                prediction.Type        = HitType.Obstacle;
                prediction.EdgeIndex   = closestEdgeIndex;
            }

            return(prediction);
        }
示例#6
0
        public static HitPrediction PredictHit(HitDetectionOptions options)
        {
            HitPrediction prediction = new HitPrediction();

            prediction.MovingObjectPosition = options.MovingObject.CopyBounds();
            prediction.Visibility           = options.Visibility;
            if (options.Visibility == 0)
            {
                prediction.Direction = Direction.None;
                prediction.Type      = HitType.None;
                return(prediction);
            }


            var effectiveObstacles = options.Obstacles.Where(o => o.CalculateDistanceTo(options.MovingObject) <= options.Visibility + options.Precision).ToList();

            var        endPoint = options.MovingObject.MoveTowards(options.Angle, options.Visibility);
            ILocationF lkg      = null;

            for (var dPrime = options.Precision; dPrime < options.Visibility; dPrime += options.Precision)
            {
                var testArea = options.MovingObject.MoveTowards(options.Angle, dPrime);
                prediction.Path.Add(testArea);
                var obstacleHit = effectiveObstacles.Where(o =>
                {
                    var simpleTest = o.Touches(testArea) == true;
                    if (simpleTest == false)
                    {
                        return(false);
                    }

                    if (o.Touches(options.MovingObject))
                    {
                        var overlapBefore = options.MovingObject.NumberOfPixelsThatOverlap(o);
                        var overlapAfter  = testArea.NumberOfPixelsThatOverlap(o);

                        if (overlapAfter < overlapBefore)
                        {
                            return(false);
                        }
                        else
                        {
                            return(true);
                        }
                    }
                    else
                    {
                        return(true);
                    }
                }).FirstOrDefault();

                if (obstacleHit != null)
                {
                    prediction.Type        = HitType.Obstacle;
                    prediction.ObstacleHit = obstacleHit;
                    prediction.LKG         = lkg;
                    return(prediction);
                }
                else
                {
                    lkg = testArea.TopLeft();
                }
            }

            var obstacleHitFinal = effectiveObstacles.Where(o => o.Touches(endPoint) == true).FirstOrDefault();

            if (obstacleHitFinal != null)
            {
                prediction.Type        = HitType.Obstacle;
                prediction.ObstacleHit = obstacleHitFinal;
                prediction.LKG         = lkg;
                return(prediction);
            }

            prediction.Type = HitType.None;
            return(prediction);
        }
示例#7
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();
            }
        }