完成攀爬状态-精细

This commit is contained in:
Ziyu
2025-06-16 14:44:47 +08:00
parent 7e7ad40ef9
commit 2e0edb950c
4 changed files with 29 additions and 2 deletions
+5 -1
View File
@@ -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:
// 核心循环方法
+15
View File
@@ -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;
+8
View File
@@ -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 <spdlog/spdlog.h>
namespace game::component::state {
@@ -29,6 +30,13 @@ std::unique_ptr<PlayerState> IdleState::handleInput(engine::core::Context& conte
return std::make_unique<ClimbState>(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<ClimbState>(player_component_);
}
// 如果按下了左右移动键,则切换到 WalkState
if (input_manager.isActionDown("move_left") || input_manager.isActionDown("move_right")) {
return std::make_unique<WalkState>(player_component_);
+1 -1
View File
@@ -57,7 +57,7 @@ std::unique_ptr<PlayerState> 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<FallState>(player_component_);
}