Oh hello what is this, a city simulator.. but.. I'm a huge city simulator nerd! I'll be looking forward to this!
I'm also a big visuals nerd and one of the things that immediately struck me was how some of the windows on highrises feel very wide or square, to the point where they detract from the verticality of a cyberpunk cityscape and visually forze stuff down horizontally. Saying this while realizing it's all early stuff and polish will follow etc.
Anyways, looking forward to more updates and good luck on the project
Hells, Kinnas, your game's art looks amazing. Thank you for the feedback, I'll be working on that some more once I get skyscrapers again.
This really looks great. I love cyberpunk and i'm a huge fan of SimCity for more than 20 years
The corporation stuff is promising, i hope you will pull it off good
Thanks! I won't let you down.
Where to start...
The foundationsI started designing a lot more than implementing and realized that many of my game systems are connected to core "city building" stuff that isn't done yet. For example, Corporations can screw people out of a fair wage, or they can harm the environment so much that their life expectancy drops simply by working at their factories. These all depend on "wage", "life expectancy", "security", "desirability", "pollution", "taxes" etc etc... endless lists of features that just aren't complete or even started yet. So I took a step back and I'm pausing the Corporation and Culture arcs and saving that for later.
Now... on to the good stuff.
Terrain ElevationThis is important! Without terrain variations building location becomes a meaningless decision. Should I build north? east? west? south? It doesn't matter at all on flat terrain. At its core, a city building game needs elevation and terrain details to force meaningful decisions about where to build. Should luxury condos occupy that hill over there? Or should it be reserved for wind power plants?
Well, I've only built out the visuals so far and incongruous terrain for zones are "evened out" at the highest elevation by building a foundation. It doesn't look great right now but that's alright, we can work on the visuals for that later.
More importantly, I need to figure out what to do with the elevation next. Should there be some kind of bonus to desirability for zones based on elevation? Maybe that's the simplest, dumbest thing to do right now and it'll be good enough.
Also an obvious thing that's missing is water, and trees. Oh and cliffs. My terrain generation is piss poor right now, three octaves of perlin noise. It's bad, and I'll need to work on it later. Maybe water first.
LightingThe day-time lighting you've seen before was all for debugging. I want to get back into the mood of "cyberpunk city" building so I turned back off the directional light and ...
Also gave the residential housing window lights...
And the most fun to work on was the factory lighting...
What's really cool is that I'm exploiting Unreal's socket system. Each socket has a name, position, and rotation. If the name has the word "light" in it, then the mesh generator will spawn a light there. It'll use the scale for brightness and falloff, and rotation for color... I'm quite proud of this hacky solution because you can author light locations directly in Unreal's model setup editor.
Zone ParcelingThis step was an important one because zone upgrades grow outwards first, consuming nearby zones so as to get bigger surface area, before they can grow upwards. The way I had zoning set up before was that each click and drag created a zone, which can be quite arbitrarily big. This zone parceling uses roads to determine their parcel direction. As a side-effect, residential zones can only be painted next to roads now.
This applies only to residential and commercial zones. Industrial, power, hospital, parks and everything else are just blobs of zones still and I think that's fine for now.
Health and WealthFactories have "salary" now. If a resident works there then they will get the equivalent amount of wealth.
Health is now calculated based on an 80 year base life span. Pollution, commute, and your work place can decrease your life span. Access to hospitals would increase it by a lot. If you walk to work, you'll also increase your life span for a bit.
The actual health metric isn't used in any other game system right now so I'll need to plug that in somewhere later. I'm not sure how yet.
Game Optimization for Bigger CitiesAs I started building bigger cities, I noticed the simulation was lagging the game a lot. Like 80 to 120 milliseconds a lot. That is extremely unacceptable since it causes huge choppy motions, especially when you're panning around the game world.
(speaking of which, maybe I should just disable simulation while the player is panning.. has any game ever done that?).
I know I know... you really shouldn't optimize so early in a project. However I needed to know *now* whether the problem is systemic -- if it's something I'm doing totally wrong with Javascript, or my ECS is doing something highly inefficient. I also wanted to look for low hanging fruits, anything that can give me some more speed back.
The first thing I did was write a profiler for my game rules. Each game rule is a JSON loaded from a file (for easy modding) and some take longer to finish than others. Optimizing requires you to know if you've made speed improvements, so seeing the numbers was really important.
Next, I re-did my entity evaluation that was used in the rules. Basically, each JSON rule is evaluated using an abstract syntax tree. However, that AST needed a lot of custom game-logic code to be useful (like collecting all components of type "maintenance" to get an expense report). Unfortunately I was rebuilding this custom logic every single time I wanted to evaluate an entity. This caused a lot of waste in JS and garbage collection. The solution was simply performing this construct once, and pass in the entity just before evaluating. Unfortunately this also made the game rules slightly uglier (instead of jobs.value, it's now e.jobs.value). This gave a global speed up in simulation time.
Looking at the profiler, I saw the game was spending a lot of time performing "consumption". Meaning, every tick the laborers were looking for jobs they already had, and power consumers were looking for power plants all over the map. Even though I had cached the pathfinding and "island" lookups, the step for performing these checks shouldn't be necessary at all.
Instead, I wrote a "production cache" that each consumer had to go to before consuming a resource. Every time a resource is consumed, a "receipt" is given to the entity. Upon the next tick, all the consumer has to do is check with the production cache if its receipt is still valid. A receipt can be invalidated in any number of ways: the road paths have changed, the previous office you worked at got demolished, the power plant is exploding... etc. In this way, the consumption search is only ever performed once and never again until it needs to.
Doing all of the above got the game simulation time to under 16ms even for a wide-ish city. I think that's all the optimization I'll do for the time being... there's probably tons of other things I can do but for now I'm keeping all the "could be optimized" stuff in "simulation cache" which is great because when time comes to optimize, I really shouldn't have to touch any of the actual game logic, just the parts that are built for optimization.
A future optimization could be for consumers that keep looking for resources (like laborers hunting for jobs) should be given a delay on when the next time they can search, so that it doesn't spam up the update tick.
The build as of Jan 2017So what's next on my agenda?
I feel like I have a near infinite number of "basic" stuff I need to do before getting to the fun parts.
- Residents with 0 employment should start losing wealth (do they even start with wealth?)
- Design and implement an education system. In this game it's called "tech" and your tech level determines the type of jobs you can get
- Start adding some kind of commercial zone. Perhaps retail stores? I also worry about the art...
- I need a way to differentiate between different types of demand for different industries. Right now demand is universal across their own zone type (all industrial has the same demand).
- Right now zone upgrading is kind of broken and buggy. Zones don't upgrade properly.
- I need a procedural model data format to describe the lots (parking lot, swimming pool, garden, factory space tiles) and the actual procedural structure itself. And I need to do so by keeping the Wealth (quality of building) and Desirability (how wide and tall to build). This is going to be hard to solve all at once and I'll need to start fresh somewhere. Perhaps on a proc-gen test bed map or something.
Anyway, if you sat through this rant, happy new years!