Advertisement

Writing a game engine - Need beginner-ish structure advice

Started by November 20, 2018 06:20 PM
6 comments, last by Defend 6 years ago

Obligatory disclaimer - Yes this is for academic purposes, not for making actual games.

I've been employed as a Software Engineer for 2 years but still feel like a beginner when it comes to writing a game engine (and much of coding in general). What little experience I have with writing 3D software from scratch is from super rough university projects (which we called "engine" but that's definitely debatable). Meanwhile, my current job doesn't really take me down this line of learning.

 

This thread is to ask for advice; mainly pointers to good guides, or comments on what structural approaches are considered to be good ones. I'm looking for something that teaches me about how to structure a game engine so that:

  • it's good for learning about writing an engine
  • it's not completely devoid of modern techniques
  • it will be usable for later feature learning; networking, AI, unit testing, etc. (I imagine this criterion is typically a given anyway.)

 

Some things I'm aware of so far (you may want to comment on any of these):

 

Regarding ECS: For all the flak it appears to generate nowadays, it is at least a structure. If ECS isn't recommended I'm interested in what other general structural approaches there are.

Regarding Unreal: I'd love to jump in and learn how Unreal Engine's structure works, but it might be biting off more than I can chew. 

Language of choice is C++.

 

Thanks :)

 

Here are my thoughts, I consider myself to still be a noob (5 year hobbyist)

KISS, keep it simple and in modules, ie start with openGL stuff then move on to inputs, audio etc, then iterate.

Look for simple engine examples, I like this one: https://github.com/Marzac/le3d/tree/master/engine

Focus on design (data structures and functions) of the underlying tech and simple abstractions, ie mesh'es to openGL and wav files to audio system etc.

But don't get hooked on OOP/ECS design, messaging or other non core systems at the start, these are actually far more complex then a simple engine exercise is, so KISS!

Re: Game Engine Architecture, I think it's too academic to be of any benefit to a noob, instead I recommend  http://www.mcshaffry.com/GameCode/

It's not perfect, but a lot more practical!

 

Re big engine source code, it's great that it's open, but too complex to understand it all, especially as a beginner.

Even Doom source code today is hard to understand, and that's magnitudes smaller.

 

I don't see why the need for a  disclaimer "academic purposes", if you make it, why not use it? commercially or free.. as long as it's not buggy and deemed finished, I don't see why it has to be purely academic.

Edit: gameplay3d engine is very understandable, but IMO abit on the big side:

https://github.com/gameplay3d/GamePlay

Edit, while I'm on github, here are a few good C++ smaller engines:

includes animation, a bit dated, but still relevant.

https://github.com/horde3d/Horde3D

Pico, very tiny engine, no frills, no animation, but a good simple example

https://github.com/AlexMartinelle/PicoEngine

Advertisement

You might also be interested in this recent article.

This definitely shouldn't be disclaimed as purely academic.

Making a game engine is hard, and obviously if your objective is to push a game to market then you'll do that faster using a professional engine.

With this said, making an engine from scratch is an extremely valuable chunk of experience that looks brilliant on a CV. It's one thing to say you've made a game in Unity but quite another to say you've made a game on your own engine.

Making your own engine also gives you an unlimited amount of flexibility, which is extremely useful in situations where your game design requirements would otherwise be stifled by the limitations and common practices imposed by something ready-built.

Anyway, if you're looking for a resource that explains from top to bottom how to make an engine, you might be out of luck. You'll find the occasional blog dedicated to it, but might not find anything in-depth;

Having built engines before, my advice to you is to break the whole thing down into categories and then research each of them. You'll find many resources detailing OpenGL and other similar open standards.

As for what categories you'll need to break things down into. It will change from game to game, but generally I find it helpful to have these separate areas in mind:

  • Rendering
    • Meshes
    • Textures
    • Shaders/Programs
    • Viewport, Camera and Projection matrices
  • Physics
    • Coillision Detection
    • Ray/Sphere casting
    • Impulse Resolution
    • Collision Shapes
  • Scene/Room Management
    • Entity Model (ECS or whatever)
  • Pathfinding
    • Usually relies on your scenes and how they're laid out.
  • AI
    • Usually relies on your pathfinding and raycasting

I personally found this website extremely useful for rendering https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL. Be warned: many OpenGL resources will be out of date and might recommend using features that are deprecated. With that said, even the out of date ones often cover the basics in a perfectly usable way, even in later versions.

I started my own route in 2009 when I started at university first in C# using an OpenGL wrapper and later changed to C++. I had a lot of try and throw away prototypes up to my current stable version and also tried the same ammount of project architecture. Having a look at certain features of other engines like Unreal Engine 4, Urho3D, Cry Engine and anything I found on the web is a good approach when you are at a state where you have basic knowledge of what you do and especially why you do something.

First and most important point that I think when looking back today is your general project structure. This sounds redundant but as your project grows you will end up with a mess of code and script/ config files quickly if you don't take care about that early. As I wrote in this post, I'm currently on the go to analyse the dependency structure when building and print those diagrams for project analysis in order to keep the project clean.

Second thing that pointed out in past years is your building pipeline. There is nothing more annoyng than a bunch of plain script files and/or the need to maintain those or call some magic make/nmake every time you want to setup or compile your code. This is why I started to dissect Unreal's build tool and 'm now on the go to write my own one. I figured out that there are little information you need to setup project files for different Visual Studio, Visual Studio Code and whatever IDE you prefer while most of those informations like platform settings are always the same for the whole project. I'm also now on the road to quit the use of config files for my build completely after reading this article about automated build systems.

My build tool currently performs a complete project folder analysis using certain hard coded rules like

  • Every subfolder in my project root is an own project
  • For every project found in root collect all files and decide what kind of project it is
  • Every project in root can contain multiple projects (mixing C# and C++ files result in two project files on the same project)
  • Use code analysis to find relations between projects in the same root

So what should I say, it works suprisingly well :D

Another clue about my build tool is a Javascript kind of mechanic, mixins. I use the same method Unreal does using .Build.cs files all over my project root and sub folders to control my build tool's behavior. This is what Gigi Sayfan did with his Python scripts. But no, those aren't "just another build file" you need to maintain, those are micro plugins. My program detects all of them and loads them into the runtime to add/extend or override single functions that stay in specially marked classes; just as Javascript mixins work.

I also have the chance to provide plugins but they are limited to predefined interfaces to provide build profiles (local build, remote build, cloud build ...), build systems (C#, C++ and whatever or even different platform exports) and I use C# for any of my tools because it pointed out that C# is a good language for rapid tooling and tool prototyping.

The last important point in my opinion is modularity. I seperated my engine into several modules each maintaining it's own sub-project. This has the reason that I wanted my design to be flexible to the needs of the game it is used for and one could easily work in parallel on different features. This comes with nearly no overhead in C++ because of static linking. Any module I have is a static library.

Another advantage of the modular approach is also the project setup. I have a package manager tool that is able to download features and their dependencies from GitHub for example (and also may include additional .Build.cs files if needed)

Now I want to tell you something about how I started and what my modules contain, you may take or don't take this as a suggestion for a roadmap.

I first started with my current implementation (after several reworks since 2009) to think about basics. New and delete wasted my early code and also leaded to heavy memory leaks at some of past professional prohjects I participated to so I found and read this blog post about memory management and implemented a similar approach including my own STL like container structures for better control over memory consumption. It pointed out that a lot of classes could just inherit from my Array class (dynamic resizeable continious memory management class that behaves like a plain C array but could dynamically resize to certain element count) like Vector (as I come from the C# world, some more convinience was needed like the C# List<T> equivalent), Queue, Stack, hashTable and Map for example are such classes.

I force any function that operates on blocks of memory to have the Allocator& parameter pointing to the default allocator set once at startup. Driving this route I never had hidden memory leaks again in my code because the Allocator instantly complained about unreleased memory.

Then I added some file and asset management because this is the most used topic in every modern game and every modern engine. Assets are always present and have to be loaded, cached and cleaned frequently while playing. Anything working with data in my engine uses streams because they provide some features like the position pointer that benefit in my opinion against plain arrays of data. One of those features for example is caching (in case of files) or the position pointer (very usefull on parsing/processing data).

Memory Mapped Files also turned out to be a basic technology you won't want to miss inc ase of threaded asset loading.

RTTI/ Reflection and dynamic calling was a research topic just for interest but I don't want to renounce nowdays. Driving my own implementation tooks some research but especially in case of serialization and editor to engine code it is very usefull. I also added a huge delegate and dynamic calling feature into my engine that is used for example in the in-game console to parse and call methods in game code. Another Javascript/ Typescript mechanic I used here for my editor interface are dynamic interfaces defining an interface class and convert a matching object to that interface even if it dosent belong to the inheritance chain is quite usefull to bind functionality to editor components and also enables hot reloading.

I havent used it that much but you could also write a wrapper struct that behaves like an C# object, assigning any kind of class/ struct and convert it back to whatever it was when needed.

Last but not least ECS. It is an overused buzzword these days that is true but it is also usefull and you again don't want to miss it once tasted. The principles of ECS are to provide objects that define their existence of components that could interact with static business code in systems. So far one could say that ECS is the most flexible way to define data that is used in certain way to reach an expected result.

Using systems for rendering, UI and gameplay elements is an easy alternative to OOP because you know the data to expect and could write logic once on a centrally place instead of spreading the logic all over classes and class specializations. This also prevents the so called god object to occure.

ECS is for example used in the render graph, a feature that decides of those objects to render, performs object parent/ child relation chaining and transformation updates. In Unity or Unreal, a scene contains of a render graph.

This are just my thoughts so feel free to take whatever you need

Actually I totally forgot to mention.

When you're looking into the physics portion of the engine, look up the Separating Axis Theorem. It's a brilliant and lightweight way of dealing with oriented polygons and oriented boxes.

It's fairly straightforward to implement as well.

I don't have any links unfortunately, but if you google for it you should find several explanation and quickly understand the process it uses.

Advertisement

Thanks all for your replies, especially those links you guys have thought of. _Silence_, I found that article in particle quite interesting.


The pointers to simple engines should also be helpful, since while I've asked about guiding structures for writing I do indeed practise in merely recognising structures of other engines.

Quote

First and most important point that I think when looking back today is your general project structure. This sounds redundant but as your project grows you will end up with a mess of code and script/ config files quickly if you don't take care about that early.

Yep, exactly this is the kind of thing I'm wanting to be better at. 

I've had a glance all the articles & posts linked. They all get my interest but I'll prioritise those around engine structure advice.

 

(Regarding the side topic of "Don't make an engine if you want to make a game", the disclaimer I wrote is just to keep such suggestions at bay. They're good suggestions but there's already a lot of internet covering it.)

This topic is closed to new replies.

Advertisement