From bda1b19083aac35d54b9695a881e276e4c8e88cb Mon Sep 17 00:00:00 2001 From: Maxim Rodionov Date: Sun, 2 Nov 2025 02:26:02 +0300 Subject: [PATCH 1/3] refactor: engine files structure --- README.md | 7 +++- engine/CMakeLists.txt | 7 +++- engine/{ => core}/camera.cpp | 2 +- engine/{ => core}/camera.h | 0 engine/{ => core}/engine.cpp | 2 +- engine/{ => core}/engine.h | 10 ++--- engine/{ => core}/input.cpp | 4 +- engine/{ => core}/input.h | 0 engine/{ => core}/loop.h | 2 +- engine/{ => core}/render.cpp | 8 ++-- engine/{ => core}/render.h | 2 +- engine/{ => core}/render_frame.h | 0 engine/{ => ecs}/components.h | 0 engine/{ => ecs}/systems.cpp | 15 ++++---- engine/{ => ecs}/systems.h | 4 +- engine/{ => ecs}/tile.h | 0 engine/{ => ecs}/utils.h | 0 engine/{ => resources}/image_manager.cpp | 0 engine/{ => resources}/image_manager.h | 0 engine/{ => resources}/serializable_world.cpp | 4 -- engine/{ => resources}/serializable_world.h | 2 +- engine/tests/camera_test.cpp | 2 +- engine/tests/system_animation_test.cpp | 4 +- engine/tests/system_create_entities_test.cpp | 6 +-- engine/tests/system_input_test.cpp | 6 +-- engine/tests/system_movement_test.cpp | 6 +-- .../tests/system_npc_movement_logic_test.cpp | 4 +- game/loops/game_loop.cpp | 15 ++++---- game/loops/game_loop.h | 6 +-- game/main.cpp | 2 +- scripts/build.sh | 38 ++++++++++++++++++- 31 files changed, 97 insertions(+), 61 deletions(-) rename engine/{ => core}/camera.cpp (97%) rename engine/{ => core}/camera.h (100%) rename engine/{ => core}/engine.cpp (98%) rename engine/{ => core}/engine.h (92%) rename engine/{ => core}/input.cpp (94%) rename engine/{ => core}/input.h (100%) rename engine/{ => core}/loop.h (98%) rename engine/{ => core}/render.cpp (97%) rename engine/{ => core}/render.h (99%) rename engine/{ => core}/render_frame.h (100%) rename engine/{ => ecs}/components.h (100%) rename engine/{ => ecs}/systems.cpp (98%) rename engine/{ => ecs}/systems.h (98%) rename engine/{ => ecs}/tile.h (100%) rename engine/{ => ecs}/utils.h (100%) rename engine/{ => resources}/image_manager.cpp (100%) rename engine/{ => resources}/image_manager.h (100%) rename engine/{ => resources}/serializable_world.cpp (84%) rename engine/{ => resources}/serializable_world.h (98%) diff --git a/README.md b/README.md index c6a27db..5249be6 100644 --- a/README.md +++ b/README.md @@ -58,9 +58,12 @@ sudo apt install \ ### Build ```shell -./scripts/build.sh +./scripts/build.sh --release +``` +If you want to build without tests: +```shell +./scripts/build.sh --release --without-tests ``` - ### Play ```shell diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 8a09df1..9fdb22d 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -1,4 +1,5 @@ -file(GLOB SOURCES_CXX *.cpp) +file(GLOB_RECURSE SOURCES_CXX *.cpp) +list(FILTER SOURCES_CXX EXCLUDE REGEX ".*/tests/.*") add_library(engine ${SOURCES_CXX}) target_link_libraries(engine PUBLIC @@ -9,4 +10,6 @@ target_link_libraries(engine PUBLIC cereal) target_include_directories(engine PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -add_subdirectory(tests) +if(BUILD_TESTING) + add_subdirectory(tests) +endif() diff --git a/engine/camera.cpp b/engine/core/camera.cpp similarity index 97% rename from engine/camera.cpp rename to engine/core/camera.cpp index 60845f0..8cdf4eb 100644 --- a/engine/camera.cpp +++ b/engine/core/camera.cpp @@ -1,4 +1,4 @@ -#include "camera.h" +#include "core/camera.h" #include #include diff --git a/engine/camera.h b/engine/core/camera.h similarity index 100% rename from engine/camera.h rename to engine/core/camera.h diff --git a/engine/engine.cpp b/engine/core/engine.cpp similarity index 98% rename from engine/engine.cpp rename to engine/core/engine.cpp index 0d1df65..1d8e4fa 100644 --- a/engine/engine.cpp +++ b/engine/core/engine.cpp @@ -1,4 +1,4 @@ -#include "engine.h" +#include "core/engine.h" #include #include diff --git a/engine/engine.h b/engine/core/engine.h similarity index 92% rename from engine/engine.h rename to engine/core/engine.h index 1bf7aef..a5205e1 100644 --- a/engine/engine.h +++ b/engine/core/engine.h @@ -1,10 +1,10 @@ #pragma once -#include "camera.h" -#include "image_manager.h" -#include "input.h" -#include "loop.h" -#include "render.h" +#include "core/camera.h" +#include "core/input.h" +#include "core/loop.h" +#include "core/render.h" +#include "resources/image_manager.h" namespace engine { diff --git a/engine/input.cpp b/engine/core/input.cpp similarity index 94% rename from engine/input.cpp rename to engine/core/input.cpp index 00b628f..a74537a 100644 --- a/engine/input.cpp +++ b/engine/core/input.cpp @@ -1,6 +1,6 @@ -#include "input.h" +#include "core/input.h" -#include "render.h" +#include "core/render.h" namespace engine { diff --git a/engine/input.h b/engine/core/input.h similarity index 100% rename from engine/input.h rename to engine/core/input.h diff --git a/engine/loop.h b/engine/core/loop.h similarity index 98% rename from engine/loop.h rename to engine/core/loop.h index 9c39ba2..a1b74e7 100644 --- a/engine/loop.h +++ b/engine/core/loop.h @@ -1,6 +1,6 @@ #pragma once -#include "input.h" +#include "core/input.h" #include namespace engine { diff --git a/engine/render.cpp b/engine/core/render.cpp similarity index 97% rename from engine/render.cpp rename to engine/core/render.cpp index 93531d2..497b8dc 100644 --- a/engine/render.cpp +++ b/engine/core/render.cpp @@ -1,8 +1,8 @@ -#include "render.h" +#include "core/render.h" -#include "camera.h" -#include "loop.h" -#include "tile.h" +#include "core/camera.h" +#include "core/loop.h" +#include "ecs/tile.h" #include namespace engine { diff --git a/engine/render.h b/engine/core/render.h similarity index 99% rename from engine/render.h rename to engine/core/render.h index ff0795d..87e8e8e 100644 --- a/engine/render.h +++ b/engine/core/render.h @@ -1,6 +1,6 @@ #pragma once -#include "render_frame.h" +#include "core/render_frame.h" #include #include #include diff --git a/engine/render_frame.h b/engine/core/render_frame.h similarity index 100% rename from engine/render_frame.h rename to engine/core/render_frame.h diff --git a/engine/components.h b/engine/ecs/components.h similarity index 100% rename from engine/components.h rename to engine/ecs/components.h diff --git a/engine/systems.cpp b/engine/ecs/systems.cpp similarity index 98% rename from engine/systems.cpp rename to engine/ecs/systems.cpp index d65a65c..a4d750a 100644 --- a/engine/systems.cpp +++ b/engine/ecs/systems.cpp @@ -1,10 +1,11 @@ -#include "systems.h" -#include "camera.h" -#include "components.h" -#include "image_manager.h" -#include "input.h" -#include "render_frame.h" -#include "utils.h" +#include "ecs/systems.h" + +#include "core/camera.h" +#include "core/input.h" +#include "core/render_frame.h" +#include "ecs/components.h" +#include "ecs/utils.h" +#include "resources/image_manager.h" #include #include diff --git a/engine/systems.h b/engine/ecs/systems.h similarity index 98% rename from engine/systems.h rename to engine/ecs/systems.h index 5a11b1d..dd46626 100644 --- a/engine/systems.h +++ b/engine/ecs/systems.h @@ -1,7 +1,7 @@ #pragma once -#include "components.h" -#include "tile.h" +#include "ecs/components.h" +#include "ecs/tile.h" #include namespace engine { diff --git a/engine/tile.h b/engine/ecs/tile.h similarity index 100% rename from engine/tile.h rename to engine/ecs/tile.h diff --git a/engine/utils.h b/engine/ecs/utils.h similarity index 100% rename from engine/utils.h rename to engine/ecs/utils.h diff --git a/engine/image_manager.cpp b/engine/resources/image_manager.cpp similarity index 100% rename from engine/image_manager.cpp rename to engine/resources/image_manager.cpp diff --git a/engine/image_manager.h b/engine/resources/image_manager.h similarity index 100% rename from engine/image_manager.h rename to engine/resources/image_manager.h diff --git a/engine/serializable_world.cpp b/engine/resources/serializable_world.cpp similarity index 84% rename from engine/serializable_world.cpp rename to engine/resources/serializable_world.cpp index 857f8de..5b884b1 100644 --- a/engine/serializable_world.cpp +++ b/engine/resources/serializable_world.cpp @@ -1,12 +1,8 @@ #include "serializable_world.h" -#include #include #include #include -#include -#include -#include namespace engine { diff --git a/engine/serializable_world.h b/engine/resources/serializable_world.h similarity index 98% rename from engine/serializable_world.h rename to engine/resources/serializable_world.h index 7a8287b..73e055f 100644 --- a/engine/serializable_world.h +++ b/engine/resources/serializable_world.h @@ -1,8 +1,8 @@ #pragma once #include +#include #include -#include #include namespace engine { diff --git a/engine/tests/camera_test.cpp b/engine/tests/camera_test.cpp index 3272c55..b50ac0f 100644 --- a/engine/tests/camera_test.cpp +++ b/engine/tests/camera_test.cpp @@ -1,4 +1,4 @@ -#include "camera.h" +#include "core/camera.h" #include "gtest/gtest.h" const float TOLERANCE = 0.0001f; diff --git a/engine/tests/system_animation_test.cpp b/engine/tests/system_animation_test.cpp index 007ef8e..3a03fa3 100644 --- a/engine/tests/system_animation_test.cpp +++ b/engine/tests/system_animation_test.cpp @@ -1,5 +1,5 @@ -#include "components.h" -#include "systems.h" +#include "ecs/components.h" +#include "ecs/systems.h" #include "gtest/gtest.h" #include diff --git a/engine/tests/system_create_entities_test.cpp b/engine/tests/system_create_entities_test.cpp index 0838d7f..62a0852 100644 --- a/engine/tests/system_create_entities_test.cpp +++ b/engine/tests/system_create_entities_test.cpp @@ -1,6 +1,6 @@ -#include "components.h" -#include "engine.h" -#include "systems.h" +#include "core/engine.h" +#include "ecs/components.h" +#include "ecs/systems.h" #include "gtest/gtest.h" #include #include diff --git a/engine/tests/system_input_test.cpp b/engine/tests/system_input_test.cpp index 62d762c..7887166 100644 --- a/engine/tests/system_input_test.cpp +++ b/engine/tests/system_input_test.cpp @@ -1,6 +1,6 @@ -#include "components.h" -#include "input.h" -#include "systems.h" +#include "core/input.h" +#include "ecs/components.h" +#include "ecs/systems.h" #include "gtest/gtest.h" #include #include diff --git a/engine/tests/system_movement_test.cpp b/engine/tests/system_movement_test.cpp index 8ee859c..af5b65f 100644 --- a/engine/tests/system_movement_test.cpp +++ b/engine/tests/system_movement_test.cpp @@ -1,6 +1,6 @@ -#include "components.h" -#include "input.h" -#include "systems.h" +#include "core/input.h" +#include "ecs/components.h" +#include "ecs/systems.h" #include "gtest/gtest.h" #include diff --git a/engine/tests/system_npc_movement_logic_test.cpp b/engine/tests/system_npc_movement_logic_test.cpp index 213508c..7b187db 100644 --- a/engine/tests/system_npc_movement_logic_test.cpp +++ b/engine/tests/system_npc_movement_logic_test.cpp @@ -1,5 +1,5 @@ -#include "components.h" -#include "systems.h" +#include "ecs/components.h" +#include "ecs/systems.h" #include "gtest/gtest.h" #include #include diff --git a/game/loops/game_loop.cpp b/game/loops/game_loop.cpp index da9205f..7d68c84 100644 --- a/game/loops/game_loop.cpp +++ b/game/loops/game_loop.cpp @@ -1,13 +1,12 @@ #include "game_loop.h" -#include "camera.h" -#include "components.h" -#include "engine.h" -#include "image_manager.h" -#include "render.h" -#include "render_frame.h" -#include "serializable_world.h" -#include "systems.h" +#include "core/camera.h" +#include "core/engine.h" +#include "core/render.h" +#include "core/render_frame.h" +#include "ecs/components.h" +#include "ecs/systems.h" +#include "resources/image_manager.h" #include GameLoop::GameLoop() { diff --git a/game/loops/game_loop.h b/game/loops/game_loop.h index 3d35131..9a1fee4 100644 --- a/game/loops/game_loop.h +++ b/game/loops/game_loop.h @@ -1,8 +1,8 @@ #pragma once -#include "loop.h" -#include "serializable_world.h" -#include "tile.h" +#include "core/loop.h" +#include "ecs/tile.h" +#include "resources/serializable_world.h" #include #include #include diff --git a/game/main.cpp b/game/main.cpp index 7fee083..16768fb 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -1,4 +1,4 @@ -#include "engine.h" +#include "core/engine.h" #include "loops/game_loop.h" #include diff --git a/scripts/build.sh b/scripts/build.sh index c345f14..81f6c68 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -3,5 +3,39 @@ BASEDIR=$(realpath "$(dirname "$0")") ROOTDIR=$(realpath "$BASEDIR/..") -cmake -S . -B "$ROOTDIR/build" -DBUILD_TESTING=ON -cmake --build "$ROOTDIR/build" +RELEASE=false +WITH_TESTS=true +BUILD_DIR="$ROOTDIR/build" +CMAKE_BUILD_TYPE="" +CMAKE_OPTIONS="" + +for arg in "$@"; do + case $arg in + --release) + RELEASE=true + ;; + --without-tests) + WITH_TESTS=false + ;; + *) + echo "Unknown argument: $arg" + ;; + esac +done + +if [ "$RELEASE" = true ]; then + CMAKE_BUILD_TYPE="-DCMAKE_BUILD_TYPE=Release" + CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_TESTING=OFF" + echo "Release build" +else + CMAKE_BUILD_TYPE="-DCMAKE_BUILD_TYPE=Debug" + echo "Debug build" + if [ "$WITH_TESTS" = true ]; then + CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_TESTING=ON" + else + CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_TESTING=OFF" + fi +fi + +cmake -S "$ROOTDIR" -B "$BUILD_DIR" $CMAKE_BUILD_TYPE $CMAKE_OPTIONS +cmake --build "$BUILD_DIR" --config $( [ "$RELEASE" = true ] && echo "Release" || echo "Debug" ) From 07c03fd10acca0d9c360e7d275e0a4a5a2bd6cfb Mon Sep 17 00:00:00 2001 From: Maxim Rodionov Date: Sun, 2 Nov 2025 03:27:57 +0300 Subject: [PATCH 2/3] refactor: move some code from game into engine --- engine/ecs/utils.h | 27 +++++++++++++++++++++++++++ engine/ecs/world_loader.cpp | 29 +++++++++++++++++++++++++++++ engine/ecs/world_loader.h | 34 ++++++++++++++++++++++++++++++++++ game/loops/game_loop.cpp | 35 ++++++++--------------------------- 4 files changed, 98 insertions(+), 27 deletions(-) create mode 100644 engine/ecs/world_loader.cpp create mode 100644 engine/ecs/world_loader.h diff --git a/engine/ecs/utils.h b/engine/ecs/utils.h index 3573420..cd5ccea 100644 --- a/engine/ecs/utils.h +++ b/engine/ecs/utils.h @@ -1,6 +1,11 @@ #pragma once + +#include "ecs/tile.h" +#include "resources/image_manager.h" +#include "resources/serializable_world.h" #include #include +#include namespace engine { @@ -55,4 +60,26 @@ inline sf::IntRect calculateContentRect(const sf::Image &image, return {{minX, minY}, {(maxX - minX) + 1, (maxY - minY) + 1}}; } + +/** + * @brief Generates a mapping from tile IDs to their corresponding visual data. + * @param textures A map of tile IDs to their texture metadata (`TileTexture`). + * @param imgMgr Reference to the `ImageManager` used to load or retrieve textures. + * @return An unordered_map where each key is a tile ID and the value is a `TileData` + * struct containing a pointer to the image and the tile's height. + */ +inline std::unordered_map +makeTileData(const std::unordered_map &textures, + ImageManager &imgMgr) { + std::unordered_map tileImages; + + for (auto keyvalue : textures) { + int key = keyvalue.first; + auto tex = keyvalue.second; + tileImages[key] = {&imgMgr.getImage(tex.texture_src), tex.height}; + } + + return tileImages; +} + } // namespace engine diff --git a/engine/ecs/world_loader.cpp b/engine/ecs/world_loader.cpp new file mode 100644 index 0000000..0c01765 --- /dev/null +++ b/engine/ecs/world_loader.cpp @@ -0,0 +1,29 @@ +#include "ecs/world_loader.h" + +namespace engine { + +void WorldLoader::loadWorldFromJson( + const std::string &filename, int &width, int &height, + std::unordered_map &tileTextures, std::vector &tiles) { + SerializableWorld world = of_json("game/assets/worlds/meadow.json"); + height = world.world_height; + width = world.world_width; + tiles.resize(width * height); + tileTextures = world.textures; + + auto getIndex = [&](int x, int y) { + return (y + height / 2) * width + (x + width / 2); + }; + + for (int i = 0; i < world.areas.size(); i++) { + auto a = world.areas[i]; + + for (int x = a.posX; x < a.posX + a.sizeX; ++x) { + for (int y = a.posY; y < a.posY + a.sizeY; ++y) { + tiles[getIndex(x, y)] = a.tile; + } + } + } +} + +} // namespace engine diff --git a/engine/ecs/world_loader.h b/engine/ecs/world_loader.h new file mode 100644 index 0000000..282fca0 --- /dev/null +++ b/engine/ecs/world_loader.h @@ -0,0 +1,34 @@ +#pragma once + +#include "ecs/tile.h" +#include "resources/serializable_world.h" +#include +#include +#include + +namespace engine { + +/** + * @brief Loads a tile-based game world from a JSON file. + * + * Responsible for parsing a serialized world description, initializing the + * tile layout and tile texture data. Converts JSON representation of world + * areas into a flat tile vector for use by the engine. + */ +class WorldLoader { + public: + /** + * @brief Loads world data from a JSON file into provided containers. + * @param filename Path to the JSON file describing the world. + * @param width Output parameter for the width of the world in tiles. + * @param height Output parameter for the height of the world in tiles. + * @param tileTextures Output map of tile ID to `TileTexture` metadata. + * @param tiles Output vector of tiles representing the world layout. + */ + static void loadWorldFromJson(const std::string &filename, int &width, + int &height, + std::unordered_map &tileTextures, + std::vector &tiles); +}; + +} // namespace engine diff --git a/game/loops/game_loop.cpp b/game/loops/game_loop.cpp index 7d68c84..fe91bd3 100644 --- a/game/loops/game_loop.cpp +++ b/game/loops/game_loop.cpp @@ -6,28 +6,14 @@ #include "core/render_frame.h" #include "ecs/components.h" #include "ecs/systems.h" +#include "ecs/utils.h" +#include "ecs/world_loader.h" #include "resources/image_manager.h" #include GameLoop::GameLoop() { - engine::SerializableWorld world = - engine::of_json("game/assets/worlds/meadow.json"); - height = world.world_height; - width = world.world_width; - tiles.resize(width * height); - tileTextures = world.textures; - auto getIndex = [&](int x, int y) { - return (y + height / 2) * width + (x + width / 2); - }; - for (int i = 0; i < world.areas.size(); i++) { - auto a = world.areas[i]; - - for (int x = a.posX; x < a.posX + a.sizeX; ++x) { - for (int y = a.posY; y < a.posY + a.sizeY; ++y) { - tiles[getIndex(x, y)] = a.tile; - } - } - } + engine::WorldLoader::loadWorldFromJson("game/assets/worlds/meadow.json", width, + height, tileTextures, tiles); } void GameLoop::init() { @@ -36,19 +22,14 @@ void GameLoop::init() { sf::Vector2f screenCenter = m_engine->camera.worldToScreen(worldCenter); m_engine->camera.position = screenCenter; - // Generate tiles once + // Create and generate world tiles once - auto &imageManager = m_engine->imageManager; - std::unordered_map tileImages; - for (auto keyvalue : tileTextures) { - int key = keyvalue.first; - auto tex = keyvalue.second; - tileImages[key] = {&imageManager.getImage(tex.texture_src), tex.height}; - } const int tileWidth = 32.f; const int tileHeight = 32.f; m_engine->camera.setTileSize(tileWidth, tileHeight / 2); + auto tileImages = engine::makeTileData(tileTextures, m_engine->imageManager); + std::vector staticTiles = tiles; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { @@ -76,7 +57,7 @@ void GameLoop::init() { m_engine->render.generateTileMapVertices(m_staticMapPoints, m_engine->camera, staticTiles, width, height, tileImages); - // Creating entities (player, NPC, etc.) + // Create entities (player, NPC, etc.) sf::Vector2f targetWolfSize{64.f, 64.f}; sf::IntRect frameRect({0, 0}, {64, 64}); From dbf56a869692eef6789ba2329e47562c9db967e4 Mon Sep 17 00:00:00 2001 From: Maxim Rodionov Date: Sun, 2 Nov 2025 04:32:29 +0300 Subject: [PATCH 3/3] test: add tests for loadWorldFromJson --- engine/ecs/world_loader.cpp | 2 +- engine/tests/world_loader_test.cpp | 111 +++++++++++++++++++++++++++++ scripts/build.sh | 12 ++-- 3 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 engine/tests/world_loader_test.cpp diff --git a/engine/ecs/world_loader.cpp b/engine/ecs/world_loader.cpp index 0c01765..bf88c94 100644 --- a/engine/ecs/world_loader.cpp +++ b/engine/ecs/world_loader.cpp @@ -5,7 +5,7 @@ namespace engine { void WorldLoader::loadWorldFromJson( const std::string &filename, int &width, int &height, std::unordered_map &tileTextures, std::vector &tiles) { - SerializableWorld world = of_json("game/assets/worlds/meadow.json"); + SerializableWorld world = of_json(filename); height = world.world_height; width = world.world_width; tiles.resize(width * height); diff --git a/engine/tests/world_loader_test.cpp b/engine/tests/world_loader_test.cpp new file mode 100644 index 0000000..51d6624 --- /dev/null +++ b/engine/tests/world_loader_test.cpp @@ -0,0 +1,111 @@ +#include "ecs/world_loader.h" +#include "resources/serializable_world.h" +#include "gtest/gtest.h" +#include + +using namespace engine; + +// --- Test loading basic world --- +TEST(WorldLoaderTest, LoadBasicWorld) { + SerializableWorld world; + world.world_width = 8; + world.world_height = 8; + world.textures = {{1, {"grass.png", 1}}, {2, {"stone.png", 1}}}; + + // Area 1 + Area area1; + area1.posX = 0; + area1.posY = 0; + area1.sizeX = 2; + area1.sizeY = 2; + area1.tile.layerIds = {1}; + area1.tile.solid = false; + world.areas.push_back(area1); + + // Area 2 + Area area2; + area2.posX = 2; + area2.posY = 2; + area2.sizeX = 2; + area2.sizeY = 2; + area2.tile.layerIds = {2}; + area2.tile.solid = true; + world.areas.push_back(area2); + + std::string filename = "test_world.json"; + to_json(world, filename); + + int width = 0, height = 0; + std::unordered_map tileTextures; + std::vector tiles; + + WorldLoader::loadWorldFromJson(filename, width, height, tileTextures, tiles); + + // Check dimensions + EXPECT_EQ(width, 8); + EXPECT_EQ(height, 8); + EXPECT_EQ(tiles.size(), 64u); + + // Check tileTextures loaded + EXPECT_EQ(tileTextures.size(), 2u); + EXPECT_TRUE(tileTextures.find(1) != tileTextures.end()); + EXPECT_TRUE(tileTextures.find(2) != tileTextures.end()); + + // Check specific tiles + auto getIndex = [&](int x, int y) { + return (y + height / 2) * width + (x + width / 2); + }; + + // Area1 tiles + for (int x = 0; x < 2; ++x) { + for (int y = 0; y < 2; ++y) { + const Tile &t = tiles[getIndex(x, y)]; + ASSERT_EQ(t.layerIds.size(), 1); + EXPECT_EQ(t.layerIds[0], 1); + EXPECT_FALSE(t.solid); + } + } + + // Area2 tiles + for (int x = 2; x < 4; ++x) { + for (int y = 2; y < 4; ++y) { + const Tile &t = tiles[getIndex(x, y)]; + ASSERT_EQ(t.layerIds.size(), 1); + EXPECT_EQ(t.layerIds[0], 2); + EXPECT_TRUE(t.solid); + } + } + + // Cleanup + std::filesystem::remove(filename); +} + +// --- Test empty world (no areas) --- +TEST(WorldLoaderTest, LoadEmptyWorld) { + SerializableWorld world; + world.world_width = 1; + world.world_height = 1; + world.textures = {}; + + std::string filename = "empty_world.json"; + to_json(world, filename); + + int width = 0, height = 0; + std::unordered_map tileTextures; + std::vector tiles; + + WorldLoader::loadWorldFromJson(filename, width, height, tileTextures, tiles); + + EXPECT_EQ(width, 1); + EXPECT_EQ(height, 1); + EXPECT_EQ(tiles.size(), 1u); + EXPECT_TRUE(tileTextures.empty()); + + // All tiles should be default-initialized + for (const auto &t : tiles) { + EXPECT_TRUE(t.layerIds.empty()); + EXPECT_FALSE(t.solid); + } + + std::filesystem::remove(filename); +} diff --git a/scripts/build.sh b/scripts/build.sh index 81f6c68..a150682 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -25,16 +25,16 @@ done if [ "$RELEASE" = true ]; then CMAKE_BUILD_TYPE="-DCMAKE_BUILD_TYPE=Release" - CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_TESTING=OFF" echo "Release build" else CMAKE_BUILD_TYPE="-DCMAKE_BUILD_TYPE=Debug" echo "Debug build" - if [ "$WITH_TESTS" = true ]; then - CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_TESTING=ON" - else - CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_TESTING=OFF" - fi +fi + +if [ "$WITH_TESTS" = true ]; then + CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_TESTING=ON" +else + CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_TESTING=OFF" fi cmake -S "$ROOTDIR" -B "$BUILD_DIR" $CMAKE_BUILD_TYPE $CMAKE_OPTIONS