Game Engine Adventures

I don’t recommend re-inventing the wheel. So why would I develop my own game engine instead of using one of the many available ones? Because I was working on an engine 20 years ago, before all these shiny new engines were freely available, and it has always been a passion of mine. And because I am not actually planning on making a game engine, but rather I want to learn what is new and different in the world of C++ development, and figured I’d learn it within the context of implementing a game engine.

Package Management

One thing that I have always found frustrating when developing C++ applications is package management. Fortunately there are a couple of modern solutions for C++ that work like npm, pip, or other package managers. The two most popular that I saw were vcpkg and conan.

vcpkg

I briefly looked at vcpkg. It does seem to support Windows, Mac, and Linux. But it is a Microsoft solution, so there is distaste for tying myself to it. And the number of packages it supports appears to be far less than conan, therefore I didn’t actually do any testing with it purely based on personal preferences.

conan.io

This looks like a promising solution. It supports multiple package repositories so you can add tens of thousands of different packages to your system, if you trust the sources. By default conan.io hosts packages on a JFrog Artifactory backend, which I currently use at work, and have a high level of confidence in. The packages I am interested in using for development seem to be available by default, without needing to add additional repositories. And, it supports a simple conanfile.txt configuration, or a more powerful conanfile.py configuration as code solution. I use python daily, so this is quite appealing to me.

A quick configuration file looks like this:

conanfile.py

from conans import ConanFile, CMake

class Dread(ConanFile):
    settings = "os", "compiler", "build_type", "arch"
    requires = [
        "msys2/20210105",
        "cmake/3.20.4",
    ]
    generators = [
        "virtualenv",
        "cmake",
        "gcc",
        "txt"
    ]
    default_options = {}

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

My initial requires section installs msys2 and cmake on my Windows laptop, which I normally just use for gaming since I prefer to do my daily development on a Mac. Eventually I would like to explore cross-compilation, but don’t want to slow myself down by doing too much at once.

The generators section tells conan what kind of outputs to generate using the requires (and other) sections, and the build function tells conan how to build using cmake.

With that conanfile.py in place I can simply install the dependencies and build my code with like this:

cd build
conan install ..
conan build ..

I think the .. path style is an odd choice on the part of conan, but it is cleaner looking that the alternative “conan install . –install-folder build”.

Build Tools

Before I selected CMake I was looking at a few options. The top choices in my mind were: CMake, SCons, and Bazel.

SCons

This was originally brought to my attention by a couple of projects that I was familiar with and thought about giving it a try. After spending some time familiarizing myself with it, I became more and more aware of the lack of support behind it. First of all, it was more popular a few years ago and has been in a steady decline since 2017. The second factor against it was, as I was looking at other tools, the general support for SCons was “nobody uses it so we haven’t really tested this” and comments from other blogs saying “if you are supporting legacy systems then use it, if you are starting a new project then don’t use it”. So I moved on to checking out other tools.

Bazel

I thought it might be nice to check out Bazel because, well, Google. But, again, looking at trends, it appears there has been a HUGE drop off in Bazel popularity. I don’t know if this is purely pandemic related, or if there are other factors at play, but it looks like its popularity has died off in the last year. Combine that with the fact that it is written in Java and I’m not really interested in adding Java requirements to this project, I moved on from Bazel.

CMake

I made a bit of a long circularly loop to get back to CMake. But it really came down using something with minimal overhead, wider support, and introducing the least extra tooling and complexity. CMake is at least somewhat similar to traditional Makefiles (more so than SCons or Bazel because it generates Makefiles), and getting started using it with conan is well supported and very straight forward.

CMakeLists.txt

cmake_minimum_required(VERSION 3.20.4)
project(Dread)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(NO_OUTPUT_DIRS)

link_libraries(
    ${CONAN_LIBS}
)

add_executable(Dread src/main.cpp)

The conan cmake generator creates a conanbuildinfo.cmake file that contains ALL your header and library definitions for the packages you’ve installed with conan. This makes it very easy to include them in your CMakeLists.txt file and quickly have a working build.

Conclusion

With package management and a build system in place I was able to easily compile my main.cpp source file and run a simple SDL demo to prove my development environment worked.

In my next post I will cover how I have set up my IDE, project directory structure, and the initial entry point for the engine.

Next Post: OpenGL Quick Start

mbrandeis