I liked the way the first stages of project Hex turned out. While a few people had artistic criticisms of it, the idea and the implementation were solid. I want to try the same thing, only making a more conventional first-person style engine. This is far more ambitious. Here are my new goals:
- Use the established pixelated, quasi-8-bit graphics.
- The world should be vast. Maybe not Minecraft “bigger than the actual Earth” sort of vast, but big. Basically, I want to be free to adjust the size of the world based on what seems “fun”. Maybe this will be Fuel-sized. Maybe smaller. But I need to design this engine with the idea that it should be able to handle lots and lots of data in bulk.
- Procedurally generated world. Because that’s my thing.
- Variety. I don’t want ten thousand square miles of same-y terrain. Lots of different lighting, coloring, texturing, topography, etc.
- Decent view distance. The world should feel vast.
- Should run acceptably on old hardware. (For now, this just means keeping the GPU, CPU, and memory usage low. Whether it actually runs well on old hardware is another matter, but I want to make sure I don’t cut off low-end machines by design.)
- It should be as platform-agnostic as possible. Okay, I’m working in Microsoft Visual Studio 2010, so this is Windows native. But I don’t want to load up the guts of my engine with Microsoft-specific code. I’ll be using SDL, and OpenGL.
This is much too ambitious. It’s a starry-eyed pipe dream, doomed to failure. Let’s get started.
I spend the first couple of hours ripping the hex-based logic out of project hex and building it up again based on square grids. I also rip out the cheapo RTS-style camera and replace it with a proper “flycam”.
You know, I don’t like to add visual gloss until I have the underlying system working right, but right now it’s hard to see the topography. So, I drop in some basic lighting. Note that this is using the standard OpenGL lighting model, nothing fancy. I have no idea how my lighting system will work long term, but this is good enough for now. (See this post for a bit about what I might have to deal with if I decide to make my own lighting system.)
It seems to have lost a great deal of its charm in the move from overhead hex map to where we are now. It’s less cartoon-ish and vibrant. We can worry about that later. Note that my hills are now generated by sine waves. Those suck. Let’s fix that.
First up, I import a few blobs of hill-types smears that I doodled by hand:
Compared to the sine wave hills, these are
much better still completely awful. Hills are not shaped like noise. Hills are not usually shaped like domes. (Unless they are small or man-made.) On any kind of respectable scale, erosion has its way with the land and the sides of hills end up shaped sort of like tree roots. It will have arms that reach out, with steeper sections between them.
The easiest way to achieve this is to run an erosion simulation on it. No, really. Erosion simulation. Just a bit. What you do is this:
- Pass over the map one “pixel” at a time, performing the following process on each space:
- Drop an imaginary water droplet onto the current space.
- Now look around, and see which of the neighboring spaces is lowest. Move the droplet to that space.
- Every time the droplet moves, chip a bit of elevation away from where it was.
- Once the droplet arrives at a space where it can no longer move down, abandon it and drop the next one. Repeat until you’ve passed over the entire map.
There’s a quality vs. performance cost associated here. It’s better to pass over the map many times, taking only a slight bit of land away with each pass. But if you’re in a hurry, you can run over the whole thing just once and take a bigger chunk away. The land ends up looking a little “jaggy” when you do this. The slow way gives much more realistic erosion shapes.
Simple. Cheap. I’ve done this sort of thing before, and I can say that erosion systems are very prone to oversimulation. You CAN write one that takes into account sediment, and the different ways in which rock and dirt erode, and the effect of flowing water on steep slopes as opposed to gradual ones. Likely as not, it will be tough to balance those behaviors well enough to produce useful results, but if you DO manage it, you’ll end up with geography that looks 10% better than the cheapo system I outlined above. If all you need is a bit of topography that can look presentable, then there’s no reason to waste your time and CPU making a deep simulation.
Eh. Better than a poke in the eye. The world is still set to a (small) fixed size. It loads up all the data at startup, and displays a fixed-size world. Next time we’ll add paging so it can build the world as we go. And maybe do something about it being so dang ugly.