I started the month off by adding in custom intersection lane connections, in case the auto generated ones are inefficient for the current traffic pattern. After that, I began to think about the game's art direction. Originally I wanted to do a pure top down game, but everything felt so flat. If I wasn't a one man team, I would likely take the isometric path. So tilted top down is the compromise. I spent some time developing new art assets (floors and walls mostly). I also added in some basic functionality to change the wall color and floor design.
Another big adventure I had was diving into multi-threading. Since I moved the path storage to a vector, I figured parallelizing the path tree would be simple... and it was! All I needed to do was batch the processes by contiguously-grouped indexes. There was a little bit of playing around to figure out what code C++ thought was acceptable. I couldn't find a clean way to call a class function with a thread object, so I ended up using lambda's after searching around online. My machine has six cores (hyper threading does not seem to make much of an impact), thus I was able to cut the path storage time down by 83%. This is great because generating all paths for a 50 x 50 grid of intersections took about a minute. Now it takes 10 seconds. Arguably this is overkill. A 50 x 50 grid of Manhattan sized blocks is equivalent to 13 square miles, or nine Cities: Skylines tiles. Most cities never get that big. But since it only took a day to implement, I dont feel guilty.
The next logical step was to make unit movement concurrent. This is a lot more tricky to do right (which I haven't bothered with yet), because right now I am using a hash table to store positions/check for collisions. A naive implementation creates data races (when multiple units attempt to update the same index at the same time). In game, all this does is create gaps in the traffic, temporarily blocking a unit from moving forward. Eventually I plan to solve this problem correctly, either by storing the units in queues within the edge it is currently pathing in, or figuring out an efficient collision algorithm based on position (quad trees?). That being said, the game can now path around 500,000 to 1,000,000 units to unique destinations in real time. This is totally overkill, as I dont expect more than 100,000 units to be traveling at the same time in a huge city. But again, it took a day to implement, so I don't feel guilty.
Mid June I spent working on media, a lgoo, my website, and my blog. I also created a new video showing off the progress I've made. I ended up deleting my Wordpress installation (it was too frustrating) and started writing my website myself. I also spent some time combining some graphics code to make it more scaleable. I keep needing more SFML vertex layers to layer sprites on the screen.
Additionally, units can now path from building to building, or road to building, or building to road. I added waypoints with a flag indicating if the next set of points to travel to is on or off road, and then the engine passes the unit to the proper path finding function. All off road path finding is using A*. Since this is a relatively inefficient method for path finding units (there's a small noticeable delay when moving 10,000 units over a short distance), my plan is to either only use A* when the units are on screen (otherwise, delay teleport the unit), or use some hierarchical methods and use doors as the way points. Teleporting off screen wont affect the game negatively since there is no traffic nor tile capacity inside buildings.
I had to slow down the last couple weeks to give my wrist some rest.
Published Date: 06/26/2022
Total Development Time: 7 months