Double Abstraction in Game Programming
Published: 2025-08-31
If nobody got you, jaydenpb.net reading music got you.
Preface: Nobody cares about how your game was made
And itâs hard for them to. Non artists and non musicians can listen to music and look at art and appreciate them, they might not have the vocabulary or taste someone skilled in the trade would, but they can derive some enjoyment or assessment of quality out of it. Not only is programming generally invisible, either being compiled directly into machine code or requiring some kind of disassembler to re-create, it also requires the person to have the domain knowledge of programming to understand it. People are usually only able to judge software quality based on if it runs on their platform of choice and how good it is at that compared to other games that appear to do similar things.
The ideal of game programming is simply acting as an invisible interface between a userâs computerâs multimedia input and output, any consideration of the way a game was constructed manifesting itself as hitches that break the illusion of seamless connectivity from the users controller to their monitor.
It can be disheartening to remember that your work is at itâs best when the user forgets itâs there at all, but If nobody cares about how your game was made, it can be made however youâd like. Conveniently itâs also never been easier to make a video game.
Noel Berry recently released a blog post about his workflow for modern C# game development, opting to use more âhandmadeâ tools like SDL3. He argues the benefits of making games without a large prebuilt engine, ending with:
âDo I think you should make games without a big engine? My answer is: If it sounds fun.
Inspired by this I set out to make games in a similar fashion (Raylib being my library of choice), and surprising nobody, Iâve found it to be incredibly fun. Recently made a puzzle game with a friend for this yearâs GMTK Game Jam.
Double abstraction
As someone who only ever knew game development within large engines, it gives you the impression that itâs the only reasonable approach to making games. Games are complex beasts, before Unity released the only other method of making games had to have been to take up an apprenticeship under one of those old guys with gray beards who can open up a text file, type assembly instructions, and have RollerCoaster Tycoon comes out the other side.
A very common piece of advice you hear is âDonât make an engine if youâre interested in making gamesâ. Sound advice, but I still take some issue with it. The words we use to describe the tool we use to make games with is confusing.
When we use the phrase âgame engineâ we think of an engine, as in: the core that manages/runs a game we build around it. This isnât a sound analogy, we have the game engine itself sure, but itâs abstract, (most) engines arenât designed for any specific genre or mechanics. We still need to use the capabilities of the engineâs API to build the specific engine that powers our game-play.
This gives us two layers of abstraction before we get to making things people can actually play: The abstract âimplementationâ layer that we build or engine in, and the specific abstract âengineâ layer we write. Afterwards we make the specific game-play content within our engine (levels, items, enemies etc). This is what I consider the âdouble abstractionâ of game engines.
When people use the phrase âgame engineâ, they tend to conflate the two layers with each other. âEngine-lessâ game development would then be like building a car without an engine (Soapbox cars donât count, their engine is gravity). Games canât exist without engines, something needs to facilitate the game-play happening.
The important distinction between using an engine and not using an engine is if the tools youâre using to build your game with are reusable or bespoke. When people hear the phrase âengine-lessâ development, they think of us making our own âfirst layerâ, a similar reusable abstract implementation interface that could implement any kind of video game. Us toiling away in a cave recreating a worse version of Unity. This is generally regarded as a Bad Idea and is what that that advice I quoted earlier is trying to stop you from doing, as building an abstract engine first gives you generic functionality that has solved no tangible problems and isnât particularly useful to anyone.
But nobody is still (well, Iâm sure someone is) is making games by writing assembly instructions in a text file. Even âengine-lessâ development relies on some kind of abstraction layer. So when does whatever youâre using to implement your game engine cross the threshold from game âframeworkâ or âlibraryâ into full blown âengineâ?
What is a game engine?
Everyone seems to have an arbitrary cut off point for what they consider a âGame Engineâ to be. A game engine or ânon engine-lessâ development has you build your games within a managed, usually pre-compiled, application. Everything you include (code, sprites, sounds) are assets that are interpreted by the engine and executed by in a managed runtime. This includes helpful features like automatic threading/parallelization of your code, a scene system, a gui to arrange assets within, and automatically building/exporting your game for target platforms. Most modern games development happens in software like these.
âEnginelessâ development is usually done within a Game âframeworkâ. These are regular âol software libraries that you import into your favorite programming language, and provides you an unopinionated api for implementing game related functionality. Generally things like input, audio, rendering, and window management. How you manage your gameâs code and call these functions is your responsibility.
To put that in significantly less words: Did you write the game loop yourself? If yes, you made an engine, if no, you used an engine.
Why donât we just implement our games code directly anymore? (how did we get here)
But back when engine programmers and game programmers werenât different roles, there was no âabstract implementation interfaceâ built for the game, the gameâs systems were the engine, games were simpler, computers were simpler, and there simply wasnât that much room for abstraction in 64kb of RAM. Games originally were just written in assembly directly targeting the target computerâs CPU, no 30 million lines in between.
Imagine instead of picking your operating system from your boot menu, you could boot into⊠Fortnite. Console development is still quite similar to embedded systems, with strict hardware requirements and different architectures on single board computers. But Iâve never written a console port so Iâm super unqualified to talk about that (as opposed to the usual amount of unqualified I am on topics I talk about).
Idtech: the first âgame engineâ
Idtech1 was the first popular âabstracted engine and specific game-play contentâ game engine, with the separation between the engine (source ports) and the .wad files that ran the game. The games engine code was separate from the game-play âassetsâ that were loaded in. But thereâs still only two layers compared to the 3 of today. Idtech wasnât a general purpose abstract api either, it was designed only for doom levels. You can use abstract implementation layers of today to create doom source port engines, someone made one with Godot for example.
GPU drivers
GPU drivers (DirectX, Vulkan, Metalđ„, OpenGL) made it so people didnât need to write code targeting specific GPUs, GPU manufacturers would simply support specific APIs in their cardâs firmware. This made your code exponentially more portable. itâs like the java virtual machine but for graphics programming
Renderware: the first abstract implementation layer
Renderware was a reusable graphics and rendering abstraction api that was supported on major 6th generation consoles as well as DirectX and OpenGL for computers. It was one of the first popular commercial licensed set of âabstract implementation toolsâ that was mass adopted across the industry, but resembles a game framework much more than a modern large game engine. Renderwareâs capabilities are actually quite interesting, and relevant documentation and whitepapers about the engine are available on EAâs github if you feel like skimming through it and learning about what game programmers were using in the early 00âs.
With Renderware being bought out and killed by EA, having itâs market share overtaken by Unreal we start to transition into where we find ourselves today.
Where we are today
Game development started getting complicated, and that led to it getting expensive, fast. Investing in an engine before making the game that would see the return on said investments started to become too much money for large AAA companies to front-load, so it made more sense to outsource that work to an engine development company that focused on abstract reusable feature sets and portability, along with a GUI to promote interdisciplinary development with non-technical team members.
Unity and Unreal are the result of that that, third party licenced software that you can build your game within, and build your game within their application. The industry took to them, and gave them a monopoly on game engineering.
Controversial opinion I know, but Iâm not a fan of this monopoly. There are obviously issues with leaving the implementation of your software to separate companies whoâs goals and visions could not be (and usually arenât) aligned with yours, we need no reminder of how that trust has been challenged recently.
But another issue is that Unity, Unreal, and other large engines are especially thick, opinionated standard layers for people to build their games within. I already mentioned the 30 million line problem (yeah I watched handmade hero, fat structs! Hawaiian t-shirts!) but in general, software is becoming increasingly and unnecessarily complicated. Itâs getting harder to understand how the code you write is compiled and executed by your computer. You could have a perfectly accurate mental model of how the computer system you were programming for in the 90s worked simply because there werenât that many moving parts and the interfaces we used to talk to computers were much simpler. Unity is like GPU abstraction but over every aspect of your game.
Itâs a well engineered abstraction layer, and if you need exactly what itâs offering then itâll work out great for you, but itâs lead to a decline in people considering the things their specific game needs, and simply opting in for whatever is within the large âdo everythingâ engine theyâre using. Abstraction isnât inherently bad, GPU drivers are good (in concept), but simplicity is a tremendously valuable resource, and a lot of modern programming is about abstracting for things that we have specific information on, making us prepare for use cases or that wonât exist or running on platforms it wonât.
Godot the anomaly
Godot being open source but feature comparable to large commercial engines could help with creating a base engine that other companies can build upon to make separate abstract implementation layers for their games, similar to how Linux was adopted over licencing windows server software. A base extendable abstract implementation layer for building your company specific abstract implementation layer⊠were 4 layers deep baby!
This does solve the issue of having your systems be built within a âBlack Boxâ. Godot is what Iâd describe as an âopaque boxâ. Itâs free and open source but itâs precompiled, peeking into and modifying the source code is very separate thing from downloading and using the engine. It is very nice to be able to hit gd on my keyboard (I use neovim btw) and to to the implementation of a function, and itâs something I miss in Godot. But when Iâm looking to use a large engine for a project Godot is always what Iâll reach for.
Complicated games are complicated
âDouble Abstractionâ get us to think about our games very abstractly. Abstraction is complex and simplicity is a scarce resource in programming. Game engine development is all about creating reusable components while Game development is all about implementing concrete requirements.
Game development is also a eclectic process, no two games have exactly the same needs. Itâs important for us as developers to think about the requirements of our specific game and the resources we have to put it together. Game development can be much simpler and arguably more enjoyable if we simply try to only use the things we need.
- If your game is 2d, you donât need a 3d renderer!
- Your game isnât targeting consoles? you can use OpenGL.
- If I need big prestige AAA graphics, I know I can reach for Unreal.
- If your programmers are also your game designers then you donât need a scripting language (unless you canât implement hot reloading and compile times are unproductively slow).
Itâs not about making everything yourself, or not using large engines. Itâs about considering what you need and picking the best tools that will accomplish that. Large general purpose engines werenât designed with a specific game in mind, so you need to build your games engine within their engine (double abstraction).
If Iâm making a platformer with simple AABB collision detection, it would probably make for a simpler developer experience to write a tiny âphysicsâ library myself that just handles those things. If Iâm making a game that requires nuanced physics interactions then I can always reach for a library like Box2d, and drop that into my project.
But Iâm just a hobbyist who like interfacing with their tools in very specific ways, enjoys the freedom of organizing things as I wish, and fostering holistic understandings of software systems. You make games for yourself first (when itâs not your job at least). Use whatever languages libraries or engines you enjoy working in the most. If you find yourself fighting against or having to re-implement your tools to suit your fancy, consider trying something else, something simpler perhaps.
An argument for getting lower
Using simpler tools gives you more exposure and understanding to fundamental game programming concepts, things like sequencing patterns, vertex buffers, rendering frames⊠that can be used irrespective of specific tools. Youâll get to apply the things past section 1 of game programming patterns. Imagine a large tree (the data structure not the plant) with nodes of software tools/libraries/engines. The more âhandmadeâ/simple of a tool you use, the closer to the root you are. The closer to the root you are the more flexibility you have, flexibility in how you solve your problems and model your data.
If you only know React, then any web development tools you use would have to be react or something that uses react, learning HTML/CSS/Javascript gives you the ability to write those directly or use anything that is based on those, which includes react if thatâs what you decide is best for the project!
Going lower gives you knowledge, and that knowledge gives you freedom, freedom to understand problems and potentially make better solutions.
I donât want the take away from this post to be âGodot became too popular for Jayden so now he has to use more niche toolsâ, The point is that engineless development isnât as scary as a lot of of mightâve thought, and you should consider trying to make games with simpler tools to see if you enjoy it. But if you really like the current workflow you have and donât feel any need to change then thatâs fine! Use what you enjoy.