Esempio n. 1
0
        /// <summary>
        /// Makes the car approach the target and slow down.
        /// </summary>
        /// <param name="velocity">Current velocity of the car</param>
        /// <param name="yaw">Current relative yaw of the car</param>
        /// <param name="addedRotation">Amount of rotation (in degrees) to add</param>
        /// <param name="distanceToDestination">Distance to the destination</param>
        public void HandleApproachTarget(ref Vector velocity, ref double yaw, ref double addedRotation, ref double distanceToDestination)
        {
            // Get the current speed and rotation of the car.
            var speed    = velocity.Length;
            var rotation = MathUtil.VelocityToRotation(velocity);

            // Check if we're going too fast, have passengers or are near the destination.
            if (speed > maxTurningSpeed / 2d || Car.PassengerCount > 0 || distanceToDestination < 20)
            {
                // Check if we need to drop passengers off.
                if (Car.PassengerCount > 0 && /*speed < 0.05 && */ speed > 0)
                {
                    var distance = Car.DistanceTraveled - Car.PassengersBoardDistance;
                    var price    = GPSSystem.CalculatePrice(distance);
                    App.Console.Print($"[C{Car.Id}] Charged €{price:F2} for {distance:F1} units", Colors.Blue);

                    App.Console.Print($"[C{Car.Id}] Dropping customers", Colors.Blue);
                    var passenger = Car.Passengers[0];
                    TripEnd?.Invoke(this, new TripEventArgs(passenger.Group, passenger.Building.Location, Car.Location, Car));
                    Car.Passengers.Clear();
                    MainScreen.AILoop.Unsubscribe(Update);
                }

                // Slow down the car.
                velocity = speed > 0.05
                    ? Vector.Add(velocity, CalculateDeccelerationVector(velocity))
                    : new Vector();
            }

            // Get the target and current location.
            var destination = Car.Destination.Location;
            var location    = Car.Location;

            // Calculate the angle between the car and the target.
            var sub = new Vector(
                destination.X - location.X,
                destination.Y - location.Y
                );

            sub.Normalize();
            var angle = Vector.AngleBetween(rotation, sub);

            // If we need to go to the right and are able to, do so.
            if (angle > 0)
            {
                if (yaw > -maxInLaneRotation)
                {
                    addedRotation -= rotationSpeed;
                }
            }
            // If we need to go to the left and are able to, do so.
            else
            {
                if (yaw < maxInLaneRotation)
                {
                    addedRotation += rotationSpeed;
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Accelerates (or deccelerates) the car depending on the surroundings.
        /// </summary>
        /// <param name="velocity">Current velocity of the car</param>
        /// <param name="distanceToTarget">Distance to the current local target</param>
        public void HandleAccelerate(ref Vector velocity, ref double distanceToTarget)
        {
            // Get the current speed of the car.
            var speed = velocity.Length;

            // Check if we're far away enough from the target
            if (distanceToTarget > brakingDistance * Car.MaxSpeed / 2d)
            {
                if (!braking)
                {
                    // If we're not braking, accelerate the car.
                    if (Math.Abs(speed) < 0.001)
                    {
                        velocity = Vector.Divide(Car.Direction.GetVector(), accelerationDivider);
                    }
                    else if (speed < Car.MaxSpeed)
                    {
                        velocity = Vector.Add(velocity, CalculateAccelerationVector(velocity));
                    }
                }
            }
            else if (braking)
            {
                // If we are braking, deccelerate the car.
                velocity = speed > 0.1
                    ? Vector.Add(velocity, CalculateDeccelerationVector(velocity))
                    : new Vector();
            }
            else
            {
                // Otherwise we're in a turn, so slow down a little.
                if (speed > maxTurningSpeed)
                {
                    velocity = Vector.Add(velocity, CalculateDeccelerationVector(velocity));
                }
            }
        }
Esempio n. 3
0
        /*
         * All the Handle functions take references to variable from the Update function.
         * They will modify these variables to change behaviour of the car. The value of
         * these variables shouldn't be overwritten, but only changed (adding, multiplying, etc)
         */

        /// <summary>
        /// Makes the car turn on an intersection towards the target.
        /// </summary>
        /// <param name="velocity">Current velocity of the car</param>
        /// <param name="yaw">Current relative yaw of the car</param>
        /// <param name="addedRotation">Amount of rotation (in degrees) to add</param>
        public void HandleTurn(ref Vector velocity, ref double yaw, ref double addedRotation)
        {
            // Get the current speed and rotation of the car.
            var speed        = velocity.Length;
            var rotation     = MathUtil.VelocityToRotation(velocity);
            var intersection = Car.CurrentIntersection;

            // If we're going too fast to turn, slow down.
            if (speed > maxTurningSpeed)
            {
                velocity = Vector.Add(velocity, CalculateDeccelerationVector(velocity));
            }

            // If we're not on the intersection yet, just keep driving straight.
            if (intersection == null)
            {
                HandleStayInLane(ref velocity, ref yaw, ref addedRotation);
                return;
            }

            // Get the target and current location.
            var target   = Car.CurrentTarget;
            var location = Car.Location;

            // Calculate the angle between the car and the target.
            var targetAngle = new Vector(
                target.X - location.X,
                target.Y - location.Y
                );
            var angle = Vector.AngleBetween(rotation, targetAngle);

            if (angle < 0)
            {
                angle += 360;
            }

            // If the angle is more than 225 degrees (-90 - 45), rotate to the left.
            if (angle > 225 && angle < 315)
            {
                // If we're not turning around, slowly turn left.
                if (!flipping)
                {
                    addedRotation += rotationSpeed * 0.8;
                }
                // If we are turning around, keep steering steeply left.
                else
                {
                    addedRotation += rotationSpeed * 6;
                }
            }
            // If the angle is more than 135 degrees (180 - 45), turn around.
            else if (angle > 135 && angle < 315)
            {
                if (!flipping)
                {
                    flipping = true;
                    App.Console.Print($"[C{Car.Id}] Initiating turn-around", Colors.Blue);
                }

                addedRotation += rotationSpeed * 6;
            }
            // If the angle is more than 45 degrees (90 - 45), rotate to the right.
            else if (angle > 45 && angle < 315)
            {
                addedRotation -= rotationSpeed * 6;
            }
            // Otherwise, keep going straight.
            else
            {
                addedRotation = yaw < 0 ? rotationSpeed : -rotationSpeed;
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Runs the main car logic. Needs to be subscribed to the MainLoop.
        /// </summary>
        public void Update()
        {
            // If we're not initialized, initialize!
            if (!initialized)
            {
                Init();
            }

            // Update the passenger count.
            Car.PassengerCount = Car.Passengers.Count;

            // Update the current road with the road at our location.
            Car.CurrentRoad         = GPSSystem.GetRoad(Car.Location);
            Car.CurrentIntersection = GPSSystem.FindIntersection(Car.Location);

            if (Car.CurrentRoad == null && Car.CurrentIntersection == null)
            {
                if (!resetTarget)
                {
                    resetTarget = true;
                    var closestRoad = GPSSystem.NearestRoad(Car.Location);
                    if (closestRoad != null && Car != null)
                    {
                        Car.CurrentTarget =
                            MathUtil.Distance(closestRoad.End, Car.Location) >
                            MathUtil.Distance(closestRoad.Start, Car.Location)
                                ? closestRoad.Start
                                : closestRoad.End;
                        App.Console.Print($"[C{Car.Id}] Lost road, trying to get back on, targeting {Car.CurrentTarget}", Colors.Blue);
                    }
                    ;
                }
            }
            else if (resetTarget)
            {
                App.Console.Print($"[C{Car.Id}] Road found again", Colors.Blue);
                resetTarget = false;
            }

            // Calculate the distance to the local target (usually the next intersection).
            var distanceToTarget = MathUtil.Distance(Car.Location, Car.CurrentTarget);
            // Calculate the distance to the destination.
            var distanceToDestination = MathUtil.Distance(Car.Location, Car.Destination.Location);
            // Calculate the relative yaw (in degrees).
            var yaw = MathUtil.VectorToAngle(Car.Rotation, Car.Direction);
            // Get the current velocity of the car.
            var velocity = Car.Velocity;
            // Create a variable to store the added rotation in this update call.
            var addedRotation      = 0.0;
            var closeToDestination = CloseToDestination();

            // Check if we're close to our target but not the destination.
            if (distanceToTarget < 20 && !closeToDestination && !resetTarget)
            {
                // Check if we've not obtained a new target yet.
                if (!obtainedNewTarget)
                {
                    // Find the nearest intersection.
                    var intersection = GPSSystem.FindIntersection(GetClosestRoadPoint(Car.Location));
                    if (intersection == null)
                    {
                        return;
                    }

                    App.Console.Print($"[C{Car.Id}] Requesting new target from intersection {intersection.Location}...", Colors.Blue);

                    // Request the next target from the GPSSystem.
                    var target = GPSSystem.GetDirection(Car, intersection);

                    // Update our target.
                    newTarget         = target.Location;
                    obtainedNewTarget = true;

                    var distance = Math.Round(MathUtil.Distance(newTarget, Car.Location));
                    App.Console.Print($"[C{Car.Id}] Obtained a new target {newTarget} ({distance}m away)", Colors.Blue);
                }
            }
            else
            {
                obtainedNewTarget = false;
            }

            // Check if we are turning.
            if (turning > 0)
            {
                turning--;

                // Check if we locked on the new target yet.
                if (newTarget.X > -1)
                {
                    // Lock on the new target and reset newTarget.
                    Car.CurrentTarget = newTarget;
                    newTarget         = new Vector(-1, -1);
                    App.Console.Print($"[C{Car.Id}] Locked on to target", Colors.Blue);
                }

                // Call the handle function to turn.
                HandleTurn(ref velocity, ref yaw, ref addedRotation);
            }
            // Check if we're still turning around.
            else if (flipping)
            {
                // Stop turning around.
                flipping = false;
                App.Console.Print($"[C{Car.Id}] Turn-around done", Colors.Blue);
            }

            // Check if we're on an intersection.
            if (Car.CurrentIntersection != null)
            {
                // Reset our turn timer.
                turning = 20;
            }
            else
            {
                // Check if we're not close to the destination.
                if (!closeToDestination)
                {
                    // If we're still approaching, stop approaching.
                    if (approach)
                    {
                        approach = false;
                        App.Console.Print($"[C{Car.Id}] Approach done", Colors.Blue);
                    }

                    // Call the handle functions to stay in the lane and accelerate/deccelerate.
                    HandleStayInLane(ref velocity, ref yaw, ref addedRotation);
                    HandleAccelerate(ref velocity, ref distanceToTarget);
                }
                else
                {
                    // If we're not approaching, start approaching.
                    if (!approach)
                    {
                        approach = true;
                        App.Console.Print($"[C{Car.Id}] Initiating approach", Colors.Blue);
                    }

                    // Call the handle function to approach the target.
                    HandleApproachTarget(ref velocity, ref yaw, ref addedRotation, ref distanceToDestination);
                }
            }

            // Update the car's velocity with the result of the handle functions:
            // Temporarily store the current speed.
            var speed = velocity.Length;

            // Rotate the velocity based on the addedRotation this tick.
            velocity = MathUtil.RotateVector(velocity, -addedRotation);
            // Normalize the velocity and multiply with the speed to make sure it stays the same.
            velocity.Normalize();
            velocity = Vector.Multiply(velocity, speed);
            // Actually update the car's velocity.
            Car.Velocity = velocity;

            // Calculate the rotation by normalizing the velocity.
            var rotation = new Vector(velocity.X, velocity.Y);

            rotation.Normalize();

            // If the rotation vector is invalid or the car is not moving, set the rotation to the absolute direction.
            if (rotation.Length < 0.9 || double.IsNaN(rotation.Length) || velocity.Length < 0.1)
            {
                rotation = Car.Direction.GetVector();
            }

            // Actually update the rotation and update the absolute direction.
            Car.Rotation  = rotation;
            Car.Direction = DirectionCarMethods.Parse(rotation);

            // Update the car's location by adding the velocity to it.
            Car.Location          = Vector.Add(Car.Location, Car.Velocity);
            Car.DistanceTraveled += Car.Velocity.Length;
        }