|
|
@@ -0,0 +1,146 @@
|
|
|
+#include "TileMap.h"
|
|
|
+#include <stdexcept>
|
|
|
+#include <iostream>
|
|
|
+
|
|
|
+TileMap::TileMap(const std::string& mapName, int wChunks, int hChunks)
|
|
|
+ : name(mapName), mapWidthInChunks(wChunks), mapHeightInChunks(hChunks)
|
|
|
+{
|
|
|
+ if (wChunks <= 0 || hChunks <=0)
|
|
|
+ {
|
|
|
+ throw std::invalid_argument("TileMap dimensions must be positive");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+Chunk* TileMap::GetChunk(int worldChunkX, int worldChunkY)
|
|
|
+{
|
|
|
+ if (worldChunkX < 0 || worldChunkX >= mapWidthInChunks ||
|
|
|
+ worldChunkY < 0 || worldChunkY >= mapHeightInChunks)
|
|
|
+ {
|
|
|
+ return nullptr; // Out of bounds
|
|
|
+ }
|
|
|
+
|
|
|
+ uint64_t key = MakeKey(worldChunkX, worldChunkY);
|
|
|
+
|
|
|
+ auto it = chunks.find(key);
|
|
|
+ if (it == chunks.end())
|
|
|
+ {
|
|
|
+ // Lazy chunk creation -- only allocate when first accessed
|
|
|
+ auto [newIt, inserted] = chunks.emplace(key, Chunk(worldChunkX, worldChunkY));
|
|
|
+ return &newIt->second;
|
|
|
+ }
|
|
|
+
|
|
|
+ return &it->second;
|
|
|
+}
|
|
|
+
|
|
|
+const Chunk* TileMap::GetChunk(int worldChunkX, int worldChunkY) const
|
|
|
+{
|
|
|
+ // Const version delegates to non-const version using const_cast
|
|
|
+ return const_cast<TileMap*>(this)->GetChunk(worldChunkX, worldChunkY);
|
|
|
+}
|
|
|
+
|
|
|
+// Convert world tile coords into chunk+local coords
|
|
|
+// Returns pointer to the Tile or nullptr if out of bounds
|
|
|
+Tile* TileMap::GetTile(int worldTileX, int worldTileY)
|
|
|
+{
|
|
|
+ // Convert world tile position to chunk position + local position inside chunk
|
|
|
+ int chunkX = worldTileX / CHUNK_SIZE;
|
|
|
+ int chunkY = worldTileY / CHUNK_SIZE;
|
|
|
+
|
|
|
+ int localX = worldTileX % CHUNK_SIZE;
|
|
|
+ int localY = worldTileY % CHUNK_SIZE;
|
|
|
+
|
|
|
+ // Handle negative coords
|
|
|
+ if (worldTileX < 0)
|
|
|
+ {
|
|
|
+ chunkX--;
|
|
|
+ localX = CHUNK_SIZE + (worldTileX % CHUNK_SIZE);
|
|
|
+ }
|
|
|
+ if (worldTileY < 0)
|
|
|
+ {
|
|
|
+ chunkY--;
|
|
|
+ localY = CHUNK_SIZE + (worldTileY % CHUNK_SIZE);
|
|
|
+ }
|
|
|
+
|
|
|
+ Chunk* chunk = GetChunk(chunkX, chunkY);
|
|
|
+ if (!chunk)
|
|
|
+ {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ return &chunk->GetTile(localX, localY);
|
|
|
+}
|
|
|
+
|
|
|
+const Tile* TileMap::GetTile(int worldTileX, int worldTileY) const
|
|
|
+{
|
|
|
+ return const_cast<TileMap*>(this)->GetTile(worldTileX, worldTileY);
|
|
|
+}
|
|
|
+
|
|
|
+// Set tile at world coordinates
|
|
|
+// Create chunk if necessary
|
|
|
+void TileMap::SetTile(int worldTileX, int worldTileY, const Tile& tile)
|
|
|
+{
|
|
|
+ int chunkX = worldTileX / CHUNK_SIZE;
|
|
|
+ int chunkY = worldTileY / CHUNK_SIZE;
|
|
|
+
|
|
|
+ int localX = worldTileX % CHUNK_SIZE;
|
|
|
+ int localY = worldTileY % CHUNK_SIZE;
|
|
|
+
|
|
|
+ if (worldTileX < 0)
|
|
|
+ {
|
|
|
+ chunkX--;
|
|
|
+ localX = CHUNK_SIZE + (worldTileX % CHUNK_SIZE);
|
|
|
+ }
|
|
|
+ if (worldTileY < 0)
|
|
|
+ {
|
|
|
+ chunkY--;
|
|
|
+ localY = CHUNK_SIZE + (worldTileY % CHUNK_SIZE);
|
|
|
+ }
|
|
|
+
|
|
|
+ Chunk* chunk = GetChunk(chunkX, chunkY);
|
|
|
+ if (chunk)
|
|
|
+ {
|
|
|
+ chunk->SetTile(localX, localY, tile);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Returns list of chunks that intersects with camera rectangle
|
|
|
+// i.e. only draw visible chunks
|
|
|
+std::vector<Chunk*> TileMap::GetVisibleChunks(int cameraWorldX, int cameraWorldY,
|
|
|
+ int cameraWidth, int cameraHeight)
|
|
|
+{
|
|
|
+ std::vector<Chunk*> visible;
|
|
|
+
|
|
|
+ // Convert camera coords to chunk coords
|
|
|
+ int startChunkX = cameraWorldX / CHUNK_SIZE;
|
|
|
+ int startChunkY = cameraWorldY / CHUNK_SIZE;
|
|
|
+
|
|
|
+ int endChunkX = (cameraWorldX + cameraWidth + CHUNK_SIZE - 1) / CHUNK_SIZE;
|
|
|
+ int endChunkY = (cameraWorldY + cameraHeight + CHUNK_SIZE - 1) / CHUNK_SIZE;
|
|
|
+
|
|
|
+ // Small margin to avoid popping at edges
|
|
|
+ startChunkX -= 1;
|
|
|
+ startChunkY -= 1;
|
|
|
+ endChunkX += 1;
|
|
|
+ endChunkY += 1;
|
|
|
+
|
|
|
+ for (int cy = startChunkY; cy <= endChunkY; ++cy)
|
|
|
+ {
|
|
|
+ for (int cx = startChunkX; cx <= endChunkX; ++cx)
|
|
|
+ {
|
|
|
+ Chunk* chunk = GetChunk(cx, cy);
|
|
|
+ if (chunk && chunk->IsValid())
|
|
|
+ {
|
|
|
+ visible.push_back(chunk);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return visible;
|
|
|
+}
|
|
|
+
|
|
|
+void TileMap::PrintInfo() const
|
|
|
+{
|
|
|
+ std::cout << "[TileMap] Map: " << name
|
|
|
+ << " | Size: " << mapWidthInChunks << "x" << mapHeightInChunks
|
|
|
+ << " chunks | Loaded chunks: " << chunks.size() << "\n";
|
|
|
+}
|