Selaa lähdekoodia

Tiles/Chunks/TileMaps

Vitaliy Polonski 3 tuntia sitten
vanhempi
commit
48b74a1cb1
8 muutettua tiedostoa jossa 411 lisäystä ja 1 poistoa
  1. 4 1
      CMakeLists.txt
  2. 25 0
      src/tiles/Chunk.cpp
  3. 24 0
      src/tiles/Chunk.h
  4. 18 0
      src/tiles/Tile.h
  5. 146 0
      src/tiles/TileMap.cpp
  6. 41 0
      src/tiles/TileMap.h
  7. 111 0
      src/tiles/TileMapManager.cpp
  8. 42 0
      src/tiles/TileMapManager.h

+ 4 - 1
CMakeLists.txt

@@ -54,7 +54,10 @@ add_executable(kariokaEngine
 
 	# Components
 
-	# etc
+	# TileMap
+	src/tiles/Chunk.cpp
+	src/tiles/TileMap.cpp
+	src/tiles/TileMapManager.cpp
 )
 
 target_link_libraries(kariokaEngine PRIVATE

+ 25 - 0
src/tiles/Chunk.cpp

@@ -0,0 +1,25 @@
+#include "Chunk.h"
+
+Chunk::Chunk(int x, int y) : chunkX(x), chunkY(y)
+{
+    tiles.resize(CHUNK_SIZE * CHUNK_SIZE);
+}
+
+Tile& Chunk::GetTile(int localX, int localY)
+{
+    if (localX < 0 || localX >= CHUNK_SIZE || localY < 0 || localY >= CHUNK_SIZE)
+    {
+        throw std::out_of_range("Local tile coordinates out of chunk bonds");
+    }
+    return tiles[localY * CHUNK_SIZE + localX];
+}
+
+const Tile& Chunk::GetTile(int localX, int localY) const
+{
+    return const_cast<Chunk*>(this)->GetTile(localX, localY);
+}
+
+void Chunk::SetTile(int localX, int localY, const Tile& tile)
+{
+    GetTile(localX, localY) = tile;
+}

+ 24 - 0
src/tiles/Chunk.h

@@ -0,0 +1,24 @@
+#ifndef __TILES__CHUNK_H__
+#define __TILES__CHUNK_H__
+
+#include "Tile.h"
+#include <vector>
+#include <cstdint>
+
+constexpr int CHUNK_SIZE = 32;
+
+struct Chunk
+{
+    std::vector<Tile> tiles;
+    int chunkX = 0;
+    int chunkY = 0;
+    
+    Chunk(int x = 0, int y = 0);
+    
+    Tile& GetTile(int localX, int localY);
+    const Tile& GetTile(int localX, int localY) const;
+    void SetTile(int localX, int localY, const Tile& tile);
+    bool IsValid() const { return !tiles.empty(); }
+};
+
+#endif

+ 18 - 0
src/tiles/Tile.h

@@ -0,0 +1,18 @@
+#ifndef __TILES__TILE_H__
+#define __TILES__TILE_H__
+
+#include <cstdint>
+
+struct Tile
+{
+public:
+    uint32_t tileId = 0;
+    uint8_t  flags = 0;
+    
+    bool isSolid() const { return (flags & 0x01) != 0; }
+
+private:
+
+};
+
+#endif

+ 146 - 0
src/tiles/TileMap.cpp

@@ -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";
+}

+ 41 - 0
src/tiles/TileMap.h

@@ -0,0 +1,41 @@
+#ifndef __TILES__TILE_MAP_H__
+#define __TILES__TILE_MAP_H__
+
+#include "Chunk.h"
+#include <unordered_map>
+#include <string>
+
+class TileMap
+{
+public:
+    std::string name;
+    int mapWidthInChunks = 0;
+    int mapHeightInChunks = 0;
+    
+    TileMap(const std::string& mapName, int wChunks, int hChunks);
+    
+    // World coordinates to chunk + local
+    Chunk* GetChunk(int worldChunkX, int worldChunkY);
+    const Chunk* GetChunk(int worldChunkX, int worldChunkY) const;
+    
+    Tile* GetTile(int worldTileX, int worldTileY);
+    const Tile* GetTile(int worldTileX, int worldTileY) const;
+
+    void SetTile(int worldX, int worldY, const Tile& tile);
+    
+    // Return only chunks that intersects camera
+    std::vector<Chunk*> GetVisibleChunks(int cameraX, int cameraY, int cameraW, int cameraH);
+    
+    void PrintInfo() const;
+
+private:
+    std::unordered_map<uint64_t, Chunk> chunks; // key = (y << 32) | x
+    
+    uint64_t MakeKey(int cx, int cy) const
+    {
+        return (static_cast<uint64_t>(cy) << 32 | static_cast<uint32_t>(cx));
+    }
+
+};
+
+#endif

+ 111 - 0
src/tiles/TileMapManager.cpp

@@ -0,0 +1,111 @@
+#include "TileMapManager.h"
+#include <iostream>
+
+TileMapManager::TileMapManager()
+{
+}
+
+void TileMapManager::CreateMap(const std::string& name, 
+                               int widthInChunks, 
+                               int heightInChunks)
+{
+    if (name.empty())
+    {
+        std::cerr << "[TileMapManager] Error: Map name cannot be empty\n";
+        return;
+    }
+    if (widthInChunks <= 0 || heightInChunks <= 0)
+    {
+        std::cerr << "[TileMapManager] Error: Map dimensions must be positive\n";
+        return;
+    }
+    
+    // Create and store map
+    maps.emplace(name, TileMap(name, widthInChunks, heightInChunks));
+    
+    // If this is the first map -- make it current
+    if (currentMapName.empty())
+    {
+        currentMapName = name;
+        std::cout << "[TileMapManager] Created and set as current: " << name << "\n";
+    }
+    else
+    {
+        std::cout << "[TileMapManager] Created map: " << name << "\n";
+    }
+}
+
+// Returns pointer to a map or nullptr
+TileMap* TileMapManager::GetMap(const std::string& name)
+{
+    auto it = maps.find(name);
+    if (it == maps.end())
+    {
+        return nullptr;
+    }
+    return &it->second;
+}
+
+const TileMap* TileMapManager::GetMap(const std::string& name) const
+{
+    auto it = maps.find(name);
+    if (it == maps.end())
+    {
+        return nullptr;
+    }
+    return &it->second;
+}
+
+// Returns current map or nullptr
+TileMap* TileMapManager::GetCurrentMap()
+{
+    return GetMap(currentMapName);
+}
+
+const TileMap* TileMapManager::GetCurrentMap() const
+{
+    return GetMap(currentMapName);
+}
+
+// Switch active map (returns true on success)
+bool TileMapManager::SetCurrentMap(const std::string& name)
+{
+    if (!HasMap(name))
+    {
+        std::cerr << "[TileMapManager] Error: Map " << name << " not found\n";
+        return false;
+    }
+    if (currentMapName == name)
+    {
+        std::cout << "[TileMapManager] Map " << name << " already loaded\n";
+        return true;
+    }
+    
+    currentMapName = name;
+    std::cout << "[TileMapManager] Map " << name << " loaded\n";
+    return true;
+}
+
+// Returns list of all map names
+std::vector<std::string> TileMapManager::GetAllMapNames() const
+{
+    std::vector<std::string> names;
+    names.reserve(maps.size());
+    for (const auto& pair : maps)
+    {
+        names.push_back(pair.first);
+    }
+    return names;
+}
+
+// Check if map exists
+bool TileMapManager::HasMap(const std::string& name) const
+{
+    return maps.find(name) != maps.end();
+}
+
+// Prints all maps and current map
+void TileMapManager::PrintAllMaps() const
+{
+    // TODO: Later
+}

+ 42 - 0
src/tiles/TileMapManager.h

@@ -0,0 +1,42 @@
+#ifndef __TILES__TILE_MAP_MANAGER_H__
+#define __TILES__TILE_MAP_MANAGER_H__
+
+#include "TileMap.h"
+#include <unordered_map>
+#include <string>
+#include <vector>
+
+class TileMapManager
+{
+public:
+    TileMapManager();
+
+    // Create new fixed-size map
+    void CreateMap(const std::string& name, int widthInChunks, int heightInChunks);
+    
+    // Get map by name
+    TileMap* GetMap(const std::string& name);
+    const TileMap* GetMap(const std::string& name) const;
+    
+    // Get currently active map
+    TileMap* GetCurrentMap();
+    const TileMap* GetCurrentMap() const;
+    
+    // Switch to another map on the fly    
+    bool SetCurrentMap(const std::string& name);
+    
+    // Utilities
+    std::vector<std::string> GetAllMapNames() const;
+    bool HasMap(const std::string& name) const;
+    void PrintAllMaps() const;
+    
+    // Python friendly later
+    std::vector<std::string> GetMapNames() const;
+
+private:
+    std::unordered_map<std::string, TileMap> maps;
+    std::string currentMapName;
+
+};
+
+#endif