top of page

Custom Game Engine Development

As part of my passion for game development, I have been building a custom game engine from scratch in C++. This project demonstrates my deep understanding of low-level programming, architecture design, and the foundational systems required to create and run games effectively.

Role

Lead Developer

team size 

1 person

development time

1 months

Key Features

1. Platform-Specific Configuration

  • Windows-only Support:
    The engine is designed to run exclusively on Windows (#ifdef MGE_PLATFORM_WINDOWS), ensuring platform-specific behaviour.

  • Dynamic Linking:
    Uses __declspec(dllexport) and __declspec(dllimport) to manage symbols for building and consuming a shared library (My_Game_Engine.dll).

2. Modular Game Engine Architecture​

  • Application Class:
    Provides a base class (Application) for client applications, encapsulating the main game loop (Run() method).

  • Client-Defined Entry Point:
    Clients implement their own CreateApplication() function to initialise their specific application logic (e.g., Sandbox).

3. Logging System​

  • Core and Client Loggers:
    Implements two separate loggers:

    • Core Logger for engine logs.

    • Client Logger for application-specific logs.

  • spdlog Integration:
    Uses the spdlog library for flexible, high-performance logging with features like coloured output and formatted messages.

  • Macros for Logging:
    Simplifies logging with macros such as:

    • MGE_CORE_Warn(...) for engine warnings.

    • MGE_INFO(...) for client information messages.

4. Utility Features

  • Bitmask Macro:
    BIT(x) simplifies creating bitmasks for flags or states by shifting bits (1 << x).

5. Build System Configuration​

  • Multi-Project Setup:
    Two projects:

    • My_Game_Engine: A shared library (the engine itself).

    • Sandbox: A client application that uses the engine.

  • Build Configurations:
    Configures different build modes:

    • Debug (symbol generation for debugging).

    • Release (optimised build).

    • Dist (distribution build).

  • Post-Build Commands:
    Automates DLL copying from the engine project to the client project directory.

6. Simplified Application Loop​

  • Infinite Loop (Run):
    Demonstrates the concept of a game loop. Currently a placeholder (while (true)), but sets the foundation for further game logic integration.

7. Entry Point​

  • Centralised main():
    Handles:

    • Initialisation of the logging system.

    • Creation and execution of the client application.

    • Clean-up via memory management (delete app).

8. Vendor Library Integration

  • Third-Party Dependency Management:
    Includes and integrates the spdlog library for logging, with clear project paths for source and header files.

9. Cross-Module Communication

  • Shared Functionality Export:
    The engine exposes its core functionality to the client application through exported symbols (e.g., MY_GAME_ENINGE_API).

Technologies Used

Programming Language

  • C++:

    • The primary language for implementing the game engine and client application.

    • Features like object-oriented programming, manual memory management, and preprocessor directives are used extensively.

Logging Library

  • spdlog (take from a github repository):

    • A fast, header-only logging library integrated into the engine for high-performance logging.

    • Supports coloured console output, formatted messages, and adjustable log levels.

Build System

  • Premake (or similar build configuration tool):

    • Likely used to generate project files and manage builds.

    • Handles build configurations (Debug, Release, Dist) and platform-specific settings.

Object-Oriented Design

  • Inheritance and Polymorphism:

    • The Sandbox class inherits from My_Game_Engine::Application, allowing customisation of application behaviour.

Code Example

1. Preprocessor Directives and Platform Configuration

  • #pragma once: Ensures the header file is only included once during compilation.

  • __declspec(dllexport) and __declspec(dllimport):

    • Used to define whether symbols are exported (for DLL creation) or imported (for client-side usage).

    • The MY_GAME_ENINGE_API macro toggles between these based on whether MGE_BUILD_DLL is defined.

  • #ifdef MGE_PLATFORM_WINDOWS: Ensures the engine only builds on Windows. If another platform is detected, compilation stops with an error.

2. Utility Macros

  • BIT(x): Creates a bitmask by shifting 1 left by x bits. For example, BIT(3) results in 00001000 in binary.

3. Sandbox Class

  • Sandbox: A client application that inherits from the engine's Application class.

  • CreateApplication(): A factory function defined by the engine but implemented in the client. It creates and returns an instance of Sandbox.

4. Logging System

  • Uses the spdlog library for logging.

  • Two loggers:

    • s_CoreLogger: For engine-specific logs.

    • s_ClientLogger: For client application logs.

  • Log::Init(): Initialises both loggers with a custom log pattern.

  • Macros simplify log calls:

5. Core Engine Functionality

  • Application: Base class for client applications.

  • Run(): Contains the main application loop (while (true) for now).

Implementation

  • Run(): Simplified for now but serves as the core game/application loop.

6. Entry Point

  • Defines main() as the entry point for applications.

  • Steps:

    1. Initialise the logging system.

    2. Create the client application via CreateApplication().

    3. Run the application loop.

    4. Clean up memory.

7. Build System Configuration

  • Defines My_Game_Engine as a shared library (DLL).

  • Adds necessary headers and source files.

  • Specifies build settings for different configurations (Debug, Release, Dist).

Sandbox Project

  • Defines Sandbox as a console application.

  • Links against the My_Game_Engine library.

Technical Challenges Overcome

  1. Modular API Design:
    Ensured the engine's API supports future scalability, allowing developers to easily extend or modify its core functionalities.

  2. Cross-Module Logging:
    Developed a shared logging infrastructure that distinguishes between engine-level and application-level messages, enhancing clarity during debugging.

  3. Dynamic Linking:
    Addressed the complexities of building and managing DLLs for Windows, ensuring seamless export/import of symbols across modules.

Future Goals

  • Introduce a robust event system for handling user input and internal messaging.

  • Develop a graphics rendering pipeline leveraging modern APIs like DirectX or Vulkan.

  • Build a basic physics engine to handle collision detection and response.

  • Add support for cross-platform deployment by abstracting platform-specific dependencies.

  • Facebook
  • Twitter
  • LinkedIn

©2021 by Joseph Merrick. Proudly created with Wix.com

bottom of page