A New Game Engine

Engine
Photo by Garett Mizunaka / Unsplash

In my GMTK 2025 Game Jam Retrospective I mentioned that I had started my own game engine. Today I wanted to talk a little bit about how that came to be and where it stands today.

Where it started

This is mostly a summary of where this engine project started. I have been interested in game development since I learned to code in high school, which somehow was almost 13 years ago.

Peeking through the abstractions

One of the most valuable things I learned in my undergrad education was how much it pays to understand at least one layer of abstraction underneath what you're using. For example, in my day job I build web services. You don't need to know how your platform's runtime manages memory or how your ORM translates queries to SQL to build a functional website. But knowing how to efficiently manage those resources can be the difference in thousands of dollars per year in hosting costs - especially in the public cloud.

In 2022 I was developing games off and on using the Unity engine. A little after Thanksgiving that year, I bought a copy of Game Engine Architecture. This book is 1,240 pages and is one of the thickest books on my shelf. I wanted to learn about what Unity was doing for me, in the hopes that it would make me a better game programmer. Over Christmastime I read that book from beginning to end. In case it's not obvious: game engines are complex. Producing 60 frames per second only gives you 16.6 milliseconds to process input, update the game state, and issue commands to peripherals (e.g. to render graphics, send data over a network, play audio). Luckily, computers are fast! A simple simulation can run a thousand frames per second. Most games built today aren't AAA games - they're indie games with relatively modest requirements.

High Performance C#

I learned to code in C# in high school. Throughout my career, I have somehow been able to use C# daily. For more than 10 years! C# and .NET have been through a lot in those 10 years. No one would have called C# a high performance language back then. That reputation has unfortunately stuck with it. However, since the .NET Core days, performance has really taken center stage. There has been significant progress: from new APIs allowing more careful memory management (such as Span<T> and friends), through runtime improvement in the JIT, PGO, and the garbage collector. As more performant APIs get added, the .NET team updates code in the framework to use them. When updating .NET versions it's not at all uncommon to see graphs like this:

From https://devblogs.microsoft.com/dotnet/bing-on-dotnet-8-the-impact-of-dynamic-pgo/ by Ben Watson

I've been looking for a reason to learn more about writing high performance C#. In my job, it usually isn't needed because optimizing a SQL query gives orders of magnitude more performance improvement than shaving a few instructions off of a loop. Of course there are exceptions to that rule – for example, when I wrote an optimized standards-compliant iCal serializer – so it's nice to have an easy toolkit to dip into.

To summarize for my own game engine, being able to write it in C# has a few advantages:

  1. It's a language I'm familiar and productive with, and one that learning more about can help my career.
  2. There's a rich ecosystem of libraries I can lean on. Microbenchmarks? Check. Unit test framework? Check. Graphics library bindings? Check.
  3. There's support for multi-platform development. I knew I would be developing on Linux, but most people that would actually play my games would be on Windows.
  4. I can start with horribly inefficient code and optimize as needed.

Other Game Engines

I have built games with both Unity and Godot. Both of them are capable of producing good games, no doubt about it. I initially stopped using Unity for a combination of reasons (licensing controversy, certain controversial acquisitions, and my general disagreement with how the business operates). Godot was much more my speed: both by being open source and the interface.

Both have the same shortcoming for me: C#, and code in general, isn't really treated as a first class citizen. Godot doesn't include C# support in the main distribution. In both you are mostly writing scripts that get attached to nodes. It's a perfectly valid and effective way to build a game. For someone who is used to writing full programs though, it feels... awkward and clumsy.

I also should mention open source C# game engines. There are a variety of them in their different stages of development. Of the ones I've seen, none really met what I was looking for (though Prowl comes close!).

Engine wishlist

Here are the guiding principles I'm using for my engine:

  1. No native (C++) dependencies except for what is required to interface with the OS (for example for windowing, GPU, and audio).
  2. The engine and game code needs to be unit testable.
  3. Code first.
  4. Cross-platform.
  5. Avoid dependencies.

Mostly I'm tying to develop an engine where games are built more like a modern software project.

Why take on an engine project?

Most people would tell you that if your goal is to build games, building an engine is a terrible way to go about it. You'll be much more productive using an established engine. I would 1,000% agree with that. Luckily for me, producing a finished game project isn't what is fun for me. I much prefer working on the nuts and bolts.

My day job is way more management than authoring code. That can be a problem for me because writing code is why I got into software development. So I like to code on my "off" hours just simply because it's something I enjoy doing. Games (and engines) provide a rich set of options to work on! If I get bored or frustrated with a certain component, I can usually put it down and work on something else.

What it can do today

Very, very little.

At a high level: it can render 2D sprites, run C# code for managing game objects, set some camera parameters, and process inputs. There's a simplistic UI layer that can't accept input and there are hand-built logging and dependency injection systems. But! It does all of that using code that I wrote, which feels good.