diff --git a/App/editor/InspectorPanel.cpp b/App/editor/InspectorPanel.cpp index 0a997f8..5c88694 100644 --- a/App/editor/InspectorPanel.cpp +++ b/App/editor/InspectorPanel.cpp @@ -8,6 +8,7 @@ #include "InspectorPanel.h" #include "Engine/ECS/Components.h" #include "Engine/Renderer/Model.h" +#include "Engine/Physics/PhysicsWorld.h" // Apply Impulse 调试(GetPhysics 门面) #include @@ -263,6 +264,16 @@ void InspectorPanel::Draw(const EditorContext& ctx, entt::entity selected) { ImGui::Text("vel: %.2f, %.2f, %.2f m/s", rb->velocity.x, rb->velocity.y, rb->velocity.z); + + // 驱动调试(冲量瞬态不序列化):直接推一把看响应 + static glm::vec3 s_debugImpulse{0.0f, 5.0f, 0.0f}; + ImGui::DragFloat3("impulse", &s_debugImpulse.x, 0.1f); + if (ImGui::Button("Apply Impulse")) + { + ctx.app->GetPhysics().AddImpulse( + static_cast(entt::to_integral(selected)), + s_debugImpulse); + } } } } diff --git a/Engine/include/Engine/Physics/PhysicsWorld.h b/Engine/include/Engine/Physics/PhysicsWorld.h index 8196220..5b967c7 100644 --- a/Engine/include/Engine/Physics/PhysicsWorld.h +++ b/Engine/include/Engine/Physics/PhysicsWorld.h @@ -75,6 +75,19 @@ namespace Engine { bool RayCast(const glm::vec3& origin, const glm::vec3& dir, f32 maxDist, RayHit& outHit) const; + // ---- 刚体驱动(游戏逻辑/编辑器调试;按实体位模式寻址)---- + // Jolt 力在每步模拟后清零:游戏逻辑每帧持续施加 = 正确用法; + // 冲量一次性改变动量(自动唤醒休眠体);速度直写会打断自然 + // 模拟(Unity 同语义)。body 不存在或类型不符时静默忽略: + // 力/扭矩/冲量仅动态体,速度直写动态+运动学体 + void AddForce(u32 entityBits, const glm::vec3& force); + void AddImpulse(u32 entityBits, const glm::vec3& impulse); + void AddTorque(u32 entityBits, const glm::vec3& torque); + void SetLinearVelocity(u32 entityBits, const glm::vec3& velocity); + void SetAngularVelocity(u32 entityBits, const glm::vec3& angularVelocity); + // 无 body / 静态体返回零向量 + glm::vec3 GetLinearVelocity(u32 entityBits) const; + private: // 创建时缓存的参数(变更检测 → 重建 body) struct BodyRecord { @@ -104,6 +117,7 @@ namespace Engine { ECS::RigidBodyComponent& rb, ECS::TransformComponent& tr); void RemoveBody(u32 entityBits); + const BodyRecord* FindRecord(u32 entityBits) const; // 刚体驱动寻址 void QueueEvent(CollisionEvent&& ev); // 回调线程 append(多线程并发,加锁) bool TryBitsByBodyId(const JPH::BodyID& id, u32& outBits) const; diff --git a/Engine/src/Physics/PhysicsWorld.cpp b/Engine/src/Physics/PhysicsWorld.cpp index b875696..e880ccf 100644 --- a/Engine/src/Physics/PhysicsWorld.cpp +++ b/Engine/src/Physics/PhysicsWorld.cpp @@ -578,6 +578,63 @@ namespace Engine { return true; } + // ---- 刚体驱动(游戏逻辑/编辑器调试;见头文件语义注释)---- + + const PhysicsWorld::BodyRecord *PhysicsWorld::FindRecord(const u32 entityBits) const { + const auto found = m_Bodies.find(entityBits); + return found != m_Bodies.end() ? &found->second : nullptr; + } + + // 力/扭矩/冲量:仅动态体(Jolt 对静态/运动学体施加力无意义) + void PhysicsWorld::AddForce(const u32 entityBits, const glm::vec3 &force) { + const auto *rec = FindRecord(entityBits); + if (!rec || rec->type != static_cast(ECS::RigidBodyComponent::BodyType::Dynamic)) + return; + m_System->GetBodyInterface().AddForce( + rec->id, JPH::Vec3(force.x, force.y, force.z)); + } + + void PhysicsWorld::AddImpulse(const u32 entityBits, const glm::vec3 &impulse) { + const auto *rec = FindRecord(entityBits); + if (!rec || rec->type != static_cast(ECS::RigidBodyComponent::BodyType::Dynamic)) + return; + m_System->GetBodyInterface().AddImpulse( + rec->id, JPH::Vec3(impulse.x, impulse.y, impulse.z)); + } + + void PhysicsWorld::AddTorque(const u32 entityBits, const glm::vec3 &torque) { + const auto *rec = FindRecord(entityBits); + if (!rec || rec->type != static_cast(ECS::RigidBodyComponent::BodyType::Dynamic)) + return; + m_System->GetBodyInterface().AddTorque( + rec->id, JPH::Vec3(torque.x, torque.y, torque.z)); + } + + // 速度直写:动态+运动学体都有效(运动学体速度即其运动方式) + void PhysicsWorld::SetLinearVelocity(const u32 entityBits, const glm::vec3 &velocity) { + const auto *rec = FindRecord(entityBits); + if (!rec || rec->type == static_cast(ECS::RigidBodyComponent::BodyType::Static)) + return; + m_System->GetBodyInterface().SetLinearVelocity( + rec->id, JPH::Vec3(velocity.x, velocity.y, velocity.z)); + } + + void PhysicsWorld::SetAngularVelocity(const u32 entityBits, const glm::vec3 &angularVelocity) { + const auto *rec = FindRecord(entityBits); + if (!rec || rec->type == static_cast(ECS::RigidBodyComponent::BodyType::Static)) + return; + m_System->GetBodyInterface().SetAngularVelocity( + rec->id, JPH::Vec3(angularVelocity.x, angularVelocity.y, angularVelocity.z)); + } + + glm::vec3 PhysicsWorld::GetLinearVelocity(const u32 entityBits) const { + const auto *rec = FindRecord(entityBits); + if (!rec || rec->type == static_cast(ECS::RigidBodyComponent::BodyType::Static)) + return {0.0f, 0.0f, 0.0f}; + const JPH::Vec3 v = m_System->GetBodyInterface().GetLinearVelocity(rec->id); + return {v.GetX(), v.GetY(), v.GetZ()}; + } + // ---- 写回:动态体姿态 → Transform(标脏,帧循环统一 Compose)---- void PhysicsWorld::Writeback() const {