How the player entity is built.

Player doesn't do anything itself, it owns components that do things. The Player class is an owner and coordinator. Game logic accesses behaviour through the thin interfaces each component implements.

Player : IGameEntity
Player owns -> SpriteComponent HealthComponent StatComponent x3 Inventory HUDComponent CursorComponent

Four thin interfaces.

Every game object derives from one or more of four pure-virtual interfaces. IGameEntity bundles all four for common game objects. Lighter components pick only what they need.

Interface Contract Used by
IRenderable render(sf::RenderTarget&): any drawable object satisfies this. The game loop never knows what it's drawing. Player, WorldObject, WorldItem, PointOfInterest, HUDComponent...
IUpdatable update(sf::Time): fixed-timestep loop calls this on all registered entities. Each entity is responsible for its own state. Player, HealthComponent, StatComponent, Enemy types...
IPositionable getPosition() / setPosition(): enables generic position queries without knowing the concrete type. Player, WorldObject, WorldItem, PointOfInterest...
ICollidable getBounds() returns world-space sf::FloatRect for broad-phase collision pre-checks. Player, WorldObject, WorldItem, PointOfInterest...

Six systems.

01: State Management

A Pushdown Automaton in GameStateManager handles MainMenu, Playing, Paused, Settings, and GameOver. The key behaviour: pushing a state saves the current one on a stack. Popping returns to it. This is what lets Settings be opened from both main menu and pause menu and return correctly to the right prior state each time.

02: Collision Detection

Two phases. Broad-phase AABB check first, if the bounding boxes don't overlap, skip everything else. Narrow-phase SAT for convex polygons loaded from .tmx files. Minimum Translation Vector resolution pushes entities cleanly out of geometry. Flyweight-shared collision shapes mean thousands of world objects don't each own a copy of their polygon data.

03: Input Controller

Abstracts keyboard and gamepad behind InputAction enums. wasJustPressed and wasJustReleased are O(1) array lookups using memcpy state snapshots, current frame vs previous frame. Runtime key rebinding stored in std::unordered_map for O(1) lookup.

04: Enemy AI

Two enemy types with state machines. SavageEnemy: Idle -> Chase -> Lost using line-of-sight raycasting. ChomperEnemy adds a Leap state, a velocity-locked lunge with its own cooldown that aborts on wall contact via applyCollisionCorrection(). Both managed by EnemyManager using fixed-size object pools.

05: Inventory and Items

A 2x5 slot grid with drag-and-drop, right-click context menus (Use / Drop), and a Flyweight ItemTypeRegistry that stores one data block per item type. Items in the world use WorldItemPool, 64 pre-allocated slots, activated and deactivated rather than heap-allocated per spawn.

06: Rendering and Camera

Dual SFML views: m_gameView follows the player with map-bounds clamping; m_uiView is fixed to screen space. All UI renders under the fixed view, this is what fixed the HUD drift bug where bars were moving with the camera. Frustum culling on tiles, POIs, world objects, and items.