A new engine

November 2024

This month, I've ported a large part of the codebase to c++. So far, the game is functional up to and including the pond manipulation mechanics. The DNA system has also been ported, and I'm currently working on implementing the koi again.

Digging
Digging

To get this far, most of the basic components of the engine had to be ported first, and I've been able to make a lot of improvements under the hood that will be used by all future additions.

One of the first things I had to port was the multithreading system. The Javascript prototype used multithreading for specific workloads, like generating koi and pond models, and there isn't much more you can do with Javascript. One of the big advantages of using C++ is that you can implement threading wherever you want, although synchronization quickly becomes an issue. I've designed a system that separates game state updates and frame rendering, which is pretty standard in game engines, although it's almost impossible to do well in Javascript. Separating this means that game state updates can take longer than the time it takes to render a frame. The game state can update for example 40 times per second, while the game produces 60 frames per second. This has enormous performance benefits, because frames don't have to wait for an update to finish, which is a huge constraint on high refresh rate monitors. On a 240Hz monitor for example, a state update in Javascript wouldn't be able to take more than 1/240 of a second, which is practically impossible. I'm not sure what the standard of refresh rates will be when the game comes out, and I'm not really in touch with these developments since I'm still using 60Hz monitors, but I'm guessing 60Hz monitors will be a thing of the past soon if they aren't already. Especially the new beautiful OLED monitors have very high refresh rates.

The Javascript renderer was written for WebGPU. This API is available in C++, but it's limited, so I ported the renderer to the Vulkan API instead. This gives me access to all modern GPU features, which in practice means that the renderer uses the GPU much more efficiently. All GPU power that's not wasted can be used to render things at higher quality levels, and it allows for lower minimum specs if the rendering quality settings are lowered. It also means I can use features like tessellation and even ray tracing, if it ever makes sense to use them.

WebGPU has a limited feature set, which is understandable because it's designed to run on all browsers and on all devices. However, some very annoying limitations kept bothering me:

  • Leveraging the GPU for culling (not rendering things outside the view) was practically impossible. Because of this limitation, a lot of GPU power was wasted on rendering things that are not even in view.
  • Multithreading is too limited. GPU work can overlap a lot, model uploads can happen while the scene renders for example, but WebGPU does not expose these features.
  • While being much faster than WebGL (which Koi Farm 1 used), it still doesn't really facilitate rendering large batches of objects well.
  • Last but not least, it cannot be ported to consoles.

Because the algorithms now run in a more powerful language, they are significantly faster, and they use memory much more efficiently. One of the advantages of this is that I was able to drop the scene size limit, which means players can now make much larger koi gardens without sacrificing performance.

ImGui
A new debugging interface

Of course, Javascript wasn't all bad. It's very easy to prototype and iterate quickly, and the entire web rendering capabilities exist by default. I was able to create great debugging interfaces quickly, and I really need those for development. Unfortunately, there's no such thing in C++ by default, but the industry standard for this kind of thing is ImGui. It works within any Vulkan renderer, which I have, and allows me to create debug interfaces easily. After I get used to it, it may even take fewer lines of code than creating a web interface did.

Writing a game from scratch in C++ and Vulkan takes some effort, but I'm an artisan programmer and I have the time, so I might as well enjoy building things beautifully. I'm pleasantly surprised by the amount of work I was able to do in one month, and I'm optimistic about seeing C++ powered koi swimming around before the end of the year. By then, I won't be bothered by all the annoying performance limits that Javascript imposed on me, as well as a lack of language features that forced me to write code in awkward ways to keep things performant. This means I can make the game I want to make, rather than the game the technology allows me to make.