From 45367bed411d582f592e95cb5b96dc7b10b64aa2 Mon Sep 17 00:00:00 2001 From: Ziyu Date: Mon, 9 Jun 2025 09:59:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90AI=E7=BB=84=E4=BB=B6=E4=B8=8E?= =?UTF-8?q?AI=E8=A1=8C=E4=B8=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 4 ++ assets/maps/level1.tmj | 12 ++-- src/game/component/ai/ai_behavior.h | 30 +++++++++ src/game/component/ai/jump_behavior.cpp | 77 +++++++++++++++++++++++ src/game/component/ai/jump_behavior.h | 44 +++++++++++++ src/game/component/ai/patrol_behavior.cpp | 57 +++++++++++++++++ src/game/component/ai/patrol_behavior.h | 40 ++++++++++++ src/game/component/ai/updown_behavior.cpp | 58 +++++++++++++++++ src/game/component/ai/updown_behavior.h | 43 +++++++++++++ src/game/component/ai_component.cpp | 65 +++++++++++++++++++ src/game/component/ai_component.h | 60 ++++++++++++++++++ src/game/component/player_component.h | 6 +- src/game/component/state/jump_state.cpp | 2 +- src/game/scene/game_scene.cpp | 31 ++++----- 14 files changed, 504 insertions(+), 25 deletions(-) create mode 100644 src/game/component/ai/ai_behavior.h create mode 100644 src/game/component/ai/jump_behavior.cpp create mode 100644 src/game/component/ai/jump_behavior.h create mode 100644 src/game/component/ai/patrol_behavior.cpp create mode 100644 src/game/component/ai/patrol_behavior.h create mode 100644 src/game/component/ai/updown_behavior.cpp create mode 100644 src/game/component/ai/updown_behavior.h create mode 100644 src/game/component/ai_component.cpp create mode 100644 src/game/component/ai_component.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e32827..f0e4e44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ add_executable(${TARGET} src/engine/scene/level_loader.cpp src/game/scene/game_scene.cpp src/game/component/player_component.cpp + src/game/component/ai_component.cpp src/game/component/state/player_state.cpp src/game/component/state/idle_state.cpp src/game/component/state/walk_state.cpp @@ -66,6 +67,9 @@ add_executable(${TARGET} src/game/component/state/fall_state.cpp src/game/component/state/hurt_state.cpp src/game/component/state/dead_state.cpp + src/game/component/ai/patrol_behavior.cpp + src/game/component/ai/updown_behavior.cpp + src/game/component/ai/jump_behavior.cpp ) # 链接库 diff --git a/assets/maps/level1.tmj b/assets/maps/level1.tmj index 005f38b..c4ec653 100644 --- a/assets/maps/level1.tmj +++ b/assets/maps/level1.tmj @@ -138,8 +138,8 @@ "type":"", "visible":true, "width":40, - "x":720, - "y":144 + "x":730.5, + "y":174.666666666667 }, { "gid":607, @@ -162,8 +162,8 @@ "type":"", "visible":true, "width":35, - "x":958, - "y":148 + "x":958.666666666667, + "y":148.333333333333 }, { "gid":610, @@ -174,8 +174,8 @@ "type":"", "visible":true, "width":36, - "x":416, - "y":160 + "x":413.5, + "y":159 }, { "gid":612, diff --git a/src/game/component/ai/ai_behavior.h b/src/game/component/ai/ai_behavior.h new file mode 100644 index 0000000..ec0fd1c --- /dev/null +++ b/src/game/component/ai/ai_behavior.h @@ -0,0 +1,30 @@ +#pragma once + +namespace game::component { + class AIComponent; +} + +namespace game::component::ai { + +/** + * @brief AI 行为策略的抽象基类。 + */ +class AIBehavior { + friend class game::component::AIComponent; +public: + AIBehavior() = default; + virtual ~AIBehavior() = default; + + //禁止移动和拷贝 + AIBehavior(const AIBehavior&) = delete; + AIBehavior& operator=(const AIBehavior&) = delete; + AIBehavior(AIBehavior&&) = delete; + AIBehavior& operator=(AIBehavior&&) = delete; + +protected: + // --- 没有保存owner指针,因此需要传入 AIComponent 引用 --- + virtual void enter(AIComponent&) {} ///< @brief enter函数可选是否实现,默认为空 + virtual void update(float, AIComponent&) = 0; ///< @brief 更新 AI 行为逻辑(具体策略),必须实现 +}; + +} // namespace game::component::ai diff --git a/src/game/component/ai/jump_behavior.cpp b/src/game/component/ai/jump_behavior.cpp new file mode 100644 index 0000000..d91349e --- /dev/null +++ b/src/game/component/ai/jump_behavior.cpp @@ -0,0 +1,77 @@ +#include "jump_behavior.h" +#include "../ai_component.h" +#include "../../../engine/component/physics_component.h" +#include "../../../engine/component/transform_component.h" +#include "../../../engine/component/sprite_component.h" +#include "../../../engine/component/animation_component.h" +#include "../../../engine/object/game_object.h" +#include + +namespace game::component::ai { + +JumpBehavior::JumpBehavior(float min_x, float max_x, glm::vec2 jump_vel, float jump_interval) + : patrol_min_x_(min_x), + patrol_max_x_(max_x), + jump_vel_(jump_vel), + jump_interval_(jump_interval) +{ + if (patrol_min_x_ >= patrol_max_x_) { // 确保巡逻范围是有效的 + spdlog::error("JumpBehavior: min_x ({}) 应小于 max_x ({})。行为可能不正确。", min_x, max_x); + patrol_min_x_ = patrol_max_x_; + } + if (jump_interval_ <= 0.0f) { // 确保跳跃间隔是正数 + spdlog::error("JumpBehavior: jump_interval ({}) 应为正数。已设置为 2.0f。", jump_interval); + jump_interval_ = 2.0f; + } + if (jump_vel_.y > 0) { // 确保垂直跳跃速度是负数(向上) + spdlog::error("JumpBehavior: 垂直跳跃速度 ({}) 应为负数(向上)。已取相反数。", jump_vel_.y); + jump_vel_.y = -jump_vel_.y; + } +} + +void JumpBehavior::update(float delta_time, AIComponent& ai_component) { + // 获取必要的组件 + auto* physics_component = ai_component.getPhysicsComponent(); + auto* transform_component = ai_component.getTransformComponent(); + auto* sprite_component = ai_component.getSpriteComponent(); + auto* animation_component = ai_component.getAnimationComponent(); + if (!physics_component || !transform_component || !sprite_component || !animation_component) { + spdlog::error("JumpBehavior:缺少必要的组件,无法执行跳跃行为。"); + return; + } + + auto is_on_ground = physics_component->hasCollidedBelow(); // 着地标志 + if (is_on_ground) { // 如果在地面上 + jump_timer_ += delta_time; // 增加跳跃计时器 + physics_component->velocity_.x = 0.0f; // 停止水平移动(否则会有惯性) + + if (jump_timer_ >= jump_interval_) { // 时间到,准备跳跃 + jump_timer_ = 0.0f; // 重置计时器 + + // --- 检查是否需要更新跳跃方向 --- + auto current_x = transform_component->getPosition().x; + // 如果右边超限或者撞墙,向左跳 + if (jumping_right_ && (physics_component->hasCollidedRight() || current_x >= patrol_max_x_)) { + jumping_right_ = false; + // 如果左边超限或者撞墙,向右跳 + } else if (!jumping_right_ && (physics_component->hasCollidedLeft() || current_x <= patrol_min_x_)) { + jumping_right_ = true; + } + auto jump_vel_x = jumping_right_ ? jump_vel_.x : -jump_vel_.x; // 确定水平跳跃方向 + physics_component->velocity_= {jump_vel_x, jump_vel_.y}; // 设置速度 + animation_component->playAnimation("jump"); // 播放跳跃动画 + sprite_component->setFlipped(jumping_right_); // 更新精灵翻转 + + } else { // 还在地面等待 + animation_component->playAnimation("idle"); + } + } else { // 在空中, 根据垂直速度判断是上升(jump)还是下落(fall) + if (physics_component->getVelocity().y < 0) { + animation_component->playAnimation("jump"); + } else { + animation_component->playAnimation("fall"); + } + } +} + +} // namespace game::component::ai \ No newline at end of file diff --git a/src/game/component/ai/jump_behavior.h b/src/game/component/ai/jump_behavior.h new file mode 100644 index 0000000..7826122 --- /dev/null +++ b/src/game/component/ai/jump_behavior.h @@ -0,0 +1,44 @@ +#pragma once +#include "ai_behavior.h" +#include + +namespace game::component::ai { + +/** + * @brief AI 行为:在指定范围内周期性地跳跃。 + * + * 在地面时等待,然后向当前方向跳跃。 + * 撞墙或到达边界时改变下次跳跃方向。 + */ +class JumpBehavior final : public AIBehavior { + friend class game::component::AIComponent; +private: + float patrol_min_x_ = 0.0f; ///< @brief 巡逻范围的左边界 + float patrol_max_x_ = 0.0f; ///< @brief 巡逻范围的右边界 + glm::vec2 jump_vel_ = glm::vec2(100.0f, -300.0f); ///< @brief 跳跃速度 + float jump_interval_ = 2.0f; ///< @brief 跳跃间隔时间 (秒) + float jump_timer_ = 0.0f; ///< @brief 距离下次跳跃的计时器 + bool jumping_right_ = false; ///< @brief 当前是否向右跳跃 + +public: + /** + * @brief 构造函数。 + * @param min_x 巡逻范围的最小 x 坐标。 + * @param max_x 巡逻范围的最大 x 坐标。 + * @param jump_vel 跳跃速度向量 (水平, 垂直)。 + * @param jump_interval 两次跳跃之间的间隔时间。 + */ + JumpBehavior(float min_x, float max_x, glm::vec2 jump_vel = glm::vec2(100.0f, -300.0f), float jump_interval = 2.0f); + ~JumpBehavior() override = default; + + // 禁止拷贝和移动 + JumpBehavior(const JumpBehavior&) = delete; + JumpBehavior& operator=(const JumpBehavior&) = delete; + JumpBehavior(JumpBehavior&&) = delete; + JumpBehavior& operator=(JumpBehavior&&) = delete; + +private: + void update(float delta_time, AIComponent& ai_component) override; +}; + +} // namespace game::component::ai \ No newline at end of file diff --git a/src/game/component/ai/patrol_behavior.cpp b/src/game/component/ai/patrol_behavior.cpp new file mode 100644 index 0000000..9265153 --- /dev/null +++ b/src/game/component/ai/patrol_behavior.cpp @@ -0,0 +1,57 @@ +#include "patrol_behavior.h" +#include "../ai_component.h" +#include "../../../engine/component/physics_component.h" +#include "../../../engine/component/transform_component.h" +#include "../../../engine/component/sprite_component.h" +#include "../../../engine/component/animation_component.h" +#include "../../../engine/object/game_object.h" +#include + +namespace game::component::ai { + +PatrolBehavior::PatrolBehavior(float min_x, float max_x, float speed) + : patrol_min_x_(min_x), + patrol_max_x_(max_x), + move_speed_(speed) +{ + if (patrol_min_x_ >= patrol_max_x_) { + spdlog::error("PatrolBehavior:min_x ({}) 应小于 max_x ({})。行为可能不正确。", min_x, max_x); + patrol_min_x_ = patrol_max_x_; // 修正为相等,避免逻辑错误 + } +} + +void PatrolBehavior::enter(AIComponent& ai_component) { + // 播放动画 (进行 patrol 行为的对象应该有 'walk' 动画) + if (auto* animation_component = ai_component.getAnimationComponent(); animation_component) { + animation_component->playAnimation("walk"); + } +} + +void PatrolBehavior::update(float /*delta_time*/, AIComponent& ai_component) { + // 获取必要的组件 + auto* physics_component = ai_component.getPhysicsComponent(); + auto* transform_component = ai_component.getTransformComponent(); + auto* sprite_component = ai_component.getSpriteComponent(); + if (!physics_component || !transform_component || !sprite_component) { + spdlog::error("PatrolBehavior:缺少必要的组件,无法执行巡逻行为。"); + return; + } + + // --- 检查碰撞和边界 --- + auto current_x = transform_component->getPosition().x; + + // 撞右墙或到达设定目标则转向左 + if (physics_component->hasCollidedRight() || current_x >= patrol_max_x_) { + physics_component->velocity_.x = -move_speed_; + moving_right_ = false; + // 撞墙左或到达设定目标则转向右 + }else if (physics_component->hasCollidedLeft() || current_x <= patrol_min_x_) { + physics_component->velocity_.x = move_speed_; + moving_right_ = true; + } + + // 更新精灵翻转(向左移动时,不翻转) + sprite_component->setFlipped(moving_right_); +} + +} // namespace game::component::ai \ No newline at end of file diff --git a/src/game/component/ai/patrol_behavior.h b/src/game/component/ai/patrol_behavior.h new file mode 100644 index 0000000..5b4f44b --- /dev/null +++ b/src/game/component/ai/patrol_behavior.h @@ -0,0 +1,40 @@ +#pragma once +#include "ai_behavior.h" + +namespace game::component::ai { + +/** + * @brief AI 行为:在指定范围内左右巡逻。 + * + * 遇到墙壁或到达巡逻边界时会转身。 + */ +class PatrolBehavior final : public AIBehavior { + friend class game::component::AIComponent; +private: + float patrol_min_x_ = 0.0f; ///< @brief 巡逻范围的左边界 + float patrol_max_x_ = 0.0f; ///< @brief 巡逻范围的右边界 + float move_speed_ = 50.0f; ///< @brief 移动速度 (像素/秒) + bool moving_right_ = false; ///< @brief 当前是否向右移动 + +public: + /** + * @brief 构造函数。 + * @param min_x 巡逻范围的最小 x 坐标。 + * @param max_x 巡逻范围的最大 x 坐标。 + * @param speed 移动速度。 + */ + PatrolBehavior(float min_x, float max_x, float speed = 50.0f); + ~PatrolBehavior() override = default; + + // 禁止拷贝和移动 + PatrolBehavior(const PatrolBehavior&) = delete; + PatrolBehavior& operator=(const PatrolBehavior&) = delete; + PatrolBehavior(PatrolBehavior&&) = delete; + PatrolBehavior& operator=(PatrolBehavior&&) = delete; + +private: + void enter(AIComponent& ai_component) override; + void update(float delta_time, AIComponent& ai_component) override; +}; + +} // namespace game::component::ai \ No newline at end of file diff --git a/src/game/component/ai/updown_behavior.cpp b/src/game/component/ai/updown_behavior.cpp new file mode 100644 index 0000000..31aa4b9 --- /dev/null +++ b/src/game/component/ai/updown_behavior.cpp @@ -0,0 +1,58 @@ +#include "updown_behavior.h" +#include "../ai_component.h" +#include "../../../engine/component/physics_component.h" +#include "../../../engine/component/transform_component.h" +#include "../../../engine/component/animation_component.h" +#include "../../../engine/object/game_object.h" +#include + +namespace game::component::ai { + +UpDownBehavior::UpDownBehavior(float min_y, float max_y, float speed) + : patrol_min_y_(min_y), + patrol_max_y_(max_y), + move_speed_(speed) +{ + if (patrol_min_y_ >= patrol_max_y_) { + spdlog::error("UpDownBehavior:min_y ({}) 应小于 max_y ({})。行为可能不正确。", min_y, max_y); + patrol_min_y_ = patrol_max_y_; // 修正为相等,避免逻辑错误 + } +} + +void UpDownBehavior::enter(AIComponent& ai_component) { + // 播放动画 (进行 up-down 行为的对象应该有 'fly' 动画) + if (auto* animation_component = ai_component.getAnimationComponent(); animation_component) { + animation_component->playAnimation("fly"); + } + + // 禁用重力 + if (auto* physics_component = ai_component.getPhysicsComponent(); physics_component) { + physics_component->setUseGravity(false); + } +} + +void UpDownBehavior::update(float /*delta_time*/, AIComponent& ai_component) { + // 获取必要的组件 + auto* physics_component = ai_component.getPhysicsComponent(); + auto* transform_component = ai_component.getTransformComponent(); + if (!physics_component || !transform_component) { + spdlog::error("UpdownBehavior:缺少必要的组件,无法执行巡逻行为。"); + return; + } + + // --- 检查碰撞和边界 --- + auto current_y = transform_component->getPosition().y; + + // 到达上边界或碰到上方障碍,向下移动 + if (physics_component->hasCollidedAbove() || current_y <= patrol_min_y_) { + physics_component->velocity_.y = move_speed_; + moving_down_ = true; + // 到达下边界或碰到下方障碍,向上移动 + } else if (physics_component->hasCollidedBelow() || current_y >= patrol_max_y_) { + physics_component->velocity_.y = -move_speed_; + moving_down_ = false; + } + /* 不需要翻转精灵图 */ +} + +} // namespace game::component::ai \ No newline at end of file diff --git a/src/game/component/ai/updown_behavior.h b/src/game/component/ai/updown_behavior.h new file mode 100644 index 0000000..a3a4ec6 --- /dev/null +++ b/src/game/component/ai/updown_behavior.h @@ -0,0 +1,43 @@ +#ifndef GAME_COMPONENT_AI_UPDOWN_BEHAVIOR_H +#define GAME_COMPONENT_AI_UPDOWN_BEHAVIOR_H + +#include "ai_behavior.h" + +namespace game::component::ai { + +/** + * @brief AI 行为:在指定范围内上下垂直移动。 + * + * 到达边界或碰到障碍物时会反向。 + */ +class UpDownBehavior final : public AIBehavior { + friend class game::component::AIComponent; +private: + float patrol_min_y_ = 0.0f; ///< @brief 巡逻范围的上边界 (Y 坐标较小值) + float patrol_max_y_ = 0.0f; ///< @brief 巡逻范围的下边界 (Y 坐标较大值) + float move_speed_ = 50.0f; ///< @brief 移动速度 (像素/秒) + bool moving_down_ = false; ///< @brief 当前是否向下移动 + +public: + /** + * @brief 构造函数。 + * @param min_y 巡逻范围的最小 y 坐标。 + * @param max_y 巡逻范围的最大 y 坐标。 + * @param speed 移动速度。 + */ + UpDownBehavior(float min_y, float max_y, float speed = 50.0f); + ~UpDownBehavior() override = default; + + // 禁止拷贝和移动 + UpDownBehavior(const UpDownBehavior&) = delete; + UpDownBehavior& operator=(const UpDownBehavior&) = delete; + UpDownBehavior(UpDownBehavior&&) = delete; + UpDownBehavior& operator=(UpDownBehavior&&) = delete; + +private: + void enter(AIComponent& ai_component) override; + void update(float delta_time, AIComponent& ai_component) override; +}; + +} // namespace game::component::ai +#endif // GAME_COMPONENT_AI_UPDOWN_BEHAVIOR_H \ No newline at end of file diff --git a/src/game/component/ai_component.cpp b/src/game/component/ai_component.cpp new file mode 100644 index 0000000..e1f1c9c --- /dev/null +++ b/src/game/component/ai_component.cpp @@ -0,0 +1,65 @@ +#include "ai_component.h" +#include "ai/ai_behavior.h" +#include "../../engine/object/game_object.h" +#include "../../engine/component/transform_component.h" +#include "../../engine/component/physics_component.h" +#include "../../engine/component/sprite_component.h" +#include "../../engine/component/animation_component.h" +#include "../../engine/component/health_component.h" +#include + +namespace game::component { + +void AIComponent::init() { + if (!owner_) { + spdlog::error("PlayerComponent 没有所属游戏对象!"); + return; + } + + // 获取并缓存必要的组件指针 + transform_component_ = owner_->getComponent(); + physics_component_ = owner_->getComponent(); + sprite_component_ = owner_->getComponent(); + animation_component_ = owner_->getComponent(); + + // 检查是否所有必需的组件都存在 + if (!transform_component_ || !physics_component_ || !sprite_component_ || !animation_component_) { + spdlog::error("GameObject '{}' 上的 AIComponent 缺少必需的组件", owner_->getName()); + } +} + +void AIComponent::update(float delta_time, engine::core::Context&) { + // 将更新委托给当前的行为策略 + if (current_behavior_) { + current_behavior_->update(delta_time, *this); + } else { + spdlog::warn("GameObject '{}' 上的 AIComponent 没有设置行为。", owner_ ? owner_->getName() : "Unknown"); + } +} + +void AIComponent::setBehavior(std::unique_ptr behavior) { + current_behavior_ = std::move(behavior); + spdlog::debug("GameObject '{}' 上的 AIComponent 设置了新的行为。", owner_ ? owner_->getName() : "Unknown"); + if (current_behavior_) { + current_behavior_->enter(*this); // 调用新行为的 enter 方法 + } +} + +bool AIComponent::takeDamage(int damage) +{ + bool success = false; + if (auto* health_component = getOwner()->getComponent(); health_component) { + success = health_component->takeDamage(damage); + // TODO: 可以设置受伤/死亡后的行为 + } + return success; +} + +bool AIComponent::isAlive() const { + if (auto* health_component = getOwner()->getComponent(); health_component) { + return health_component->isAlive(); + } + return true; // 如果没有生命组件,默认返回存活状态 +} + +} // namespace game::component diff --git a/src/game/component/ai_component.h b/src/game/component/ai_component.h new file mode 100644 index 0000000..cad6a6c --- /dev/null +++ b/src/game/component/ai_component.h @@ -0,0 +1,60 @@ +#pragma once +#include "../../engine/component/component.h" +#include "ai/ai_behavior.h" +#include + +namespace game::component::ai { class AIBehavior; } +namespace engine::component { + class TransformComponent; + class PhysicsComponent; + class SpriteComponent; + class AnimationComponent; +} + +namespace game::component { + +/** + * @brief 负责管理 GameObject 的 AI 行为。 + * + * 使用策略模式,持有一个具体的 AIBehavior 实例来执行实际的 AI 逻辑。 + * 提供对 GameObject 其他关键组件的访问。 + */ +class AIComponent final : public engine::component::Component { + friend class engine::object::GameObject; +private: + std::unique_ptr current_behavior_ = nullptr; ///< @brief 当前 AI 行为策略 + /* 未来可添加一些敌人属性 */ + + // --- 缓存组件指针 --- + engine::component::TransformComponent* transform_component_ = nullptr; + engine::component::PhysicsComponent* physics_component_ = nullptr; + engine::component::SpriteComponent* sprite_component_ = nullptr; + engine::component::AnimationComponent* animation_component_ = nullptr; + +public: + AIComponent() = default; + ~AIComponent() override = default; + + // 禁止拷贝和移动 + AIComponent(const AIComponent&) = delete; + AIComponent& operator=(const AIComponent&) = delete; + AIComponent(AIComponent&&) = delete; + AIComponent& operator=(AIComponent&&) = delete; + + void setBehavior(std::unique_ptr behavior); ///< @brief 设置当前 AI 行为策略 + bool takeDamage(int damage); ///< @brief 处理伤害逻辑,返回是否造成伤害 + bool isAlive() const; ///< @brief 检查对象是否存活 + + // --- Setters and Getters --- + engine::component::TransformComponent* getTransformComponent() const { return transform_component_; } + engine::component::PhysicsComponent* getPhysicsComponent() const { return physics_component_; } + engine::component::SpriteComponent* getSpriteComponent() const { return sprite_component_; } + engine::component::AnimationComponent* getAnimationComponent() const { return animation_component_; } + +private: + // 核心循环方法 + void init() override; + void update(float delta_time, engine::core::Context&) override; +}; + +} // namespace game::component diff --git a/src/game/component/player_component.h b/src/game/component/player_component.h index d027d9a..24a5b59 100644 --- a/src/game/component/player_component.h +++ b/src/game/component/player_component.h @@ -40,7 +40,7 @@ private: float move_force_ = 200.0f; ///< @brief 水平移动力 float max_speed_ = 120.0f; ///< @brief 最大移动速度 (像素/秒) float friction_factor_ = 0.85f; ///< @brief 摩擦系数 (Idle时缓冲效果,每帧乘以此系数) - float jump_force_ = 350.0f; ///< @brief 跳跃力 (按下"jump"键给的瞬间向上的力) + float jump_vel_ = 350.0f; ///< @brief 跳跃速度 (按下"jump"键给的瞬间向上的速度) // --- 属性相关参数 --- float stunned_duration_ = 0.4f; ///< @brief 玩家被击中后的硬直时间(单位:秒) @@ -72,8 +72,8 @@ public: float getMaxSpeed() const { return max_speed_; } ///< @brief 获取最大移动速度 void setFrictionFactor(float friction_factor) { friction_factor_ = friction_factor; } ///< @brief 设置摩擦系数 float getFrictionFactor() const { return friction_factor_; } ///< @brief 获取摩擦系数 - void setJumpForce(float jump_force) { jump_force_ = jump_force; } ///< @brief 设置跳跃力 - float getJumpForce() const { return jump_force_; } ///< @brief 获取跳跃力 + void setJumpVelocity(float jump_vel) { jump_vel_ = jump_vel; } ///< @brief 设置跳跃速度 + float getJumpVelocity() const { return jump_vel_; } ///< @brief 获取跳跃速度 void setStunnedDuration(float duration) { stunned_duration_ = duration; } ///< @brief 设置硬直时间 float getStunnedDuration() const { return stunned_duration_; } ///< @brief 获取硬直时间 diff --git a/src/game/component/state/jump_state.cpp b/src/game/component/state/jump_state.cpp index 2da2eaf..6d3abce 100644 --- a/src/game/component/state/jump_state.cpp +++ b/src/game/component/state/jump_state.cpp @@ -15,7 +15,7 @@ namespace game::component::state { void JumpState::enter() { playAnimation("jump"); // 播放跳跃动画 auto physics_component = player_component_->getPhysicsComponent(); - physics_component->velocity_.y = -player_component_->getJumpForce(); // 向上跳跃 + physics_component->velocity_.y = -player_component_->getJumpVelocity(); // 向上跳跃 spdlog::debug("PlayerComponent 进入 JumpState,设置初始垂直速度为: {}", physics_component->velocity_.y); } diff --git a/src/game/scene/game_scene.cpp b/src/game/scene/game_scene.cpp index d453336..b3e088c 100644 --- a/src/game/scene/game_scene.cpp +++ b/src/game/scene/game_scene.cpp @@ -14,6 +14,10 @@ #include "../../engine/input/input_manager.h" #include "../../engine/render/camera.h" #include "../../engine/render/animation.h" +#include "../component/ai_component.h" +#include "../component/ai/patrol_behavior.h" +#include "../component/ai/updown_behavior.h" +#include "../component/ai/jump_behavior.h" #include #include @@ -136,27 +140,24 @@ bool GameScene::initEnemyAndItem() bool success = true; for (auto& game_object : game_objects_){ if (game_object->getName() == "eagle"){ - if (auto* ac = game_object->getComponent(); ac){ - ac->playAnimation("fly"); - } else { - spdlog::error("Eagle对象缺少 AnimationComponent,无法播放动画。"); - success = false; + if (auto* ai_component = game_object->addComponent(); ai_component){ + auto y_max = game_object->getComponent()->getPosition().y; + auto y_min = y_max - 80.0f; // 让鹰的飞行范围 (当前位置与上方80像素 的区域) + ai_component->setBehavior(std::make_unique(y_min, y_max)); } } if (game_object->getName() == "frog"){ - if (auto* ac = game_object->getComponent(); ac){ - ac->playAnimation("idle"); - } else { - spdlog::error("Frog对象缺少 AnimationComponent,无法播放动画。"); - success = false; + if (auto* ai_component = game_object->addComponent(); ai_component){ + auto x_max = game_object->getComponent()->getPosition().x - 10.0f; + auto x_min = x_max - 90.0f; // 青蛙跳跃范围(右侧 - 10.0f 是为了增加稳定性) + ai_component->setBehavior(std::make_unique(x_min, x_max)); } } if (game_object->getName() == "opossum"){ - if (auto* ac = game_object->getComponent(); ac){ - ac->playAnimation("walk"); - } else { - spdlog::error("Opossum对象缺少 AnimationComponent,无法播放动画。"); - success = false; + if (auto* ai_component = game_object->addComponent(); ai_component){ + auto x_max = game_object->getComponent()->getPosition().x; + auto x_min = x_max - 200.0f; // 负鼠巡逻范围 + ai_component->setBehavior(std::make_unique(x_min, x_max)); } } if (game_object->getTag() == "item"){