what is to be done: custom engines and the death of unity
20230914
over a year ago i wrote a blog post like this the last time unity did something indefensible.
that blog post still has some useful information but i wanted to write an update to address changes in my own opinion and responses i’ve received.
i. against the big-box engines
by a huge margin, the most common response to the news of unity’s continual enshittification i see is the desire to learn godot or unreal engine. many of the people saying this learned to make games using unity (like i did) and have never substantially used a tool other than unity.
i refer to these sorts of tools as “big-box engines,” or sometimes as “black box engines,” though this specific term is more applicable to unity than it is to godot and unreal. the big box engine promises to be an all-in-one solution to the problem of video game development. it features a friendly graphical user interface to a wide range of tools such that, especially when you are just starting out, it seems as if any problem you have has already been solved.
this is, of course, a complete illusion. anyone who has used any of these tools to work on a complete commercial project will tell you how much of a lie that promise is.
video games are extremely complex software objects. each video game is unique and has unique requirements for tooling, graphics pipelines, input handling, architecture, etc. the goal of unity, unreal, godot, and similar engines is to provide a complete pipeline that will solve every conceivable problem in every conceivable type of game.
this is impossible, and has two key results. the first is that these engines are enormously complex. they are harder to use than tools designed for your specific use case. they also come with a huge variety of unavoidable strange bugs. anyone who has made games for a while in one of these engines can tell you about their project being derailed by a bug caused by doing the exact combination of things they want to do. and because these tools have so many users, fixing your bug is of unknown priority. in an open-source engine like godot you at least have the possibility of fixing the bug yourself, but at that point you have to have an in-depth understanding of the engine codebase to such a degree that you’re not actually getting any benefit out of using a tool designed to make game development “simpler.”
i have specific technical and other criticisms of both godot and unreal:
- godot’s GDscript language is awful and the promise of GDExtension does not solve this problem, i was there when unity supported three scripting languages you cannot lie to me
- unreal’s two programming languages are C++ and blueprints which are both atrocious in their own obvious ways
- both godot and unreal take a “fuck it, man” approach to project architecture which means that as you work on your games you will hate yourself exponentially more
- fuck epic games
but all of these problems either pale in comparison to or are direct results of the base problem that their goal is completely impossible. i might endorse these tools as a friendly way to get into game development, but i would not recommend producing a full commercial project using them unless you hate yourself (which, buddy, if i liked anything about myself i wouldn’t be here right now).
the second result is a broader cultural one: the flattening of games as a medium. i have written about this before elsewhere but the past decade has been defined by the increasing dominance of this big box engines to devastating consequences for the medium as a whole. every game is made out of recycled parts. the opportunity cost of designing meaningfully new mechanics has blown through the roof, because all the time you spend trying to come up with something new could be saved by deciding to make something that’s already been made before. why write your own character controller when you could use the same one everyone else uses?
this goes from top to bottom. obviously AAA studios have always been primarily vendors of warmed-over trash, but this tendency has accelerated in the era of the unreal engine. we once spoke of “AA” developers but these have been gradually replaced by the new “middle class” of video games, the so-called “triple-I” indie studios with millions in publisher funding and typical team sizes of 20-40 people. these developers are squeezed even more aggressively by exploitative publisher deals, lack of development time and lack of team expertise towards playing it safe and creating endlessly derivative simulacra of video games. these games can scarcely even be said to have been “designed.”
and i hate to say it, because i came up in these spaces, but even the landscape of weirdo art games on itch.io has been flattened into interchangeable parts by this transition. the end result of this process of so-called “democratization” has been that every allegedly “personal” art game on itch.io is indistinguishable from any other. like the AAA and “indie” games, the art games are now just simulacra, copies without an original, unable to serve as the personal expression they are intended as.
i have seen worry that without tools like unity and unreal, the mid-sized teams i have talked about will be unable to realize projects of the scope they currently do. my response to this is that they never could. we have been living in a bubble created by free money and low interest rates that propped up a convenient illusion of so-called democratization. now that the money has dried up, unity is popping the bubble. epic games still floats on a cushion of seemingly infinite fortnite dollars, but one day that will be gone too and the smug-feeling unreal engine users will face the same fate as the unity developers.
the problem is vendor lock-in, and this remains a problem whether your vendor is unity technologies or epic games or yoyo games or the godot developers. the only sustainable approach is to rely on a small number of replaceable dependencies that you carefully evaluate to make sure the benefits they provide exceed the inherent complex risk of bringing dependencies into your project.
i am sympathetic to the unity users, because i was once one of you. there’s a lot of people out there who want to make games while interacting as little as possible with the actual process of making software, and there are lots of companies that will prey on that desire. in the end, though, wanting to make a game without having to write any code or understand how games work under the hood is a bit like wanting to be a chef without ever wanting to touch a stove.
ii. practical tips for custom engines
a. mindset
last time i linked to this blog post by tyler glaiel, which remains an excellent source of tips.
something i want to emphasize is that you honestly shouldn’t even think about your project as “making an engine.” you are a making a game. to quote tyler:
I’ll get straight to the point: Make a game at the same time as you’re making the engine. This is an unbreakable rule. The only unbreakable rule. Get the basics in as fast as you possibly can and then immediately start making a game on top of it. An engine is nothing without a game.
i would go even further and say that you shouldn’t even really think of yourself as “making a custom engine,” but rather just as “making a game.” if you can reuse the tools you build for future projects that’s great, but it’s not necessary or even desirable. every game is unique, and one of the benefits of custom tech is being able to build just the parts you need for your project, which may vary!
another important aspect of mindset is: you can make a game with custom tech. i don’t care who you are. you don’t have to be a turbo genius or a computer science major. you can learn to make video games without relying on the snake oil tech of corporate ghouls. i believe in you. this isn’t to say it’s not hard: it is hard. it’s really hard! the difference is that i’m being honest when i tell you it’s hard, and the snake oil salesmen will tell you that they’ve made it easy and you won’t find out they’re lying until it’s too late.
and, while it is hard now, the more of us who do this and write about our experiences, the easier it will get. right now it’s hard in part because these are ancient lost arts buried in the sands of the internet. so i implore you to not only make games with custom tech, but write about your custom tech, publish your custom tech on github, and be a mentor to future developers following in your footsteps.
in the first section i wrote about evaluating dependencies, and i want to speak generally about that process. when using unity or unreal (and in web development), it’s common practice to install dependencies with reckless abandon. the first step of adding a new feature is often to search to see if anyone has done it for you, and if they have, you’re done, just use their solution.
dependencies, however, don’t come free. the person or people who maintain your dependencies can abandon the project, or change it so that it no longer suits your needs. when considering whether to use a dependency or write your own code, you must consider:
- the reliability of the source of the dependency (how likely are they to still be maintaining the project in a year? two years? five? ten?)
- the difficulty of replicating the features of the software (specifically, how hard would it be to make your own with just the parts you need?)
the ideal dependency performs a complex task and is maintained by a reliable developer or group of developers who have a track record of sticking with their projects. a good example of a great dependency is SDL. it’s been around for a very long time, and it performs the very difficult task of regularizing window and rendering context management across platforms to a single, easy to use API.
another quality of a good dependency that is harder to quantify is how self-contained it is. the dependency should, ideally, be replaceable by a different dependency with a similar API. a good example of this is, as we’ll talk about later, FNA and moonworks. their APIs are dissimilar, but if for some reason you had to switch from one to the other, you could do so while minimally altering much of your game’s codebase. you would have to rewrite your rendering, input handling, and audio code (among other things) but all your game logic could stay mostly the same, because these frameworks don’t specify a particular format or architecture. all your other dependencies could also probably remain the same.
compare this to switching from unity to unreal: you have no choice but to completely re-create your game from scratch. the engines are so totalizing in how they determine the structure of your project that there is simply no conversion between them.
a useful proxy for many of these qualities is simply how many other people are using the dependency. this isn’t always reliable, but it can be a good indicator. dependencies like FNA and SDL have years of road-tested experience being used to make real, full scale projects.
another helpful indicator of quality is what’s known in the software world as “dogfooding,” i.e. technology made by an organization or developer for internal use that has been released into the world. this is true of moonworks (developed by evan hemlsey to make samurai gunn 2) and luxe(developed by ruby0x1 for mossfield origins). this isn’t the be-all-end-all, especially for tools and libraries that have been around for a while and become industry standards like SDL, but it relates to tyler glaiel’s unbreakable rule (make a game at the same time as you’re making the engine).
b. specific tools
i listed out a bunch of frameworks i’m aware of in my old post, and honestly i haven’t come across anything new that i’d really want to add, so consult that post for a full list. i have some changes i’d make to how i presented the information in that post, however.
the upshot is: i recommend that you make a custom engine in FNA or moonworks with moontools.ecs. the other options i talked about are still available but i present them with strong qualifiers.
first, i presented love2d rather enthusiastically, and even promised to produce some tutorials on making games with love2d. the process of working on and abandoning the first of those tutorials convinced me that love2d is pretty much a dead end.
i really do like the love2d API, and i think the team is great, but lua is such a terrible programming language that i would consider any engine that uses it to be completely untenable. there are some ways around this with languages that compile to lua, like fennel, typescript to lua, and moonscript but
- a language that transpiled to your target language is yet another dependency that can break or be abandoned, and this must be carefully weighed against its potential benefits
- none of the languages that compile to lua improve the experience of writing lua substantially enough for me to recommend them.
in general i maintain that dynamic typing was a mistake and for large, complex projects like video games, choosing a statically typed language will result in you going significantly less insane. lua has a number of other issues that result in it being measurably worse than other dynamically typed languages, but the dynamic typing is the most significant issue.
secondly, i spoke about haxe and heaps, and while i maintain that this language and toolset is quite good and worth investigating, the haxe ecosystem features no ecs library.
this is something i want to emphasize: i very firmly believe that ecs is the best way to make video games. i also have, over the past year, come to believe even more firmly that moontools.ecs is the best available ecs library.
when ecs is discussed, many programmers want only to talk about its performance implications: cache alignment, whatever. these are important, and moontools.ecs has performance benefits compared to an actor model system, but the real benefit of ecs is ergonomic. once you learn how to think about problems in an ecs way, there’s no going back. it radically improves the development process in just about every way imaginable. i will have to do a full article on ecs someday, which will probably be in the form of a tutorial, but suffice to say that if you are writing a custom engine, i implore you to use ecs.
i also i think undersold how hard it is to write your own ecs. it’s not unmanageable, and many of the hard problems have been solved, but there aren’t a lot of good resources out there on the topic and a naive approach can easily result in poor performance. this means that haxe is a hard sell for me.
similarly, i spoke about C/C++ and flecs in my old post, and what ultimately led me to abandon my engine written with those tools was, actually, flecs. i just missed the extremely ergonomic moontools.ecs. the messaging system is extremely handy, and making ecs systems classes instead of just pure functions opens up a lot of flexibility that will save you time and headaches.
also, i wrote about moonworks at the time as a promising tool for the future that was a little unstable right now. i have been using moonworks on a project since february and i am happy to say the situation has changed: moonworks is great now. it’s a little less batteries-included than other options, but i love it.
this post is targeted squarely at people jumping ship from unity, so FNA and moonworks have the big advantage that you already know C#. as a result of its use in unity and XNA, even outside of any specific framework or engine ecosystem C# has a vibrant game development community. using C# gives you access to wonderful tools like ink, which was designed for integration with unity but is easily usable in other C# contexts.
so, FNA and moonworks. here are the pros and cons as i see it:
FNA
pros:
- an extremely stable API that is guaranteed to never change, for backwards compatibility reasons
- take advantage of the litany of XNA tutorials on the internet from 10-15 years ago
- more “batteries included,” includes features such as a default 3d renderer and a sprite batcher
- larger community of users and developers
cons:
- a preservation project, so don’t expect many new features
- new features necessary for preservation have to be added in ways that preserve the API, which can cause minor issues
- dogshit ass shader system (i’m sorry fna maintainers i know are reading this, i know this is hard to fix lmao)
MoonWorks
pros:
- responsive developer willing to add features and restructure the API if it means improving the framework
- a modern rendering API based on vulkan
- much better SPIR-V based shader system
- if you’re doing 3d you’ll want to replace FNA’s renderer anyway
- much better built-in font rendering than FNA
- built-in fixed-point math libraries for networking (the nichest pro of all time)
cons:
- earlier in development, so a less stable API
- only one active maintainer, please be patient
- very few batteries included, write your own renderer, sprite batch, etc
- documentation is sparser and more out of date, expect to ask questions in the discord.
in general, i would say if you’re making a 2D game i would lean towards FNA, and if you’re making a 3D game i would lean towards moonworks. FNA is also easier to get started with if you’re new to custom engines.
FNA has a pretty good set of basic tutorials that you can reference. moonworks doesn’t have a tutorial yet but it has some documentation which is only a little bit out of date. i also made a project template for using FNA with moontools.ecs. and an explainer about the .NET build system, the achilles heel of FNA and moonworks. i plan to, in the future, produce tutorials of my own on FNA and moonworks.
there are options besides these two for C# frameworks. i think moonworks and FNA are far and away the best. other options either have fewer useful features, worse APIs, or they’re just unofficial bindings to C or C++ APIs that could stop being maintained at any moment. the big exception to this is monogame, which appeals to many people because of the effort put in by the team into making starting a project easier, but i would warn against using monogame for the reasons i outlined in last year’s post.
iii. the killer whales remain
i have no real hope that this blog post will change anyone’s mind about anything. despite the likes of brandon sheffield declaring this the death of unity, i have very little faith this will even be that, let alone what it actually has to be in order to make a difference: the death of all of these stupid snake oil tools that promise the world and deliver trash.
i do think you should do all these things i talk about in this post. i’m happier as a result, you’ll be happier as a result. but our individual choices stand no chance against the forces against us. the reason things are like this isn’t because of individual people making individually bad choices, it’s because everything is awful and getting worse and we’re all terrified and there is no future.
i do know as well as i did a year ago that it doesn’t have to be like this. we could have made the world like anything, and we made it like this. in after the future, franco berardi writes of his vision for making the world better without the now-impossible task of imagining the future:
In order to subjectivate this revolution we have to proliferate singularities. This, in my humble opinion, is our cultural and political task. (…) By the word singularity I mean the expression of a never seen before concatenation. The actor of this expression can be an individual, a collective but also an event. We call it singularity if this actor recombines the multiple flows traversing its field of existence following a principle that is not repetitive and referring to any pre-existing form of subjected subjectivity. By the world singularity, I mean an agency that does not follow any rule of conformity and repetition, and is not framed in any historical necessity. Singularity is a process that is not necessary, because it is not implied in the consequentiality of history neither logically nor materially. It is the emerging of a self-creative process.
this is, of course, beyond the scope of a blog post about making video games. but i implore you to at least consider making your production of art less aligned with the interests of capital, and proliferate some singularities once in a while.