Repository navigation
About the project
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.
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 architecture is based on one simple rule:
Coreowns reusable engine systems.Gameowns 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.
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 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 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 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.
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.
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.
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.
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.
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:
- Start with
main.cppto see how the application is created. - Read
Core/App/Application.*to understand the main loop and service initialization. - Read
Core/App/IGame.hto understand the game module interface. - Read
Core/App/AppContext.hto see what services games can access. - Read
Game/MainMenu/MainMenuGame.*to understand runtime demo selection. - Read
Game/Pong/PongGame.*first if you want the simplest complete game. - Read
Core/Gameplay/Scene.*andGameplayComponents.hif you want the ECS-style layer. - Read
Core/Graphics/Rendering/RenderContext.*to understand render mode switching and render system ownership. - Read
Core/Graphics/Rendering/Pipeline/Passes/*to study individual frame stages. - Read
Game/Katamari/*last, because it combines the most systems at once.
A new mini-game should reuse the existing runtime instead of creating its own engine shell.
Typical steps:
- Create a new folder under
Game, for exampleGame/MyDemo. - Create
MyDemoGame.handMyDemoGame.cpp. - Implement the
IGamelifecycle. - Add the new files to
CMakeLists.txt. - Add a new button or menu option in
Game/MainMenu/MainMenuGame.*. - Put demo-specific assets under
Game/MyDemo/Assetsif needed. - 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.
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.