diff --git a/src/engine/component/physics_component.h b/src/engine/component/physics_component.h index 195f225..a5b254c 100644 --- a/src/engine/component/physics_component.h +++ b/src/engine/component/physics_component.h @@ -33,7 +33,8 @@ private: bool collided_above_ = false; bool collided_left_ = false; bool collided_right_ = false; - bool collided_ladder_ = false; + bool collided_ladder_ = false; ///< @brief 是否与梯子发生碰撞 + bool is_on_top_ladder_ = false; ///< @brief 是否在梯子顶层(梯子上方没有瓦片) public: /** @@ -76,6 +77,7 @@ public: collided_left_ = false; collided_right_ = false; collided_ladder_ = false; + is_on_top_ladder_ = false; } void setCollidedBelow(bool collided) { collided_below_ = collided; } ///< @brief 设置下方碰撞标志 @@ -83,12 +85,14 @@ public: void setCollidedLeft(bool collided) { collided_left_ = collided; } ///< @brief 设置左方碰撞标志 void setCollidedRight(bool collided) { collided_right_ = collided; } ///< @brief 设置右方碰撞标志 void setCollidedLadder(bool collided) { collided_ladder_ = collided; } ///< @brief 设置梯子碰撞标志 + void setOnTopLadder(bool on_top) { is_on_top_ladder_ = on_top; } ///< @brief 设置是否在梯子顶层 bool hasCollidedBelow() const { return collided_below_; } ///< @brief 检查是否与下方发生碰撞 bool hasCollidedAbove() const { return collided_above_; } ///< @brief 检查是否与上方发生碰撞 bool hasCollidedLeft() const { return collided_left_; } ///< @brief 检查是否与左方发生碰撞 bool hasCollidedRight() const { return collided_right_; } ///< @brief 检查是否与右方发生碰撞 bool hasCollidedLadder() const { return collided_ladder_; } ///< @brief 检查是否与梯子发生碰撞 + bool isOnTopLadder() const { return is_on_top_ladder_; } ///< @brief 检查是否在梯子顶层 private: // 核心循环方法 diff --git a/src/engine/physics/physics_engine.cpp b/src/engine/physics/physics_engine.cpp index 106195c..7cd378a 100644 --- a/src/engine/physics/physics_engine.cpp +++ b/src/engine/physics/physics_engine.cpp @@ -209,6 +209,21 @@ void PhysicsEngine::resolveTileCollisions(engine::component::PhysicsComponent* p new_obj_pos.y = tile_y * layer->getTileSize().y - obj_size.y; pc->velocity_.y = 0.0f; pc->setCollidedBelow(true); + // 如果两个角点都位于梯子上,则判断是不是处在梯子顶层 + } else if (tile_type_left == engine::component::TileType::LADDER && tile_type_right == engine::component::TileType::LADDER) { + auto tile_type_up_l = layer->getTileTypeAt({tile_x, tile_y - 1}); // 检测左角点上方瓦片类型 + auto tile_type_up_r = layer->getTileTypeAt({tile_x_right, tile_y - 1}); // 检测右角点上方瓦片类型 + // 如果上方不是梯子,证明处在梯子顶层 + if (tile_type_up_r != engine::component::TileType::LADDER && tile_type_up_l != engine::component::TileType::LADDER) { + // 通过是否使用重力来区分是否处于攀爬状态。 + if (pc->isUseGravity()) { // 非攀爬状态 + pc->setOnTopLadder(true); // 设置在梯子顶层标志 + pc->setCollidedBelow(true); // 设置下方碰撞标志 + // 让物体贴着梯子顶层位置(与SOLID情况相同) + new_obj_pos.y = tile_y * layer->getTileSize().y - obj_size.y; + pc->velocity_.y = 0.0f; + } else {} // 攀爬状态,不做任何处理 + } } else { // 检测斜坡瓦片(下方两个角点都要检测) auto width_left = obj_pos.x - tile_x * tile_size.x; diff --git a/src/game/component/state/idle_state.cpp b/src/game/component/state/idle_state.cpp index 3aefed9..51d2fc5 100644 --- a/src/game/component/state/idle_state.cpp +++ b/src/game/component/state/idle_state.cpp @@ -7,6 +7,7 @@ #include "../../../engine/core/context.h" #include "../../../engine/input/input_manager.h" #include "../../../engine/component/physics_component.h" +#include "../../../engine/component/transform_component.h" #include namespace game::component::state { @@ -29,6 +30,13 @@ std::unique_ptr IdleState::handleInput(engine::core::Context& conte return std::make_unique(player_component_); } + // 如果按下“move_down”且在梯子顶层,则切换到 ClimbState + if (physics_component->isOnTopLadder() && input_manager.isActionDown("move_down")) { + // 需要向下移动一点,确保下一帧能与梯子碰撞(否则会切换回FallState) + player_component_->getTransformComponent()->translate(glm::vec2(0, 2.0f)); + return std::make_unique(player_component_); + } + // 如果按下了左右移动键,则切换到 WalkState if (input_manager.isActionDown("move_left") || input_manager.isActionDown("move_right")) { return std::make_unique(player_component_); diff --git a/src/game/component/state/jump_state.cpp b/src/game/component/state/jump_state.cpp index c7a76e6..9d3079b 100644 --- a/src/game/component/state/jump_state.cpp +++ b/src/game/component/state/jump_state.cpp @@ -57,7 +57,7 @@ std::unique_ptr JumpState::update(float, engine::core::Context&) physics_component->velocity_.x = glm::clamp(physics_component->velocity_.x, -max_speed, max_speed); // 如果速度为正,切换到 FallState - if (physics_component->velocity_.y > 0.0f) { + if (physics_component->velocity_.y >= 0.0f) { return std::make_unique(player_component_); }