feat(app): WASDMove script (WASD camera-relative movement)

ScriptBehavior gains App() host access (Application injected via
ScriptRuntime), TryGet<T> and EntityBits for physics facade addressing.
WASDMove maps WASD to the editor camera's horizontal heading (UE
gameplay convention): dynamic bodies go through the physics velocity
facade preserving the vertical component (zeroing Y would cancel
gravity mid-fall), bodiless entities translate their transform directly.
Editor-mode key conflict is naturally avoided: RMB-held flight consumes
WASD, release hands keys to the script.
This commit is contained in:
2026-10-03 18:27:12 +08:00
parent 3403822a52
commit cad0481bc0
5 changed files with 106 additions and 5 deletions
+71
View File
@@ -0,0 +1,71 @@
//
// WASDMove.cpp:WASD 控制实体移动(相机水平朝向参考,UE gameplay 语义)。
//
// 移动语义分派:
// - Dynamic 刚体 → 走物理速度门面(每帧喂水平速度,Y 归物理——
// 重力/跳跃不受影响;松键喂零速 = 立即停,Unity velocity 语义)
// - 无刚体 → 直接平移 Transform
//
// 编辑器形态键位天然不冲突:RMB 按住 = 相机吃 WASD 飞行(脚本也读
// 到按键 → 同时在动,测移动时松开 RMB 即可);游戏形态 WASD 常开。
//
#include <Engine/Scripting/Script.h>
#include <Engine/Core/Application.h>
#include <Engine/Core/Window.h>
#include <Engine/Renderer/Renderer.h>
#include <Engine/Renderer/EditorCamera.h>
#include <Engine/Physics/PhysicsWorld.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
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<Engine::ECS::RigidBodyComponent>();
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