Monday, March 22, 2021

Working on the wall system

The bulk of this system is already done, I just need to add variable wall height and optimize the UI interface.
There are a couple more stuff I want to add, like connecting the wall to nearby terrain (like it does other walls and some buildings) to act as a bracing wall and building a roof to provide extra protection (Abwurfach??? imma just gonna go with "roof" on this one) but I don't know if I'll get to it now.

Right now walls are just a fixed height above the terrain they're on, first thing to do is add a variable to the wall class for the actual height, I'll be using a byte for this.
Change the constant wall height to a minimum height (the height walls start from at 0 height), add a constant for how much each physical height each level adds(I'm thinking half the terrain step elevation) and a constant for the maximum height steps a wall can have (I don't think I'll be using the full 128 values a byte has, a couple dozen top)



Hmmm.. on second thought, maybe I should start on the UI, it'll make testing everything much easier and I always end up getting to it last and cutting corners because I don't like doing UI.

Currently the interface is very wonky, it takes up too much space and requires more clicking than actually needed.
you can see the edge selector on the right, the group of buttons on the bottom are the controls for the entire wall segments and the group on top are for the selected edge.




To remedy all of these problems I'm going to compact everything (and the new height control) into the area the edge selector currently takes and make everything a one-click operation.
What I did is place a small hex in a big hex and connect the corners - creating a central hex for the global controls with six trapezoids extensions, one for each edge.
Now I can place all the buttons on the appropriate areas, all accessible all the time.

Here's what it looked like during the design, you can see the seven segments (center + six edges), the letters are where all the buttons are gonna go and the red circle mark the safe area for placing the center buttons (the graphic is spinning with the camera to align the edges to the view and the center buttons don't rotate)




This is the button legend:
  • CR - crenellations (either edge or all)
  • MC - machicolations (edge or all)
  • G - gate
  • L - lock gate (edge or all)
  • ST - stairs
  • MH - murderhole
  • (-) - decrease height
  • 99 - current height
  • (+) - increase height
  • R - roof

After settling on the layout I made it a bit prettier (but it still needs another pass! 😅), got it into Unity and added all the other elements to it(they don't have fancy graphics yet), this is how it looks now:




I like it, still needs more polish and the buttons are still jarringly ugly - but that'll come in due time.
I want to make the buttons flip when upside down, but I think i'm gonna hold off on that, see if I can make some icons that are easily legible from all angles first.



Now back to my safe space the code, first to make a few adjustments to accommodate how the new UI works, this is also a great opportunity to refactor all this code over to the InputMaster class. (it didn't exists when the old UI code was created)
Redoing all the UI code and wiring it up was pretty repetitive work, it took an hour or two, to finish,
Next step is to make the walls actually have variable height, this turned out to be way simpler than I thought - lucky I over engineered it when I first created it!
I changed around some of the constants to work with the new per-wall math, instead of using a constant "wallHeight" for everything I used the new height(that is on the wall) multiplied a constant "wallStepHeight".
Then it was just a simple matter of copy-pasting(only made four errors!) the new math where the old constant value was in the triangulation code, and it actually worked!
I made some other changes like disallowing gateways on wall lower then a height of six units, the gates are still a constant height, I'm thinking of maybe changing it a bit later on - maybe big entities can't pass though the small gate? we'll see.

Oh, and texturing them might be a good idea also - totally planned on it and forgot.
We can just pretend it's a very good whitewash for now. 😳

Anyway, here's a screenshot of the finished product, you can see an arrow pointing to the selected wall segment, the outer part of the inspector is rotating to match the actual orientation but the center doesn't spin.




I'll be working on a showcase video soon, so come back for more!
Thanks for reading.

Friday, March 19, 2021

Creating the climate simulation

Developing this system was quite the journey, I've been working on it for a few months now and I'm still ironing it out, but it's finished for the most part.

Right now I'm simulation surface water, ground water, clouds, salt/mineral, wind, air temperature and ground temperature.
But I didn't start with all that, at first I was afraid I couldn't make the climate simulation fast enough to be simulated during the game - so I designed it so the climate will be simulated in the map editor and remain static during the actual gameplay.

I started with generating a humidity map and a salinity map for the map, I based it on procedural noise and started adding stuff to it, the main thing I did was go over each hex and if it's part of a waterbody or a river I made it increase the humidity value of the nearby area, to get some intelligent results I ran a D* algorithm on the map (using the A* grid I use for navigation) from each hex to get the hexes it effects and the travel distance to each hex, I made going up in elevation very expensive and going down to be very cheap - that gave me quite the decent flood plane.

Building on that I did the same for the salt map, only using different values for how far it reaches and how strong it is.
I gave the waterbodies a bool for fresh or salty and if the hex is part of a waterbody marked as salty or part of a river coming out of a salty waterbody it's gonna run the algorithm and add salt to whatever it reaches.



That was the basis for the climate, I knew it wasn't good yet, but couldn't think of any way to improve it.. one thing that got my attention is Catlike again, in his tutorial he's simulating a water cycle to paint the terrain pretty much like I wanted to do (and other stuff not relevant to me, but go check him out if your interested in that), I started doing the same but made some changes to the water movement logic.

Right now I had humidity and salinity, I added clouds too to bring it into line with Catlike.
I started playing around with it and it became clearer and clearer that one major thing missing in my sim is wind, so I started looking into ways to do that.

In Catlike's tutorial what he's doing is deciding on a global wind angle that is perfectly aligned to one of the six hexagonal directions (0, 60, 120, 180, 240, 300) and have a constant global strength, I did not like that part at all. (not to trash Catlike or anything, the tutorial is excellent - just not what I need here)

I wanted to make the wind more organic, simulate that too so it'll appear to have some validity to the terrain.
I looked for tutorials, libraries, or anything to help me out with this - nothing fruitful came up on my radar, so I started creating math for this.. (oh geez!)

I need ways to represent both angle and strength separately, and I wanted both of them to be normalized to a 0-1 range so I can later use them however I want.
I need to be able to know what hex neighbors a given direction is pointing towards and the ratios between them (a direction can point at only 2 hex edges at a time)
I need to know how the terrain effects the wind.
And I need a way to add/move the wind from one hex to another - how the hell do you that that with straight up angles? let's just create a function that converts an angle to a vector and do some simple and familiar vector math.

This surprisingly took a shorter time than I thought, I got it down in 3 days, but my brain was done for, math is not my strongest side, had to take some time off to recover mentally.

Coming back to it I started creating the wind simulation, what I did is generate the wind before the water cycle starts, and it was then used as conveyor belt for the clouds.
Finally the clouds aren't just hanging around water, they started to be effected by the wind - major improvement.



One other thing that was annoying me is the water flow, at this point humidity was pretty close to what's on Catlike's tutorial, it evaporates into clouds (and precipitate back), flows to neighbors (faster if they are lower elevation, slower if they are higher elevation) and carries salt when it flows (leaving it behind when evaporating).

That made all of the hexes that have a neighbor lower than them significantly drier than the surrounding environment.
I tried playing around with the values for way too long and no combination gave me the results I wanted.
I tried blurring the final map, created an algorithm that does gaussian-style blur on a hex texture, but that only took care of around 30% of the problem... oh well, at least I got that blur thingy, that'll be useful sometime.

The solution I came up with is to separate humidity into two "layers", surface water and ground water.
Surface water takes the role humidity currently plays, moves exactly the same way, evaporates (and receive precipitation) and carries salt.
Ground water acts as a capacitor of sorts, they flows to rules very similar to that of the surface water but much slower and they do not evaporate or carry salt.
The way they interact with each other is by osmosis, they try and reach a "biased equilibrium" ( 20% surface and 60% ground is "equal", for example - ratio is editable)

That worked great, made the water cycle much more stable.
At this point I started working on other stuff, like the building system and plant system, but they'll get their own development post, this one is about the climate.

After playing around with the climate system for a while I saw that it wasn't good enough..
The way you create terrain, generate wind and then water+salt works in a very unfriendly way to the user, and while that is part of the map editor - I still want as much people as possible to use it.
But the biggest issue I have with this whole system is that it's static, nothing you do in game has any effect of the climate, and that was part of the point to the game - sure, the plant and animal system are much more prevailing here gameplay-wise, but the climate itself is an integral part of the whole environment.
If you terraform field into a mound and build a castle wall over it, it should have implications to the climate in the long run, and it's just not feasible to run the climate baking algorithm every time there is a change to the map, it also means that every changes takes effect instantly - that's not gonna do at all!

After doing some thinking, I decided to make the climate dynamic in game.
This was a risky step to take, I wasn't sure at all I could pull it off in it's current state and I still had stuff I wanted to add to this system - but without this I don't think the game can be what I want it to be, so time to be a little crazy with my decision making!
I made some big changes to how the algorithm works, I tore the wind logic and the water/salt cycle logic out of their separate functions and created a new system that alternates between iterating both of them.
I don't mean to make it sound easy, it took a couple days to figure out how to structure it and then debug all the new errors.

The magic number I came up with for one whole iteration time is 37.5 seconds(on X1 game speed), a game day is 900 seconds long, and the climate ticks one time each game hour (900/24=37.5).
Now that's all fine and lovely - but how much does the climate simulation actually take? well, it's not that simple.. that depends both on the hardware it's running on and the map size, and we're still not done with adding stuff so I'll get into some actual numbers later on this post. (spoiler alert - we're good to go!)



Okay, so by this point I've got a climate system I'm happy with, it solved all the previously mentioned problems.
Players no longer need to fiddle around with 2 messy "baking" systems in the map editor - they just unpause the game time(or hit a button that simulates as fast as possible to get a new map to simulate quickly), and now if you do any sort of terraforming, build big buildings, consume or dump significant amounts of water/salt into the simulation you're gonna effect the whole climate, and it's gonna slowly work its way to accommodate changes, one iteration after another.

And to top it off it made the visuals much nicer - on the previous version both the wind and the clouds were static during gameplay, now both of them move and change over time, creating some great organic visual effects, I just need to find a better way to draw them, right now I'm just drawing a white hexagon with the GL library above each hex with alpha(transparency) by the cloud value, and that's fine, but it could be much nicer.
One thing I'm considering is sticking to my current style but give the clouds some serious geometry.
Another thing I want to experiment with is creating volumetric fog to visualize the clouds, but doing that kind of stuff is not my strongest side... best to hold off on that for now.



Now, the only thing that is missing is temperature, temperature plays a quite the role in the simulation and it's split to 2 layers in a similar way to water, air temperature and ground temperature.
High temperature increase evaporation rate, low temperature decreases evaporation rate.
Evaporation causes cooling, precipitation causes heating.
Freezing ground temperatures stops water from moving, trapping water on cold mountain tops.
Air temperature difference creates wind, wind carries air temperature just like clouds.
Ground temperature moves with ground water movement.
Osmosis happens between air and ground, like surface and ground water but this time it's a true equilibrium regarding the levels but the ground has much more thermal capacity - one hex with 100% ground temperature has the same "kinetic energy" as 42(by default, editable) hexes with 100% air temperature.
So if a hex is subject only to osmosis, ground temperature is at 100% and air temperature is at 0%, they won't meet at 50%, they'll meet at around 98%, if ground is at 0 and air is at 100 they'll meet at around 2%.

This addition was the final piece of the climate puzzle, now all that's left is to fine-tune and optimize it.

This is around when I started recording my development, I made a little video showing how the air temperature and wind interact.
It's a hydrothermal vent in an empty world, so you see a central point that is being heated.
You can see it on youtube



The major problem I encountered is salt taking over everything in certain maps..
Let me explain more clearly, the way water and salt enters the system is though the waterbodies, they add surface water and salt directly to the simulation, if a waterbody is fresh and not salty it removes from the simulation.
If we're trying to simulate a map with a large shoreline what ends up happening is the shore just keeps getting bigger and bigger, eventually taking over the whole map, I had to find someway to control it.
The first thing I tried was making the salt decay over time, that did the job, but created another problem - salt planes started disappearing (how did I not see this coming?).
After a little think what I came up with is to destroy a little salt when clouds precipitate(rain) - shores are always gonna have some amount of precipitation, even if the wind is blowing directly from inland out to sea 99% of the time, and a dry salt plane doesn't get rain so it won't get bothered.

I've made a few timelapses of a the simulation at this point, and you can see the difference visually.
Version 1 - when salt was just destroyed over time
Version 2 - removed salt destruction over time & changed how clouds are rendered
Version 3 - continuing the map from version 2, rain is now destroying salt.



About the terrain textures, they indicate the climate conditions.
it goes from sand to earth to grass based on water, high salt levels move it back to sand.
it's combined with a rock texture based on the terrain hardness, soft (no rock), medium ( 1/3 rock) and hard ( 2/3 rock)
if temperature is low enough and there is enough ground water you get snow on top of the texture.

You can see a video showcase of all different texture on youtube



About the iteration times, like I've said it depends both on the hardware and on the map.
This currently runs on the CPU, but I'm planning on doing all this work on the GPU once I figure out compute shaders, that should improve time significantly.
On the map side it depends mainly on the map size but the terrain complexity also plays a role here.
The numbers listed here are on my machine (intel i-7 7700K) and are for "worst case" map (highest complexity), and I'll also take this opportunity to list the map sizes I have planned.

Mini (35x35) - 700ms
Small (50x50) - 1800ms
Medium (70x70) - 3600ms
Large (100x100) - 7300ms
XLarge (135x135) - 13000ms

Those would be the common map sizes, but you can do any size you want and you can use different sizes for each axis (75x110, for example)

Creating a smaller map (10x10-20x20) can be useful to play with the climate values and see it iterate fast before starting it up on a big map.

Creating bigger maps is possible but requires a lot of RAM, the limit for 4GB is around 50x50, for 8GB is around 80x80 and for 16GB is around 140x140
I can't say for more RAM seeing as I only have 16GB.
Those aren't exact numbers either, seeing as not all the system ram is available to me and I need to also do other stuff with it, I was able to create a 200x200 map on my 16GB machine, but I had to drop the draw distance all the way down and it crashed after trying to generate the other stuff on the world (plants, animals, buildings)

And like I've said before - my target iteration time is 37.5 seconds (37500ms) on 1X game speed, judging from these numbers the available game speed in the world can be up to X10 on stronger machines and smaller maps, and at least X2/3 on weaker machines and bigger maps.
I think that's perfectly acceptable.



And that's about it for now..
Wow, this post is way longer than I thought it would be, thank you for reading!

Thursday, March 18, 2021

First Steps: Creating the terrain and wall systems

The first step in creating the game was the terrain, I went through a fair amount of trying stuff out myself, I good some decent results but they didn't work the way I needed them to work for the game.

One thing I experimented with is shallow water equations (that's how they implemented the water system is Cities: Skyline) with all kinds of erosions and tectonics.
rocky terrain rises from the fractures and erodes into sand the water can carry, it was very cool and I planned soil to be generated from organic decomposition - but it didn't go with the well with the rest of the design and didn't scale to the map sizes I need... just too much for me, let's save that one for Hex Hold 2 ;)

Finally I decided on using Catlike Coding's Hex Map tutorial.
The terrain, water and river mesh triangulation code is pretty much what is featured in Catlike's tutorial, changes I made to them are very minor.
I created my own chunk/batching system, and used Amit Patel's hex guide for all the hex related math, coordinate system and etc.

What I changed on the visual side is the textures and the terrain shader - I added specular, smoothness and AO textures.
Also tried adding normal maps, but it didn't go well with the aesthetics.

The terrain textures reflect the state of the climate, you can think of them having 3 layers.
the bottom is the rock layer, it shows the terrain hardness, terrain can be either soft (showing no rock), medium ( 1/3 of the texture is rock) or hard ( 2/3 of the texture is rock)
the middle layer is the main layer, it goes from sand-earth-grass depending on the total humidity (ground and surface water) and salt levels (I need to add temperature here too)
the top layer is snow, it comes in 4 levels (none, light, medium, heavy) and it shows when it's cold and wet enough (ground temperature and ground water)


You can see a video of all different terrain textures on youtube



After the terrain system was completed I began work on the castle walls, I wanted something similar to the walls in stronghold, the requirements I came up with are:

  • each wall segment takes a full cell

  • can connect to neighboring segments and to special buildings

  • can be made into a gatehouse and have stairs 

  • can have battlements: crenellations, machicolations and murderholes

Creating a system that does all of this wasn't trivial(at least for me), I spend about 2 weeks figuring out how to triangulate and implement it, here are some of the sketches I made during that time:




Pen & paper? where'd I get such ancient technology? anyway, you can see a video of the wall system in game on youtube


And that's how the game started to materialize..
Thanks for reading, if you have any questions feel free to ask.

Sunday, March 14, 2021

What (TF) is... - Hex Hold?

Hex Hold is a medieval themed city builder-RTS hybrid set in a dynamic environment, in this introductory post I'll briefly go over all of the major elements in the game, so without wasting any more time..


  • The main focus of the game is the city builder aspect, you play as the ruler of a faction from a "bird-eye" view and you need to make sure you and your kingdom survive though out the ages.

  • The RTS comes into play in that you can meet other (AI) factions in the game, faction to faction interaction include (but are not limited to) resource trading, citizen immigration/emigration, and of course.. war. and alliances, probably.

  • The "environment" (climate, plants and wildlife) is completely dynamic and your actions can effect all it's aspects and come back to bite you in the butt, when expanding you will have to consider more then just strategic location but this also creates the option to utilize the climate in war, kill all the prey near your enemy to cut down his food supplies and send nearby predators to find the only prey is his citizens, plant some useless and aggressive plants around him to overgrow the local plants and wreak havoc on the ecosystem, geoengineer the map(by building a dam or whatever) to flood your opponent into a swamp or dry him up to a desert.

  • Climate system include surface/ground water, clouds, salt/minerals, ground/air temperature and wind.

  • Plant grow, spread and die, they depend on the climate system to flourish, factions harvest for food and materials, herbivore wildlife eats plants.

  • Animals live in the world, eat plants or hunt other entities(animals or faction units like citizens or soldiers), reproduce and die, factions can hunt animals for food and materials

  • You do not have direct control of your citizens but can influence their actions and behavior in many ways like laws, regulations, healthcare, education, work, housing, entertainment, etc.

  • You have direct control over military units, move here, guard this, attack that - you know, the usual RTS stuff.

  • You build your kingdom by placing build orders, citizens working in construction will proceed to carry out the build itself. (prepare ground, collect resources, build building)

  • Production chains will be quite complex, but will be easy to automate if you're not into micromanagement, you just just request an end product and your citizens will create it (provided you gave them some access to all the requirements)

There is much more to the game and each element, all will have their own dedicated post soon, thanks for reading and check back for more!