完成玩家组件与状态机
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
#include "fall_state.h"
|
||||
#include "idle_state.h"
|
||||
#include "walk_state.h"
|
||||
#include "../player_component.h"
|
||||
#include "../../../engine/core/context.h"
|
||||
#include "../../../engine/input/input_manager.h"
|
||||
#include "../../../engine/component/physics_component.h"
|
||||
#include "../../../engine/component/sprite_component.h"
|
||||
#include <glm/common.hpp>
|
||||
|
||||
namespace game::component::state {
|
||||
|
||||
void FallState::enter() {
|
||||
|
||||
}
|
||||
|
||||
void FallState::exit() {
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<PlayerState> FallState::handleInput(engine::core::Context& context)
|
||||
{
|
||||
auto input_manager = context.getInputManager();
|
||||
auto physics_component = player_component_->getPhysicsComponent();
|
||||
auto sprite_component = player_component_->getSpriteComponent();
|
||||
|
||||
// 下落状态下可以左右移动
|
||||
if (input_manager.isActionDown("move_left")) {
|
||||
if (physics_component->velocity_.x > 0.0f) physics_component->velocity_.x = 0.0f;
|
||||
physics_component->addForce({-player_component_->getMoveForce(), 0.0f});
|
||||
sprite_component->setFlipped(true);
|
||||
} else if (input_manager.isActionDown("move_right")) {
|
||||
if (physics_component->velocity_.x < 0.0f) physics_component->velocity_.x = 0.0f;
|
||||
physics_component->addForce({player_component_->getMoveForce(), 0.0f});
|
||||
sprite_component->setFlipped(false);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<PlayerState> FallState::update(float, engine::core::Context&)
|
||||
{
|
||||
// 限制最大速度(水平方向)
|
||||
auto physics_component = player_component_->getPhysicsComponent();
|
||||
auto max_speed = player_component_->getMaxSpeed();
|
||||
physics_component->velocity_.x = glm::clamp(physics_component->velocity_.x, -max_speed, max_speed);
|
||||
|
||||
// 如果下方有碰撞,则根据水平速度来决定 切换到 IdleState 或 WalkState
|
||||
if (physics_component->hasCollidedBelow()) {
|
||||
if (glm::abs(physics_component->velocity_.x) < 1.0f) {
|
||||
return std::make_unique<IdleState>(player_component_);
|
||||
} else {
|
||||
return std::make_unique<WalkState>(player_component_);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace game::component::state
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "player_state.h"
|
||||
|
||||
namespace game::component::state {
|
||||
|
||||
class FallState final : public PlayerState {
|
||||
friend class game::component::PlayerComponent;
|
||||
public:
|
||||
FallState(PlayerComponent* player_component) : PlayerState(player_component) {}
|
||||
~FallState() override = default;
|
||||
|
||||
private:
|
||||
void enter() override;
|
||||
void exit() override;
|
||||
std::unique_ptr<PlayerState> handleInput(engine::core::Context&) override;
|
||||
std::unique_ptr<PlayerState> update(float delta_time, engine::core::Context&) override;
|
||||
};
|
||||
|
||||
} // namespace game::component::state
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "idle_state.h"
|
||||
#include "fall_state.h"
|
||||
#include "jump_state.h"
|
||||
#include "walk_state.h"
|
||||
#include "../player_component.h"
|
||||
#include "../../../engine/core/context.h"
|
||||
#include "../../../engine/input/input_manager.h"
|
||||
#include "../../../engine/component/physics_component.h"
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace game::component::state {
|
||||
|
||||
void IdleState::enter() {
|
||||
|
||||
}
|
||||
|
||||
void IdleState::exit() {
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<PlayerState> IdleState::handleInput(engine::core::Context& context)
|
||||
{
|
||||
auto input_manager = context.getInputManager();
|
||||
// 如果按下了左右移动键,则切换到 WalkState
|
||||
if (input_manager.isActionDown("move_left") || input_manager.isActionDown("move_right")) {
|
||||
return std::make_unique<WalkState>(player_component_);
|
||||
}
|
||||
|
||||
// 如果按下“jump”则切换到 JumpState
|
||||
if (input_manager.isActionPressed("jump")) {
|
||||
return std::make_unique<JumpState>(player_component_);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<PlayerState> IdleState::update(float, engine::core::Context&)
|
||||
{
|
||||
// 应用摩擦力(水平方向)
|
||||
auto physics_component = player_component_->getPhysicsComponent();
|
||||
auto friction_factor = player_component_->getFrictionFactor();
|
||||
physics_component->velocity_.x *= friction_factor;
|
||||
|
||||
// 如果下方没有碰撞,则切换到 FallState
|
||||
if (!physics_component->hasCollidedBelow()) {
|
||||
return std::make_unique<FallState>(player_component_);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace game::component::state
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "player_state.h"
|
||||
|
||||
namespace game::component::state {
|
||||
|
||||
class IdleState final : public PlayerState {
|
||||
friend class game::component::PlayerComponent;
|
||||
public:
|
||||
IdleState(PlayerComponent* player_component) : PlayerState(player_component) {}
|
||||
~IdleState() override = default;
|
||||
|
||||
private:
|
||||
void enter() override;
|
||||
void exit() override;
|
||||
std::unique_ptr<PlayerState> handleInput(engine::core::Context&) override;
|
||||
std::unique_ptr<PlayerState> update(float delta_time, engine::core::Context&) override;
|
||||
};
|
||||
|
||||
} // namespace game::component::state
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "jump_state.h"
|
||||
#include "idle_state.h"
|
||||
#include "walk_state.h"
|
||||
#include "fall_state.h"
|
||||
#include "../player_component.h"
|
||||
#include "../../../engine/core/context.h"
|
||||
#include "../../../engine/input/input_manager.h"
|
||||
#include "../../../engine/component/physics_component.h"
|
||||
#include "../../../engine/component/sprite_component.h"
|
||||
#include <glm/common.hpp>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace game::component::state {
|
||||
|
||||
void JumpState::enter() {
|
||||
auto physics_component = player_component_->getPhysicsComponent();
|
||||
physics_component->velocity_.y = -player_component_->getJumpForce(); // 向上跳跃
|
||||
spdlog::debug("PlayerComponent 进入 JumpState,设置初始垂直速度为: {}", physics_component->velocity_.y);
|
||||
}
|
||||
|
||||
void JumpState::exit() {
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<PlayerState> JumpState::handleInput(engine::core::Context& context)
|
||||
{
|
||||
auto input_manager = context.getInputManager();
|
||||
auto physics_component = player_component_->getPhysicsComponent();
|
||||
auto sprite_component = player_component_->getSpriteComponent();
|
||||
|
||||
// 跳跃状态下可以左右移动
|
||||
if (input_manager.isActionDown("move_left")) {
|
||||
if (physics_component->velocity_.x > 0.0f) physics_component->velocity_.x = 0.0f;
|
||||
physics_component->addForce({-player_component_->getMoveForce(), 0.0f});
|
||||
sprite_component->setFlipped(true);
|
||||
} else if (input_manager.isActionDown("move_right")) {
|
||||
if (physics_component->velocity_.x < 0.0f) physics_component->velocity_.x = 0.0f;
|
||||
physics_component->addForce({player_component_->getMoveForce(), 0.0f});
|
||||
sprite_component->setFlipped(false);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<PlayerState> JumpState::update(float, engine::core::Context&)
|
||||
{
|
||||
// 限制最大速度(水平方向)
|
||||
auto physics_component = player_component_->getPhysicsComponent();
|
||||
auto max_speed = player_component_->getMaxSpeed();
|
||||
physics_component->velocity_.x = glm::clamp(physics_component->velocity_.x, -max_speed, max_speed);
|
||||
|
||||
// 如果速度为正,切换到 FallState
|
||||
if (physics_component->velocity_.y > 0.0f) {
|
||||
return std::make_unique<FallState>(player_component_);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace game::component::state
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "player_state.h"
|
||||
|
||||
namespace game::component::state {
|
||||
|
||||
class JumpState final : public PlayerState {
|
||||
friend class game::component::PlayerComponent;
|
||||
public:
|
||||
JumpState(PlayerComponent* player_component) : PlayerState(player_component) {}
|
||||
~JumpState() override = default;
|
||||
|
||||
private:
|
||||
void enter() override;
|
||||
void exit() override;
|
||||
std::unique_ptr<PlayerState> handleInput(engine::core::Context&) override;
|
||||
std::unique_ptr<PlayerState> update(float delta_time, engine::core::Context&) override;
|
||||
};
|
||||
|
||||
} // namespace game::component::state
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace engine::core {
|
||||
class Context;
|
||||
}
|
||||
|
||||
namespace game::component {
|
||||
class PlayerComponent;
|
||||
}
|
||||
|
||||
namespace game::component::state {
|
||||
|
||||
/**
|
||||
* @brief 玩家状态机的抽象基类。
|
||||
*/
|
||||
class PlayerState {
|
||||
friend class game::component::PlayerComponent;
|
||||
protected:
|
||||
PlayerComponent* player_component_ = nullptr; ///< @brief 指向拥有此状态的玩家组件
|
||||
|
||||
public:
|
||||
PlayerState(PlayerComponent* player_component) : player_component_(player_component) {}
|
||||
virtual ~PlayerState() = default;
|
||||
|
||||
// 禁止拷贝和移动
|
||||
PlayerState(const PlayerState&) = delete;
|
||||
PlayerState& operator=(const PlayerState&) = delete;
|
||||
PlayerState(PlayerState&&) = delete;
|
||||
PlayerState& operator=(PlayerState&&) = delete;
|
||||
|
||||
protected:
|
||||
// 核心状态方法
|
||||
virtual void enter() = 0; ///< @brief 进入
|
||||
virtual void exit() = 0; ///< @brief 离开
|
||||
virtual std::unique_ptr<PlayerState> handleInput(engine::core::Context&) = 0; ///< @brief 处理输入
|
||||
virtual std::unique_ptr<PlayerState> update(float, engine::core::Context&) = 0; ///< @brief 更新
|
||||
/* handleInput 和 update 返回值为下一个状态,如果不需要切换状态,则返回 nullptr */
|
||||
|
||||
};
|
||||
|
||||
} // namespace game::component::state
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "walk_state.h"
|
||||
#include "jump_state.h"
|
||||
#include "fall_state.h"
|
||||
#include "idle_state.h"
|
||||
#include "../player_component.h"
|
||||
#include "../../../engine/core/context.h"
|
||||
#include "../../../engine/input/input_manager.h"
|
||||
#include "../../../engine/object/game_object.h"
|
||||
#include "../../../engine/component/physics_component.h"
|
||||
#include "../../../engine/component/sprite_component.h"
|
||||
#include <glm/common.hpp>
|
||||
|
||||
|
||||
namespace game::component::state {
|
||||
|
||||
void WalkState::enter() {
|
||||
|
||||
}
|
||||
|
||||
void WalkState::exit() {
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<PlayerState> WalkState::handleInput(engine::core::Context& context)
|
||||
{
|
||||
auto input_manager = context.getInputManager();
|
||||
auto physics_component = player_component_->getPhysicsComponent();
|
||||
auto sprite_component = player_component_->getSpriteComponent();
|
||||
|
||||
// 如果按下“jump”则切换到 JumpState
|
||||
if (input_manager.isActionPressed("jump")) {
|
||||
return std::make_unique<JumpState>(player_component_);
|
||||
}
|
||||
|
||||
// 步行状态可以左右移动
|
||||
if (input_manager.isActionDown("move_left")) {
|
||||
if (physics_component->velocity_.x > 0.0f) {
|
||||
physics_component->velocity_.x = 0.0f; // 如果当前速度是向右的,则先减速到0 (增强操控手感)
|
||||
}
|
||||
// 添加向左的水平力
|
||||
physics_component->addForce({-player_component_->getMoveForce(), 0.0f});
|
||||
sprite_component->setFlipped(true); // 向左移动时翻转
|
||||
} else if (input_manager.isActionDown("move_right")) {
|
||||
if (physics_component->velocity_.x < 0.0f) {
|
||||
physics_component->velocity_.x = 0.0f; // 如果当前速度是向左的,则先减速到0
|
||||
}
|
||||
// 添加向右的水平力
|
||||
physics_component->addForce({player_component_->getMoveForce(), 0.0f});
|
||||
sprite_component->setFlipped(false); // 向右移动时不翻转
|
||||
} else {
|
||||
// 如果没有按下左右移动键,则切换到 IdleState
|
||||
return std::make_unique<IdleState>(player_component_);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<PlayerState> WalkState::update(float, engine::core::Context&)
|
||||
{
|
||||
// 限制最大速度
|
||||
auto physics_component = player_component_->getPhysicsComponent();
|
||||
auto max_speed = player_component_->getMaxSpeed();
|
||||
physics_component->velocity_.x = glm::clamp(physics_component->velocity_.x, -max_speed, max_speed);
|
||||
|
||||
// 如果下方没有碰撞,则切换到 FallState
|
||||
if (!physics_component->hasCollidedBelow()) {
|
||||
return std::make_unique<FallState>(player_component_);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace game::component::state
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "player_state.h"
|
||||
|
||||
namespace game::component::state {
|
||||
|
||||
class WalkState final : public PlayerState {
|
||||
friend class game::component::PlayerComponent;
|
||||
public:
|
||||
WalkState(PlayerComponent* player_component) : PlayerState(player_component) {}
|
||||
~WalkState() override = default;
|
||||
|
||||
private:
|
||||
void enter() override;
|
||||
void exit() override;
|
||||
std::unique_ptr<PlayerState> handleInput(engine::core::Context&) override;
|
||||
std::unique_ptr<PlayerState> update(float delta_time, engine::core::Context&) override;
|
||||
};
|
||||
|
||||
} // namespace game::component::state
|
||||
Reference in New Issue
Block a user