Are you sick of rivers overflowing and flooding everything? Use this guide to understand how rivers work in Cities Skylines 2.
For a stream source, you can use the formula:
For the most part, radius doesn't matter.
For example, a river that's 20 meters deep, 100 meters wide, and flows at a 1% grade should have
This should fill the river all the way to the top, so you may want to lower the number a bit to leave some wiggle room.
You can also use this rule to match the flow between different sections of a river:
- For any combination of X, Y = wide, deep, or steep
- If you make the river twice as X, make it half as Y
- If you make the river twice as X, give it twice as much flow
- For example
- If you make the river twice as wide, make it half as steep
- If you make the river half as steep, make it twice as deep
- If you give the river twice as much flow, make it twice as deep
The area of the river channel is
Draw a road along the river's direction of flow to get the grade. Divide the grade by 100 when using the formula.
Since a lot of us have intuitions of what rivers should look like based on real life, we can compare how the game is different.
The formula above talks about flow, but
In real life, the Manning formula says* that
so the Cities Skylines version is a lot simpler. In real life, bigger rivers flow faster because they have less friction. So big rivers in Cities Skylines flow a little slower than they should. Also in real life, steep rivers experience a lot more friction than flatter rivers (since friction increases with velocity squared), so steep rivers in Cities Skylines flow faster than they should and carry more water than they should.
(*This assumes that roughly
Based on the observed results, here is a likely explanation for how the water simulation works.
Imagine you have two cells next to each other. Each cell has a water level W and a ground level G. And between the cells you have a volumetric flow rate Q.
We observed
(Side note - there's nothing stopping the game devs from using the Manning formula
Then, to ensure conservation of mass, we turn speed into flow by multiplying the water depth:
And if we define a stream source, it just injects the same amount of water into the cell every second, which we can call
So there are three flows we need to keep track of - water flowing in from the left, water flowing out to the right, and water generated by a source. If more water is flowing in than flowing out, the water level will rise. So we get an update rule:
For cell 2, this comes out to:
And then this simulation is super simple to run for all of the cells in a grid in parallel on a GPU.
I used a test map to calibrate the flow rates. River banks are at a 45 degree angle / 100% grade, and the bottom of the river channel is flat. I used increments of 4 heightmap pixels, equal to 14 meters, for testing. I tested at 1%, 2%, 4%, 6%, and 8% grades. I added a buffer of 140 meters between rivers and added a 5% grade in case the river overflowed a little.
Here are the height maps I generated - one local heightmap and one world heightmap.
Then I added water sources and tuned the flow until they just barely hit the top of the rivver
Here is the raw data I generated
Grade (%) | Width (m) | Depth (m) | Area (sq. m) | Full Width (m) | Flow |
---|---|---|---|---|---|
1 | 42 | 14 | 588 | 56 | 0.35 |
1 | 98 | 14 | 1372 | 112 | 0.8 |
1 | 84 | 28 | 2352 | 112 | 1.45 |
1 | 196 | 28 | 5488 | 224 | 3.2 |
1 | 168 | 56 | 9408 | 224 | 5.5 |
1 | 392 | 56 | 21952 | 448 | 11.5 |
1 | 336 | 112 | 37632 | 448 | 21 |
2 | 42 | 14 | 588 | 56 | 0.65 |
2 | 98 | 14 | 1372 | 112 | 1.5 |
2 | 84 | 28 | 2352 | 112 | 2.7 |
4 | 42 | 14 | 588 | 56 | 1.4 |
4 | 98 | 14 | 1372 | 112 | 3.4 |
6 | 42 | 14 | 588 | 56 | 2 |
6 | 98 | 14 | 1372 | 112 | 4.5 |
8 | 42 | 14 | 588 | 56 | 2.9 |
8 | 98 | 14 | 1372 | 112 | 5.8 |
I fit the data using the formula at the top of the page, and the fit was very good. Here is a residual plot of all the data:
And here is a plot of flow vs. area by grade