Calyros DevLog #1 - Creating a heightmap and unit testing
Published on
Hey you, and welcome to my first DevLog for the so-far unnamed multiplayer RPG I'm creating.
This is actually the fourth post I've written, but in the first three I spent a lot of time waffling about what I'm building and why - stuff you might not care about.
I thought a better introduction to this project would be to dive in to what I've been building.
Writing tests
When I started the project, I began by writing tests.
During my day job, I'm a software developer, so when I'm writing code I'm not very comfortable with, I know that writing tests first is a good approach.
The point of tests (for the non-coders) is to provide a way for you to know if your changes have broken anything. When you modify the code - if you've written them well - running your tests will tell you if you've broken anything.
In my case though, I'm just starting with Godot. Unfamiliarity meant that I was breaking things more often than not and I was spending way more time writing and fixing tests than I was learning about Godot's features.
So I stopped writing tests. I want to go back to them in the future, because it's a good way to ensure you deliver a robust product, but for now, they're getting the way of progress.
Creating a heightmap
After abandoning testing, I moved on to my next task.
Whatever else my game may or may not contain, I knew it needed a map. By this point I was pretty sure I wanted a point-and-click tile-based game and so generating the map should be simple, theoretically. I just need a grid of 1x1 squares.
Step one was to decide on the size of the game world I was going to generate. I feel fairly settled on a vaguely ancient-Greek themed world, so I opened up Google Maps and checked the size of the area I wanted to replicate. Greece is around 300 square kilometers.
Even now, I knew 300,000 kilometers is probably too many kilometers.
Like the fool I am, I divided it by 10 and thought "that's a much more realistic world size" and got to work on generating 30,000 tiles.
The concept is pretty simple. Moving from right to left, and from top to bottom in a grid, I needed to generate a "height" for each point.
The height of Olympus - the tallest mountain in Greece - is about 2,900 meters. I rounded it to 3,000. Since I divided the world size by 10, I could just divide the mountain size by 10 too. So the highest point on my map would be 300m. For simplicity, I decided the lowest point on my map would be -300m. That would mean a value of 0 and above were land and below 0 was sea.
But I wasn't generating 30,000 data points, was I? That would only be the width. For it to be square, I needed to generate 30,000 by 30,000 meters.
Which is... checks maths ...900 million data points, oof.
Even if I was able to store the each point on the map as a single byte - which would mean the minimum variation in height between two points would be 2.5m - I'd need to store 858MiB. Okay. So 30,000 by 30,000 was unrealistic.
So I looked up some game world sizes.
-
Skyrim is 24 square kilometers (really? I can run across it in 10 minutes).
-
World of Warcraft is supposed to be 142 square kilometers.
-
GTA V is 75 square km.
30 square kilometers was probably too many. But I noticed two things...
-
It doesn't matter how big your world is. Skyrim is the smallest of those examples, but it's packed with things to do and so it feels large.
-
Secondly, I'm not Bethesda or Rockstar. I couldn't make a world of that size feel alive if I wanted to.
So, I went back to the drawing board. I settled on 4 square kilometers this time, and got to work on my procedural generation code.
Now, as it turns out, using noise to generate 16 million data points takes a really long time. Especially if - like me - you're trying to do it in GDScript on the CPU.
I spent weeks doing this. Generate map. Write a tweak. Generate map. Write a tweak.
Finally, frustrated that I hadn't made any progress in the things that mattered and gave up, and I learnt my first lesson of amateur game development. Start small.
I moved the code I had written out of my project and settled on a 16 by 16 tile map. Small and achieveable.
Instead of trying to craft a whole world at once, I'm going to focus on building all of my functionality and features, and putting them in a small space - which I'm calling the "Pub Garden".
The time wasn't totally wasted though.
Lessons learnt
- Start small, focus on quality
- Procedural generation is hard
- Unit testing isn't going to work for me yet
Onwards and upwards
All of that time playing with procedural generation hadn't left me empty handed. I had generated and saved to disk a 16x16 meter heightmap. It had an altitude of about 10 meters and slightly bumpy "terrain".
Now that I had that heightmap though, I could turn my ambitions towards turning that into terrain.
For now though, I'll leave this post here.
~ Sam