
(this article is reposted from pikuma.com)
Game development has always been a great helper to get my students motivated to learn more about more advanced computer science topics.
One of my tutors, Dr. Sepi, once said:
"Some people think games are kid's stuff, but gamedev is one of the few areas that uses almost every item of the standard CS curriculum."
- Dr. Sepideh Chakaveh
She's absolutely right! If we expose what is hidden under the development stack of any modern game, we'll see that it touches many concepts that are familiar to any computer science student.
Depending on the nature of your game, you might need to dive even deeper into more specialized areas, like distributed systems or human-computer interaction. Game development is serious business and it can be a powerful tool to learn serious CS concepts.
This article will go over some of the fundamental building blocks that are required to create a simple game engine with C++. I'll explain the main elements that are required in a game engine, and give some personal recommendations on how I like to approach writing one from scratch.
That being said, this will not be a coding tutorial. I won't go into too much technical detail or explain how all these elements are glued together via code. If you are looking for a comprehensive video book on how to write a C++ game engine, this is a great starting point: Create a 2D Game Engine with C++ & Lua.
What is a Game Engine?
If you are reading this, chances are you already have a good idea of what a game engine is, and possibly even tried to use one yourself. But just so we are all on the same page, let's quickly review what game engines are and what they help us achieve.
A game engine is a set of software tools that optimizes the development of video games. These engines can be small and minimalist, providing just a game loop and a couple of rendering functions, or be large and comprehensive, similar to IDE-like applications where developers can script, debug, customize level logic, AI, design, publish, collaborate, and ultimately build a game from start to finish without the need to ever leave the engine.
Game engines and game frameworks usually expose an API to the user. This API allows the programmer to call engine functions and perform hard tasks as if they were black boxes.
To really understand how this API thing works, let's put it into context. For example, it is not rare for a game engine API to expose a function called "IsColliding()" that developers can invoke to check if two game objects are colliding or not. There is no need for the programmer to know how this function is implemented or what is the algorithm required to correctly determine if two shapes are overlapping. As far as we are concerned, the IsColliding function is a black box that does some magic and correctly returns true or false if those objects are colliding with each other or not. This is an example of a function that most game engines expose to their users.
if (IsColliding(player, bullet)) {
lives--;
if (lives == 0) {
GameOver();
}
}
Besides a programming API, another big responsibility of a game engine is hardware abstraction. For example, 3D engines are usually built upon a dedicated graphics API like OpenGL, Vulkan, or Direct3D. These APIs provide a software abstraction for the Graphics Processing Unit (GPU).
Speaking of hardware abstraction, there are also low-level libraries (like DirectX, OpenAL, and SDL) that provide abstraction & multi-platform access to many other hardware elements. These libraries help us access and handle keyboard events, mouse movement, network connection, and even audio.
The Rise of Game Engines
In the early years of the game industry, games were built using a custom rendering engine and the code was developed to squeeze as much performance as possible from slower machines. Every CPU cycle was crucial, so code reuse or generic functions that worked for multiple scenarios was not a luxury that developers could afford.
As games and development teams grew in both size and complexity, most studios ended up reusing functions and subroutines between their games. Studios developed in-house engines that were basically a collection of internal files and libraries that dealt with low-level tasks. These functions allowed other members of the development team to focus on high-level details like gameplay, map creation, and level customization.
Some popular classic engines are id Tech, Build, and AGI. These engines were created to aid the development of specific games, and they allowed other members of the team to rapidly develop new levels, add custom assets, and customize maps on the fly. These custom engines were also used to mod or create expansion packs for their original games.
Id Software developed id Tech. id Tech is a collection of different engines where each iteration is associated with a different game. It is common to hear developers describe id Tech 0 as "the Wolfenstein3D engine", id Tech 1 as "the Doom engine", and id Tech 2 as "the Quake engine."
Build is another example of engine that helped shape the history of 90's games. It was created by Ken Silverman to help customize first-person shooters. Similar to what happened to id Tech, Build evolved with time and its different versions helped programmers develop games such as Duke Nukem 3D, Shadow Warrior, and Blood. These are arguably the most popular titles created using the Build engine, and are often referred as "The Big Three."
Yet another example of game engine from the 90s was the "Script Creation Utility for Manic Mansion" (SCUMM). SCUMM was an engine developed at LucasArts, and it is the base of many classic Point-and-Click games like Monkey Island and Full Throttle.
The SCUMM scripting language was used to manage Full Throttle's dialogs and actions.
As machines evolved and became more powerful, so did game engines. Modern engines are packed with feature-rich tools that require fast processor speeds, ridiculous amounts of memory, and dedicated graphics cards.
With power to spare, modern engines trade machine cycles for more abstraction. This trade-off means we can view modern game engines as general-purpose tools to create complex games at low cost and short development times.
Why Make a Game Engine?
This is a very common question, and different game programmers will have their own take on this topic depending on the nature of the game being developed, their business needs, and other driving forces being considered.
There are many free, powerful, and professional commercial engines that developers can use to create and deploy their own games. With so many game engines to choose from, why would anyone bother to make a game engine from the ground up?
I wrote a blog post explaining some of the reasons programmers might decide to make a game engine from scratch. In my opinion, the top reasons are:
Learning opportunity: a low-level understanding of how game engines work under the hood can make you grow as a developer.
Workflow control: you'll have more control over special aspects of your game and adjust the solution to fit your workflow needs.
Customization: you'll be able to tailor a solution for a unique game requirement.
Minimalism: a smaller codebase can reduce the overhead that comes with bigger game engines.
Innovation: you might need to implement something completely new or target an unorthodox hardware that no other engine supports.