Why Making a Game Engine is the Hardest Way to Actually Ship a Game

Why Making a Game Engine is the Hardest Way to Actually Ship a Game

You’re sitting there, staring at a blank C++ file. You want to make a game. But instead of drawing a character or designing a level, you’re thinking about memory allocation. You’re thinking about how to get a triangle onto the screen using Vulkan or DirectX 12. Honestly? Most people will tell you you're crazy. They’ll say, "Just use Unreal" or "Godot is right there." And they aren't exactly wrong.

But you want to do it anyway.

Making a game engine is a rite of passage that most modern developers skip. We live in an era of "black box" development where you click a button and a physics engine just works. When you decide to build your own tech stack from scratch, you aren’t just making a game; you’re building the universe that the game lives in. It is tedious. It is frustrating. It is, quite frankly, a massive time sink that will likely delay your actual game by years.

Yet, for some of us, that's the whole point.

The Brutal Reality of Low-Level Architecture

Let’s be real for a second. If you start making a game engine today, you won't see a pixel on the screen for a while. You’ll spend the first week—or month—fighting with build systems. CMake is a nightmare. Header files will break. You’ll realize that "cross-platform support" is a lie that requires writing three different versions of the same code.

Everything in a custom engine is a trade-off. In a commercial engine like Unity, the developers have already decided how the memory is handled. They’ve decided how the scene graph looks. When you build your own, you have to choose: do I use a simple Object-Oriented approach? Or do I go full Data-Oriented Design (DOD) with an Entity Component System (ECS)?

Mike Acton, formerly of Insomniac Games and Unity, has spent years preaching about the importance of data-oriented design. The core idea is simple: hardware hates your fancy abstractions. Modern CPUs are incredibly fast, but memory is slow. If your data is scattered all over the place in "objects," the CPU spends all its time waiting for RAM. When you're making a game engine, you have to think about the cache. You have to think about how the data is laid out in memory so the CPU can go fast. If you don't care about this, you might as well just use an existing engine.

Graphics Are No Longer Just About Triangles

Remember when you could just call glBegin(GL_TRIANGLES) and things happened? Those days are dead.

Modern graphics APIs like Vulkan or Metal are "explicit." This means they don't do anything for you. You have to manage the GPU memory yourself. You have to write the synchronization primitives so the GPU doesn't try to read a texture while the CPU is still writing to it. It’s a lot. Honestly, it’s why libraries like bgfx or Sokol exist. They provide a thin abstraction over the horror of modern graphics APIs while still letting you feel like you’re building something from the ground up.

If you’re dead set on writing the renderer yourself, start with a simple forward renderer. Don't worry about deferred shading or clustered lighting yet. Just get a single mesh to show up with a basic shader. That feeling when that first 3D model appears? That’s the high you’ll be chasing for the next two years.

The Hidden Costs of Tools and Editors

Here is the secret: a game engine isn't just a renderer. It’s a suite of tools.

You need a way to import models. You need a way to edit levels. You need a way to tweak variables while the game is running without recompiling the entire project. This is where most "custom engine" projects go to die. Developers spend all their time on the cool graphics code and zero time on the workflow.

Think about it. If it takes you five minutes to change the gravity setting and restart the game, you’re going to lose momentum. Real engines—the ones that actually ship games—prioritize iteration time.

  • Hot Reloading: Being able to swap out DLLs or recompile scripts while the game is live.
  • Asset Pipeline: Automatically converting a 2GB 4K texture into a format the GPU actually likes (like BC7) the moment you save it in Photoshop.
  • Debug Visualization: Drawing lines in the world to show where physics rays are hitting.

If you don't build these things, you aren't making a game engine; you're making a tech demo. There’s a big difference.

📖 Related: Jupiter Next to Earth: What Most People Get Wrong

Why Hand-Rolling Your Physics is Usually a Bad Idea

Physics is math. Very hard math.

Unless your game has a very specific need—like the planet-scale physics in Outer Wilds or the unique destruction in Teardown—you should probably use a library. PhysX is open source now. Jolt Physics (used in Horizon Forbidden West) is incredible and incredibly fast.

Writing a stable rigid-body solver is a rabbit hole. You’ll deal with objects "tunneling" through walls because the frame rate dropped. You’ll deal with "jitter" where boxes won't stop shaking. It’s a distraction from the actual game. Use a library for the heavy lifting so you can focus on the parts of your engine that actually make your game unique.

The Architecture of Choices: C++ vs. Rust vs. Zig

For decades, C++ was the only choice. It’s still the king. Every major console, every AAA engine (Unreal, Frostbite, RE Engine), they all run on C++. It has the libraries and the community support.

But things are changing.

Rust is becoming a serious contender. Projects like the Bevy engine are proving that you can build high-performance game tech without the memory safety nightmares of C++. It feels different. It’s more restrictive, but that restriction often prevents the kind of "heisenbugs" that haunt C++ developers for weeks.

Then there’s Zig. It’s the "new kid," but it’s gaining traction because it’s basically "C, but better." It gives you total control without the baggage of 40 years of C++ legacy features.

Whatever language you pick, stick with it. Switching languages halfway through is the fastest way to make sure your engine never gets finished.

Case Studies: When the Custom Route Paid Off

Look at No Man's Sky. Hello Games couldn't have made that with Unity back in 2013. They needed a custom engine to handle the procedural generation of entire galaxies on the fly. The engine was the game.

Or look at Factorio. The developers built their own engine because they needed to handle hundreds of thousands of active entities on screen at once. Standard engines have too much overhead for that kind of specific optimization.

When you have a specific technical hurdle that "general purpose" engines can't solve, that is the only time making a game engine becomes a logical business decision. Every other time, it's just a hobby. And that’s okay.

Practical Steps to Get Started

If you’re still reading, you’re probably going to do this. Fine. Let’s talk about how to actually make progress without losing your mind.

  1. Don't build a "General Purpose" engine. Do not try to make the next Unreal. Make an engine that only does what your specific game needs. If your game is a 2D platformer, you don't need a 3D skeletal animation system.
  2. Use libraries for the boring stuff. Use SDL2 or GLFW for window management. Use stb_image for loading pictures. Use ImGui for your editor UI. Dear ImGui is the single most important tool for engine developers; it lets you build complex debug menus in minutes.
  3. Focus on the "Loop" first. Get the game loop running. Handle input. Update the state. Draw the frame. This is the heartbeat of your engine.
  4. Keep it simple. Use a flat file structure. Don't over-engineer your class hierarchies. You will rewrite this code three times anyway, so don't get attached to your first version.

Making a game engine is a marathon. It’s a journey into the deepest parts of how computers work. You will learn more about software engineering in six months of engine dev than in four years of a computer science degree. Just don't forget to actually make a game with it eventually.

The best way to start is to write a "Software Renderer." Forget the GPU for a weekend. Just try to write code that colors pixels in a 2D array and displays it. Once you understand how a pixel gets to the screen, the rest of the mountain starts to look a lot more climbable.

Stop reading about it and go open your IDE. Create a main function. That's step one.