Beispiel #1
0
        /// <summary>
        /// Get closest moving entities based on distance radius.
        /// </summary>
        public List <MovingEntity> GetClosestMovingEntities(MovingEntity entityRef, int distance)
        {
            var _entities = new List <MovingEntity>();

            foreach (BaseEntity entity in _map.Values)
            {
                // Try to cast to MovingEntiy
                var movingEntity = entity as MovingEntity;

                // If not a movingEntity just continue the loop
                if (movingEntity != null)
                {
                    // Get distance from ref
                    Vector2 posDiff = movingEntity.Pos - entityRef.Pos;

                    // Account for bounding radius (physic boundaries of the object)
                    double radius = distance + movingEntity.BRadius;

                    // Tag if different from reference and close enough to reference
                    if (movingEntity != entityRef && (posDiff.LengthSquared() < (radius * radius)))
                    {
                        _entities.Add(movingEntity);
                    }
                }
            }

            // Return all entities closed enough
            return(_entities);
        }
        /// <summary>
        /// Evade from another agent. Opposite to pursuit. This time predicted
        /// next position is used to Flee from agent.
        /// </summary>
        private Vector2 Evade(MovingEntity pursuer)
        {
            Vector2 pursuerPos          = pursuer.Pos;
            Vector2 notDesiredDirection = pursuerPos - Agent.Pos;
            // Assuming MaxSpeed for Agent and current speed for pursuer
            float timeNextPosition = notDesiredDirection.Length() /
                                     (Agent.MaxSpeed + pursuer.Speed);

            // Flee predicted position
            return(Flee(pursuerPos + Vector2.Multiply(pursuer.Velocity, timeNextPosition)));
        }
        /// <summary>
        /// Make orientation of agent factor by some time.
        /// A coefficient to scale the returned value
        /// The higher the max turn rate of the vehicle, the higher `coefDelay` value should be.
        /// If the vehicle is heading in the opposite direction to its target position,
        /// a `coefDelay` of 0.5 return a delay of 1 second.
        /// </summary>
        /// <param name="entity">The entity direction that must be delay.</param>
        /// <param name="targetPos">The position that the target must reached.</param>
        /// <param name="coefDelay">A coefficient to delay the modification of direction.</param>
        public double TurnArroundTime(MovingEntity entity, Vector2 targetPos, double coefDelay = 0.5)
        {
            Vector2 desiredDirection = Vector2.Normalize(targetPos - entity.Pos);
            // Give a value in [-1, 1] where 1 means ahead target and -1 behind
            float cos_angle = Vector2.Dot(entity.Heading, desiredDirection);

            // Substrate 1 to add no change when already facing desired orientation
            // Multiply by coef to define the scaling
            // Multiply by -1 to get a positive value
            return((cos_angle - 1) * coefDelay * -1);
        }
        /// <summary>
        /// Pursuit account for target next position to intercept it.
        /// </summary>
        private Vector2 Pursuit(MovingEntity target)
        {
            Vector2 targetPos = target.Pos;
            Vector2 toTarget  = targetPos - Agent.Pos;
            float   cos_angle = Vector2.Dot(Agent.Heading, target.Heading);

            // Face if angle between agents head is lower than 20°
            // (180 - 20 used to get angle when both facing each other)
            if (cos_angle < Math.Cos(MathHelper.ToRadians(180 - 20)) &&
                Vector2.Dot(toTarget, Agent.Heading) > 0)
            {
                // Target is ahead and facing the agent
                return(Seek(targetPos));
            }
            // Target is not ahead, find next position
            // Assuming MaxSpeed for Agent and current speed for target
            double timeNextPosition = toTarget.Length() /
                                      (Agent.MaxSpeed + target.Speed);

            // Delay orientation
            timeNextPosition += TurnArroundTime(Agent, target.Pos, 0.05);

            return(Seek(target.Pos + Vector2.Multiply(target.Velocity, (float)timeNextPosition)));
        }