private void InitializeLane(Street street, int lane, bool directionTowardsEnd) { float speedInLane = speedPerLaneMph[lane] * PhysicsHelper.milesPerHourToMetersPerSecond; float safetyDistance = safetyDistanceTime * speedInLane; var emptySections = new List <(float, float)>(); emptySections.Add((safetyDistance, street.length - safetyDistance)); int carsCount = Mathf.RoundToInt(density * street.length + Random.value); if (density == 0) { carsCount = 0; } for (int i = 0; i < carsCount; i++) { // Stop if there are no more empty sections. if (emptySections.Count == 0) { break; } // Place a car at a random position in a random empty section. int emptySectionIndex = Random.Range(0, emptySections.Count); (float start, float end) = emptySections[emptySectionIndex]; emptySections.RemoveAt(emptySectionIndex); float position = Mathf.Lerp(start, end, Random.value); AddCar(street, lane, position, directionTowardsEnd); // Create two new empty sections, if they're long enough. if (position - safetyDistance > start) { emptySections.Add((start, position - safetyDistance)); } if (position + safetyDistance < end) { emptySections.Add((position + safetyDistance, end)); } } }
private void StopSimulatingStreet(Street street) { simulatedStreets.Remove(street); foreach (CarTracker carTracker in trafficCarTrackers) { if (carTracker.street == street) { Destroy(carTracker.gameObject); carTrackersToBeRemoved.Add(carTracker); } } foreach (CarTracker carTracker in carTrackersToBeRemoved) { trafficCarTrackers.Remove(carTracker); } carTrackersToBeRemoved.Clear(); }
private void StartSimulatingStreet(Street street) { simulatedStreets.Add(street); // Initialize traffic on this street. if (street.isOneWay) { for (int lane = 1; lane <= street.lanesCount; lane++) { InitializeLane(street, lane, !street.oneWayDirectionGoesToStart); } } else { for (int lane = 1; lane <= street.lanesCount / 2; lane++) { InitializeLane(street, lane, true); InitializeLane(street, lane, false); } } }
public Vector2 GetSize() { int widthLanesCount = 2; int heightLanesCount = 2; Street northSouthStreet = northStreet ?? southStreet; Street eastWestStreet = eastStreet ?? westStreet; if (northSouthStreet != null) { widthLanesCount = northSouthStreet.lanesCount; } if (eastWestStreet != null) { heightLanesCount = eastWestStreet.lanesCount; } float width = 2 * City.sidewalkWidth + widthLanesCount * City.laneWidth; float height = 2 * City.sidewalkWidth + heightLanesCount * City.laneWidth; return(new Vector2(width, height)); }
private void AddCar(Street street, int lane, float positionAlongStreet, bool directionTowardsEnd) { Vector3 positionStreet; Vector3 directionStreet; float sidePosition = City.sidewalkWidth + (lane - 0.5f) * City.laneWidth; if (directionTowardsEnd) { positionStreet = new Vector3(sidePosition, 0, positionAlongStreet); directionStreet = Vector3.forward; } else { positionStreet = new Vector3(street.width - sidePosition, 0, street.length - positionAlongStreet); directionStreet = Vector3.back; } Vector3 position = street.transform.TransformPoint(positionStreet); Vector3 direction = street.transform.TransformDirection(directionStreet); Quaternion rotation = Quaternion.LookRotation(direction, Vector3.up); GameObject car = Instantiate(trafficCarPrefab, position, rotation, carTrafficRoot); CarTracker carTracker = car.GetComponent <CarTracker>(); carTracker.city = city; trafficCarTrackers.Add(carTracker); CarAudio carAudio = car.GetComponent <CarAudio>(); carAudio.gameMode = gameMode; float initialSpeed = speedPerLaneMph[lane] * PhysicsHelper.milesPerHourToMetersPerSecond; car.GetComponent <Car>().InitializeSpeed(initialSpeed); }
protected Street AddStreet(Vector2Int fromBlock, Vector2Int toBlock, int lanesCount, bool isOneWay = false) { // Assert lane restrictions. if (lanesCount != 2 && lanesCount != 4 && lanesCount != 6) { Debug.LogError($"Street with invalid lanes count ({lanesCount}) added."); return(null); } if (isOneWay && lanesCount != 2) { Debug.LogError($"One way streets can only have 2 lanes."); return(null); } // Create the street. var street = new Street { lanesCount = lanesCount, isOneWay = isOneWay }; streets.Add(street); // Determine one way direction and set start/end locations (converted from blocks to meters). Vector2Int start = fromBlock * 100; Vector2Int end = toBlock * 100; void FlipDirection() { (start, end) = (end, start); if (isOneWay) { street.oneWayDirectionGoesToStart = true; } } if (fromBlock.x == toBlock.x) { // This is a N-S road. Flip direction if necessary. if (fromBlock.y > toBlock.y) { FlipDirection(); } } else { // This is an E-W road. Flip direction if necessary. if (fromBlock.x > toBlock.x) { FlipDirection(); } } // Create intersections if necessary and assign them to the street. Intersection CreateIntersection(Vector2Int location) { var intersection = new Intersection { position = location }; intersections[location] = intersection; return(intersection); } street.startIntersection = intersections.ContainsKey(start) ? intersections[start] : CreateIntersection(start); street.endIntersection = intersections.ContainsKey(end) ? intersections[end] : CreateIntersection(end); // Assign the streets to the intersections. if (fromBlock.x == toBlock.x) { // This is a N-S road. street.startIntersection.northStreet = street; street.endIntersection.southStreet = street; } else { // This is an E-W road. street.startIntersection.eastStreet = street; street.endIntersection.westStreet = street; } return(street); }
public int GetLanesCountInDrection(CardinalDirection direction) { Street street = GetStreetInOrientation(DirectionHelpers.cardinalDirectionStreetOrientations[direction]); return(street != null ? street.lanesCount : 2); }
public float GetStreetWidthInDrection(CardinalDirection direction) { Street street = GetStreetInOrientation(DirectionHelpers.cardinalDirectionStreetOrientations[direction]); return(street != null ? street.width : (City.sidewalkWidth + City.laneWidth) * 2); }
public bool HasStopLineForStreet(Street street) { if (isFourWayIntersection) { // Intersections with traffic lights (4-6 lanes) always have stop lines. if (hasTrafficLights) { return(true); } // When two 4-lane streets cross, east-west has priority; Street northSouthStreet = northStreet ?? southStreet; Street eastWestStreet = eastStreet ?? westStreet; if (northSouthStreet.lanesCount == 4 && eastWestStreet.lanesCount == 4) { return(street == northStreet || street == southStreet); } // When two one-way streets cross, east-west has priority; if (northSouthStreet.isOneWay && eastWestStreet.isOneWay) { return(street == northStreet || street == southStreet); } // One-way streets crossing non-one way streets always have stop signs if entering the intersection. if (street.isOneWay) { bool streetIsEnteringIfGointToStart = street == northStreet || street == eastStreet; return(streetIsEnteringIfGointToStart && street.oneWayDirectionGoesToStart); } // Street with 2 lanes always has a stop sign except if the other is a one-way street. if (street.lanesCount == 2) { if (street == northStreet || street == southStreet) { return(!eastWestStreet.isOneWay); } else { return(!northSouthStreet.isOneWay); } } // This must be a higher priority road so it has no stop sign. return(false); } else if (isTIntersection) { bool hasStopSign = false; // Street that doesn't continue has the stop sign. if (street == northStreet && southStreet == null) { hasStopSign = true; } if (street == southStreet && northStreet == null) { hasStopSign = true; } if (street == eastStreet && westStreet == null) { hasStopSign = true; } if (street == westStreet && eastStreet == null) { hasStopSign = true; } if (hasStopSign) { // Make sure this is not a one-way street that is exiting the intersection. if (street.isOneWay) { bool streetIsEnteringIfGointToStart = street == northStreet || street == eastStreet; return(streetIsEnteringIfGointToStart && street.oneWayDirectionGoesToStart); } else { return(true); } } return(false); } else { return(false); } }
public void Generate(City city) { // Create the intersection game object as a child of Intersections. gameObject = new GameObject($"Intersection ({position.x}, {position.y})"); gameObject.transform.parent = city.transform.Find("Intersections"); // Position in the game world. Vector2 size = GetSize(); gameObject.transform.localPosition = new Vector3 { x = position.x - size.x / 2, z = position.y - size.y / 2 }; // Set bounds. bounds = new Bounds { center = new Vector3(position.x, City.boundsBaseY + City.boundsHeight / 2, position.y), size = new Vector3(size.x, City.boundsHeight, size.y) }; // Place prefabs. StreetPieces streetPieces = city.streetPieces; GameObject road = streetPieces.Instantiate(streetPieces.roadPrefab, gameObject); road.transform.localScale = new Vector3(size.x, 1, size.y); // Place sidewalk corners or sides. void CreateCorner(float rotation, float x, float z) { GameObject corner = streetPieces.Instantiate(streetPieces.sidewalkCornerPrefab, gameObject); corner.transform.localScale = new Vector3(City.sidewalkWidth, 1, City.sidewalkWidth); corner.transform.localRotation = Quaternion.Euler(0, rotation, 0); corner.transform.localPosition = new Vector3 { x = x, z = z }; } if (southStreet != null && westStreet != null) { CreateCorner(0, 0, 0); } if (northStreet != null && westStreet != null) { CreateCorner(90, 0, size.y); } if (northStreet != null && eastStreet != null) { CreateCorner(180, size.x, size.y); } if (southStreet != null && eastStreet != null) { CreateCorner(270, size.x, 0); } if (northStreet == null) { GameObject sidewalk = streetPieces.Instantiate(streetPieces.sidewalkPrefab, gameObject); sidewalk.transform.localScale = new Vector3(size.x, 1, City.sidewalkWidth); sidewalk.transform.localPosition = new Vector3 { z = size.y - City.sidewalkWidth }; } if (southStreet == null) { GameObject sidewalk = streetPieces.Instantiate(streetPieces.sidewalkPrefab, gameObject); sidewalk.transform.localScale = new Vector3(size.x, 1, City.sidewalkWidth); } if (eastStreet == null) { GameObject sidewalk = streetPieces.Instantiate(streetPieces.sidewalkPrefab, gameObject); sidewalk.transform.localScale = new Vector3(City.sidewalkWidth, 1, size.y); sidewalk.transform.localPosition = new Vector3 { x = size.x - City.sidewalkWidth }; } if (westStreet == null) { GameObject sidewalk = streetPieces.Instantiate(streetPieces.sidewalkPrefab, gameObject); sidewalk.transform.localScale = new Vector3(City.sidewalkWidth, 1, size.y); } // Place lines if one street has priority. bool hasLinesNorthSouth = false; bool hasLinesEastWest = false; Street northSouthStreet = northStreet ?? southStreet; Street eastWestStreet = eastStreet ?? westStreet; if (isFourWayIntersection) { // 4-way intersections have lines where there are no stop signs on both ends. hasLinesEastWest = !HasStopLineForStreet(eastStreet) && !HasStopLineForStreet(westStreet); hasLinesNorthSouth = !HasStopLineForStreet(northStreet) && !HasStopLineForStreet(southStreet); } else if (isTIntersection) { // T intersections always have priority on the street that doesn't end. hasLinesEastWest = northStreet == null || southStreet == null; hasLinesNorthSouth = eastStreet == null || westStreet == null; } if (hasLinesNorthSouth) { var brokenLineXCoordinates = new List <float>(); if (northSouthStreet.isOneWay) { brokenLineXCoordinates.Add(size.x / 2); } else { GameObject centerLine = streetPieces.Instantiate(streetPieces.solidLinePrefab, gameObject); centerLine.transform.localScale = new Vector3(1, 1, size.y); centerLine.transform.localPosition = new Vector3 { x = size.x / 2 }; } for (int i = 2; i < northSouthStreet.lanesCount; i += 2) { float sideOffset = City.sidewalkWidth + City.laneWidth * (i / 2); brokenLineXCoordinates.Add(sideOffset); brokenLineXCoordinates.Add(size.x - sideOffset); } foreach (float xCoordinate in brokenLineXCoordinates) { GameObject laneLine = streetPieces.Instantiate(streetPieces.brokenLinePrefab, gameObject); laneLine.transform.localScale = new Vector3(1, 1, size.y); laneLine.transform.localPosition = new Vector3 { x = xCoordinate }; StreetPieces.ChangeBrokenLineTiling(laneLine); } } if (hasLinesEastWest) { var brokenLineZCoordinates = new List <float>(); if (eastWestStreet.isOneWay) { brokenLineZCoordinates.Add(size.y / 2); } else { GameObject centerLine = streetPieces.Instantiate(streetPieces.solidLinePrefab, gameObject); centerLine.transform.localScale = new Vector3(1, 1, size.x); centerLine.transform.localRotation = Quaternion.Euler(0, 90, 0); centerLine.transform.localPosition = new Vector3 { z = size.y / 2 }; } for (int i = 2; i < eastWestStreet.lanesCount; i += 2) { float sideOffset = City.sidewalkWidth + City.laneWidth * (i / 2); brokenLineZCoordinates.Add(sideOffset); brokenLineZCoordinates.Add(size.y - sideOffset); } foreach (float zCoordinate in brokenLineZCoordinates) { GameObject laneLine = streetPieces.Instantiate(streetPieces.brokenLinePrefab, gameObject); laneLine.transform.localScale = new Vector3(1, 1, size.x); laneLine.transform.localRotation = Quaternion.Euler(0, 90, 0); laneLine.transform.localPosition = new Vector3 { z = zCoordinate }; StreetPieces.ChangeBrokenLineTiling(laneLine); } } // Place buildings in 4 corners. void CreateBuilding(float x, float z, float width = City.minBuildingLength, float depth = City.minBuildingLength) { GameObject building = streetPieces.Instantiate(streetPieces.buildingPrefab, gameObject); building.transform.localScale = new Vector3(width, City.buildingHeights[1], depth); building.transform.localPosition = new Vector3(x, 0, z); } CreateBuilding(-City.minBuildingLength, -City.minBuildingLength); CreateBuilding(-City.minBuildingLength, size.y); CreateBuilding(size.x, -City.minBuildingLength); CreateBuilding(size.x, size.y); // Place buildings in directions where there is no street. if (northStreet == null) { CreateBuilding(0, size.y, width: size.x); } if (southStreet == null) { CreateBuilding(0, -City.minBuildingLength, width: size.x); } if (eastStreet == null) { CreateBuilding(size.x, 0, depth: size.y); } if (westStreet == null) { CreateBuilding(-City.minBuildingLength, 0, depth: size.y); } }
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; }
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; } }
private void Update() { // See if game camera is in the same location as before. CarTracker focusedCarTracker = gameMode.currentCamera.trackedCar; if (focusedCarTracker.street != null && focusedCarTracker.street != focusedStreet || focusedCarTracker.intersection != null && focusedCarTracker.intersection != focusedIntersection) { // We have moved to a different street or intersection so we need to recalculate the simulated streets and intersections. focusedIntersection = focusedCarTracker.intersection; focusedStreet = focusedCarTracker.street; void AddIntersectionVicinity(Intersection intersection, int distance) { if (distance == 0) { return; } newSimulatedIntersections.Add(intersection); if (intersection.northStreet != null) { AddStreetVicinity(intersection.northStreet, distance); } if (intersection.southStreet != null) { AddStreetVicinity(intersection.southStreet, distance); } if (intersection.eastStreet != null) { AddStreetVicinity(intersection.eastStreet, distance); } if (intersection.westStreet != null) { AddStreetVicinity(intersection.westStreet, distance); } } void AddStreetVicinity(Street street, int distance) { if (distance == 0) { return; } newSimulatedStreets.Add(street); AddIntersectionVicinity(street.startIntersection, distance - 1); AddIntersectionVicinity(street.endIntersection, distance - 1); } if (focusedStreet != null) { AddStreetVicinity(focusedStreet, 3); } else { AddIntersectionVicinity(focusedIntersection, 2); } // Update simulated streets. foreach (Street street in simulatedStreets) { if (!newSimulatedStreets.Contains(street)) { // This street is no longer being simulated, so we can remove it, including all the cars left in it. streetsToBeStopped.Add(street); } } foreach (Street street in streetsToBeStopped) { StopSimulatingStreet(street); } streetsToBeStopped.Clear(); foreach (Street street in newSimulatedStreets) { if (!simulatedStreets.Contains(street)) { // This street isn't being simulated, so start doing it. StartSimulatingStreet(street); } } newSimulatedStreets.Clear(); // Update simulated intersections. foreach (Intersection intersection in simulatedIntersections) { if (!newSimulatedIntersections.Contains(intersection)) { // This street is no longer being simulated, so we can remove it, including all the cars left in it. intersectionsToBeStopped.Add(intersection); } } foreach (Intersection intersection in intersectionsToBeStopped) { StopSimulatingIntersection(intersection); } intersectionsToBeStopped.Clear(); foreach (Intersection intersection in newSimulatedIntersections) { if (!simulatedIntersections.Contains(intersection)) { // This street isn't being simulated, so start doing it. StartSimulatingIntersection(intersection); } } newSimulatedIntersections.Clear(); } // Remove cars that left the simulation area. foreach (CarTracker carTracker in trafficCarTrackers) { if (carTracker.street != null && !simulatedStreets.Contains(carTracker.street) || carTracker.intersection != null && !simulatedIntersections.Contains(carTracker.intersection)) { Destroy(carTracker.gameObject); carTrackersToBeRemoved.Add(carTracker); } } foreach (CarTracker carTracker in carTrackersToBeRemoved) { trafficCarTrackers.Remove(carTracker); } carTrackersToBeRemoved.Clear(); // Add cars at the edges of the simulation areas. foreach (Street street in simulatedStreets) { if (street.isOneWay) { if (street.oneWayDirectionGoesToStart) { if (!simulatedIntersections.Contains(street.endIntersection)) { SimulateStreetEntrance(street, false); } } else { if (!simulatedIntersections.Contains(street.startIntersection)) { SimulateStreetEntrance(street, true); } } } else { if (!simulatedIntersections.Contains(street.endIntersection)) { SimulateStreetEntrance(street, false); } if (!simulatedIntersections.Contains(street.startIntersection)) { SimulateStreetEntrance(street, true); } } } }