예제 #1
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;
        }
예제 #2
0
        public void Generate(City city)
        {
            // Create the street game object as a child of Streets.
            gameObject = new GameObject();
            gameObject.transform.parent = city.transform.Find("Streets");

            // Calculate size and position in the game world.
            Vector2 startIntersectionHalfSize = startIntersection.GetSize() / 2;
            Vector2 endIntersectionHalfSize   = endIntersection.GetSize() / 2;

            float roadWidth = lanesCount * City.laneWidth;

            width = roadWidth + 2 * City.sidewalkWidth;

            Vector3 boundsOrigin;
            Vector3 boundsSize;

            if (orientation == StreetOrientation.EastWest)
            {
                gameObject.name = $"Street ({startIntersection.position.x}-{startIntersection.position.x}, {endIntersection.position.y})";

                length = endIntersection.position.x - startIntersection.position.x - startIntersectionHalfSize.x - endIntersectionHalfSize.x;

                gameObject.transform.localPosition = new Vector3
                {
                    x = startIntersection.position.x + startIntersectionHalfSize.x,
                    z = startIntersection.position.y + width / 2
                };

                // Rotate the road so the local Z axis goes in the positive global X direction.
                gameObject.transform.localRotation = Quaternion.Euler(0, 90, 0);

                boundsOrigin    = gameObject.transform.localPosition;
                boundsOrigin.z -= width;
                boundsSize      = new Vector3(length, City.boundsHeight, width);
            }
            else
            {
                gameObject.name = $"Street ({startIntersection.position.x}, {startIntersection.position.y}-{endIntersection.position.y})";

                length = endIntersection.position.y - startIntersection.position.y - startIntersectionHalfSize.y - endIntersectionHalfSize.y;

                gameObject.transform.localPosition = new Vector3
                {
                    x = startIntersection.position.x - width / 2,
                    z = startIntersection.position.y + startIntersectionHalfSize.y
                };

                boundsOrigin = gameObject.transform.localPosition;
                boundsSize   = new Vector3(width, City.boundsHeight, length);
            }

            // Set bounds.
            bounds = new Bounds
            {
                min = boundsOrigin + new Vector3(0, City.boundsBaseY, 0),
                max = boundsOrigin + boundsSize
            };

            // Place prefabs.
            StreetPieces streetPieces = city.streetPieces;

            GameObject road = streetPieces.Instantiate(streetPieces.roadPrefab, gameObject);

            road.transform.localScale    = new Vector3(roadWidth, 1, length);
            road.transform.localPosition = new Vector3 {
                x = City.sidewalkWidth
            };

            GameObject sidewalkLeft = streetPieces.Instantiate(streetPieces.sidewalkPrefab, gameObject);

            sidewalkLeft.transform.localScale = new Vector3(City.sidewalkWidth, 1, length);

            GameObject sidewalkRight = streetPieces.Instantiate(streetPieces.sidewalkPrefab, gameObject);

            sidewalkRight.transform.localScale    = new Vector3(City.sidewalkWidth, 1, length);
            sidewalkRight.transform.localPosition = new Vector3 {
                x = width - City.sidewalkWidth
            };

            // Place lane division lines.
            var brokenLineXCoordinates = new List <float>();

            if (isOneWay)
            {
                brokenLineXCoordinates.Add(width / 2);
            }
            else
            {
                GameObject centerLine = streetPieces.Instantiate(streetPieces.solidLinePrefab, gameObject);
                centerLine.transform.localScale    = new Vector3(1, 1, length);
                centerLine.transform.localPosition = new Vector3 {
                    x = width / 2
                };
            }

            for (int i = 2; i < lanesCount; i += 2)
            {
                float sideOffset = City.sidewalkWidth + City.laneWidth * (i / 2);
                brokenLineXCoordinates.Add(sideOffset);
                brokenLineXCoordinates.Add(width - sideOffset);
            }

            foreach (float xCoordinate in brokenLineXCoordinates)
            {
                GameObject laneLine = streetPieces.Instantiate(streetPieces.brokenLinePrefab, gameObject);
                laneLine.transform.localScale    = new Vector3(1, 1, length);
                laneLine.transform.localPosition = new Vector3 {
                    x = xCoordinate
                };
                StreetPieces.ChangeBrokenLineTiling(laneLine);
            }

            GameObject CreateStopLine()
            {
                GameObject stopLine = streetPieces.Instantiate(streetPieces.solidLinePrefab, gameObject);

                float lineLength = roadWidth;

                if (!isOneWay)
                {
                    lineLength /= 2;
                }
                stopLine.transform.localScale = new Vector3(1, 1, lineLength);

                return(stopLine);
            }

            // Place intersection stop lines.
            if (endIntersection.HasStopLineForStreet(this))
            {
                GameObject stopLine = CreateStopLine();
                stopLine.transform.localRotation = Quaternion.Euler(0, 90, 0);
                stopLine.transform.localPosition = new Vector3 {
                    x = City.sidewalkWidth, z = length - City.lineWidth / 2
                };
            }

            if (startIntersection.HasStopLineForStreet(this))
            {
                GameObject stopLine = CreateStopLine();
                stopLine.transform.localRotation = Quaternion.Euler(0, 270, 0);
                stopLine.transform.localPosition = new Vector3 {
                    x = width - City.sidewalkWidth, z = City.lineWidth / 2
                };
            }

            // Place buildings.
            void CreateBuilding(float x, float z, float depth, int heightIndex)
            {
                GameObject building = streetPieces.Instantiate(streetPieces.buildingPrefab, gameObject);

                building.transform.localScale    = new Vector3(City.buildingWidth, City.buildingHeights[heightIndex], depth);
                building.transform.localPosition = new Vector3(x, 0, z);
            }

            void PlaceBuildings(float z, float depth)
            {
                CreateBuilding(-City.buildingWidth, z, depth, Random.Range(0, City.buildingHeights.Length));
                CreateBuilding(width, z, depth, Random.Range(0, City.buildingHeights.Length));
            }

            void PlaceBuildingsInRange(float minZ, float maxZ)
            {
                // See if we could put 2 or more buildings in this range.
                if (maxZ - minZ < City.minBuildingLength * 2)
                {
                    // No, this should be 1 building.
                    PlaceBuildings(minZ, maxZ - minZ);
                }
                else
                {
                    // Yes, split into two parts.
                    float midZ = Random.Range(minZ + City.minBuildingLength, maxZ - City.minBuildingLength);
                    PlaceBuildingsInRange(minZ, midZ);
                    PlaceBuildingsInRange(midZ, maxZ);
                }
            }

            PlaceBuildingsInRange(City.minBuildingLength, length - City.minBuildingLength);
        }