Game Design Deep Dive is an ongoing Gamasutra series with the goal of shedding light on specific design features or mechanics within a video game, in order to show how seemingly simple, fundamental design decisions aren't really that simple at all.
Check out earlier installments on the plant-growing mechanics of Grow Home and the Function system of Transistor.
Also, dig into our ever-growing Deep Dive archive for developer-minded features on everything from Amnesia's sanity meter to Alien: Isolation's save system.
Who: Antti Lehto (programmer), Damien Morello (programmer) and Karoliina Korppoo (lead designer)
We work at Colossal Order, a Finland-based independent game studio specializing in PC simulation games. Colossal Order was founded in 2009 and we have so far published three games: Cities in Motion, a public transport simulation game, Cities in Motion 2, the sequel to the former, and Cities: Skylines, an old-school city builder game. We have a team of only 13 people and are especially fond of cake and small blue birds.
While the Cities in Motion games were made for a fairly small but very dedicated audience, Skylines has reached a much larger audience and caters also to people who are less experienced in the simulation genre. We are very proud that city builder fans have been pleased with the game and are glad to see modders creating content at a rapid pace. We wanted to encourage modding and to blur the line between playing and creating, so people could really own the game.
What: Traffic systems in Cities: Skylines
Managing traffic is one of the end-game tasks in the game, possibly the most important one. There are many different road types and all need to be usable and interesting choices. The road tool is flexible to allow players to construct complex intersections to manage the traffic flow, but also simple enough to not make basic road building a chore.
There's a limit of how many citizens and vehicles can be simulated on the streets at the same time. If the limit is not met, citizens can choose to travel. Citizens in the game have possible locations they wish to visit. These locations can fill up, which will result in more demand for those locations. When a citizen leaves for a location, they choose the fastest route there.
They take into account if they have a vehicle of their own, if there are congested roads and if there is public transport available. Based on these factors they walk, use public transport or their own vehicle. Pedestrians can use pedestrian paths that are separate from roads. Pedestrians cannot walk on highways.
When vehicles plan their route, they stick to it. They will not recalculate in the middle of the journey unless something on their path has been modified. If for some reason they cannot find a route to the location they have chosen, the vehicle will teleport back to its origin point.
Vehicles belong to buildings or citizens, so they always have a place to return to. Some vehicles arrive from outside the map, but return to the outside location if they get lost. Vehicles choose their lane quite early, and they choose and stay in the lane that allows them to turn to the direction they will be taking.
The aim was from the start of the project to have cities with up to one million citizens. This is not a hard limit, it's what we estimate to be maximum amount for a fully-built city, and it has been an internal guideline for balancing city systems. With up to one million citizens, it was clear that not all of them can be on the streets at the same time if we want to keep the system requirements reasonable. This meant that we needed to create the worker system so that workers not actually physically going to their workplaces don’t give the player a penalty.
We spent a lot of time working and reworking the traffic system. It has been the single greatest challenge in the game and is a system that all players interact with, so it is one of the most important systems. During development we tried for example allowing cars to change lanes more often, which resulted in total traffic chaos as cars trying to join a crowded lane blocked two lanes and made traffic grind to a halt.
Teleporting was made as a safety feature when testing showed that less experienced players ran into huge problems when their whole road system became one huge traffic jam, and the information overlay for roads could not identify the actual bottleneck when all roads were full of waiting cars and showed as congested. This meant that the players could not locate the problem spot if they had no or little previous experience, or were generally not that into traffic.
As a solution we created a system that makes vehicles teleport back to their origin if they encounter a gridlock. The original bottleneck is still there and has vehicles standing still or inching forward, but the jam doesn't grow uncontrollably. This makes the information overlay identify the problem area, paint it red and thus clearly show the player which part of the road system needs to be looked at.
Without roads, there would be no traffic. So let's start with a high-level view on how roads are made.
When a player sets a road, they are essentially placing nodes. Two nodes create a segment and a road is made out of one or more segments. Segments have a maximum size, so a long road will be split into several segments, one of the motivations behind this approach is that roads need to follow the terrain topology, so even a straight road will need several segments so that it does not clip through the terrain, another motivation is small segments are more optimized for collision detection, rendering and whatnots.
Nodes (known as control points) hold the start and end position of a segment while a segment holds a start and an end direction. This structure is then ”converted” to a bezier curve by generating two extra control points using these positions and directions.
The road geometry is then created by using a static mesh with a set tesselation combined with a vertex shader which will transform the mesh accordingly to the spline data. This is efficient as the vertex data for roads can be shared between same road types, uvs on the length direction are also calculated in the vertex shader based on the spline length.
Intersections are created using a similar approach and segments store their connections to neightboring segments as well as their road type. Each segment can then know about their available lanes using their road type, which define the amount of lanes and their offset on the mesh.
Given the information described above, cars and trucks know where they can navigate on the roads. Instead of using a naive interpolation along the spline, vehicles are simple physics objects which use a velocity and a multiple target points along the spline they wish to follow. This allows for predicting tight curves and upcoming intersections so that the vehicle slows down or brakes depending on the circumstances. Vehicles sample their speed limit from the road type of the segment they are navigating upon.
When a citizen wants to reach a new destination, a path will be calculated from their current position to the target destination, including walking, driving, using public transport... which by the way is pretty cool as it accounts for citizens walking from a bus stop to another to switch buses. During that process, the pathfinding establishes the best driving path for the vehicle by calculating a score out of the segments/lanes data considering congestion level, speed limit and direction.
Traffic is simulated using first-come first-served logic. Vehicles use the target points mentioned earlier to create a ”watch out” segment, when two different vehicles segments intersect, we know there is going to be a collision so the velocity and the distance to the intersection point is used to determine who makes it and who needs to break. There is an exception to this rule with traffic lights which simply prevent the target points to enter the intersection, hereby causing the vehicle to slow down and stop until the light turns green.
Of course, there are several other factors which affect the traffic behaviour, but essentially, it all revolves around these simple steps.
In terms of performances, it is impossible to simulate the above by applying it to every car’s every frame. The secret to a decent performance result is to distribute the calculations as much as possible. In our case, the car movement is simulated about 4 times per second while the rendering will use two simulation frames to derive a smooth position out the position, rotation and velocity data. More complicated decisions may be calculated even less frequently, but using the same smoothing approach, it will appear like it is constantly being updated.
Some players feel the game is too easy because of the teleporting. It does make the game a lot easier than gridlocked traffic, but it really is necessary to keep the learning curve reasonable. If there was no teleportation, the reaction time required to catch the traffic problems before they escalate would simply be too short. There's a user made mod available to disable teleportation so players enjoying a lot of challenge can get it easily. All in all the amount of players talking about traffic problems is relatively low, which leads us to believe the solution works quite well.
Traffic is still the most challenging part of the game for most players. Choosing lanes early occasionally looks weird in the game. Vehicles can queue on only one lane while the other lanes look empty, because traffic using them just breezes past. Technically a congested lane still tells the player that somewhere further in the city an intersection is preventing traffic to flow smoothly, but when looking at just the long line of vehicles, some players take it as a bug.
The main challenge now is to teach users how to build working traffic systems, but looking at players’ forum discussions it's an interesting topic that people like to contribute on. After grasping the basics of the traffic system, many players seem to find it intriguing and get lots of hours of fun out of optimizing and managing traffic.