From b607b9e1dbbb00110d4a04f5aeb701ad98d1b7bb Mon Sep 17 00:00:00 2001 From: Ziyu Date: Fri, 30 May 2025 16:23:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=85=B3=E5=8D=A1=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E5=99=A8-=E7=93=A6=E7=89=87=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 1 + Tiled地图解析思路.md | 11 +- src/engine/component/tilelayer_component.cpp | 85 ++++++++++ src/engine/component/tilelayer_component.h | 104 ++++++++++++ src/engine/render/sprite.h | 5 + src/engine/resource/texture_manager.cpp | 5 + src/engine/scene/level_loader.cpp | 157 +++++++++++++++++-- src/engine/scene/level_loader.h | 36 ++++- src/main.cpp | 2 +- 9 files changed, 390 insertions(+), 16 deletions(-) create mode 100644 src/engine/component/tilelayer_component.cpp create mode 100644 src/engine/component/tilelayer_component.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d2b30d5..ff7027f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ add_executable(${TARGET} src/engine/component/sprite_component.cpp src/engine/component/transform_component.cpp src/engine/component/parallax_component.cpp + src/engine/component/tilelayer_component.cpp src/engine/scene/scene.cpp src/engine/scene/scene_manager.cpp src/engine/scene/level_loader.cpp diff --git a/Tiled地图解析思路.md b/Tiled地图解析思路.md index 41a71d4..a660aca 100644 --- a/Tiled地图解析思路.md +++ b/Tiled地图解析思路.md @@ -1,7 +1,16 @@ # Tiled地图解析思路 +- 获取tilesets数组并载入图块集的数据 + - 获取layers数组并遍历对象 - 如果 type : imagelayer,载入单一图片 - 关注"parallax","repeat","offset"字段 - 创建包含 ParallaxComponent 的游戏对象 - - 如果 type : tilelayer …… + + - 如果 type : tilelayer,载入瓦片层 + - 总共有“地图大小”个瓦片,放入容器vector中 + - 每个瓦片包含数据:Sprite,Type(例如solid类型) + - 可能引用多个图块集,因此可先*载入并保存每个图块集的数据*(载入函数),其它瓦片层(以及对象层)也能继续引用 + - 通过data数组中的gid查找所需信息(查找函数),填充瓦片vector + - 创建包含 TileLayerComponent 的游戏对象(持有瓦片vector) + - 如果 type : objectgroup …… \ No newline at end of file diff --git a/src/engine/component/tilelayer_component.cpp b/src/engine/component/tilelayer_component.cpp new file mode 100644 index 0000000..c73301a --- /dev/null +++ b/src/engine/component/tilelayer_component.cpp @@ -0,0 +1,85 @@ +#include "tilelayer_component.h" +#include "../object/game_object.h" +#include "../core/context.h" +#include "../render/renderer.h" +#include "../render/camera.h" +#include + +namespace engine::component { + +TileLayerComponent::TileLayerComponent(glm::ivec2 tile_size, glm::ivec2 map_size, std::vector&& tiles) + : tile_size_(tile_size), + map_size_(map_size), + tiles_(std::move(tiles)) +{ + if (tiles_.size() != static_cast(map_size_.x * map_size_.y)) { + spdlog::error("TileLayerComponent: 地图尺寸与提供的瓦片向量大小不匹配。瓦片数据将被清除。"); + tiles_.clear(); + map_size_ = {0, 0}; + } + spdlog::trace("TileLayerComponent 构造完成"); +} + +void TileLayerComponent::init() { + if (!owner_) { + spdlog::warn("TileLayerComponent 的 owner_ 未设置。"); + } + spdlog::trace("TileLayerComponent 初始化完成"); +} + +void TileLayerComponent::render(engine::core::Context& context) { + if (tile_size_.x <= 0 || tile_size_.y <= 0) { + return; // 防止除以零或无效尺寸 + } + // 遍历所有瓦片 + for (int y = 0; y < map_size_.y; ++y) { + for (int x = 0; x < map_size_.x; ++x) { + size_t index = static_cast(y) * map_size_.x + x; + // 检查索引有效性以及瓦片是否需要渲染 + if (index < tiles_.size() && tiles_[index].type != TileType::EMPTY) { + const auto& tile_info = tiles_[index]; + // 计算该瓦片在世界中的左上角位置 (drawSprite 预期接收左上角坐标) + glm::vec2 tile_left_top_pos = { + offset_.x + static_cast(x) * tile_size_.x, + offset_.y + static_cast(y) * tile_size_.y + }; + // 但如果图片的大小与瓦片的大小不一致,需要调整 y 坐标 (瓦片层的对齐点是左下角) + if(static_cast(tile_info.sprite.getSourceRect()->h) != tile_size_.y) { + tile_left_top_pos.y -= (tile_info.sprite.getSourceRect()->h - static_cast(tile_size_.y)); + } + // 执行绘制 + context.getRenderer().drawSprite(context.getCamera(), tile_info.sprite, tile_left_top_pos); + } + } + } +} + +const TileInfo* TileLayerComponent::getTileInfoAt(glm::ivec2 pos) const { + if (pos.x < 0 || pos.x >= map_size_.x || pos.y < 0 || pos.y >= map_size_.y) { + spdlog::warn("TileLayerComponent: 瓦片坐标越界: ({}, {})", pos.x, pos.y); + return nullptr; + } + size_t index = static_cast(pos.y * map_size_.x + pos.x); + // 瓦片索引不能越界 + if (index < tiles_.size()) { + return &tiles_[index]; + } + spdlog::warn("TileLayerComponent: 瓦片索引越界: {}", index); + return nullptr; +} + +TileType TileLayerComponent::getTileTypeAt(glm::ivec2 pos) const { + const TileInfo* info = getTileInfoAt(pos); + return info ? info->type : TileType::EMPTY; +} + +TileType TileLayerComponent::getTileTypeAtWorldPos(const glm::vec2& world_pos) const { + glm::vec2 relative_pos = world_pos - offset_; + + int tile_x = static_cast(std::floor(relative_pos.x / tile_size_.x)); + int tile_y = static_cast(std::floor(relative_pos.y / tile_size_.y)); + + return getTileTypeAt(glm::ivec2{tile_x, tile_y}); +} + +} // namespace engine::component diff --git a/src/engine/component/tilelayer_component.h b/src/engine/component/tilelayer_component.h new file mode 100644 index 0000000..bd193ac --- /dev/null +++ b/src/engine/component/tilelayer_component.h @@ -0,0 +1,104 @@ +#pragma once +#include "../render/sprite.h" +#include "component.h" +#include +#include + +namespace engine::render { +class Sprite; +} + +namespace engine::core { +class Context; +} + +namespace engine::component { +/** + * @brief 定义瓦片的类型,用于游戏逻辑(例如碰撞)。 + */ +enum class TileType { + EMPTY, ///< @brief 空白瓦片 + NORMAL, ///< @brief 普通瓦片 + SOLID, ///< @brief 静止可碰撞瓦片 + // 未来补充其它类型 +}; + +/** + * @brief 包含单个瓦片的渲染和逻辑信息。 + */ +struct TileInfo { + render::Sprite sprite; ///< @brief 瓦片的视觉表示 + TileType type; ///< @brief 瓦片的逻辑类型 + TileInfo(render::Sprite s = render::Sprite(), TileType t = TileType::EMPTY) : sprite(std::move(s)), type(t) {} +}; + +/** + * @brief 管理和渲染瓦片地图层。 + * + * 存储瓦片地图的布局、每个瓦片的精灵信息和类型。 + * 负责在渲染阶段绘制可见的瓦片。 + */ +class TileLayerComponent final : public Component { + friend class engine::object::GameObject; +private: + glm::ivec2 tile_size_; ///< @brief 单个瓦片尺寸(像素) + glm::ivec2 map_size_; ///< @brief 地图尺寸(瓦片数) + std::vector tiles_; ///< @brief 存储所有瓦片信息 (按"行主序"存储, index = y * map_width_ + x) + glm::vec2 offset_ = {0.0f, 0.0f}; ///< @brief 瓦片层在世界中的偏移量 (瓦片层通常不需要缩放及旋转,因此不引入Transform组件) + // offset_ 最好也保持默认的0,以免增加不必要的复杂性 + bool is_hidden_ = false; ///< @brief 是否隐藏(不渲染) + +public: + TileLayerComponent() = default; + + /** + * @brief 构造函数 + * @param tile_size 单个瓦片尺寸(像素) + * @param map_size 地图尺寸(瓦片数) + * @param tiles 初始化瓦片数据的容器 (会被移动) + */ + TileLayerComponent(glm::ivec2 tile_size, glm::ivec2 map_size, std::vector&& tiles); + + /** + * @brief 根据瓦片坐标获取瓦片信息 + * @param pos 瓦片坐标 (0 <= x < map_size_.x, 0 <= y < map_size_.y) + * @return const TileInfo* 指向瓦片信息的指针,如果坐标无效则返回 nullptr + */ + const TileInfo* getTileInfoAt(glm::ivec2 pos) const; + + /** + * @brief 根据瓦片坐标获取瓦片类型 + * @param pos 瓦片坐标 (0 <= x < map_size_.x, 0 <= y < map_size_.y) + * @return TileType 瓦片类型,如果坐标无效则返回 TileType::EMPTY + */ + TileType getTileTypeAt(glm::ivec2 pos) const; + + /** + * @brief 根据世界坐标获取瓦片类型 + * @param world_pos 世界坐标 + * @return TileType 瓦片类型,如果坐标无效或对应空瓦片则返回 TileType::EMPTY + */ + TileType getTileTypeAtWorldPos(const glm::vec2& world_pos) const; + + // getters and setters + glm::ivec2 getTileSize() const { return tile_size_; } ///< @brief 获取单个瓦片尺寸 + glm::ivec2 getMapSize() const { return map_size_; } ///< @brief 获取地图尺寸 + glm::vec2 getWorldSize() const { ///< @brief 获取地图世界尺寸 + return glm::vec2(map_size_.x * tile_size_.x, map_size_.y * tile_size_.y); + } + const std::vector& getTiles() const { return tiles_; } ///< @brief 获取瓦片容器 + const glm::vec2& getOffset() const { return offset_; } ///< @brief 获取瓦片层的偏移量 + bool isHidden() const { return is_hidden_; } ///< @brief 获取是否隐藏(不渲染) + + void setOffset(const glm::vec2& offset) { offset_ = offset; } ///< @brief 设置瓦片层的偏移量 + void setHidden(bool hidden) { is_hidden_ = hidden; } ///< @brief 设置是否隐藏(不渲染) + + +protected: + // 核心循环方法 + void init() override; + void update(float, engine::core::Context&) override {} + void render(engine::core::Context& context) override; +}; + +} // namespace engine::component diff --git a/src/engine/render/sprite.h b/src/engine/render/sprite.h index fe92cec..b5b6a9b 100644 --- a/src/engine/render/sprite.h +++ b/src/engine/render/sprite.h @@ -19,6 +19,11 @@ private: bool is_flipped_ = false; ///< @brief 是否水平翻转 public: + /** + * @brief 默认构造函数(创建一个空的/无效的精灵) + */ + Sprite() = default; + /** * @brief 构造一个精灵 * diff --git a/src/engine/resource/texture_manager.cpp b/src/engine/resource/texture_manager.cpp index 0a6f4b5..d4a8598 100644 --- a/src/engine/resource/texture_manager.cpp +++ b/src/engine/resource/texture_manager.cpp @@ -23,6 +23,11 @@ SDL_Texture* TextureManager::loadTexture(const std::string& file_path) { // 如果没加载则尝试加载纹理 SDL_Texture* raw_texture = IMG_LoadTexture(renderer_, file_path.c_str()); + // 载入纹理时,设置纹理缩放模式为最邻近插值(必不可少,否则TileLayer渲染中会出现边缘空隙/模糊) + if (!SDL_SetTextureScaleMode(raw_texture, SDL_SCALEMODE_NEAREST)) { + spdlog::warn("无法设置纹理缩放模式为最邻近插值"); + } + if (!raw_texture) { spdlog::error("加载纹理失败: '{}': {}", file_path, SDL_GetError()); return nullptr; diff --git a/src/engine/scene/level_loader.cpp b/src/engine/scene/level_loader.cpp index d80448c..c2fb9e4 100644 --- a/src/engine/scene/level_loader.cpp +++ b/src/engine/scene/level_loader.cpp @@ -1,10 +1,12 @@ #include "level_loader.h" #include "../component/parallax_component.h" #include "../component/transform_component.h" +#include "../component/tilelayer_component.h" #include "../object/game_object.h" #include "../scene/scene.h" #include "../core/context.h" #include "../render/sprite.h" +#include "../utils/math.h" #include #include #include @@ -14,7 +16,6 @@ namespace engine::scene { bool LevelLoader::loadLevel(const std::string& level_path, Scene& scene) { - map_path_ = level_path; // 1. 加载 JSON 文件 std::ifstream file(level_path); if (!file.is_open()) { @@ -31,7 +32,26 @@ bool LevelLoader::loadLevel(const std::string& level_path, Scene& scene) { return false; } - // 3. 加载图层数据 + // 3. 获取基本地图信息 (名称、地图尺寸、瓦片尺寸) + map_path_ = level_path; + map_size_ = glm::ivec2(json_data.value("width", 0), json_data.value("height", 0)); + tile_size_ = glm::ivec2(json_data.value("tilewidth", 0), json_data.value("tileheight", 0)); + + // 4. 加载 tileset 数据 + if (json_data.contains("tilesets") && json_data["tilesets"].is_array()) { + for (const auto& tileset_json : json_data["tilesets"]) { + if (!tileset_json.contains("source") || !tileset_json["source"].is_string() || + !tileset_json.contains("firstgid") || !tileset_json["firstgid"].is_number_integer()) { + spdlog::error("tilesets 对象中缺少有效 'source' 或 'firstgid' 字段。"); + continue; + } + auto tileset_path = resolvePath(tileset_json["source"], map_path_); // 支持隐式转换,可以省略.get()方法, + auto first_gid = tileset_json["firstgid"]; + loadTileset(tileset_path, first_gid); + } + } + + // 5. 加载图层数据 if (!json_data.contains("layers") || !json_data["layers"].is_array()) { // 地图文件中必须有 layers 数组 spdlog::error("地图文件 '{}' 中缺少或无效的 'layers' 数组。", level_path); return false; @@ -67,7 +87,7 @@ void LevelLoader::loadImageLayer(const nlohmann::json& layer_json, Scene& scene) spdlog::error("图层 '{}' 缺少 'image' 属性。", layer_json.value("name", "Unnamed")); return; } - auto texture_id = resolvePath(image_path); + auto texture_id = resolvePath(image_path, map_path_); // 获取图层偏移量(json中没有则代表未设置,给默认值即可) const glm::vec2 offset = glm::vec2(layer_json.value("offsetx", 0.0f), layer_json.value("offsety", 0.0f)); @@ -91,9 +111,32 @@ void LevelLoader::loadImageLayer(const nlohmann::json& layer_json, Scene& scene) spdlog::info("加载图层: '{}' 完成", layer_name); } -void LevelLoader::loadTileLayer(const nlohmann::json&, Scene&) +void LevelLoader::loadTileLayer(const nlohmann::json& layer_json, Scene& scene) { - // TODO + if (!layer_json.contains("data") || !layer_json["data"].is_array()) { + spdlog::error("图层 '{}' 缺少 'data' 属性。", layer_json.value("name", "Unnamed")); + return; + } + // 准备 TileInfo Vector (瓦片数量 = 地图宽度 * 地图高度) + std::vector tiles; + tiles.reserve(map_size_.x * map_size_.y); + + // 获取图层数据 (瓦片 ID 列表) + const auto& data = layer_json["data"]; + + // 根据gid获取必要信息,并依次填充 TileInfo Vector + for (const auto& gid : data) { + tiles.push_back(getTileInfoByGid(gid)); + } + + // 获取图层名称 + const std::string& layer_name = layer_json.value("name", "Unnamed"); + // 创建游戏对象 + auto game_object = std::make_unique(layer_name); + // 添加Tilelayer组件 + game_object->addComponent(tile_size_, map_size_, std::move(tiles)); + // 添加到场景中 + scene.addGameObject(std::move(game_object)); } void LevelLoader::loadObjectLayer(const nlohmann::json&, Scene&) @@ -101,18 +144,112 @@ void LevelLoader::loadObjectLayer(const nlohmann::json&, Scene&) // TODO } -std::string LevelLoader::resolvePath(std::string image_path) +engine::component::TileInfo LevelLoader::getTileInfoByGid(int gid) +{ + if (gid == 0) { + return engine::component::TileInfo(); + } + + // upper_bound:查找tileset_data_中键大于 gid 的第一个元素,返回迭代器 + auto tileset_it = tileset_data_.upper_bound(gid); + if (tileset_it == tileset_data_.begin()) { + spdlog::error("gid为 {} 的瓦片未找到图块集。", gid); + return engine::component::TileInfo(); + } + --tileset_it; // 前移一个位置,这样就得到不大于gid的最近一个元素(我们需要的) + + const auto& tileset = tileset_it->second; + auto local_id = gid - tileset_it->first; // 计算瓦片在图块集中的局部ID + const std::string file_path = tileset.value("file_path", ""); // 获取图块集文件路径 + if (file_path.empty()) { + spdlog::error("Tileset 文件 '{}' 缺少 'file_path' 属性。", tileset_it->first); + return engine::component::TileInfo(); + } + // 图块集分为两种情况,需要分别考虑 + if (tileset.contains("image")) { // 这是单一图片的情况 + // 获取图片路径 + auto texture_id = resolvePath(tileset["image"].get(), file_path); + // 计算瓦片在图片网格中的坐标 + auto coordinate_x = local_id % tileset["columns"].get(); + auto coordinate_y = local_id / tileset["columns"].get(); + // 根据坐标确定源矩形 + SDL_FRect texture_rect = { + static_cast(coordinate_x * tile_size_.x), + static_cast(coordinate_y * tile_size_.y), + static_cast(tile_size_.x), + static_cast(tile_size_.y) + }; + engine::render::Sprite sprite{texture_id, texture_rect}; + return engine::component::TileInfo(sprite, engine::component::TileType::NORMAL); // 目前只完成渲染,以后再考虑瓦片类型 + } else { // 这是多图片的情况 + if (!tileset.contains("tiles")) { // 没有tiles字段的话不符合数据格式要求,直接返回空的瓦片信息 + spdlog::error("Tileset 文件 '{}' 缺少 'tiles' 属性。", tileset_it->first); + return engine::component::TileInfo(); + } + // 遍历tiles数组,根据id查找对应的瓦片 + const auto& tiles_json = tileset["tiles"]; + for (const auto& tile_json : tiles_json) { + auto tile_id = tile_json.value("id", 0); + if (tile_id == local_id) { // 找到对应的瓦片,进行后续操作 + if (!tile_json.contains("image")) { // 没有image字段的话不符合数据格式要求,直接返回空的瓦片信息 + spdlog::error("Tileset 文件 '{}' 中瓦片 {} 缺少 'image' 属性。", tileset_it->first, tile_id); + return engine::component::TileInfo(); + } + // --- 接下来根据必要信息创建并返回 TileInfo --- + // 获取图片路径 + auto texture_id = resolvePath(tile_json["image"].get(), file_path); + // 先确认图片尺寸 + auto image_width = tile_json.value("imagewidth", 0); + auto image_height = tile_json.value("imageheight", 0); + // 从json中获取源矩形信息 + SDL_FRect texture_rect = { // tiled中源矩形信息只有设置了才会有值,没有就是默认值 + static_cast(tile_json.value("x", 0)), + static_cast(tile_json.value("y", 0)), + static_cast(tile_json.value("width", image_width)), // 如果未设置,则使用图片尺寸 + static_cast(tile_json.value("height", image_height)) + }; + engine::render::Sprite sprite{texture_id, texture_rect}; + return engine::component::TileInfo(sprite, engine::component::TileType::NORMAL); // 目前只完成渲染,以后再考虑瓦片类型 + } + } + } + // 如果能走到这里,说明查找失败,返回空的瓦片信息 + spdlog::error("图块集 '{}' 中未找到gid为 {} 的瓦片。", tileset_it->first, gid); + return engine::component::TileInfo(); +} + +void LevelLoader::loadTileset(const std::string& tileset_path, int first_gid) +{ + std::ifstream tileset_file(tileset_path); + if (!tileset_file.is_open()) { + spdlog::error("无法打开 Tileset 文件: {}", tileset_path); + return; + } + + nlohmann::json ts_json; + try { + tileset_file >> ts_json; + } catch (const nlohmann::json::parse_error& e) { + spdlog::error("解析 Tileset JSON 文件 '{}' 失败: {} (at byte {})", tileset_path, e.what(), e.byte); + return; + } + ts_json["file_path"] = tileset_path; // 将文件路径存储到json中,后续解析图片路径时需要 + tileset_data_[first_gid] = std::move(ts_json); + spdlog::info("Tileset 文件 '{}' 加载完成,firstgid: {}", tileset_path, first_gid); +} + +std::string LevelLoader::resolvePath(const std::string& relative_path, const std::string& file_path) { try { - // 获取地图文件的父目录(相对于可执行文件) “assets/maps/level1.tmj” -> “assets/maps” - auto map_dir = std::filesystem::path(map_path_).parent_path(); + // 获取地图文件的父目录(相对于可执行文件) "assets/maps/level1.tmj" -> "assets/maps" + auto map_dir = std::filesystem::path(file_path).parent_path(); // 合并路径(相对于可执行文件)并返回。 /* std::filesystem::canonical:解析路径中的当前目录(.)和上级目录(..)导航符, /* 得到一个干净的路径 */ - auto final_path = std::filesystem::canonical(map_dir / image_path); + auto final_path = std::filesystem::canonical(map_dir / relative_path); return final_path.string(); } catch (const std::exception& e) { spdlog::error("解析路径失败: {}", e.what()); - return image_path; + return relative_path; } } diff --git a/src/engine/scene/level_loader.h b/src/engine/scene/level_loader.h index 506b8e1..911f1ac 100644 --- a/src/engine/scene/level_loader.h +++ b/src/engine/scene/level_loader.h @@ -1,12 +1,25 @@ #pragma once #include -#include +#include +#include +#include + +namespace engine::component { +struct TileInfo; +} namespace engine::scene { class Scene; +/** + * @brief 负责从 Tiled JSON 文件 (.tmj) 加载关卡数据到 Scene 中。 + */ class LevelLoader final { std::string map_path_; ///< @brief 地图路径(拼接路径时需要) + glm::ivec2 map_size_; ///< @brief 地图尺寸(瓦片数量) + glm::ivec2 tile_size_; ///< @brief 瓦片尺寸(像素) + std::map tileset_data_; ///< @brief firstgid -> 瓦片集数据 + public: LevelLoader() = default; @@ -23,15 +36,30 @@ private: void loadTileLayer(const nlohmann::json& layer_json, Scene& scene); ///< @brief 加载瓦片图层 void loadObjectLayer(const nlohmann::json& layer_json, Scene& scene); ///< @brief 加载对象图层 + /** + * @brief 根据全局 ID 获取瓦片信息。 + * @param gid 全局 ID。 + * @return engine::component::TileInfo 瓦片信息。 + */ + engine::component::TileInfo getTileInfoByGid(int gid); + + /** + * @brief 加载 Tiled tileset 文件 (.tsj)。 + * @param tileset_path Tileset 文件路径。 + * @param first_gid 此 tileset 的第一个全局 ID。 + */ + void loadTileset(const std::string& tileset_path, int first_gid); + /** * @brief 解析图片路径,合并地图路径和相对路径。例如: - * 1. 地图路径:"assets/maps/level1.tmj" + * 1. 文件路径:"assets/maps/level1.tmj" * 2. 相对路径:"../textures/Layers/back.png" * 3. 最终路径:"assets/textures/Layers/back.png" - * @param image_path (图片)相对路径 + * @param relative_path 相对路径(相对于文件) + * @param file_path 文件路径 * @return std::string 解析后的完整路径。 */ - std::string resolvePath(std::string image_path); + std::string resolvePath(const std::string& relative_path, const std::string& file_path); }; } // namespace engine::scene \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index ce76ce5..738b873 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ #include int main(int /* argc */, char* /* argv */[]) { - spdlog::set_level(spdlog::level::debug); + // spdlog::set_level(spdlog::level::debug); engine::core::GameApp app; app.run();