Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
CollisionMap.h
Go to the documentation of this file.
1#pragma once
2
3#include <vector>
4#include <unordered_map>
5#include <string>
6#include <memory>
7#include <cmath>
8#include <algorithm>
9#include <queue>
10#include <functional>
11#include "vector.h"
12#include "system/system_utils.h"
13
14// Forward declarations
15namespace Olympe { namespace Editor { struct LevelDefinition; } }
16
17// ============================================================================
18// TILE DATA STRUCTURES (Rich information per tile)
19// ============================================================================
20
21enum class TerrainType : uint8_t
22{
23 Invalid = 0,
24 Ground,
25 Water,
26 Grass,
27 Sand,
28 Rock,
29 Ice,
30 Lava,
31 Mud,
32 Snow,
33 Custom = 255
34};
35
37{
38 Ground = 0, // Layer 0: Standard ground collision
39 Sky = 1, // Layer 1: Aerial navigation/flying
40 Underground = 2, // Layer 2: Underground/tunnels
41 Volume = 3, // Layer 3: 3D volumes (for stacked isometric)
42 Custom1 = 4,
43 Custom2 = 5,
44 Custom3 = 6,
45 Custom4 = 7,
46 MaxLayers = 8
47};
48
49// Tile properties (rich data per tile)
51{
52 bool isBlocked = false; // Hard collision (impassable wall)
53 bool isNavigable = true; // Can pathfind through
54 float traversalCost = 1.0f; // Cost for pathfinding (1.0 = normal, >1.0 = slow)
56 uint8_t customFlags = 0; // 8 bits for custom gameplay flags
57
58 // Multi-layer support
60
61 // Dynamic state support (destructible walls, buildable bridges, openable doors)
62 bool isDynamic = false; // Can this tile change state?
63 std::string onDestroyedState; // State name after destruction (e.g., "Rubble")
64 std::string onBuiltState; // State name after construction (e.g., "Bridge")
65 std::string metadata; // JSON metadata for custom gameplay logic
66
67 // Pre-calculated world coordinates (tile center) - for performance optimization
68 float worldX = 0.0f;
69 float worldY = 0.0f;
70
71 TileProperties() = default;
72};
73
74// Grid projection types
76{
77 Ortho = 0,
78 Iso = 1,
79 HexAxial = 2
80};
81
82// ============================================================================
83// COLLISION MAP SINGLETON (with multi-layer support)
84// ============================================================================
85
87{
88public:
89 static CollisionMap& Get()
90 {
92 return instance;
93 }
94
95 // Initialize with layers
96 void Initialize(int width, int height, GridProjectionType projection,
97 float tileWidth, float tileHeight, int numLayers = 1,
98 float tileOffsetX = 0.0f, float tileOffsetY = 0.0f);
99
100 // Layer management
101 void SetActiveLayer(CollisionLayer layer);
103 int GetNumLayers() const { return m_numLayers; }
104
105 // Tile properties access (current layer)
106 void SetTileProperties(int x, int y, const TileProperties& props);
107 const TileProperties& GetTileProperties(int x, int y) const;
108
109 // Tile properties access (specific layer)
110 void SetTileProperties(int x, int y, CollisionLayer layer, const TileProperties& props);
111 const TileProperties& GetTileProperties(int x, int y, CollisionLayer layer) const;
112
113 // Quick collision checks (backward compatibility)
114 void SetCollision(int x, int y, bool hasCollision);
115 bool HasCollision(int x, int y) const;
116 bool HasCollision(int x, int y, CollisionLayer layer) const;
117
118 // Dynamic state transitions (NEW: for destructible walls, buildable bridges, openable doors)
119 typedef std::function<void(TileProperties&)> TileUpdateFunc;
120 void UpdateTileState(int x, int y, TileUpdateFunc updateFunc);
121 void UpdateTileState(int x, int y, CollisionLayer layer, TileUpdateFunc updateFunc);
122
123 // World-to-grid conversion
124 void WorldToGrid(float worldX, float worldY, int& outGridX, int& outGridY) const;
125 void GridToWorld(int gridX, int gridY, float& outWorldX, float& outWorldY) const;
126
127 // Validation
128 bool IsValidGridPosition(int x, int y) const;
129 bool IsValidGridPosition(int x, int y, CollisionLayer layer) const;
130
131 // Getters
132 int GetWidth() const { return m_width; }
133 int GetHeight() const { return m_height; }
135 float GetTileWidth() const { return m_tileWidth; }
136 float GetTileHeight() const { return m_tileHeight; }
137
138 // Access raw grid (for visualization)
139 const std::vector<std::vector<TileProperties>>& GetLayer(CollisionLayer layer) const;
140
141 // Sectorization support (for future dynamic loading)
142 struct Sector
143 {
144 int x, y; // Sector grid position
145 int width, height; // Sector size in tiles
146 bool isLoaded = false;
147 bool isActive = false;
148 };
149
150 void RegisterSector(int sectorX, int sectorY, int width, int height);
151 void LoadSector(int sectorX, int sectorY);
152 void UnloadSector(int sectorX, int sectorY);
153 const std::vector<Sector>& GetSectors() const { return m_sectors; }
154
155 // Clear
156 void Clear();
157
158
159 CollisionMap() = default;
160 ~CollisionMap() = default;
161 CollisionMap(const CollisionMap&) = delete;
163
164 // Multi-layer storage: layers[layer][y][x]
165 std::vector<std::vector<std::vector<TileProperties>>> m_layers;
166 int m_numLayers = 1;
168
169 int m_width = 0;
170 int m_height = 0;
172 float m_tileWidth = 32.0f;
173 float m_tileHeight = 32.0f;
174
175 // Tile offset for coordinate calculations (isometric alignment)
176 float m_tileOffsetX = 0.0f;
177 float m_tileOffsetY = 0.0f;
178
179 // Sectorization (for future dynamic loading)
180 std::vector<Sector> m_sectors;
181
182 // Default empty tile (returned for invalid queries)
184};
185
186// ============================================================================
187// NAVIGATION MAP SINGLETON (pathfinding-optimized)
188// ============================================================================
189
191{
192public:
194 {
195 static NavigationMap instance;
196 return instance;
197 }
198
199 // Initialize
200 void Initialize(int width, int height, GridProjectionType projection,
201 float tileWidth, float tileHeight, int numLayers = 1);
202
203 // Layer management
204 void SetActiveLayer(CollisionLayer layer);
206
207 // Tile properties access (delegates to CollisionMap for consistency)
208 void SetNavigable(int x, int y, bool isNavigable, float cost = 1.0f);
209 bool IsNavigable(int x, int y) const;
210 float GetTraversalCost(int x, int y) const;
211
212 // Layer-specific access
213 bool IsNavigable(int x, int y, CollisionLayer layer) const;
214 float GetTraversalCost(int x, int y, CollisionLayer layer) const;
215
216 // World-to-grid conversion
217 void WorldToGrid(float worldX, float worldY, int& outGridX, int& outGridY) const;
218 void GridToWorld(int gridX, int gridY, float& outWorldX, float& outWorldY) const;
219
220 // Validation
221 bool IsValidGridPosition(int x, int y) const;
222
223 // Getters
224 int GetWidth() const { return m_width; }
225 int GetHeight() const { return m_height; }
227
228 // Pathfinding support (A*)
229 struct PathNode
230 {
231 int x, y;
232 float gCost; // Cost from start
233 float hCost; // Heuristic to goal
234 float fCost() const { return gCost + hCost; }
236
237 PathNode() : x(0), y(0), gCost(0), hCost(0), parent(nullptr) {}
238 PathNode(int _x, int _y) : x(_x), y(_y), gCost(0), hCost(0), parent(nullptr) {}
239 };
240
241 // A* pathfinding
242 bool FindPath(int startX, int startY, int goalX, int goalY,
243 std::vector<Vector>& outPath, CollisionLayer layer = CollisionLayer::Ground, int maxIterations = 10000);
244
245 // NEW: Get random navigable point within radius from center position
246 // Returns true if found, false if all attempts failed
247 // outX, outY: world coordinates of the found point
248 bool GetRandomNavigablePoint(float centerX, float centerY, float radius,
249 int maxAttempts, float& outX, float& outY,
251
252 // Clear
253 void Clear();
254
255
256 NavigationMap() = default;
257 ~NavigationMap() = default;
258 NavigationMap(const NavigationMap&) = delete;
260
261 int m_width = 0;
262 int m_height = 0;
264 float m_tileWidth = 32.0f;
265 float m_tileHeight = 32.0f;
267 int m_numLayers = 1;
268
269 // Helper: calculate heuristic for A*
270 float Heuristic(int x1, int y1, int x2, int y2) const;
271
272 // Helper: get neighbors (handles ortho/iso/hex)
273 void GetNeighbors(int x, int y, std::vector<std::pair<int, int>>& outNeighbors) const;
274};
GridProjectionType
CollisionLayer
TerrainType
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
void LoadSector(int sectorX, int sectorY)
std::vector< std::vector< std::vector< TileProperties > > > m_layers
static const TileProperties s_emptyTile
int GetHeight() const
void GridToWorld(int gridX, int gridY, float &outWorldX, float &outWorldY) const
void SetActiveLayer(CollisionLayer layer)
const TileProperties & GetTileProperties(int x, int y) const
CollisionLayer GetActiveLayer() const
void RegisterSector(int sectorX, int sectorY, int width, int height)
float GetTileHeight() const
CollisionLayer m_activeLayer
float GetTileWidth() const
void SetCollision(int x, int y, bool hasCollision)
void UpdateTileState(int x, int y, TileUpdateFunc updateFunc)
GridProjectionType GetProjection() const
const std::vector< std::vector< TileProperties > > & GetLayer(CollisionLayer layer) const
bool IsValidGridPosition(int x, int y) const
int GetWidth() const
std::vector< Sector > m_sectors
CollisionMap()=default
void SetTileProperties(int x, int y, const TileProperties &props)
std::function< void(TileProperties &)> TileUpdateFunc
CollisionMap & operator=(const CollisionMap &)=delete
bool HasCollision(int x, int y) const
void Initialize(int width, int height, GridProjectionType projection, float tileWidth, float tileHeight, int numLayers=1, float tileOffsetX=0.0f, float tileOffsetY=0.0f)
GridProjectionType m_projection
float m_tileOffsetY
void UnloadSector(int sectorX, int sectorY)
int GetNumLayers() const
static CollisionMap & Get()
const std::vector< Sector > & GetSectors() const
float m_tileOffsetX
void WorldToGrid(float worldX, float worldY, int &outGridX, int &outGridY) const
~CollisionMap()=default
CollisionMap(const CollisionMap &)=delete
NavigationMap(const NavigationMap &)=delete
NavigationMap & operator=(const NavigationMap &)=delete
bool FindPath(int startX, int startY, int goalX, int goalY, std::vector< Vector > &outPath, CollisionLayer layer=CollisionLayer::Ground, int maxIterations=10000)
int GetHeight() const
CollisionLayer GetActiveLayer() const
void WorldToGrid(float worldX, float worldY, int &outGridX, int &outGridY) const
void SetNavigable(int x, int y, bool isNavigable, float cost=1.0f)
bool GetRandomNavigablePoint(float centerX, float centerY, float radius, int maxAttempts, float &outX, float &outY, CollisionLayer layer=CollisionLayer::Ground) const
NavigationMap()=default
static NavigationMap & Get()
int GetWidth() const
float Heuristic(int x1, int y1, int x2, int y2) const
float GetTraversalCost(int x, int y) const
bool IsValidGridPosition(int x, int y) const
CollisionLayer m_activeLayer
void Initialize(int width, int height, GridProjectionType projection, float tileWidth, float tileHeight, int numLayers=1)
bool IsNavigable(int x, int y) const
GridProjectionType GetProjection() const
void SetActiveLayer(CollisionLayer layer)
~NavigationMap()=default
void GetNeighbors(int x, int y, std::vector< std::pair< int, int > > &outNeighbors) const
void GridToWorld(int gridX, int gridY, float &outWorldX, float &outWorldY) const
GridProjectionType m_projection
PathNode(int _x, int _y)
TileProperties()=default
CollisionLayer layer
std::string onDestroyedState
uint8_t customFlags
std::string onBuiltState
std::string metadata
TerrainType terrain