/// <summary>
 /// Stop movement
 /// </summary>
 /// <param name="physics">The physics component of the thinking character</param>
 public void Stop(ref PhysicsComponent2D physics)
 {
     physics.SetTargetValues(true, null, null, null);
 }
        /// <summary>
        /// Evade movement
        /// Code is based on the code in the AI book
        /// </summary>
        /// <param name="physics">The physics component of the thinking character</param>
        public void Evade(ref PhysicsComponent2D physics)
        {
            if (targetVelocity.Length() == 0)
            {
                Flee(ref physics);
                return;
            }

            float maxPrediction = 0.1f;
            float prediction;

            Vector2 direction = targetPosition - physics.Position;
            float distance = direction.Length();

            float speed = physics.Velocity.Length();

            if (speed <= distance / maxPrediction)
            {
                prediction = maxPrediction;
            }
            else
            {
                prediction = distance / speed;
            }

            Vector2 targetPos = targetPosition;
            targetPos += targetVelocity * prediction;

            // Pursue normally
            targetPos = (targetPos - physics.Position);
            physics.SetTargetValues(false, targetPos, null, null);
        }
        /// <summary>
        /// Wander movement
        /// </summary>
        /// <param name="physics">The physics component of the thinking character</param>
        public void Wander(ref PhysicsComponent2D physics)
        {
            Vector2 direction;
            float angle;

            if (physics.Direction.Length() == 0)
            {
                float x, y;

                do
                {
                    x = Game1.random.Next(-10, 11);
                } while (x == 0);

                do
                {
                    y = Game1.random.Next(-10, 11);
                } while (y == 0);

                direction = new Vector2(x, y);
                if (direction.LengthSquared() > 0)
                    direction.Normalize();
            }
            else
            {
                do
                {
                    angle = MathHelper.ToRadians(5 * (float)normallyDistributedRandomNumber());
                    Vector2 previousDirection = physics.Direction;
                    direction.X = (float)Math.Cos(angle) * previousDirection.X - (float)Math.Sin(angle) * previousDirection.Y;
                    direction.Y = (float)Math.Sin(angle) * previousDirection.X + (float)Math.Cos(angle) * previousDirection.Y;
                    if (direction.LengthSquared() > 0)
                        direction.Normalize();
                }
                while (direction.Length() == 0);
            }

            // Seek normally
            physics.SetTargetValues(false, direction, null, null);
        }
 /// <summary>
 /// Flee movement
 /// </summary>
 /// <param name="physics">The physics component of the thinking character</param>
 public void Flee(ref PhysicsComponent2D physics)
 {
     // Flee normally
     Vector2 toFlee = (physics.Position - targetPosition);
     physics.SetTargetValues(false, toFlee, null, null);
 }
 /// <summary>
 /// Seek movement
 /// </summary>
 /// <param name="physics">The physics component of the thinking character</param>
 public void Seek(ref PhysicsComponent2D physics)
 {
     // Seek normally
     physics.SetTargetValues(false, targetPosition - physics.Position, null, null);
 }
        /// <summary>
        /// Align to the desired orientation
        /// Code is based on the code in the AI book
        /// </summary>
        /// <param name="physics">Physics component of the target</param>
        private void align(ref PhysicsComponent2D physics)
        {
            float rotation = MathHelper.WrapAngle(targetOrientation - physics.Orientation);
            float rotationSize = Math.Abs(rotation);

            if (rotationSize < arrivalRadiusRotation)
            {
                physics.SetTargetValues(targetOrientation, -Math.Sign(physics.Rotation) * physics.MaxAngularAcceleration);
                return;
            }

            if (rotationSize > slowDownRadiusRotation)
            {
                targetRotation = physics.MaxRotation;
            }
            else
            {
                targetRotation = physics.MaxRotation * rotationSize / slowDownRadiusRotation;
            }

            targetRotation *= rotation / rotationSize;

            float angular = (targetRotation - physics.Rotation) / timeToTarget;

            float angularAcceleration = Math.Abs(angular);

            if (angularAcceleration > physics.MaxAngularAcceleration)
            {
                angular /= angularAcceleration;
                angular *= physics.MaxAngularAcceleration;
            }

            physics.SetTargetValues(targetOrientation, angular);
        }
        /// <summary>
        /// Steering arrive to the target
        /// Code is based on the code in the AI book
        /// </summary>
        /// <param name="physics">Physics component of the target</param>
        private void steeringArrive(ref PhysicsComponent2D physics)
        {
            Vector2 direction = targetPosition - physics.Position;
            float distance = direction.Length();
            float speed;

            if (distance < arrivalRadius)
            {
                return;
            }

            if (distance > slowDownRadius)
            {
                speed = physics.MaxVelocity;
            }
            else
            {
                speed = physics.MaxVelocity * distance / slowDownRadius;
            }

            Vector2 velocity = direction;
            if(velocity.LengthSquared() > 0)
                velocity.Normalize();
            velocity *= speed;

            Vector2 targetAcceleration = velocity - physics.Velocity;
            targetAcceleration /= timeToTarget;

            if (targetAcceleration.Length() > physics.MaxAcceleration)
            {
                if (targetAcceleration.LengthSquared() > 0)
                    targetAcceleration.Normalize();
                targetAcceleration *= physics.MaxAcceleration;
            }

            physics.SetTargetValues(false, velocity, null, targetAcceleration);
        }
        /// <summary>
        /// Kinematic arrive to the target
        /// Code is based on the code in the AI book
        /// </summary>
        /// <param name="physics">Physics component of the target</param>
        private void kinematicArrive(ref PhysicsComponent2D physics)
        {
            Vector2 velocity = targetPosition - physics.Position;

            if (velocity.Length() < arrivalRadius)
            {
                return;
            }

            velocity /= timeToTarget;

            if (velocity.Length() > physics.MaxVelocity)
            {
                if(velocity.LengthSquared() > 0)
                    velocity.Normalize();
                velocity *= physics.MaxVelocity;
            }

            physics.SetTargetValues(false, velocity, velocity, null);
        }