From e5399af1d6e9be61e2d1084381e444c0eda10bc0 Mon Sep 17 00:00:00 2001 From: Ziyu Date: Sun, 8 Jun 2025 09:43:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=8E=A9=E5=AE=B6=E4=B8=8E?= =?UTF-8?q?=E5=85=B6=E4=BB=96=E5=AF=B9=E8=B1=A1=E4=BA=A4=E4=BA=92-1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/maps/actor.tsj | 5 +- src/game/scene/game_scene.cpp | 109 ++++++++++++++++++++++++++++++++-- src/game/scene/game_scene.h | 12 +++- 3 files changed, 117 insertions(+), 9 deletions(-) diff --git a/assets/maps/actor.tsj b/assets/maps/actor.tsj index 89c60ee..0a9006e 100644 --- a/assets/maps/actor.tsj +++ b/assets/maps/actor.tsj @@ -21,10 +21,11 @@ "objectgroup": { "draworder":"index", + "id":2, "name":"", "objects":[ { - "height":39, + "height":24.6363636363636, "id":1, "name":"", "rotation":0, @@ -32,7 +33,7 @@ "visible":true, "width":32, "x":3, - "y":0 + "y":14.3636363636364 }], "opacity":1, "type":"objectgroup", diff --git a/src/game/scene/game_scene.cpp b/src/game/scene/game_scene.cpp index 71bc803..009dc27 100644 --- a/src/game/scene/game_scene.cpp +++ b/src/game/scene/game_scene.cpp @@ -8,10 +8,12 @@ #include "../../engine/component/collider_component.h" #include "../../engine/component/tilelayer_component.h" #include "../../engine/component/animation_component.h" +#include "../../engine/component/health_component.h" #include "../../engine/physics/physics_engine.h" #include "../../engine/scene/level_loader.h" #include "../../engine/input/input_manager.h" #include "../../engine/render/camera.h" +#include "../../engine/render/animation.h" #include #include @@ -52,6 +54,7 @@ void GameScene::init() { void GameScene::update(float delta_time) { Scene::update(delta_time); + handleObjectCollisions(); } void GameScene::render() { @@ -60,7 +63,6 @@ void GameScene::render() { void GameScene::handleInput() { Scene::handleInput(); - testHealth(); // 测试生命值组件 } void GameScene::clean() { @@ -168,12 +170,109 @@ bool GameScene::initEnemyAndItem() return success; } -void GameScene::testHealth() +void GameScene::handleObjectCollisions() { - auto input_manager = context_.getInputManager(); - if (input_manager.isActionPressed("attack")) { - player_->getComponent()->takeDamage(1); + // 从物理引擎中获取碰撞对 + auto collision_pairs = context_.getPhysicsEngine().getCollisionPairs(); + for (const auto& pair : collision_pairs) { + auto* obj1 = pair.first; + auto* obj2 = pair.second; + + // 处理玩家与敌人的碰撞 + if (obj1->getName() == "player" && obj2->getTag() == "enemy") { + PlayerVSEnemyCollision(obj1, obj2); + } else if (obj2->getName() == "player" && obj1->getTag() == "enemy") { + PlayerVSEnemyCollision(obj2, obj1); + } + // 处理玩家与道具的碰撞 + else if (obj1->getName() == "player" && obj2->getTag() == "item") { + PlayerVSItemCollision(obj1, obj2); + } else if (obj2->getName() == "player" && obj1->getTag() == "item") { + PlayerVSItemCollision(obj2, obj1); + } } } +void GameScene::PlayerVSEnemyCollision(engine::object::GameObject *player, engine::object::GameObject *enemy) +{ + // --- 踩踏判断逻辑:1. 玩家中心点在敌人上方 2. 重叠区域:overlap.x > overlap.y + auto player_aabb = player->getComponent()->getWorldAABB(); + auto enemy_aabb = enemy->getComponent()->getWorldAABB(); + auto player_center = player_aabb.position + player_aabb.size / 2.0f; + auto enemy_center = enemy_aabb.position + enemy_aabb.size / 2.0f; + auto overlap = glm::vec2(player_aabb.size / 2.0f + enemy_aabb.size / 2.0f) - glm::abs(player_center - enemy_center); + + // 踩踏判断成功,敌人受伤 + if (overlap.x > overlap.y && player_center.y < enemy_center.y) { + spdlog::info("玩家 {} 踩踏了敌人 {}", player->getName(), enemy->getName()); + auto enemy_health = enemy->getComponent(); + if (!enemy_health) { + spdlog::error("敌人 {} 没有 HealthComponent 组件,无法处理踩踏伤害", enemy->getName()); + return; + } + enemy_health->takeDamage(1); // 造成1点伤害 + if (!enemy_health->isAlive()) { + spdlog::info("敌人 {} 被踩踏后死亡", enemy->getName()); + enemy->setNeedRemove(true); // 标记敌人为待删除状态 + createEffect(enemy_center, enemy->getTag()); // 创建(死亡)特效 + } + // 玩家跳起效果 + player->getComponent()->velocity_.y = -300.0f; // 向上跳起 + } + // 踩踏判断失败,玩家受伤 + else { + spdlog::info("敌人 {} 对玩家 {} 造成伤害", enemy->getName(), player->getName()); + player->getComponent()->takeDamage(1); + // TODO: 其他受伤逻辑 + } +} + +void GameScene::PlayerVSItemCollision(engine::object::GameObject * player, engine::object::GameObject * item) +{ + if (item->getName() == "fruit") { + player->getComponent()->heal(1); // 加血 + } else if (item->getName() == "gem") { + //TODO: 加分 + } + item->setNeedRemove(true); // 标记道具为待删除状态 + auto item_aabb = item->getComponent()->getWorldAABB(); + createEffect(item_aabb.position + item_aabb.size / 2.0f, item->getTag()); // 创建特效 +} + +void GameScene::createEffect(const glm::vec2& center_pos, const std::string &tag) +{ + // --- 创建游戏对象和变换组件 --- + auto effect_obj = std::make_unique("effect_" + tag); + effect_obj->addComponent(center_pos); + + // --- 根据标签创建不同的精灵组件和动画--- + auto animation = std::make_unique("effect", false); + if (tag == "enemy") { + effect_obj->addComponent("assets/textures/FX/enemy-deadth.png", + context_.getResourceManager(), + engine::utils::Alignment::CENTER); + for (auto i = 0; i < 5; ++i) { + animation->addFrame({static_cast(i * 40), 0.0f, 40.0f, 41.0f}, 0.1f); + } + } else if (tag == "item") { + effect_obj->addComponent("assets/textures/FX/item-feedback.png", + context_.getResourceManager(), + engine::utils::Alignment::CENTER); + for (auto i = 0; i < 4; ++i) { + animation->addFrame({static_cast(i * 32), 0.0f, 32.0f, 32.0f}, 0.1f); + } + } else { + spdlog::warn("未知特效类型: {}", tag); + return; + } + + // --- 根据创建的动画,添加动画组件,并设置为单次播放 --- + auto* animation_component = effect_obj->addComponent(); + animation_component->addAnimation(std::move(animation)); + animation_component->setOneShotRemoval(true); + animation_component->playAnimation("effect"); + safeAddGameObject(std::move(effect_obj)); // 安全添加特效对象 + spdlog::debug("创建特效: {}", tag); +} + } // namespace game::scene \ No newline at end of file diff --git a/src/game/scene/game_scene.h b/src/game/scene/game_scene.h index 681890b..877eeba 100644 --- a/src/game/scene/game_scene.h +++ b/src/game/scene/game_scene.h @@ -1,6 +1,7 @@ #pragma once #include "../../engine/scene/scene.h" #include +#include // 前置声明 namespace engine::object { @@ -30,9 +31,16 @@ private: [[nodiscard]] bool initPlayer(); ///< @brief 初始化玩家 [[nodiscard]] bool initEnemyAndItem(); ///< @brief 初始化敌人和道具 - // 测试函数 - void testHealth(); ///< @brief 测试生命值组件 + void handleObjectCollisions(); ///< @brief 处理游戏对象间的碰撞逻辑(从PhysicsEngine获取信息) + void PlayerVSEnemyCollision(engine::object::GameObject* player, engine::object::GameObject* enemy); ///< @brief 玩家与敌人碰撞处理 + void PlayerVSItemCollision(engine::object::GameObject* player, engine::object::GameObject* item); ///< @brief 玩家与道具碰撞处理 + /** + * @brief 创建一个特效对象(一次性)。 + * @param center_pos 特效中心位置 + * @param tag 特效标签(决定特效类型,例如"enemy","item") + */ + void createEffect(const glm::vec2& center_pos, const std::string& tag); }; } // namespace game::scene \ No newline at end of file