Hello Everyone. Today I’d like to explain a few technical aspects of what we have been working on recently.
The next playable update to download will be available in June.
Grid map data
The map is divided into grids. As you can see here, the resolution of the grid is two times higher than the grid you see when you construct buildings. The reason for that is that it allows us to end up with a variety of patterns when placing buildings.
As you see below in the middle, there can still be a path between objects even though they are placed next to each other. If we would allow you to build on the small grid then you would have much more micromanagement to do in order to keep the desired space.
For some objects this is not the case, such as houses. Those you can place wall on wall while their full area is not walkable by units. The blue cells indicate this, those have a special value. This also means that we can have multiple objects on the same grid cell as long as the rules allow it.
We add more and more layers but this has proven itself. It aids performance, decoupled code architecture, and multithreading to read the values from the grid map rather than iterating over entities and their data.
Grid map Simulation
We have several layers of data that are derived from the core data which we assign through the terrain or the buildings. Some of them are updated constantly but at a low rate. Due to performance issues, these layers had to be downsampled and we could even downscale them once more if we have to.
The system works good and on a separate Task (C#). Currently, we only suffer a bit from garbage allocation but we will tackle this next week, the core algorithm is very memory friendly.
Used for pathfinding. The trader vehicle is a much bigger object than a human being. The vehicle should avoid narrow paths where it wouldn’t fit or had issues to steer. By using thresholds to cost on such tiles (on Dijkstra integration cost) we achieve that the vehicle bypasses narrow paths.
Nevertheless, this is a threshold and not explicit. If the required bypass becomes too big then the vehicle would even drive over piles on the ground.
Indicates how densely an area is cultivated. This can be used to find out where city borders are and where it might be nicer to live. Animals will usually avoid the town area. Therefore children usually stay within the town area. Well, usually.
So far the only simulated value. By that I mean it changes over time. If there are corpses, waste or unclean outhouses then their environment will become polluted. Once the source of pollution is gone the area will recover.
Pollution is not only stinky but also a threat to health. Food will rot faster in polluted areas and that can be a tipping point as rotting food causes organic waste which causes a higher rate of rotting.
Island IDs are used for pathfinding and tell the AI if there even exists a path between two points even before a pathfinding algorithm is being initiated. For each encapsulated area there is a new island. There are also portals (general term for doors, gates, stairs, etc.) that can connect islands.
There are many more data sets but these are the derived data sets.
Entity Component System
We are using an Entity Component System (ECS). In short form, this divides the code into entities, components, and systems. All aspects in the game like a building or a unit is an entity with various components assigned. Components are for instance Production, Cattle, or Inventory which hold relevant data and can be saved to disk.
Most of the game logic is performed in systems. Usually, there is one system for each Component but some systems also handle multiple components.
We use this right from the beginning but made tremendous changes to the code base. Now it is much more flexible and easier to extend and maintain.
Our entities are designed in the editor using ScriptableObjects which we call StaticData. Here is an example of what this looks like for the pasture.
Notice that it has a pasture component which (in fact its system) is responsible for most of the logic of this building but it also needs other components like the inventory so it can store food for the animals.
Also, each building has a construction component that defines everything required to construct the building.
We developed a new system for power. Power is a general term, it can be produced by various sources: wind, solar, combustion, and electricity.
Electricity basically is only a medium for power and was generated by one of the other sources.
What we changed was the way power generation and consumption happens. We are now very flexible in designing new facilities, thanks to the new ECS setup.
For instance, each component can be powered. By default it has an efficiency of 100%. When we link a power source to the feature then the efficiency will be defined by the source instead. Here are some examples to illustrate this:
A workshop only requires labor force, therefore the production component has no power source attached.
A workshop that requires electricity is linked to a power source: electricity component and will therefore only work if it is connected to the electricity grid and power is available.
A solar collector has a power generator component which is connected to a power source: solar component. So depending on sunlight the efficiency of the power generator changes and outputs more or less electricity.
The flexibility here is that we can use the same component and change its behavior by simply adding another component and leaving the other one unchanged. But most importantly each existing component class like the production component does not have to know anything about the power system at all.