Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
ECS_Systems.h
Go to the documentation of this file.
1/*
2Olympe Engine V2 - 2025
3Nicolas Chereau
4nchereau@gmail.com
5
6This file is part of Olympe Engine V2.
7
8ECS Systems purpose: Define systems that operate on entities with specific components.
9
10*/
11
12#pragma once
13
14#include "Ecs_Entity.h"
15#include "Ecs_Components.h"
16#include <set>
17#include <SDL3/SDL.h>
18#include "vector.h"
19#include <unordered_map>
20#include "system/message.h"
21
22// Forward declaration
23struct CameraTransform;
26
27// Prototype function to render entities for a given camera
31// Get the active camera transform for a specific player
33
34// The System class handles game logic over entities with specific components.
36{
37public:
38 // The signature required for an Entity to be processed by this System
40
41 // The set of Entities this System processes in its Update loop
42 std::set<EntityID> m_entities;
43
45
46 // The core logic of the System
47 virtual void Process() {}
48 virtual void Render() {}
49 virtual void RenderDebug() {}
50
51 void AddEntity(EntityID entity) { m_entities.insert(entity); }
52 void RemoveEntity(EntityID entity) { m_entities.erase(entity); }
53};
54
55
56// Input System: processes entities with Input_data
57class InputSystem : public ECS_System
58{
59 public:
61 virtual void Process() override;
62 };
63
64// InputEventConsumeSystem: Consumes Input domain events from EventQueue
65// and updates ECS components (Controller_data, PlayerBinding_data)
66// Replaces the old UpdateECSInputFromMessage callback-based approach
68{
69public:
71 virtual void Process() override;
72};
73
74// GameEventConsumeSystem: Consumes Gameplay domain events from EventQueue
75// Handles game state changes (pause/resume/quit), player add/remove via keyboard
76// Replaces VideoGame::OnEvent callback-based approach
78{
79public:
81 virtual void Process() override;
82};
83
84// UIEventConsumeSystem: Consumes UI domain events from EventQueue
85// Handles menu activation/deactivation and validation
86// Replaces GameMenu::OnEvent callback-based approach
88{
89public:
91 virtual void Process() override;
92};
93
94// CameraEventConsumeSystem: Consumes Camera domain events from EventQueue
95// Handles camera control events (shake, zoom, follow, etc.)
96// Replaces CameraSystem::OnEvent callback-based approach
98{
99public:
101 virtual void Process() override;
102};
103
104// AI System: processes entities with AIBehavior_data and Movement_data
105class AISystem : public ECS_System
106{
107 public:
108 AISystem();
109 virtual void Process() override;
110};
111// Detection System: processes entities with TriggerZone_data and Position_data
113{
114 public:
116 virtual void Process() override;
117};
118// Physics System: processes entities with Transform_data and PhysicsBody_data
120{
121 public:
123 virtual void Process() override;
124};
125// Collision System: processes entities with BoundingBox_data and Position_data
127{
128 public:
130 virtual void Process() override;
131};
132// Trigger System: processes entities with TriggerZone_data and Position_data
134{
135 public:
137 virtual void Process() override;
138};
139// Navigation System: processes entities with NavigationAgent_data
141{
142public:
144 virtual void Process() override;
145
146 // Request pathfinding for entity
147 void RequestPath(EntityID entity, const Vector& targetPos);
148
149 // Follow current path
150 void FollowPath(EntityID entity, float deltaTime);
151
152 // Check if repath needed (obstacle detected)
153 bool NeedsRepath(EntityID entity);
154};
155// Movement System: processes entities with Transform_data and Movement_data
157{
158 public:
160 virtual void Process() override;
161};
162// Rendering System: processes entities with Transform_data and VisualSprite_data
164{
165public:
167 virtual void Render() override;
168};
169// Rendering Editor System: displays editor-specific visuals (grid, gizmos, etc.)
171{
172public:
174 virtual void Render() override;
175};
176//-------------------------------------------------------------
177class GridSystem : public ECS_System
178{
179public:
180 GridSystem();
181 virtual void Render() override;
183
184 const GridSettings_data* FindSettings() const;
185
186 void DrawLineWorld(const CameraTransform& cam, const Vector& aWorld, const Vector& bWorld, const SDL_Color& c);
187
188 // **NEW: Draw filled rectangle in world space (for overlays)**
189 void DrawFilledRectWorld(const CameraTransform& cam, const Vector& worldPos, float width, float height, const SDL_Color& c);
190
192
194 void RenderIso(const CameraTransform& cam, const GridSettings_data& s);
195 void RenderHex(const CameraTransform& cam, const GridSettings_data& s);
196
197 // **NEW: Overlay rendering methods**
200
201 // **NEW: Helper functions for drawing overlay shapes**
202 void DrawIsometricTileOverlay(float centerX, float centerY, float width, float height, const SDL_Color& color);
203 void DrawHexagonOverlay(float centerX, float centerY, float radius, const SDL_Color& color);
204};
205//-------------------------------------------------------------
206// UI Rendering System: Pass 2 rendering for UI/HUD/Menu (always on top)
207// Renders UI elements independently of world depth sorting
209{
210public:
212 virtual void Render() override;
213
214 void RenderHUD(const CameraTransform& cam);
217};
218//-------------------------------------------------------------
219// Player Control System: processes entities with PlayerBinding_data and Controller_data
221{
222 public:
224 virtual void Process() override;
225};
226// Input Mapping System: maps hardware input to gameplay actions
228{
229 public:
231 virtual void Process() override;
232};
233
234//-------------------------------------------------------------
235// Olympe Effect System: Plasma bloom background with glowing orbs
236// No entity required - autonomous visual effect system
238{
239public:
241 virtual ~OlympeEffectSystem();
242
243 virtual void Process() override;
244 virtual void Render() override;
245
246 void Initialize();
247
248private:
249 // Implementation details hidden - defined in OlympeEffectSystem.cpp
250 struct Implementation;
252};
253//-------------------------------------------------------------
254// CameraSystem - Manages all camera entities in the ECS
256{
257public:
258 CameraSystem();
259 virtual ~CameraSystem();
260
261 // Core ECS system methods
262 virtual void Process() override; // Update cameras each frame
263 virtual void Render() override; // Update viewport settings
264
265 // Camera creation and management
269
270 // Input binding
274
275 // Target setting
278
279 // Rendering support
281
282 // Event handling
283 void OnEvent(const Message& msg);
284
285 // Update methods called during Process()
286 void UpdateCameraInput(EntityID entity, float dt);
287 void UpdateCameraFollow(EntityID entity, float dt);
288 void UpdateCameraZoom(EntityID entity, float dt);
289 void UpdateCameraRotation(EntityID entity, float dt);
290 void UpdateCameraShake(EntityID entity, float dt);
291 void ApplyCameraBounds(EntityID entity);
292
293 // Input processing
296 float ApplyDeadzone(float value, float deadzone);
297
298 // Camera control
299 void ResetCameraControls(EntityID entity);
300 void SyncZoomLevelIndex(Camera_data& cam); // Helper to sync currentZoomLevelIndex with targetZoom
301
302 // Player camera mapping
303 std::unordered_map<short, EntityID> m_playerCameras; // Map player ID to camera entity
304 EntityID m_defaultKeyboardCamera = INVALID_ENTITY_ID; // Default keyboard-controlled camera
305};
306//-------------------------------------------------------------
307
308// Structure that holds camera transformation data for rendering
310{
311 Vector worldPosition; // Camera position in world space
312 Vector screenOffset; // Screen offset (control + shake)
313 float zoom = 0.f; // Zoom level
314 float rotation = 0.f; // Rotation angle in degrees
315 SDL_FRect viewport = {0.f, 0.f, 0.f, 0.f}; // Viewport rectangle
316 bool isActive = false; // Is this camera active
317
318 // Transform a world position to screen coordinates
319 Vector WorldToScreen(const Vector& worldPos) const
320 {
321 if (!isActive)
322 return worldPos;
323
324 // 1. Calculate position relative to camera
325 Vector relative = worldPos;
327
328 // 2. Apply rotation (convert degrees to radians)
329 if (rotation != 0.0f)
330 {
331 float rotRad = rotation * (float)(k_PI / 180.0);
332 float cosRot = std::cos(rotRad);
333 float sinRot = std::sin(rotRad);
334
335 float rotatedX = relative.x * cosRot - relative.y * sinRot;
336 float rotatedY = relative.x * sinRot + relative.y * cosRot;
337
338 relative.x = rotatedX;
339 relative.y = rotatedY;
340 }
341
342 // 3. Apply zoom
343 relative.x *= zoom;
344 relative.y *= zoom;
345
346 // 4. Apply screen offset (control offset + shake)
349
350 // 5. Center in viewport
351 // SDL viewport is already set; coordinates are viewport-local
352 // Add half viewport dimensions to center within viewport bounds
353 relative.x += viewport.w / 2.0f;
354 relative.y += viewport.h / 2.0f;
355
356 return relative;
357 }
358
359 // Transform a world size to screen size
360 Vector WorldSizeToScreenSize(const Vector& worldSize) const
361 {
362 Vector size = worldSize;
363 return size * zoom;
364 }
365
366 // Transform a screen position to world coordinates (inverse of WorldToScreen)
368 {
369 if (!isActive)
370 return screenPos;
371
372 // 1. Remove viewport offset
373 // screenPos is viewport-local when SDL viewport is set
374 // Coordinates are relative to viewport's top-left corner (0,0)
376 relative.x = screenPos.x - viewport.w / 2.0f;
377 relative.y = screenPos.y - viewport.h / 2.0f;
378
379 // 2. Remove screen offset (shake + control)
382
383 // 3. Inverse zoom
384 relative.x /= zoom;
385 relative.y /= zoom;
386
387 // 4. Inverse rotation (if any)
388 if (rotation != 0.0f)
389 {
390 float rotRad = -rotation * (float)(k_PI / 180.0);
391 float cosRot = std::cos(rotRad);
392 float sinRot = std::sin(rotRad);
393
394 float rotatedX = relative.x * cosRot - relative.y * sinRot;
395 float rotatedY = relative.x * sinRot + relative.y * cosRot;
396
397 relative.x = rotatedX;
398 relative.y = rotatedY;
399 }
400
401 // 5. Add world position
404
405 return relative;
406 }
407
408 // Check if a world-space bounding box is visible in this camera
409 bool IsVisible(const SDL_FRect& worldBounds) const
410 {
411 if (!isActive)
412 return false;
413
414 // Transform all four corners of the bounding box
415 Vector corners[4] = {
416 Vector(worldBounds.x, worldBounds.y, 0.f),
420 };
421
422 // Transform all corners to screen space
424 for (int i = 0; i < 4; i++)
425 {
427 }
428
429 // Calculate screen bounding box
430 float minX = screenCorners[0].x;
431 float maxX = screenCorners[0].x;
432 float minY = screenCorners[0].y;
433 float maxY = screenCorners[0].y;
434
435 for (int i = 1; i < 4; i++)
436 {
437 if (screenCorners[i].x < minX) minX = screenCorners[i].x;
438 if (screenCorners[i].x > maxX) maxX = screenCorners[i].x;
439 if (screenCorners[i].y < minY) minY = screenCorners[i].y;
440 if (screenCorners[i].y > maxY) maxY = screenCorners[i].y;
441 }
442
443 // Check if screen bounding box intersects viewport
444 // WorldToScreen returns viewport-local coordinates (since SDL_SetRenderViewport is used)
445 // So we check against viewport-local bounds [0, viewport.w] x [0, viewport.h]
446 bool intersects = !(maxX < 0.f ||
447 minX > viewport.w ||
448 maxY < 0.f ||
449 minY > viewport.h);
450
451 return intersects;
452 }
453};
@ FollowPath
Follow the path (check progression)
std::bitset< MAX_COMPONENTS > ComponentSignature
Definition ECS_Entity.h:31
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
std::uint64_t EntityID
Definition ECS_Entity.h:21
const EntityID INVALID_ENTITY_ID
Definition ECS_Entity.h:23
void RenderSingleEntity(const CameraTransform &cam, EntityID entity)
void RenderMultiLayerForCamera(const CameraTransform &cam)
CameraTransform GetActiveCameraTransform(short playerID)
void RenderEntitiesForCamera(const CameraTransform &cam)
static SDL_Renderer * renderer
virtual void Process() override
virtual void Process() override
void BindCameraToJoystick(EntityID cameraEntity, short playerID, SDL_JoystickID joystickId)
EntityID GetCameraEntityForPlayer(short playerID)
EntityID CreateCameraForPlayer(short playerID, bool bindToKeyboard=false)
void BindCameraToKeyboard(EntityID cameraEntity)
void ProcessJoystickInput(EntityID entity, CameraInputBinding_data &binding)
void UpdateCameraFollow(EntityID entity, float dt)
void ClearCameraTarget(EntityID cameraEntity)
virtual void Process() override
void OnEvent(const Message &msg)
void ApplyCameraBounds(EntityID entity)
float ApplyDeadzone(float value, float deadzone)
void ApplyCameraToRenderer(SDL_Renderer *renderer, short playerID)
void SetCameraTarget_ECS(EntityID cameraEntity, EntityID targetEntity)
void UpdateCameraRotation(EntityID entity, float dt)
void ProcessKeyboardInput(EntityID entity, CameraInputBinding_data &binding)
void SyncZoomLevelIndex(Camera_data &cam)
void UnbindCameraKeyboard(EntityID cameraEntity)
std::unordered_map< short, EntityID > m_playerCameras
void ResetCameraControls(EntityID entity)
virtual void Render() override
void UpdateCameraInput(EntityID entity, float dt)
void RemoveCameraForPlayer(short playerID)
EntityID m_defaultKeyboardCamera
void UpdateCameraShake(EntityID entity, float dt)
void UpdateCameraZoom(EntityID entity, float dt)
virtual void Process() override
virtual void Process() override
virtual void Process()
Definition ECS_Systems.h:47
virtual void Render()
Definition ECS_Systems.h:48
std::set< EntityID > m_entities
Definition ECS_Systems.h:42
virtual void RenderDebug()
Definition ECS_Systems.h:49
void RemoveEntity(EntityID entity)
Definition ECS_Systems.h:52
ComponentSignature requiredSignature
Definition ECS_Systems.h:39
void AddEntity(EntityID entity)
Definition ECS_Systems.h:51
virtual void Process() override
void RenderIso(const CameraTransform &cam, const GridSettings_data &s)
SDL_FRect GetWorldVisibleBounds(const CameraTransform &cam)
void RenderHex(const CameraTransform &cam, const GridSettings_data &s)
void DrawHexagonOverlay(float centerX, float centerY, float radius, const SDL_Color &color)
void RenderOrtho(const CameraTransform &cam, const GridSettings_data &s)
void DrawFilledRectWorld(const CameraTransform &cam, const Vector &worldPos, float width, float height, const SDL_Color &c)
void RenderCollisionOverlay(const CameraTransform &cam, const GridSettings_data &s)
const GridSettings_data * FindSettings() const
void RenderNavigationOverlay(const CameraTransform &cam, const GridSettings_data &s)
void DrawIsometricTileOverlay(float centerX, float centerY, float width, float height, const SDL_Color &color)
void DrawLineWorld(const CameraTransform &cam, const Vector &aWorld, const Vector &bWorld, const SDL_Color &c)
void RenderForCamera(const CameraTransform &cam)
virtual void Render() override
virtual void Process() override
virtual void Process() override
virtual void Process() override
virtual void Process() override
bool NeedsRepath(EntityID entity)
virtual void Process() override
void RequestPath(EntityID entity, const Vector &targetPos)
virtual void Process() override
virtual void Render() override
Implementation * pImpl
virtual void Process() override
virtual void Process() override
virtual void Render() override
virtual void Render() override
virtual void Process() override
virtual void Process() override
void RenderInGameMenu(const CameraTransform &cam)
virtual void Render() override
void RenderHUD(const CameraTransform &cam)
void RenderDebugOverlay(const CameraTransform &cam)
float y
Definition vector.h:27
float x
Definition vector.h:27
Vector ScreenToWorld(const Vector &screenPos) const
Vector WorldToScreen(const Vector &worldPos) const
bool IsVisible(const SDL_FRect &worldBounds) const
Vector WorldSizeToScreenSize(const Vector &worldSize) const
SDL_FRect viewport
constexpr double k_PI