A modular, high-performance 2D Game Engine and Editor built with C++20, SFML 3.2, and Dear ImGui (docking branch).
Elysium has evolved from a standalone 2D physics engine into a full-featured 2D Game Engine featuring a dockable editor suite, type-safe event architecture, decoupled layer/overlay hierarchy, offscreen viewport rendering, and interactive component reflection.
- Overview & Architecture
- Key Features
- Project Directory Layout
- Subsystem Guides
- Prerequisites & Dependencies
- Building & Running
- Developer & Contributor Guide
- Roadmap
- License
Elysium follows a modular, decoupled engine design:
+-------------------------------------------------------------------------+
| ElysiumApp |
| (Client Entry Point / Sandbox Application) |
+-------------------------------------------------------------------------+
|
v
+-------------------------------------------------------------------------+
| Application Core |
| - Master Game Loop (Variable/Fixed Timestep via sf::Clock) |
| - LayerStack (Game Layers & Editor UI Overlays) |
| - Window Abstraction (sf::RenderWindow + SFML 3 Event Pump) |
+-------------------------------------------------------------------------+
| |
v v
+------------------------+ +------------------------+
| Event System | | Editor Layer |
| - Type-Safe Events | | - ImGui DockSpace |
| - EventDispatcher | | - Menu Bar & Hotkeys |
| - Key & Mouse Codes | | - Modular Panels |
+------------------------+ +------------------------+
| |
v v
+------------------------+ +------------------------+
| Scene & Entities | | Offscreen Viewport |
| - GameObject System | | - sf::RenderTexture |
| - Component Pipeline | | - 2D Editor Camera |
| - SpriteRenderer | | - SimpleRenderer |
+------------------------+ +------------------------+
|
v
+-------------------------------------------------------------------------+
| Physics Engine |
| - RigidBody Dynamics & Inertia Tensors |
| - BroadPhase Spatial Grid & NarrowPhase SAT Detection |
| - Circle & Box Colliders |
+-------------------------------------------------------------------------+
- Dockable Engine Editor:
- ImGui docking branch with workspace persistence and custom modern dark theme.
- Comprehensive Main Menu Bar (
File,Edit,Scene,Entities,View,Options). - Play, Pause, and Single-Frame Step toolbar controls to toggle between Edit Mode and Simulation Mode.
- Off-Screen Viewport:
- Scene is rendered into an
sf::RenderTextureand displayed viaImGui::Image. - Independent 2D Editor Camera with smooth panning (Right-Click / Middle-Click drag) and zooming (Mouse Wheel), completely decoupled from the editor UI.
- Scene is rendered into an
- Scene Hierarchy & Entity Inspector:
- Filterable live entity list with selection highlight.
- Interactive component reflection for
Transform(Position, Rotation, Scale),RigidBody2D(Mass, Linear/Angular Velocity, Static/Dynamic toggle, Friction, Restitution),Collider2D(Sphere radius, Box extents), andSpriteRenderer. - Instant two-way synchronization: inspector edits sync physics bodies and transforms in real time.
- Application & LayerStack:
Applicationsingleton owns the master game loop, window, andLayerStack.- Distinguishes standard
Layers (gameplay, simulation) fromOverlays (editor, diagnostics).
- Zero-Allocation Event System:
- Type-safe event hierarchy (
WindowCloseEvent,WindowResizeEvent,KeyPressedEvent,MouseButtonPressedEvent,MouseScrolledEvent, etc.). - Templated
EventDispatcherrouting events with category bitmasks.
- Type-safe event hierarchy (
- Real-Time Diagnostics:
- In-engine Console Panel hooked directly into
spdlogvia a custom ring-bufferedEditorLogSink. - Stats & Profiler Panel showing real-time FPS graphs, frame timing breakdown (Update, Physics, Render), entity counts, and draw call statistics.
- In-engine Console Panel hooked directly into
- 2D Physics Simulation:
- Continuous impulse-based rigid body dynamics, broadphase spatial hash grid, and narrowphase SAT collision response.
ElysiumEngine/
βββ CMakeLists.txt # Root build configuration (FetchContent for ImGui & ImGui-SFML)
βββ README.md # Main engine documentation
βββ PLAN.md # Long-term development roadmap and technical design
βββ LICENSE # MIT License
βββ app/
β βββ main.cpp # Client entry point (instantiates Sandbox Application)
βββ engine/
β βββ CMakeLists.txt # Engine library build target (ElysiumEngine)
β βββ core/ # Application core, windowing, and entity systems
β β βββ include/
β β β βββ Application.hpp # Application singleton and master loop
β β β βββ Window.hpp # sf::RenderWindow encapsulation and event pump
β β β βββ Layer.hpp # Base class for engine layers
β β β βββ LayerStack.hpp # Ordered layer and overlay stack
β β β βββ Timestep.hpp # Frame delta time wrapper (seconds/ms)
β β β βββ KeyCodes.hpp # Platform-independent key codes
β β β βββ MouseCodes.hpp # Platform-independent mouse codes
β β β βββ GameObject.hpp # Entity definition and component container
β β β βββ Component.hpp # Component base interface
β β β βββ SpriteRenderer.hpp # Visual shape/sprite renderer component
β β β βββ Scene.hpp # Scene container and physics world binding
β β β βββ SimpleRenderer.hpp # Off-screen & target-agnostic 2D renderer
β β β βββ Input.hpp # Static keyboard and mouse polling
β β β βββ Log.h # spdlog logging macros
β β β βββ Core.hpp # Platform macros and DLL exports
β β β βββ EntryPoint.hpp # Platform main() bootstrap
β β β βββ Elysium.hpp # Umbrella engine header for client apps
β β βββ src/
β β βββ Application.cpp # Engine game loop and event distribution
β β βββ Window.cpp # SFML 3 event pump and translation
β β βββ Layer.cpp # Layer base implementation
β β βββ LayerStack.cpp # LayerStack management
β β βββ Log.cpp # spdlog initialization
β βββ editor/ # Dear ImGui Editor UI module
β β βββ include/
β β β βββ EditorLayer.hpp # Engine layer driving ImGui lifecycle & docking
β β β βββ EditorContext.hpp # Shared state (camera, selection, play state, stats)
β β β βββ EditorPanel.hpp # Abstract modular editor panel interface
β β β βββ EditorLogSink.hpp # spdlog memory sink for in-editor console
β β β βββ panels/ # Concrete panel definitions
β β β βββ SceneViewportPanel.hpp # Off-screen texture & pan/zoom camera
β β β βββ SceneHierarchyPanel.hpp # Entity list, search, add/delete
β β β βββ EntityInspectorPanel.hpp # Component reflection and mutation
β β β βββ ToolbarPanel.hpp # Play, Pause, Step controls
β β β βββ ConsolePanel.hpp # Filtered log viewer
β β β βββ StatsPanel.hpp # Profiler, FPS plot, and timings
β β βββ src/
β β βββ EditorLayer.cpp # DockSpace, theme, menu bar, and shortcuts
β β βββ EditorLogSink.cpp # Circular log buffer implementation
β β βββ panels/ # Panel implementations
β βββ events/ # Event system architecture
β β βββ Event.hpp # Base Event, EventDispatcher, categories
β β βββ ApplicationEvent.hpp# WindowCloseEvent, WindowResizeEvent
β β βββ KeyEvent.hpp # KeyPressedEvent, KeyReleasedEvent, KeyTypedEvent
β β βββ MouseEvent.hpp # MouseMovedEvent, MouseScrolledEvent, MouseButtonEvent
β βββ physics/ # 2D Physics Engine
β βββ include/
β β βββ RigidBody.hpp # Mass, inertia, velocities, colliders
β β βββ Collider.hpp # Sphere and Box collider geometry
β β βββ PhysicsWorld.hpp # Simulation manager and solver loop
β β βββ BroadPhase.hpp # Spatial hash grid
β β βββ NarrowPhase.hpp # SAT collision detection and resolution
β β βββ AABB.hpp # Axis-aligned bounding boxes
β β βββ CollisionPair.hpp # Potential contact pair representation
β β βββ CoreMath.hpp # Vec2, Vec3, Mat3, Quat math primitives
β βββ src/
β βββ AABB.cpp
β βββ Collider.cpp
β βββ PhysicsWorld.cpp
β βββ RigidBody.cpp
βββ external/ # Git submodules
β βββ SFML/ # SFML 3.2.0 source
β βββ spdlog/ # spdlog header-only logging
βββ test/ # Unit tests and benchmarks
βββ BoundaryTest.cpp
βββ BroadPhasePerformanceTest.cpp
βββ FrictionTest.cpp
βββ PhysicsPerformanceTest.cpp
Client applications inherit from Elysium::Application. The engine owns the window and controls the main loop:
#include <Elysium.hpp>
class Sandbox : public Elysium::Application {
public:
Sandbox() : Application("My Elysium Game") {
// Push regular game layers:
// PushLayer(new GameplayLayer());
// Push the editor UI as an overlay (rendered on top):
PushOverlay(new Elysium::EditorLayer());
}
~Sandbox() override = default;
};
// Engine entry point defines the factory function:
Elysium::Application *Elysium::CreateApplication() {
return new Sandbox();
}The master loop in Application::Run() executes every frame:
- Calculates frame delta time and constructs a
Timestep. - Calls
Window::OnUpdate(), polling OS events and translating them into engine events. - Iterates front-to-back through
LayerStack, callinglayer->OnUpdate(timestep). - Executes the ImGui rendering pass for all layers (
layer->OnImGuiRender()). - Calls
Window::Display()to swap frame buffers.
Events inherit from Event and carry category bitmasks:
void MyLayer::OnEvent(Elysium::Event& event) {
Elysium::EventDispatcher dispatcher(event);
// Bind type-safe event handlers
dispatcher.Dispatch<Elysium::KeyPressedEvent>([this](Elysium::KeyPressedEvent& e) {
if (e.GetKeyCode() == Elysium::Key::Space) {
ELYSIUM_INFO("Space key was pressed!");
return true; // Mark as handled so layers below do not receive it
}
return false;
});
}Events are dispatched down the LayerStack in reverse order: Overlays (such as the Editor) receive events first. If an overlay handles the event (event.Handled = true), lower gameplay layers will not receive it.
EditorLayer is implemented as an engine Overlay. It manages:
- DockSpace: Full-screen docking host window (
ImGui::DockSpaceOverViewport()), allowing tabs, split panes, and floating tool windows. - Theme: Slate dark theme styled with rounded corners and high-contrast accents.
- Main Menu Bar:
File: New Scene, Open, Save, Save As, Exit.Edit: Undo, Redo, Delete Selected Entity, Deselect.Scene: Play, Pause, Step, Reset Camera View, Clear All.Entities: Quick-create Empty Entity, Ball, Box, or Platform.View: Toggle visibility for any active panel.Options: Switch themes (Dark, Classic, Light), toggle Debug Grid, Colliders, or AABBs.
- Shortcuts:
Space: Toggle Play / Pause simulation.F: Focus viewport camera on selected entity.Delete: Delete currently selected entity.
The Scene Viewport Panel (SceneViewportPanel) achieves full decoupling between the Editor UI and game graphics:
- Dynamically resizes an off-screen
sf::RenderTextureto match the ImGui window's available region. - Applies the
EditorCameraview matrix (position and zoom level). - Renders the active scene via
SimpleRenderer. - Displays the resulting texture within ImGui using
ImGui::Image(). - Viewport camera controls:
- Pan: Hold Right Mouse Button or Middle Mouse Button and drag inside the viewport.
- Zoom: Scroll the Mouse Wheel to zoom between 5% and 2000%.
- HUD Overlay: On-screen coordinates and quick "Reset View" button.
Game objects are represented by GameObject:
- Transform:
position(Vec3),rotation(Quat),scale(Vec3). - Physics: Optional attached
std::unique_ptr<RigidBody>. - Components: Extensible component array (
std::vector<std::unique_ptr<Component>>). - Lookup: Query components via
entity->GetComponent<T>()or check existence withentity->HasComponent<T>(). - Visuals: Attach
SpriteRendererfor color, rectangle sizes, or circle shapes.
In the Entity Inspector, modifying any transform parameter automatically invokes entity->SyncTransform(), instantly synchronizing the physics body's position, centroid, and orientation.
The physics engine (engine/physics/) provides robust 2D dynamics:
- RigidBody: Mass, inverse mass (0 for static objects), linear and angular velocities, friction, restitution, and inertia tensors.
- Colliders:
Collider::CreateSphere(radius, density)andCollider::CreateBox(halfExtents, density). - BroadPhase: Uniform spatial grid for rapid collision pair candidate pruning.
- NarrowPhase: Separating Axis Theorem (SAT) for box-box, sphere-sphere, and box-sphere contact manifold generation.
- Simulation Control: Toggle between Edit Mode (physics paused, live manual transform positioning) and Play Mode (active physics stepping).
- OS: Linux, Windows, or macOS
- Compiler: C++20 compliant compiler (GCC 11+, Clang 13+, MSVC 2022+)
- Build System: CMake 3.20+
- Linux Packages:
libx11-dev,libxrandr-dev,libxcursor-dev,libxi-dev,libudev-dev,libgl1-mesa-dev
- SFML 3.2.0: Included as submodule under
external/SFML - spdlog: Included as submodule under
external/spdlog(header-only mode) - Dear ImGui: Automatically fetched via CMake (
v1.91.5-dockingbranch) - ImGui-SFML: Automatically fetched via CMake (
v3.0tag)
git clone --recursive https://github.com/Devsoc-BPGC/ElysiumEngine.git
cd ElysiumEngine(If cloned without submodules, run git submodule update --init --recursive)
# Configure Release build
cmake -B build -DCMAKE_BUILD_TYPE=Release
# Build engine, editor app, and dependencies
cmake --build build -j$(nproc)./build/bin/ElysiumAppcmake -B build -DBUILD_TESTING=ON
cmake --build build -j$(nproc)
ctest --test-dir build --output-on-failureTo create a gameplay layer, inherit from Elysium::Layer:
#include <Elysium.hpp>
class GameLayer : public Elysium::Layer {
public:
GameLayer() : Layer("GameLayer") {}
void OnAttach() override {
ELYSIUM_INFO("GameLayer attached!");
}
void OnUpdate(Elysium::Timestep ts) override {
// Run gameplay logic, update timers, move entities
}
void OnImGuiRender() override {
// Optional in-game debug HUD
}
void OnEvent(Elysium::Event& event) override {
// Handle gameplay events
}
};Push the layer in your application: PushLayer(new GameLayer());.
All editor panels inherit from Elysium::EditorPanel:
#include "EditorPanel.hpp"
#include <imgui.h>
namespace Elysium {
class MyCustomPanel : public EditorPanel {
public:
MyCustomPanel() : EditorPanel("Custom Panel") {}
void OnImGuiRender(EditorContext& context, Scene& scene, SimpleRenderer& renderer) override {
if (ImGui::Begin(name.c_str(), &isOpen)) {
ImGui::Text("Hello from custom panel!");
ImGui::Text("Active entities: %zu", scene.objects.size());
}
ImGui::End();
}
};
} // namespace ElysiumRegister it in EditorLayer: AddPanel<MyCustomPanel>();.
Inherit from Component:
#include "Component.hpp"
#include "GameObject.hpp"
class HealthComponent : public Component {
public:
float currentHealth = 100.0f;
float maxHealth = 100.0f;
void Update(float dt) override {
// Regenerate or check health
}
};
// Attach to an entity:
auto entity = std::make_shared<GameObject>("Hero");
entity->AddComponent<HealthComponent>();Upcoming milestones as detailed in PLAN.md:
- Scene Serialization: YAML-based
.elyscenescene saving and loading viayaml-cpp. - Renderer2D Batching: Batched quad and circle drawing pipeline utilizing vertex buffers.
- Entity Component System (ECS): Transitioning internal storage to
EnTT. - Scripting Engine: Embedding Lua via
sol2for dynamic runtime gameplay scripting. - Audio Subsystem: Integrating SFML's spatial audio module.
Elysium Engine is open-source software licensed under the MIT License.