Gamma Hollow - Devlog 1

Hello and welcome to my new weekly devlog series. Over the course of the coming months I'll be talking about the development progress of my new game Gamma Hollow. Let's get to it.

Gamma Hollow is (will be?) a colony simulation game, my unique take on games like Dwarf Fortress, RimWorld, Oxygen Not Included, and others. You play as an AI tasked with keeping a large bank of humans in stasis pods alive, a task which is complicated by a hostile environment on an unknown planet. Seeking shelter from the high-energy radiation the planet is bathed in, your ship has burrowed beneath the surface. However, you quickly realize that you are not the first to colonize this planet, and are about to face unexpected challenges...

It's the first week of development and I've already made good progress on getting the essentials up and running (although in fairness I wrote quite a bit of the code a couple weeks ago before I had formalized my effort on this project). The main issue that's been tackled is rendering of the world. Currently, worlds are 255x255 tiles in size, which means the game needs to handle rendering over 65 thousand tiles. To enable the best performance possible, the game pre-renders the world into a large texture buffer (as large as the system's graphics backend allows), which can then be drawn every frame. This means that rather than needing to render many many tiles per frame or implement complicated culling algorithms, the game can render all 65 thousand tiles at the same time with practically no cost to performance whatsoever, as it only takes a single SDL_RenderCopy() call per frame to draw the *entire world*. This rendering system also uses only static allocation, which ensures both that there are no memory leaks, and that if the game starts at all, it will never run out of memory. That being said, I will unfortunately need to make use of dynamic allocation later in development for other features. For now, this rendering code is not only hugely performant, but also working flawlessly...

...Or so I thought. My next major task was rewriting a portion of the rendering code to allow "connected tiles": Essentially, when there are two rock wall tiles next to each other, they should "connect" so that they look like one continuous block. In other words, the wall sprite isn't drawn if it's facing another wall. I encountered some issues with this, and after about an hour of debugging, discovered that the problem had nothing to do with my new connecting tile code. The bug was actually in the basic rendering code, which was (long story short) drawing tiles to the incorrect position. I hadn't noticed this as up until then the game was just rendering random tiles for testing purposes, and if you mix a bunch of random tiles they look, y'know, still random. Once I realized what the issue was, the connecting tile code worked flawlessly.

I also added some very basic terrain generation using OpenSimplex noise to create small caves in a world which is otherwise completely filled with solid rock, and improved my camera controller (which I had written earlier to provide basic camera movement for debugging) to be much more comfortable to use by adding a little bit of inertia and proper interpolation between frames. It also works using very few floating point operations, because as any good developer should know... floating points are evil!

The last thing I worked on this week was camera zoom functionality, and oh boy, was that an... experience. Getting basic zoom controls working was fairly easy, but there was a problem: it didn't look linear. What I mean by that is, when you were already zoomed in, scrolling the mouse wheel to zoom in more felt very slow, and when you were already zoomed out, scrolling the mouse wheel to zoom out more felt way too fast. Obviously I could just tweak values until it "felt right", but clearly there's a mathematical relationship here, and I can do it the proper way? Yes... but it cost me my sanity. Long story short, I'm bad at math, and if you ever need to make scrolling look linear, just do `size_multiplier = zoom^2`, where `zoom` is a value between 0 and 1.

Until next week. It's going to be fun.