diff --git a/App/scripts/WASDMove.cpp b/App/scripts/WASDMove.cpp new file mode 100644 index 0000000..724c367 --- /dev/null +++ b/App/scripts/WASDMove.cpp @@ -0,0 +1,71 @@ +// +// WASDMove.cpp:WASD 控制实体移动(相机水平朝向参考,UE gameplay 语义)。 +// +// 移动语义分派: +// - Dynamic 刚体 → 走物理速度门面(每帧喂水平速度,Y 归物理—— +// 重力/跳跃不受影响;松键喂零速 = 立即停,Unity velocity 语义) +// - 无刚体 → 直接平移 Transform +// +// 编辑器形态键位天然不冲突:RMB 按住 = 相机吃 WASD 飞行(脚本也读 +// 到按键 → 同时在动,测移动时松开 RMB 即可);游戏形态 WASD 常开。 +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace { + + class WASDMove final : public Engine::Scripting::ScriptBehavior { + public: + const char* Name() const override { return "WASDMove"; } + + void OnUpdate(float dt) override { + // 位移方向 = 视线水平投影(W 前进 / A 左 / D 右),UE Scene + // view 移动惯例;Y 锁 0(升降/跳跃归物理或将来扩展) + const glm::quat cq = App().GetRenderer() + .GetEditorCamera() + .GetTransform() + .GetRotationQuat(); + const glm::vec3 fwd = cq * glm::vec3(0.0f, 0.0f, -1.0f); + const glm::vec3 right = cq * glm::vec3(1.0f, 0.0f, 0.0f); + + auto& win = App().GetWindow(); + glm::vec3 move(0.0f); + if (win.IsKeyPressed(GLFW_KEY_W)) move += fwd; + if (win.IsKeyPressed(GLFW_KEY_S)) move -= fwd; + if (win.IsKeyPressed(GLFW_KEY_D)) move += right; + if (win.IsKeyPressed(GLFW_KEY_A)) move -= right; + move.y = 0.0f; + if (glm::length(move) > 1e-4f) { + move = glm::normalize(move); + } + const glm::vec3 vel = move * m_Speed; + + if (auto* rb = TryGet(); + rb != nullptr && rb->bodyValid && + rb->type == Engine::ECS::RigidBodyComponent::BodyType::Dynamic) { + // 物理驱动:只覆写水平速度,Y 保留物理积分离散结果 + //(整体喂 0 会抵消重力 → 空中物体悬浮) + auto& phy = App().GetPhysics(); + const glm::vec3 cur = phy.GetLinearVelocity(EntityBits()); + phy.SetLinearVelocity(EntityBits(), {vel.x, cur.y, vel.z}); + } else { + Transform().SetPosition(Transform().GetPosition() + vel * dt); + } + } + + private: + float m_Speed = 5.0f; // m/s + }; + + ENGINE_REGISTER_SCRIPT(WASDMove) + +} // namespace diff --git a/Engine/include/Engine/Scripting/Script.h b/Engine/include/Engine/Scripting/Script.h index 11aa733..3815a1b 100644 --- a/Engine/include/Engine/Scripting/Script.h +++ b/Engine/include/Engine/Scripting/Script.h @@ -27,6 +27,9 @@ #include namespace Engine { + + class Application; // 宿主门面(Window/Renderer/Physics 入口),实现见 ScriptRuntime.cpp + namespace Scripting { class ScriptBehavior { @@ -52,17 +55,32 @@ namespace Engine { return m_Scene->GetRegistry().get(m_Entity); } + template + T* TryGet() { + return m_Scene->GetRegistry().try_get(m_Entity); + } + + // 绑定实体的 entityBits(物理门面按键值寻址) + u32 EntityBits() const { + return static_cast(entt::to_integral(m_Entity)); + } + + // 宿主应用(GetWindow/GetRenderer/GetPhysics/GetScene……) + Application& App() const; + bool Valid() const { return m_Scene != nullptr && m_Entity != entt::null; } private: friend class ScriptRuntime; - void Bind(ECS::Scene& scene, entt::entity e) { + void Bind(ECS::Scene& scene, entt::entity e, Application* app) { m_Scene = &scene; m_Entity = e; + m_App = app; } ECS::Scene* m_Scene = nullptr; entt::entity m_Entity = entt::null; + Application* m_App = nullptr; }; // ---- 按名注册表:脚本类文件级自注册,运行时按名实例化 ---- diff --git a/Engine/include/Engine/Scripting/ScriptRuntime.h b/Engine/include/Engine/Scripting/ScriptRuntime.h index 4954ebf..784edbb 100644 --- a/Engine/include/Engine/Scripting/ScriptRuntime.h +++ b/Engine/include/Engine/Scripting/ScriptRuntime.h @@ -14,6 +14,9 @@ #include namespace Engine { + + class Application; + namespace Scripting { // 实例簿记:行为对象 + OnCreate 是否已调 @@ -24,7 +27,8 @@ namespace Engine { class ScriptRuntime { public: - explicit ScriptRuntime(ECS::Scene& scene) : m_Scene(scene) {} + explicit ScriptRuntime(ECS::Scene& scene, Application* app = nullptr) + : m_Scene(scene), m_App(app) {} // 每帧调用(吃 scaled dt):对账 → OnCreate(新实例)→ OnUpdate void Update(f32 dt); @@ -33,6 +37,7 @@ namespace Engine { void Sync(); ECS::Scene& m_Scene; + Application* m_App; // 注入脚本上下文 std::unordered_map m_Instances; // entityBits }; diff --git a/Engine/src/Core/Application.cpp b/Engine/src/Core/Application.cpp index 769cb68..4ed73e4 100644 --- a/Engine/src/Core/Application.cpp +++ b/Engine/src/Core/Application.cpp @@ -103,8 +103,9 @@ namespace Engine { // 物理调试图元 → 渲染侧(PhysicsDebugPass 每帧上传绘制) m_Renderer->SetPhysicsDebugSource(&m_Physics->GetDebugFrame()); - // 脚本生命周期(对账式,组件增删/改名即时生效) - m_Scripts = CreateScope(*m_Scene); + // 脚本生命周期(对账式,组件增删/改名即时生效);this 注入脚本 + // 上下文(Window/Renderer/Physics 门面) + m_Scripts = CreateScope(*m_Scene, this); while (m_Running) { const auto frameStart = std::chrono::steady_clock::now(); diff --git a/Engine/src/Scripting/ScriptRuntime.cpp b/Engine/src/Scripting/ScriptRuntime.cpp index 94f27a8..a088489 100644 --- a/Engine/src/Scripting/ScriptRuntime.cpp +++ b/Engine/src/Scripting/ScriptRuntime.cpp @@ -10,6 +10,12 @@ namespace Engine { namespace Scripting { + // 宿主门面访问器:Application 完整类型只在脚本 cpp 里需要, + // 这里仅回引成员(避免引擎头循环依赖) + Application& ScriptBehavior::App() const { + return *m_App; + } + void ScriptRuntime::Update(f32 dt) { Sync(); @@ -61,7 +67,7 @@ namespace Engine { sc.scriptName, bits); continue; } - behavior->Bind(m_Scene, e); + behavior->Bind(m_Scene, e, m_App); ScriptInstance inst; inst.behavior = std::move(behavior);