Example #1
0
        protected override void UpdateTargetDirection(Driver.Sensors sensors, Driver.Actuators actuators)
        {
            // Read player input.
            float turningInput = Input.GetAxis("Turning");

            if (turningInput == 0)
            {
                // If the input was just released, square to 90 degrees.
                if (lastTurningInput != 0)
                {
                    CardinalDirection cardinalDirection = DirectionHelpers.GetCardinalDirectionForVector(sensors.transform.forward);
                    actuators.targetDirection = DirectionHelpers.cardinalDirectionVectors[cardinalDirection];

                    // Reset turning input time for next time.
                    turningInputNonZeroTime = 0;
                }
            }
            else
            {
                // If the input was just changed, change lane.
                if (turningInput < 0 && lastTurningInput >= 0)
                {
                    // We want to go left, but if our current target was to go right, just return to current lane.
                    if (actuators.targetLane > sensors.carTracker.currentLane)
                    {
                        actuators.targetLane = sensors.carTracker.currentLane;
                    }
                    else
                    {
                        actuators.targetLane = Math.Max(sensors.carTracker.currentLane - 1, 0);
                    }
                }
                else if (turningInput > 0 && lastTurningInput <= 0)
                {
                    // We want to go right, but if our current target was to go left, just return to current lane.
                    if (actuators.targetLane < sensors.carTracker.currentLane)
                    {
                        actuators.targetLane = sensors.carTracker.currentLane;
                    }
                    else
                    {
                        actuators.targetLane = Math.Min(sensors.carTracker.currentLane + 1, sensors.carTracker.representativeStreet.lanesCount + 1);
                    }
                }

                // If turning has been active enough time, change target direction.
                turningInputNonZeroTime += Time.deltaTime;

                if (turningInputNonZeroTime > laneChangeOnlyDuration)
                {
                    float      rotationAngleDegrees = turningInput * maxAngleChangeDifferenceDegrees * Mathf.Sign(sensors.car.speed);
                    Quaternion rotation             = Quaternion.Euler(0, rotationAngleDegrees, 0);
                    actuators.targetDirection = rotation * sensors.transform.forward;
                }
            }

            lastTurningInput = turningInput;
        }
Example #2
0
 public static CardinalDirection GetCardinalDirection(this Vector3 vector)
 {
     return(DirectionHelpers.GetCardinalDirectionForVector(vector));
 }
Example #3
0
        private void UpdateTargetLaneAndDirection(Driver.Sensors sensors, Driver.Actuators actuators)
        {
            Street       currentStreet          = sensors.carTracker.street;
            Intersection currentIntersection    = sensors.carTracker.intersection;
            float        distanceToIntersection = GetDistanceToTargetIntersection(sensors);
            float        turningTargetDistance  = Math.Max(turningTargetMinimumDistance, turningTargetTime * sensors.car.speed);

            // See if we should start performing a turn.
            bool performingTurn = false;

            switch (nextIntersectionTurningIntent)
            {
            case Driver.TurningIntent.Left:
            case Driver.TurningIntent.Right:
                // When turning left and right, start turning when close enough to the intersection.
                performingTurn = currentIntersection != null || distanceToIntersection < turningTargetDistance;
                break;

            case Driver.TurningIntent.UTurn:
                // When performing a U-turn, start in the intersection.
                performingTurn = currentIntersection != null;
                break;
            }

            if (performingTurn)
            {
                DrawDebugIntersectionArc();

                switch (nextIntersectionTurningIntent)
                {
                case Driver.TurningIntent.Left:
                case Driver.TurningIntent.Right:
                    // For right turns, follow an arc.
                    float xEnter = Vector3.Dot(nextIntersectionExitingDirection, nextIntersectionEnteringPoint);
                    float xExit  = Vector3.Dot(nextIntersectionExitingDirection, nextIntersectionExitingPoint);
                    float xDelta = xExit - xEnter;

                    float zEnter = Vector3.Dot(nextIntersectionEnteringDirection, nextIntersectionEnteringPoint);
                    float zExit  = Vector3.Dot(nextIntersectionEnteringDirection, nextIntersectionExitingPoint);
                    float zDelta = zExit - zEnter;

                    // Place a target in front of the car.
                    Vector3 carPosition = sensors.car.transform.position;
                    Vector3 target      = carPosition + sensors.car.transform.forward * turningTargetDistance;
                    Debug.DrawLine(carPosition + Vector3.up * 2, target + Vector3.up * 2, Color.magenta);

                    float xTarget = Vector3.Dot(nextIntersectionExitingDirection, target) - xEnter;
                    float zTarget = Vector3.Dot(nextIntersectionEnteringDirection, target) - zEnter;

                    // Move target onto the arc.
                    float zTargetFraction = zTarget / zDelta;
                    float xTargetFraction = xTarget / xDelta;

                    float angle = Mathf.Atan2(zTargetFraction, 1 - xTargetFraction);

                    xTargetFraction = 1 - Mathf.Cos(angle);
                    zTargetFraction = xTargetFraction > 1 ? 1 : Mathf.Sin(angle);

                    xTarget = xTargetFraction * xDelta;
                    zTarget = zTargetFraction * zDelta;
                    target  = nextIntersectionEnteringPoint + nextIntersectionExitingDirection * xTarget + nextIntersectionEnteringDirection * zTarget;

                    // Direct the car towards the adjusted target.
                    actuators.targetDirection = (target - carPosition).normalized;

                    Debug.DrawLine(carPosition + Vector3.up * 2, target + Vector3.up * 2, Color.blue);

                    break;

                case Driver.TurningIntent.UTurn:
                    // For U-turns, start by turning right as tight as possible.
                    if (Vector3.Angle(nextIntersectionEnteringDirection, sensors.car.transform.forward) < 45)
                    {
                        actuators.targetDirection = Quaternion.AngleAxis(90, Vector3.up) * nextIntersectionEnteringDirection;
                    }
                    else
                    {
                        actuators.targetDirection = nextIntersectionExitingDirection;
                    }
                    break;
                }

                actuators.targetLane = nextIntersectionExitingLane;
            }
            else if (currentStreet != null)
            {
                // If we're on a street, go to correct turning lane.
                float angleToTarget = Vector3.SignedAngle(sensors.carTracker.streetDirection, DirectionHelpers.cardinalDirectionVectors[nextIntersectionExitingCardinalDirection], Vector3.up);

                CardinalDirection currentDirection  = sensors.carTracker.streetCardinalDirection;
                CardinalDirection oppositeDirection = DirectionHelpers.GetOppositeDirection(currentDirection);

                int currentLane = sensors.carTracker.currentLane;
                int desiredLane = nextIntersectionEnteringLane;

                if (desiredLane != currentLane)
                {
                    // Start moving to the desired lane when close enough to the intersection.
                    int   laneDifference = desiredLane - currentLane;
                    float minimumDistanceToIntersection = sensors.driverProfile.distanceForChangingLane * Mathf.Abs(laneDifference);

                    // For U-turns from the sidewalk, only drive onto the sidewalk in the last meters.
                    if (nextIntersectionTurningIntent == Driver.TurningIntent.UTurn && currentLane == 1)
                    {
                        minimumDistanceToIntersection = uTurnDriveToSidewalkDistance;
                    }

                    if (distanceToIntersection < minimumDistanceToIntersection)
                    {
                        actuators.turningIntent = nextIntersectionTurningIntent;

                        // Make sure the neighbor lane is free in the safe distance region before and after the car.
                        int neighborLane = currentLane + Math.Sign(laneDifference);

                        float   safeDistance    = CalculateSafeDistance(sensors);
                        Vector3 streetDirection = sensors.carTracker.streetDirection;
                        float   carLength       = sensors.car.bounds.size.z;
                        Vector3 origin          = sensors.carTracker.GetCenterOfLanePosition(neighborLane) + (safeDistance + carLength / 2) * streetDirection + Vector3.up * sensors.car.bounds.extents.y;
                        float   checkDistance   = 2 * safeDistance + carLength;

                        if (!Physics.Raycast(origin, -streetDirection, checkDistance))
                        {
                            actuators.targetLane = desiredLane;
                            Debug.DrawRay(origin, -streetDirection * checkDistance, Color.green, 1);
                        }
                        else
                        {
                            Debug.DrawRay(origin, -streetDirection * checkDistance, Color.red);
                        }
                    }
                }

                actuators.targetDirection = sensors.carTracker.streetDirection;
            }
        }
Example #4
0
        private void UpdateNextIntersectionDirection(Driver.Sensors sensors)
        {
            // We need to be on a street and not having been on a street previously (as we would have already decided where to go).
            Street currentStreet = sensors.carTracker.street;

            if (currentStreet != null && previousStreet == null)
            {
                // Determine where to go at the end of this street.
                CardinalDirection currentDirection = sensors.carTracker.streetCardinalDirection;

                Intersection targetIntersection = GetTargetIntersection(sensors);

                // See where we might want to go.
                var potentialDirections             = new List <CardinalDirection>();
                CardinalDirection oppositeDirection = DirectionHelpers.GetOppositeDirection(currentDirection);

                foreach (CardinalDirection direction in DirectionHelpers.cardinalDirections)
                {
                    // Don't try to go backwards by default.
                    if (direction == oppositeDirection)
                    {
                        continue;
                    }

                    // Direction is possible if the intersection has this street.
                    Street street = targetIntersection.GetStreetInDirection(direction);

                    if (street != null)
                    {
                        // Make sure we're not entering into a one-way street from the wrong direction.
                        if (street.isOneWay == false || !targetIntersection.HasStopLineForStreet(street))
                        {
                            potentialDirections.Add(direction);
                        }
                    }
                }

                // Only if no options were there, go back.
                if (potentialDirections.Count == 0)
                {
                    potentialDirections.Add(oppositeDirection);
                }

                // Choose a random option.
                int randomIndex = UnityEngine.Random.Range(0, potentialDirections.Count);

                // Determine exiting values.
                nextIntersectionExitingCardinalDirection = potentialDirections[randomIndex];
                nextIntersectionExitingDirection         = DirectionHelpers.cardinalDirectionVectors[nextIntersectionExitingCardinalDirection];
                nextIntersectionExitingStreet            = targetIntersection.GetStreetInDirection(nextIntersectionExitingCardinalDirection);

                // Figure out which lane to go into.
                float  angleToTarget = Vector3.SignedAngle(sensors.carTracker.streetDirection, DirectionHelpers.cardinalDirectionVectors[nextIntersectionExitingCardinalDirection], Vector3.up);
                Street nextStreet    = targetIntersection.GetStreetInDirection(nextIntersectionExitingCardinalDirection);

                if (nextIntersectionExitingCardinalDirection == currentDirection)
                {
                    // Be in the middle (or right) lane when going straight.
                    nextIntersectionExitingLane   = nextStreet.validLanesCount / 2 + 1;
                    nextIntersectionTurningIntent = Driver.TurningIntent.Straight;
                }
                else if (nextIntersectionExitingCardinalDirection == oppositeDirection)
                {
                    // Turn into leftmost lane for U-turns.
                    nextIntersectionExitingLane   = 1;
                    nextIntersectionTurningIntent = Driver.TurningIntent.UTurn;
                }
                else if (angleToTarget < 0)
                {
                    // Be in leftmost lane after upcoming left turns.
                    nextIntersectionExitingLane   = 1;
                    nextIntersectionTurningIntent = Driver.TurningIntent.Left;
                }
                else
                {
                    // Be in the rightmost lane after upcoming right turns.
                    nextIntersectionExitingLane   = nextStreet.validLanesCount;
                    nextIntersectionTurningIntent = Driver.TurningIntent.Right;
                }

                nextIntersectionExitingPoint = nextIntersectionExitingStreet.GetCenterOfLanePosition(nextIntersectionExitingLane, 0, nextIntersectionExitingCardinalDirection);

                // Store entering values.
                nextIntersectionEnteringCardinalDirection = currentDirection;
                nextIntersectionEnteringDirection         = DirectionHelpers.cardinalDirectionVectors[currentDirection];
                nextIntersectionEnteringStreet            = currentStreet;

                // Figure out which lane to enter the intersection from.
                switch (nextIntersectionTurningIntent)
                {
                case Driver.TurningIntent.Straight:
                    // Be in the middle (or right) lane when going straight.
                    nextIntersectionEnteringLane = currentStreet.validLanesCount / 2 + 1;
                    break;

                case Driver.TurningIntent.Left:
                    // Be in leftmost lane for upcoming left turns.
                    nextIntersectionEnteringLane = 1;
                    break;

                case Driver.TurningIntent.Right:
                    // Be in the rightmost lane for upcoming right turns.
                    nextIntersectionEnteringLane = currentStreet.validLanesCount;
                    break;

                case Driver.TurningIntent.UTurn:
                    // Turn from the sidewalk for U-turns.
                    nextIntersectionEnteringLane = 0;
                    break;
                }

                nextIntersectionEnteringPoint = nextIntersectionEnteringStreet.GetCenterOfLanePosition(nextIntersectionEnteringLane, nextIntersectionEnteringStreet.length, nextIntersectionEnteringCardinalDirection);
            }

            // Update street.
            previousStreet = currentStreet;
        }
        protected virtual void UpdateTargetDirection(Driver.Sensors sensors, Driver.Actuators actuators)
        {
            float turningInput = Input.GetAxis("Turning");
            bool  performTurn  = false;

            if (Input.GetButtonDown("Turning"))
            {
                // See if the turn button is down.
                if (Input.GetButton("Turn"))
                {
                    // We want to make a turn.
                    performTurn = true;
                }
                else
                {
                    // Turn button is not down, so do a lane switch.
                    if (turningInput < 0)
                    {
                        // We want to go left, but if our current target was to go right, just return to current lane.
                        if (actuators.targetLane > sensors.carTracker.currentLane)
                        {
                            actuators.targetLane = sensors.carTracker.currentLane;
                        }
                        else
                        {
                            actuators.targetLane = Math.Max(sensors.carTracker.currentLane - 1, 0);
                        }
                    }
                    else
                    {
                        // We want to go right, but if our current target was to go left, just return to current lane.
                        if (actuators.targetLane < sensors.carTracker.currentLane)
                        {
                            actuators.targetLane = sensors.carTracker.currentLane;
                        }
                        else
                        {
                            actuators.targetLane = Math.Min(sensors.carTracker.currentLane + 1, sensors.carTracker.representativeStreet.lanesCount + 1);
                        }
                    }
                }
            }

            // If turn button is pressed and we have a direction, we should turn.
            if (Input.GetButtonDown("Turn") && turningInput != 0)
            {
                performTurn = true;
            }

            // Perform the turn if controls dictated it.
            if (performTurn)
            {
                // When going backwards, turning needs to be reversed.
                if (sensors.car.speed < 0)
                {
                    turningInput *= -1;
                }

                // Determine to which side we're currently turning.
                Vector3    forward            = sensors.car.transform.forward;
                Quaternion currentTargetDelta = Quaternion.FromToRotation(forward, actuators.targetDirection);

                // Use delta angle to wrap the angle to -180..180 range.
                float currentTargetDeltaAngle = Mathf.DeltaAngle(0, currentTargetDelta.eulerAngles.y);

                Vector3 newDirection;

                if (turningInput < 0)
                {
                    // We want to go left, but if our current target was to go right, just return to current direction.
                    if (currentTargetDeltaAngle > 45)
                    {
                        newDirection = forward;
                    }
                    else
                    {
                        newDirection = Quaternion.Euler(0, -90, 0) * forward;
                    }
                }
                else
                {
                    // We want to go right, but if our current target was to go left, just return to current direction.
                    if (currentTargetDeltaAngle < -45)
                    {
                        newDirection = forward;
                    }
                    else
                    {
                        newDirection = Quaternion.Euler(0, 90, 0) * forward;
                    }
                }

                // Square rotation to 90 degrees.
                CardinalDirection cardinalDirection = DirectionHelpers.GetCardinalDirectionForVector(newDirection);
                actuators.targetDirection = DirectionHelpers.cardinalDirectionVectors[cardinalDirection];
            }
        }