完成关卡切换-新地图

This commit is contained in:
Ziyu
2025-06-16 14:44:47 +08:00
parent cb10827fd6
commit e08b436e9a
7 changed files with 188 additions and 12 deletions
+1 -1
View File
@@ -61,7 +61,7 @@ bool GameApp::init() {
if (!initSceneManager()) return false;
// 创建第一个场景并压入栈
auto scene = std::make_unique<game::scene::GameScene>("GameScene", *context_, *scene_manager_);
auto scene = std::make_unique<game::scene::GameScene>("level1", *context_, *scene_manager_);
scene_manager_->requestPushScene(std::move(scene));
is_running_ = true;
+37 -2
View File
@@ -160,9 +160,44 @@ void LevelLoader::loadObjectLayer(const nlohmann::json& layer_json, Scene& scene
for (const auto& object : objects) {
// 获取对象gid
auto gid = object.value("gid", 0);
if (gid == 0) { // 如果gid为0 (即不存在),则代表自己绘制的形状(可能是碰撞盒、触发器等,未来按需处理)
// TODO
if (gid == 0) { // 如果gid为0 (即不存在),则代表自己绘制的形状
// 非矩形对象会有额外标识(目前不考虑)
if (object.value("point", false)) { // 如果是点对象
continue; // TODO: 点对象的处理方式
} else if (object.value("ellipse", false)) { // 如果是椭圆对象
continue; // TODO: 椭圆对象的处理方式
} else if (object.value("polygon", false)) { // 如果是多边形对象
continue; // TODO: 多边形对象的处理方式
}
// 没有这些标识则默认是矩形对象
else {
// --- 创建游戏对象并添加TransfromComponent ---
const std::string& object_name = object.value("name", "Unnamed");
auto game_object = std::make_unique<engine::object::GameObject>(object_name);
// 获取Transform相关信息 (自定义形状的坐标针对左上角)
auto position = glm::vec2(object.value("x", 0.0f), object.value("y", 0.0f));
auto dst_size = glm::vec2(object.value("width", 0.0f), object.value("height", 0.0f));
auto rotation = object.value("rotation", 0.0f);
// 添加TransformComponent,缩放为设定为1.0f
game_object->addComponent<engine::component::TransformComponent>(position, glm::vec2(1.0f), rotation);
// --- 添加碰撞组件和物理组件 ---
// 碰撞盒大小与dst_size相同
auto collider = std::make_unique<engine::physics::AABBCollider>(dst_size);
auto* cc = game_object->addComponent<engine::component::ColliderComponent>(std::move(collider));
// 自定义形状通常是trigger类型,除非显示指定 (因此默认为真)
cc->setTrigger(object.value("trigger", true));
// 添加物理组件,不受重力影响
game_object->addComponent<engine::component::PhysicsComponent>(&scene.getContext().getPhysicsEngine(), false);
// 获取标签信息并设置
if (auto tag = getTileProperty<std::string>(object, "tag"); tag) { // 如果有标签
game_object->setTag(tag.value());
}
// 添加到场景
scene.addGameObject(std::move(game_object));
spdlog::info("加载对象: '{}' 完成 (类型: 自定义形状)", object_name);
}
} else { // 如果gid存在,则按照图片解析流程
// --- 根据gid获取必要信息,每个gid对应一个游戏对象 ---
auto tile_info = getTileInfoByGid(gid);
+17 -2
View File
@@ -11,6 +11,7 @@
#include "../../engine/component/health_component.h"
#include "../../engine/physics/physics_engine.h"
#include "../../engine/scene/level_loader.h"
#include "../../engine/scene/scene_manager.h"
#include "../../engine/input/input_manager.h"
#include "../../engine/render/camera.h"
#include "../../engine/render/animation.h"
@@ -57,7 +58,7 @@ void GameScene::init() {
context_.getAudioPlayer().setMusicVolume(0.2f); // 设置背景音乐音量为20%
context_.getAudioPlayer().setSoundVolume(0.5f); // 设置音效音量为50%
// 播放背景音乐 (循环,淡入1秒)
context_.getAudioPlayer().playMusic("assets/audio/hurry_up_and_run.ogg", true, 1000);
// context_.getAudioPlayer().playMusic("assets/audio/hurry_up_and_run.ogg", true, 1000);
Scene::init();
spdlog::trace("GameScene 初始化完成。");
@@ -85,7 +86,8 @@ bool GameScene::initLevel()
{
// 加载关卡(level_loader通常加载完成后即可销毁,因此不存为成员变量)
engine::scene::LevelLoader level_loader;
if (!level_loader.loadLevel("assets/maps/level1.tmj", *this)){
auto level_path = levelNameToPath(scene_name_);
if (!level_loader.loadLevel(level_path, *this)){
spdlog::error("关卡加载失败");
return false;
}
@@ -207,6 +209,12 @@ void GameScene::handleObjectCollisions()
obj2->getComponent<game::component::PlayerComponent>()->takeDamage(1);
spdlog::debug("玩家 {} 受到了 HAZARD 对象伤害", obj2->getName());
}
// 处理玩家与关底触发器碰撞
else if (obj1->getName() == "player" && obj2->getTag() == "next_level") {
toNextLevel(obj2);
} else if (obj2->getName() == "player" && obj1->getTag() == "next_level") {
toNextLevel(obj1);
}
}
}
@@ -276,6 +284,13 @@ void GameScene::playerVSItemCollision(engine::object::GameObject * player, engin
context_.getAudioPlayer().playSound("assets/audio/poka01.mp3"); // 播放音效
}
void GameScene::toNextLevel(engine::object::GameObject *trigger)
{
auto scene_name = trigger->getName();
auto next_scene = std::make_unique<game::scene::GameScene>(scene_name, context_, scene_manager_);
scene_manager_.requestReplaceScene(std::move(next_scene));
}
void GameScene::createEffect(const glm::vec2& center_pos, const std::string &tag)
{
// --- 创建游戏对象和变换组件 ---
+5
View File
@@ -36,6 +36,11 @@ private:
void playerVSEnemyCollision(engine::object::GameObject* player, engine::object::GameObject* enemy); ///< @brief 玩家与敌人碰撞处理
void playerVSItemCollision(engine::object::GameObject* player, engine::object::GameObject* item); ///< @brief 玩家与道具碰撞处理
void toNextLevel(engine::object::GameObject* trigger); ///< @brief 进入下一个关卡
/// @brief 根据关卡名称获取对应的地图文件路径
std::string levelNameToPath(const std::string& level_name) const { return "assets/maps/" + level_name + ".tmj"; }
/**
* @brief 创建一个特效对象(一次性)。
* @param center_pos 特效中心位置