Demonstrating sprite animation, player input handling, and ImGui debug features within my custom C++/SFML engine.
This project, developed for my 'Games Engine Construction' module at Teesside University (Year 2, 2025 - Ongoing), involves building a complete 2D game engine from scratch - using C++ and SFML. The primary goal was to create a highly flexible game engine suitable to create simple 2D games. The initial project setup, including ImGui integration, was provided by the module. All visual assets used are courtesy of Kenney.nl, also provided via the module resources.
Designed and implemented core engine architecture for 2D games
Encapsulated graphics system to handle all rendering and visual aspects of the game engine
Created a base entity class for game objects, handling of animation and transformation
Player extends from the base entity to allow for keyboard controlled movement
Texture manager to prevent redundant texture loading
Animation manager to handle sprite sheet definitions (frame data, speed)
Decoupled input manager using the observer pattern
Custom rectangle class implementing AABB collision detection
Integrated ImGui panel for real-time monitoring/editing for debugging
WIP
Language: C++
Libraries/Frameworks: SFML, C++ Standard Libraries (map, vector, string, iostream)
Core Concepts: OOP (Encapsulation), Design Patterns (Observer, Singleton), Data Structures (std::map), Algorithms (AABB Collision), Asset Management, Game Loop Architecture
IDE: Visual Studio
Tools: Github, ImGui
As my most ambitious project to date, building this engine has significantly deepened my core C++ knowledge and familiarised me with tools like ImGui and SFML.
The primary challenges have been architectural: managing the project's structure to ensure proper encapsulation and maintaining a logical separation of concerns. Adhering to these principles remains crucial as I move towards implementing the simulation system.
Adapting the observer pattern from a previous project to handle simultaneous inputs also presented difficulties. Initial implementations struggled with persistent input states, but through careful debugging and patience, I developed a robust solution. This reinforced the importance of thoroughly understanding design patterns before adapting them for new contexts.