From ddb02723f5af04389689d7e56f377a6053236f89 Mon Sep 17 00:00:00 2001 From: Ziyu Date: Mon, 2 Jun 2025 17:19:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=A2=B0=E6=92=9E=E5=99=A8?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E4=B8=8E=E7=A2=B0=E6=92=9E=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 + assets/config.json | 2 +- src/engine/component/collider_component.cpp | 109 +++++++++++++++++++ src/engine/component/collider_component.h | 73 +++++++++++++ src/engine/component/transform_component.cpp | 5 + src/engine/physics/collider.h | 74 +++++++++++++ src/engine/physics/collision.cpp | 79 ++++++++++++++ src/engine/physics/collision.h | 60 ++++++++++ src/engine/physics/physics_engine.cpp | 36 ++++++ src/engine/physics/physics_engine.h | 13 +++ src/game/scene/game_scene.cpp | 24 ++++ src/game/scene/game_scene.h | 1 + 12 files changed, 477 insertions(+), 1 deletion(-) create mode 100644 src/engine/component/collider_component.cpp create mode 100644 src/engine/component/collider_component.h create mode 100644 src/engine/physics/collider.h create mode 100644 src/engine/physics/collision.cpp create mode 100644 src/engine/physics/collision.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9646804..d72c6ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,9 @@ add_executable(${TARGET} src/engine/component/parallax_component.cpp src/engine/component/tilelayer_component.cpp src/engine/component/physics_component.cpp + src/engine/component/collider_component.cpp src/engine/physics/physics_engine.cpp + src/engine/physics/collision.cpp src/engine/scene/scene.cpp src/engine/scene/scene_manager.cpp src/engine/scene/level_loader.cpp diff --git a/assets/config.json b/assets/config.json index bd0fbf0..c9c6697 100644 --- a/assets/config.json +++ b/assets/config.json @@ -9,7 +9,7 @@ "vsync": true }, "performance": { - "target_fps": 144 + "target_fps": 60 }, "audio": { "music_volume": 0.5, diff --git a/src/engine/component/collider_component.cpp b/src/engine/component/collider_component.cpp new file mode 100644 index 0000000..ae76988 --- /dev/null +++ b/src/engine/component/collider_component.cpp @@ -0,0 +1,109 @@ +#include "collider_component.h" +#include "transform_component.h" +#include "../object/game_object.h" +#include "../physics/collider.h" +#include + +namespace engine::component { + +ColliderComponent::ColliderComponent( + std::unique_ptr collider, + engine::utils::Alignment alignment, + bool is_trigger, + bool is_active) + : collider_(std::move(collider)), + alignment_(alignment), + is_trigger_(is_trigger), + is_active_(is_active) +{ + if (!collider_) { + spdlog::error("创建 ColliderComponent 时传入了空的碰撞器!"); + } +} + +void ColliderComponent::init() { + if (!owner_) { + spdlog::error("ColliderComponent 没有所有者 GameObject!"); + return; + } + transform_ = owner_->getComponent(); + if (!transform_) { + spdlog::error("ColliderComponent 需要一个在同一个 GameObject 上的 TransformComponent!"); + return; + } + + // 在获取 transform_ 之后计算初始偏移量 + updateOffset(); +} + +// 实现 setAlignment 方法 +void ColliderComponent::setAlignment(engine::utils::Alignment anchor) { + alignment_ = anchor; + // 重新计算偏移量,确保 transform_ 和 collider_ 有效 + if (transform_ && collider_) { + updateOffset(); + } +} + +void ColliderComponent::updateOffset() { + if (!collider_) return; + + // 获取碰撞盒的最小包围盒尺寸 + auto collider_size = collider_->getAABBSize(); + + // 如果尺寸无效,偏移为0 + if (collider_size.x <= 0.0f || collider_size.y <= 0.0f) { + offset_ = {0.0f, 0.0f}; + return; + } + auto scale = transform_->getScale(); + + // 根据 alignment_anchor_ 计算 AABB 左上角相对于 Transform 中心的偏移量 + switch (alignment_) { + case engine::utils::Alignment::TOP_LEFT: + offset_ = glm::vec2{0.0f, 0.0f} * scale; + break; + case engine::utils::Alignment::TOP_CENTER: + offset_ = glm::vec2{-collider_size.x / 2.0f, 0.0f} * scale; + break; + case engine::utils::Alignment::TOP_RIGHT: + offset_ = glm::vec2{-collider_size.x, 0.0f} * scale; + break; + case engine::utils::Alignment::CENTER_LEFT: + offset_ = glm::vec2{0.0f, -collider_size.y / 2.0f} * scale; + break; + case engine::utils::Alignment::CENTER: + offset_ = glm::vec2{-collider_size.x / 2.0f, -collider_size.y / 2.0f} * scale; + break; + case engine::utils::Alignment::CENTER_RIGHT: + offset_ = glm::vec2{-collider_size.x, -collider_size.y / 2.0f} * scale; + break; + case engine::utils::Alignment::BOTTOM_LEFT: + offset_ = glm::vec2{0.0f, -collider_size.y} * scale; + break; + case engine::utils::Alignment::BOTTOM_CENTER: + offset_ = glm::vec2{-collider_size.x / 2.0f, -collider_size.y} * scale; + break; + case engine::utils::Alignment::BOTTOM_RIGHT: + offset_ = glm::vec2{-collider_size.x, -collider_size.y} * scale; + break; + default: + break; // 如果 alignment_ 是 NONE,则不做任何操作(手动设置 offset_) + } +} + +engine::utils::Rect ColliderComponent::getWorldAABB() const { + if (!transform_ || !collider_) { + return {glm::vec2(0.0f, 0.0f), glm::vec2(0.0f, 0.0f)}; + } + // 计算最小包围盒的左上角坐标(position) + const glm::vec2 top_left_pos = transform_->getPosition() + offset_; + // 计算最小包围盒的尺寸(size) + const glm::vec2 base_size = collider_->getAABBSize(); + const glm::vec2 scale = transform_->getScale(); + glm::vec2 scaled_size = base_size * scale; + // 返回最小包围盒的 Rect + return { top_left_pos, scaled_size }; +} + +} // namespace engine::component \ No newline at end of file diff --git a/src/engine/component/collider_component.h b/src/engine/component/collider_component.h new file mode 100644 index 0000000..a360279 --- /dev/null +++ b/src/engine/component/collider_component.h @@ -0,0 +1,73 @@ +#pragma once +#include "./component.h" +#include "../physics/collider.h" +#include "../utils/math.h" +#include "../utils/alignment.h" +#include + +// 前置声明 +namespace engine::component { + class TransformComponent; +} + +namespace engine::component { + +/** + * @brief 碰撞器组件。 + * + * 持有 Collider 对象(如 AABBCollider)并提供获取世界坐标系下碰撞形状的方法。 + */ +class ColliderComponent final : public Component { + friend class engine::object::GameObject; +private: + TransformComponent* transform_ = nullptr; ///< @brief 缓存的 TransformComponent 指针 (非拥有) + + std::unique_ptr collider_; ///< @brief 拥有的碰撞器对象。 + glm::vec2 offset_ = {0.0f, 0.0f}; ///< @brief 碰撞器(最小包围盒的)左上角相对于变换原点的偏移量。 + engine::utils::Alignment alignment_ = engine::utils::Alignment::NONE; ///< @brief 对齐方式。 + + bool is_trigger_ = false; ///< @brief 是否为触发器 (仅检测碰撞,不产生物理响应) + bool is_active_ = true; ///< @brief 是否激活 + +public: + /** + * @brief 构造函数。 + * @param collider 指向 Collider 实例的 unique_ptr,所有权将被转移。 + * @param alignment 初始的对齐锚点。 + * @param is_trigger 此碰撞器是否为触发器。 + * @param is_active 此碰撞器是否激活。 + */ + explicit ColliderComponent( + std::unique_ptr collider, + engine::utils::Alignment alignment = engine::utils::Alignment::NONE, + bool is_trigger = false, + bool is_active = true + ); + + /** + * @brief 根据当前的 alignment_anchor_ 和 collider_ 尺寸计算 offset_。 + * @note 需要用到TransformComponent的scale,因此TransformComponent更新scale时,也要调用此方法。 + */ + void updateOffset(); + + // --- Getters --- + const TransformComponent* getTransform() const { return transform_; } ///< @brief 获取缓存的TransformComponent + const engine::physics::Collider* getCollider() const { return collider_.get(); } ///< @brief 获取 Collider 对象。 + const glm::vec2& getOffset() const { return offset_; } ///< @brief 获取当前计算出的偏移量。 + engine::utils::Alignment getAlignment() const { return alignment_; } ///< @brief 获取设置的对齐锚点。 + engine::utils::Rect getWorldAABB() const; ///< @brief 获取世界坐标系下的最小轴对齐包围盒(AABB)。 + bool isTrigger() const { return is_trigger_; } ///< @brief 检查此碰撞器是否为触发器。 + bool isActive() const { return is_active_; } ///< @brief 检查此碰撞器是否激活。 + + void setAlignment(engine::utils::Alignment anchor); ///< @brief 设置新的对齐方式并重新计算偏移量。 + void setOffset(const glm::vec2& offset) { offset_ = offset; } ///< @brief 设置偏移量。 + void setTrigger(bool is_trigger) { is_trigger_ = is_trigger; } ///< @brief 设置此碰撞器是否为触发器。 + void setActive(bool is_active) { is_active_ = is_active; } ///< @brief 设置此碰撞器是否激活。 + +private: + // 核心循环方法 + void init() override; + void update(float, engine::core::Context&) override {} +}; + +} // namespace engine::component \ No newline at end of file diff --git a/src/engine/component/transform_component.cpp b/src/engine/component/transform_component.cpp index 9cf6bc3..d400fd3 100644 --- a/src/engine/component/transform_component.cpp +++ b/src/engine/component/transform_component.cpp @@ -1,6 +1,7 @@ #include "transform_component.h" #include "../object/game_object.h" #include "sprite_component.h" +#include "collider_component.h" namespace engine::component { @@ -12,6 +13,10 @@ void TransformComponent::setScale(const glm::vec2 &scale) if (sprite_comp) { sprite_comp->updateOffset(); } + auto collider_comp = owner_->getComponent(); + if (collider_comp) { + collider_comp->updateOffset(); + } } } diff --git a/src/engine/physics/collider.h b/src/engine/physics/collider.h new file mode 100644 index 0000000..533b7ed --- /dev/null +++ b/src/engine/physics/collider.h @@ -0,0 +1,74 @@ +#pragma once +#include + +namespace engine::physics { + +/** + * @brief 定义不同类型的碰撞器。 + */ +enum class ColliderType { + NONE, + AABB, + CIRCLE, + // 未来可能添加其他类型,如 Capsule, Polygon 等 +}; + +/** + * @brief 碰撞器的抽象基类。 + * 所有具体的碰撞器都应继承此类。 + */ +class Collider { +protected: + glm::vec2 aabb_size_ = {0.0f, 0.0f}; ///< @brief 覆盖Collider的最小包围盒的尺寸(宽度和高度)。 + +public: + virtual ~Collider() = default; + virtual ColliderType getType() const = 0; ///< @brief 获取碰撞器的类型。 + + void setAABBSize(const glm::vec2& size) { aabb_size_ = size; } ///< @brief 设置最小包围盒的尺寸(宽度和高度)。 + const glm::vec2& getAABBSize() const { return aabb_size_; } ///< @brief 获取最小包围盒的尺寸(宽度和高度)。 +}; + +/** + * @brief 轴对齐包围盒 (Axis-Aligned Bounding Box) 碰撞器。 + */ +class AABBCollider final : public Collider { +private: + glm::vec2 size_ = {0.0f, 0.0f}; ///< @brief 包围盒的尺寸(和aabb_size_相同)。 + +public: + /** + * @brief 构造函数。 + * @param size 包围盒的宽度和高度。 + */ + explicit AABBCollider(const glm::vec2& size) : size_(size) { setAABBSize(size); } + ~AABBCollider() override = default; + + // --- Getters and Setters --- + ColliderType getType() const override { return ColliderType::AABB; } + const glm::vec2& getSize() const { return size_; } + void setSize(const glm::vec2& size) { size_ = size; } +}; + +/** + * @brief 圆形碰撞器。 + */ +class CircleCollider final : public Collider { +private: + float radius_ = 0.0f; ///< @brief 圆的半径。 + +public: + /** + * @brief 构造函数。 + * @param radius 圆的半径。 + */ + explicit CircleCollider(float radius) : radius_(radius) { setAABBSize(glm::vec2(radius * 2.0f, radius * 2.0f)); } + ~CircleCollider() override = default; + + // --- Getters and Setters --- + ColliderType getType() const override { return ColliderType::CIRCLE; } + float getRadius() const { return radius_; } + void setRadius(float radius) { radius_ = radius; } +}; + +} // namespace engine::physics \ No newline at end of file diff --git a/src/engine/physics/collision.cpp b/src/engine/physics/collision.cpp new file mode 100644 index 0000000..635e834 --- /dev/null +++ b/src/engine/physics/collision.cpp @@ -0,0 +1,79 @@ +#include "collision.h" +#include "../component/collider_component.h" +#include "../component/transform_component.h" + +namespace engine::physics::collision { + +bool checkCollision(const engine::component::ColliderComponent& a, const engine::component::ColliderComponent& b) { + // 获取两个碰撞盒及对应Transform信息 + auto a_collider = a.getCollider(); + auto b_collider = b.getCollider(); + auto a_transform = a.getTransform(); + auto b_transform = b.getTransform(); + + // 先计算最小包围盒是否碰撞,如果没有碰撞,那一定是返回false (不考虑AABB的旋转) + auto a_size = a_collider->getAABBSize() * a_transform->getScale(); + auto b_size = b_collider->getAABBSize() * b_transform->getScale(); + auto a_pos = a_transform->getPosition() + a.getOffset(); + auto b_pos = b_transform->getPosition() + b.getOffset(); + if (!checkAABBOverlap(a_pos, a_size, b_pos, b_size)) { + return false; + } + + // --- 如果最小包围盒有碰撞,再进行更细致的判断 --- + // AABB vs AABB, 直接返回真 + if (a_collider->getType() == engine::physics::ColliderType::AABB && b_collider->getType() == engine::physics::ColliderType::AABB) { + return true; + } + // Circle vs Circle: 判断两个圆心距离是否小于两个圆的半径之和 + else if (a_collider->getType() == engine::physics::ColliderType::CIRCLE && b_collider->getType() == engine::physics::ColliderType::CIRCLE) + { + auto a_center = a_pos + 0.5f * a_size; // 圆心位置 + auto b_center = b_pos + 0.5f * b_size; + auto a_radius = 0.5f * a_size.x; // 圆的半径等于AABB的一半宽度 + auto b_radius = 0.5f * b_size.x; + return checkCircleOverlap(a_center, a_radius, b_center, b_radius); + } + // AABB vs Circle: 判断圆心到AABB的最邻近点是否在圆内 + else if (a_collider->getType() == engine::physics::ColliderType::AABB && b_collider->getType() == engine::physics::ColliderType::CIRCLE) + { + auto b_center = b_pos + 0.5f * b_size; + auto b_radius = 0.5f * b_size.x; + auto nearest_point = glm::clamp(b_center, a_pos, a_pos + a_size); // 计算圆心到AABB的最邻近点 + return checkPointInCircle(nearest_point, b_center, b_radius); + } + // Circle vs AABB + else if (a_collider->getType() == engine::physics::ColliderType::CIRCLE && b_collider->getType() == engine::physics::ColliderType::AABB) + { + auto a_center = a_pos + 0.5f * a_size; + auto a_radius = 0.5f * a_size.x; + auto nearest_point = glm::clamp(a_center, b_pos, b_pos + b_size); // 计算圆心到AABB的最邻近点 + return checkPointInCircle(nearest_point, a_center, a_radius); + } + return false; +} + +bool checkCircleOverlap(const glm::vec2& a_center, const float a_radius, const glm::vec2& b_center, const float b_radius) +{ + return (glm::length(a_center - b_center) < a_radius + b_radius); +} + +bool checkAABBOverlap(const glm::vec2& a_pos, const glm::vec2& a_size, const glm::vec2& b_pos, const glm::vec2& b_size) { + // 检查两个AABB是否重叠 + if (a_pos.x + a_size.x <= b_pos.x || a_pos.x >= b_pos.x + b_size.x || + a_pos.y + a_size.y <= b_pos.y || a_pos.y >= b_pos.y + b_size.y) { + return false; + } + return true; +} + +bool checkRectOverlap(const engine::utils::Rect& a, const engine::utils::Rect& b) { + return checkAABBOverlap(a.position, a.size, b.position, b.size); +} + +bool checkPointInCircle(const glm::vec2 &point, const glm::vec2 ¢er, const float radius) +{ + return (glm::length(point - center) < radius); +} + +} // namespace engine::physics::collision \ No newline at end of file diff --git a/src/engine/physics/collision.h b/src/engine/physics/collision.h new file mode 100644 index 0000000..b5f883b --- /dev/null +++ b/src/engine/physics/collision.h @@ -0,0 +1,60 @@ +#pragma once +#include "../utils/math.h" + +namespace engine::component { +class ColliderComponent; +} + +namespace engine::physics::collision { + +/** + * @brief 检查两个碰撞器组件是否重叠。 + * @param a 第一个碰撞器组件。 + * @param b 第二个碰撞器组件。 + * @return true 如果碰撞器组件重叠,否则为 false。 + */ +bool checkCollision(const engine::component::ColliderComponent& a, const engine::component::ColliderComponent& b); + +/** + * @brief 检查两个圆形是否重叠。 + * + * @param a_center 第一个圆的中心。 + * @param a_radius 第一个圆的半径。 + * @param b_center 第二个圆的中心。 + * @param b_radius 第二个圆的半径。 + * @return true 如果两个圆重叠,否则为 false。 + */ +bool checkCircleOverlap(const glm::vec2& a_center, const float a_radius, const glm::vec2& b_center, const float b_radius); + +/** + * @brief 检查两个轴对齐包围盒 (AABB) 是否重叠。 + * @param a_pos 第一个AABB的左上角坐标。 + * @param a_size 第一个AABB的尺寸。 + * @param b_pos 第二个AABB的左上角坐标。 + * @param b_size 第二个AABB的尺寸。 + * @return true 如果AABB重叠,否则为 false。 + */ +bool checkAABBOverlap(const glm::vec2& a_pos, const glm::vec2& a_size, const glm::vec2& b_pos, const glm::vec2& b_size); + +/** + * @brief 检查两个矩形是否重叠。 + * + * @param a 第一个矩形。 + * @param b 第二个矩形。 + * @return true 如果矩形重叠,否则为 false。 + */ +bool checkRectOverlap(const engine::utils::Rect& a, const engine::utils::Rect& b); + +/** + * @brief 检查一个点是否在圆内。 + * + * @param point 要检查的点。 + * @param center 圆的中心。 + * @param radius 圆的半径。 + * @return true 如果点在圆内,否则为 false。 + */ +bool checkPointInCircle(const glm::vec2& point, const glm::vec2& center, const float radius); + +// 未来可以添加更多碰撞检测相关的函数, + +} // namespace engine::physics::collision \ No newline at end of file diff --git a/src/engine/physics/physics_engine.cpp b/src/engine/physics/physics_engine.cpp index ba3a9f5..643902d 100644 --- a/src/engine/physics/physics_engine.cpp +++ b/src/engine/physics/physics_engine.cpp @@ -1,6 +1,8 @@ #include "physics_engine.h" +#include "collision.h" #include "../component/physics_component.h" #include "../component/transform_component.h" +#include "../component/collider_component.h" #include "../object/game_object.h" #include #include @@ -21,6 +23,9 @@ void PhysicsEngine::unregisterComponent(engine::component::PhysicsComponent* com } void PhysicsEngine::update(float delta_time) { + // 每帧开始时先清空碰撞对列表 + collision_pairs_.clear(); + // 遍历所有注册的物理组件 for (auto* pc : components_) { if (!pc || !pc->isEnabled()) { // 检查组件是否有效和启用 @@ -46,6 +51,37 @@ void PhysicsEngine::update(float delta_time) { // 限制最大速度:v = min(v, max_speed) pc->velocity_ = glm::clamp(pc->velocity_, -max_speed_, max_speed_); } + // 处理对象间碰撞 + checkObjectCollisions(); +} + +void PhysicsEngine::checkObjectCollisions() +{ + // 两层循环遍历所有包含物理组件的 GameObject + for (size_t i = 0; i < components_.size(); ++i) { + auto* pc_a = components_[i]; + if (!pc_a || !pc_a->isEnabled()) continue; + auto* obj_a = pc_a->getOwner(); + if (!obj_a) continue; + auto* cc_a = obj_a->getComponent(); + if (!cc_a || !cc_a->isActive()) continue; + + for (size_t j = i + 1; j < components_.size(); ++j) { + auto* pc_b = components_[j]; + if (!pc_b || !pc_b->isEnabled()) continue; + auto* obj_b = pc_b->getOwner(); + if (!obj_b) continue; + auto* cc_b = obj_b->getComponent(); + if (!cc_b || !cc_b->isActive()) continue; + /* --- 通过保护性测试后,正式执行逻辑 --- */ + + if (collision::checkCollision(*cc_a, *cc_b)) { + // TODO: 并不是所有碰撞都需要插入collision_pairs_,未来会添加过滤条件 + // 记录碰撞对 + collision_pairs_.emplace_back(obj_a, obj_b); + } + } + } } } // namespace engine::physics \ No newline at end of file diff --git a/src/engine/physics/physics_engine.h b/src/engine/physics/physics_engine.h index c894aa7..59ceb55 100644 --- a/src/engine/physics/physics_engine.h +++ b/src/engine/physics/physics_engine.h @@ -1,11 +1,16 @@ #pragma once #include +#include // for std::pair #include "glm/vec2.hpp" namespace engine::component { class PhysicsComponent; } +namespace engine::object { + class GameObject; +} + namespace engine::physics { /** @@ -17,6 +22,9 @@ private: glm::vec2 gravity_ = {0.0f, 980.0f}; ///< @brief 默认重力值 (像素/秒^2, 相当于100像素对应现实1m) float max_speed_ = 500.0f; ///< @brief 最大速度 (像素/秒) + /// @brief 存储本帧发生的 GameObject 碰撞对 (每次 update 开始时清空) + std::vector> collision_pairs_; + public: PhysicsEngine() = default; @@ -30,12 +38,17 @@ public: void unregisterComponent(engine::component::PhysicsComponent* component); ///< @brief 注销物理组件 void update(float delta_time); ///< @brief 核心循环:更新所有注册的物理组件的状态 + void checkObjectCollisions(); ///< @brief 检测并处理对象之间的碰撞,并记录需要游戏逻辑处理的碰撞对。 // 设置器/获取器 void setGravity(const glm::vec2& gravity) { gravity_ = gravity; } ///< @brief 设置全局重力加速度 const glm::vec2& getGravity() const { return gravity_; } ///< @brief 获取当前的全局重力加速度 void setMaxSpeed(float max_speed) { max_speed_ = max_speed; } ///< @brief 设置最大速度 float getMaxSpeed() const { return max_speed_; } ///< @brief 获取当前的最大速度 + /// @brief 获取本帧检测到的所有 GameObject 碰撞对。(此列表在每次 update 开始时清空) + const std::vector>& getCollisionPairs() const { + return collision_pairs_; + }; }; } // namespace engine::physics \ No newline at end of file diff --git a/src/game/scene/game_scene.cpp b/src/game/scene/game_scene.cpp index ad79c0c..7db413e 100644 --- a/src/game/scene/game_scene.cpp +++ b/src/game/scene/game_scene.cpp @@ -4,6 +4,7 @@ #include "../../engine/component/transform_component.h" #include "../../engine/component/sprite_component.h" #include "../../engine/component/physics_component.h" +#include "../../engine/component/collider_component.h" #include "../../engine/physics/physics_engine.h" #include "../../engine/scene/level_loader.h" #include "../../engine/input/input_manager.h" @@ -33,6 +34,7 @@ void GameScene::init() { void GameScene::update(float delta_time) { Scene::update(delta_time); + TestCollisionPairs(); } void GameScene::render() { @@ -59,8 +61,22 @@ void GameScene::createTestObject() { test_object->addComponent(glm::vec2(100.0f, 100.0f)); test_object->addComponent("assets/textures/Props/big-crate.png", context_.getResourceManager()); test_object->addComponent(&context_.getPhysicsEngine()); + test_object->addComponent( + std::make_unique(glm::vec2(32.0f, 32.0f)) + ); // 将创建好的 GameObject 添加到场景中 (一定要用std::move,否则传递的是左值) addGameObject(std::move(test_object)); + + // 添加第二个游戏对象(不受重力影响),用于测试碰撞 + auto test_object2 = std::make_unique("test_object2"); + test_object2->addComponent(glm::vec2(50.0f, 50.0f)); + test_object2->addComponent("assets/textures/Props/big-crate.png", context_.getResourceManager()); + test_object2->addComponent(&context_.getPhysicsEngine(), false); + test_object2->addComponent( + std::make_unique(16.0f) + ); + addGameObject(std::move(test_object2)); + spdlog::trace("test_object 创建并添加到 GameScene 中。"); } @@ -89,4 +105,12 @@ void GameScene::TestObject() } } +void GameScene::TestCollisionPairs() +{ + auto collision_pairs = context_.getPhysicsEngine().getCollisionPairs(); + for (auto& pair : collision_pairs) { + spdlog::info("碰撞对: {} 和 {}", pair.first->getName(), pair.second->getName()); + } +} + } // 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 2ee35ca..8d02ab9 100644 --- a/src/game/scene/game_scene.h +++ b/src/game/scene/game_scene.h @@ -30,6 +30,7 @@ private: void createTestObject(); void testCamera(); void TestObject(); + void TestCollisionPairs(); }; } // namespace game::scene \ No newline at end of file