Skip to content

About the project

syper_olao edited this page May 13, 2026 · 2 revisions

Mini Engine With Games Wiki

Mini Engine With Games is a compact educational C++20 / DirectX 11 mini-engine built around one shared runtime and several playable demos.

It is not trying to be Unreal, Unity, Godot, or a production-ready engine. The point is smaller and more useful: this repository shows how a game runtime can be organized when you want to understand what is happening under the hood instead of hiding everything behind an editor.

The project is designed for students and beginner/intermediate graphics programmers who want to study a real but readable codebase: application loop, input, rendering, UI, audio, assets, gameplay systems, debug tools, and multiple mini-games running inside one executable.

What the project contains

The repository is split into a reusable engine-like layer and concrete game modules.

Mini-Engine-With-Games/
├── Core/        Shared runtime and engine systems
├── Game/        Playable demos and game-specific code
├── ThirdParty/  External libraries such as ImGui / ImGuizmo
├── Images/      README and wiki media
└── main.cpp     Application entry point

The executable starts as MiniEngineDemo.exe. It opens a main menu, and the user can select one of the available demos at runtime.

Demo Purpose
Pong Simple 2D game for input, UI, rules, audio, and basic game flow.
SolarSystem 3D simulation-style demo for cameras, orbit logic, tuning UI, and movement audio.
Katamari Main 3D sandbox for ECS-style gameplay, collisions, deferred rendering, particles, debug views, and UI.
LightingTest Small technical scene for checking lights, materials, models, and cameras.

The project is Windows-focused and uses DirectX 11, CMake, vcpkg, DirectXTK, Assimp, ImGui, and ImGuizmo.

The main idea

The architecture is based on one simple rule:

Core owns reusable engine systems. Game owns demo-specific behavior.

That separation is the whole point. The mini-games do not each create their own window, renderer, audio system, asset loader, or input layer. They all run inside the same application shell and receive access to shared services through AppContext.

main.cpp
   ↓
Application
   ↓
AppContext
   ├── Platform services
   ├── Input services
   ├── Graphics services
   ├── UI services
   ├── Audio services
   ├── Asset services
   └── GameHost for switching games
   ↓
Active IGame module
   ├── MainMenuGame
   ├── PongGame
   ├── SolarSystemGame
   ├── KatamariGame
   └── LightingTestGame

This makes the project easier to understand and extend. A new demo only needs to implement the game-specific part. The runtime already provides the rest.

Runtime lifecycle

Every game module implements the same IGame interface.

class IGame {
public:
    virtual ~IGame() = default;

    virtual void Initialize(AppContext& context) = 0;
    virtual void Update(AppContext& context, float deltaTime) = 0;
    virtual void Render(AppContext& context) = 0;
    virtual void Shutdown(AppContext& context) {}
};

The application owns the active game. During startup, it initializes the window, input, graphics, audio, assets, UI, and rendering context. Then it calls the selected game through the IGame lifecycle.

Application startup
   ↓
Create engine services
   ↓
Initialize active game
   ↓
Main loop
   ├── update input
   ├── calculate delta time
   ├── activeGame.Update(...)
   ├── activeGame.Render(...)
   └── present frame
   ↓
If a game switch was requested
   ├── shutdown old game
   ├── create next game
   └── initialize next game

The IGameHost interface is used when a game needs to request a transition. For example, the main menu can switch to PongGame, and mini-games can request a return to MainMenuGame.

This avoids hard-closing the application just because one demo wants to exit. Humanity has caused enough suffering already.

Core layer

Core is the reusable runtime layer. It is not tied to Pong, Katamari, or any other specific demo.

Area Responsibility
Core/App Application lifecycle, main loop, IGame, IGameHost, AppContext, service setup, and game switching.
Core/Platform Native Windows window wrapper.
Core/Input Keyboard, mouse, and raw input handling.
Core/Graphics DirectX 11 device layer, render context, frame renderer, render passes, cameras, models, shaders, particles, shadows, GBuffer resources, picking, and debug tools.
Core/Gameplay Lightweight ECS-style scene model with entities, components, systems, transforms, collision, rendering, and attachments.
Core/Physics 2D and 3D collision primitives, queries, bounds, and spatial helpers.
Core/UI Bitmap font rendering, buttons, switchers, sliders, collapsible sections, and ImGui integration.
Core/Audio DirectXTK Audio wrapper for one-shot sounds and looping sounds.
Core/Assets Asset path resolving and resource caching.
Core/Editor Debug/editor-like tools, including transform gizmo support.

The most important files for understanding this layer are:

File Why it matters
Core/App/Application.* Owns the main loop and active game lifecycle.
Core/App/IGame.h Defines the contract every demo follows.
Core/App/AppContext.h Shows which engine services are exposed to games.
Core/Graphics/Rendering/RenderContext.* Central access point for rendering systems and render mode switching.
Core/Graphics/Rendering/FrameRenderer.* Handles frame target binding and frame begin/end behavior.
Core/Gameplay/Scene.* Owns entities, components, and systems.
Core/Gameplay/GameplayComponents.h Shows the data used by the ECS-style gameplay layer.

Game layer

Game contains the actual demos. Each demo focuses on a different learning problem.

Game/MainMenu is the runtime entry screen. It draws the menu, handles keyboard/mouse selection, and switches to the selected demo through GameHost.

Game/Pong is the simplest complete game. It is useful for studying basic game flow: player input, bot behavior, collision, score rules, UI, and audio feedback.

Game/SolarSystem is a 3D simulation-style demo. It demonstrates orbit and FPS cameras, orbital bodies, projection switching, runtime settings UI, and movement-driven audio.

Game/Katamari is the largest gameplay demo. It combines ECS-style scene systems, rolling-ball control, absorption logic, collision resolution, static obstacle rendering, particles, debug overlays, deferred rendering, and UI panels.

Game/LightingTest is a focused rendering validation scene. It is useful when you want to test lighting, materials, camera behavior, and model rendering without full gameplay noise.

Rendering architecture

Rendering is organized around RenderContext, FrameRenderer, and FrameRenderPipeline.

The important design choice is that the frame is split into render passes. Instead of one giant draw function doing everything, each pass has a specific job.

Frame rendering
   ↓
FrameRenderPipeline
   ├── ShadowDepthRenderPass
   ├── MainGeometryBindRenderPass / DeferredGeometryRenderPass
   ├── GameRenderPass
   ├── DeferredLightingRenderPass
   ├── DeferredCompositeRenderPass
   ├── GBufferDebugRenderPass
   ├── ParticlesRenderPass
   ├── DebugOverlayRenderPass
   └── UserInterfaceRenderPass

This structure is useful because students can inspect the renderer one stage at a time. Shadows are not mixed randomly with UI. Particles are not buried inside model rendering. Debug overlays have their own place. Revolutionary, I know: code becomes easier to read when it is not a single cursed function.

Forward rendering path

The forward path is the simpler mode. It binds the main render targets and draws scene geometry with lighting directly into the frame.

Scene + Camera
   ↓
Shadow pass
   ↓
Main geometry / game rendering
   ↓
Particles
   ↓
Debug overlays
   ↓
UI
   ↓
Back buffer

This path is easier to understand first because the scene is rendered more directly.

Deferred rendering path

The deferred path separates geometry data from lighting.

Scene + Camera
   ↓
Shadow pass
   ↓
Deferred geometry pass
   ↓
GBuffer
   ├── albedo / material data
   ├── normals
   ├── world position / depth-related data
   └── object or picking data
   ↓
Deferred lighting pass
   ↓
Deferred composite pass
   ↓
Particles, debug overlays, UI
   ↓
Back buffer

The deferred path is more complex, but it is better for learning modern rendering structure. It makes GBuffer creation, lighting, composition, and debug visualization separate concepts instead of mixing them into one rendering soup.

The project also includes debug tools such as GBuffer visualization, cascaded shadow debug, collision debug drawing, GPU particles, object picking through GBuffer data, and ImGuizmo transform tools.

Gameplay architecture

The gameplay layer uses a small ECS-style scene model.

A Scene owns entities, component storage, and systems. An entity is a lightweight ID. Components store data. Systems apply behavior to entities that have the required component set.

Scene
   ├── Entities
   │    ├── EntityId 1
   │    ├── EntityId 2
   │    └── EntityId 3
   │
   ├── Components
   │    ├── TransformComponent
   │    ├── ModelComponent
   │    ├── MaterialComponent
   │    ├── VelocityComponent
   │    ├── SphereColliderComponent
   │    ├── BoxColliderComponent
   │    ├── TagComponent
   │    └── AttachmentComponent
   │
   └── Systems
        ├── TransformSystem
        ├── VelocityIntegrationSystem
        ├── CollisionSystem
        ├── RenderSystem
        └── CollisionDebugDraw

This is not a full industrial ECS. It is intentionally smaller and more explicit. There is no reflection system, no code generation, no custom editor, and no giant framework maze. The point is to show the idea clearly: keep data in components, keep behavior in systems, and keep game-specific rules out of the engine core when possible.

For example, Katamari has its own systems for ball control, rolling, absorption, camera behavior, and obstacle rendering. Those systems are game-specific, so they live in Game/Katamari. Generic scene mechanics stay in Core/Gameplay.

That separation keeps the engine layer reusable without pretending every gameplay rule belongs in the engine.

Why this architecture is useful for students

This repository is useful because it shows real game-engine problems at a readable scale.

A student can trace the full application flow from main.cpp to Application, then to MainMenuGame, then into one selected demo. That is much easier to study than a commercial engine where the first step is usually “open five million files and surrender your remaining hope”.

The project demonstrates several important ideas in one place:

Concept Where to study it
Application loop Core/App/Application.*
Game lifecycle Core/App/IGame.h
Runtime services Core/App/AppContext.h
Menu-based game switching Game/MainMenu/MainMenuGame.*
Simple 2D game structure Game/Pong
3D camera and simulation logic Game/SolarSystem
ECS-style gameplay Core/Gameplay and Game/Katamari
Forward/deferred rendering Core/Graphics/Rendering
Render passes Core/Graphics/Rendering/Pipeline/Passes
GBuffer debugging GBufferDebugRenderPass and deferred resources
Particles Core/Graphics/Particles and Katamari UI
Audio Core/Audio and demo-specific audio usage
UI widgets Core/UI

The main advantage is that the code is not just isolated textbook snippets. It builds into a real Windows executable with playable demos, runtime switching, rendering modes, assets, shaders, UI, audio, and debug tools.

Recommended reading path

If you are new to the repository, do not start with the biggest rendering file and then wonder why life hurts. Read it in this order:

  1. Start with main.cpp to see how the application is created.
  2. Read Core/App/Application.* to understand the main loop and service initialization.
  3. Read Core/App/IGame.h to understand the game module interface.
  4. Read Core/App/AppContext.h to see what services games can access.
  5. Read Game/MainMenu/MainMenuGame.* to understand runtime demo selection.
  6. Read Game/Pong/PongGame.* first if you want the simplest complete game.
  7. Read Core/Gameplay/Scene.* and GameplayComponents.h if you want the ECS-style layer.
  8. Read Core/Graphics/Rendering/RenderContext.* to understand render mode switching and render system ownership.
  9. Read Core/Graphics/Rendering/Pipeline/Passes/* to study individual frame stages.
  10. Read Game/Katamari/* last, because it combines the most systems at once.

How to add a new mini-game

A new mini-game should reuse the existing runtime instead of creating its own engine shell.

Typical steps:

  1. Create a new folder under Game, for example Game/MyDemo.
  2. Create MyDemoGame.h and MyDemoGame.cpp.
  3. Implement the IGame lifecycle.
  4. Add the new files to CMakeLists.txt.
  5. Add a new button or menu option in Game/MainMenu/MainMenuGame.*.
  6. Put demo-specific assets under Game/MyDemo/Assets if needed.
  7. Document the demo controls in the README or wiki.

Minimal shape:

class MyDemoGame final : public IGame {
public:
    void Initialize(AppContext& context) override;
    void Update(AppContext& context, float deltaTime) override;
    void Render(AppContext& context) override;
    void Shutdown(AppContext& context) override;
};

The important rule is simple: if the code is reusable by several demos, it probably belongs in Core. If it only makes sense for one demo, it belongs in that demo folder under Game.

Project scope

This project is good for learning:

  • C++ game architecture;
  • DirectX 11 rendering basics;
  • forward and deferred rendering structure;
  • render passes;
  • GBuffer debugging;
  • small ECS-style gameplay systems;
  • simple collision handling;
  • runtime UI;
  • audio integration;
  • debug tools;
  • mini-game organization.

This project is not trying to be:

  • a production engine;
  • a full editor;
  • a cross-platform framework;
  • a complete asset pipeline;
  • a physically accurate simulator;
  • a replacement for Unreal, Unity, or Godot.

Those limitations are intentional. The project stays useful because it is small enough to read, debug, modify, and break without needing a rescue helicopter.