Files
HelloVulkan/App/scripts/PlayerController.cpp
T
atdunbg 334819bf97 修复打靶场射击链路:发射源/玩家控制走 primary 相机实体
- TestShoot 发射源从 EditorCamera(视口 UI 状态,PIE 渲染不用它)
  改为绑定实体位姿,挂 primary 相机实体即第一人称枪口;
  仅光标捕捉态开火,防编辑器交互误射
- 新增 PlayerController:FPS 控制(鼠标捕捉/Esc 释放/点视口重捕、
  yaw+pitch 转向、WASD+Space/Ctrl 移动+Shift 加速),驱动 primary
  相机实体 Transform,PIE 所见即玩家所见
- 靶子/碎片玻璃 alpha 0.42/0.45→0.85、自发光 2→3:低不透明度在
  亮背景下靶子几乎隐形(用户误认 HUD 横条为靶子)
2026-10-09 13:13:52 +08:00

152 lines
6.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// PlayerController.cpp:FPS 玩家控制脚本——挂在场景 primary 相机实体
// (CameraComponent.primary=true)上,直接驱动该实体的 Transform。
//
// 为什么驱动实体而不是"编辑器相机":PIE 内嵌播放/游戏形态的渲染源
// 是 primary 相机实体(SceneRenderer::BuildFrame 分派,main.cpp 亦
// 注明"PIE 内嵌播放:渲染源已切 primary 相机,编辑器相机停驱")。
// 实体位姿一动,视口所见即玩家所见——这才是 Unity/UE 的正道;
// EditorCamera 是视口 UI 状态,不是场景实体,脚本够不着也不该够。
//
// 能力(全部走 Input 门面,零引擎改动):
// - 鼠标捕捉:OnStart 捕捉(FPS 语义:光标隐入、无限转向);
// Esc 释放(交还编辑器交互);未捕捉时点视口重新捕捉
// - 视角:GetMouseDelta 增量 → yaw 绕世界 up 左乘 + pitch 绕本地
// X 右乘(±89° 钳制,与编辑器相机 Camera::Update 同语义)
// - 移动:WASD 水平 + Space 升 / Ctrl 降(飞行式,无重力——
// 打靶场微调机位用);Shift 加速
//
// 注意:捕捉态下编辑器 UI 收不到鼠标——这是游戏体验的代价;
// Esc 是唯一退路(释放后可点 Inspector/改参数)。
//
// 配套:TestShoot(挂同一实体)射击,同样只在捕捉态开火。
//
#include <Engine/Scripting/Script.h>
#include <Engine/Core/Input.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
using namespace Engine; // Input 门面
using Engine::Scripting::ParamBuilder;
namespace {
class PlayerController final : public Engine::Scripting::ScriptBehavior {
public:
const char* Name() const override { return "PlayerController"; }
void DeclareParams(ParamBuilder& pb) override {
pb.Field("LookSensitivity", &m_Sensitivity, 0.12f); // 度/像素
pb.Field("MoveSpeed", &m_MoveSpeed, 4.0f); // 平移速度 m/s
pb.Field("RunSpeed", &m_RunSpeed, 8.0f); // Shift 加速 m/s
pb.Field("CaptureOnStart", &m_CaptureOnStart, true);
}
void OnStart() override {
if (m_CaptureOnStart) {
Input::SetCursorCaptured(true);
}
}
void OnUpdate(f32 dt) override {
// ---- 捕捉管理:Esc 释放 / 点视口重捕 ----
bool captured = Input::IsCursorCaptured();
if (captured && Input::IsKeyDown(Input::Key::Escape)) {
Input::SetCursorCaptured(false);
captured = false;
}
const bool leftDown =
Input::IsMouseButtonDown(Input::MouseButton::Left);
if (!captured) {
// 未捕捉时点击(点在视口内才收得到——ImGui 捕获的
// 区域静默)→ 重捕进入操作态
if (leftDown && !m_LeftWasDown) {
Input::SetCursorCaptured(true);
}
m_LeftWasDown = leftDown;
return; // 释放态:不转向不移动(编辑器交互让路)
}
m_LeftWasDown = leftDown;
Look();
Move(dt);
}
private:
void Look() {
f32 dx = 0.0f, dy = 0.0f;
Input::GetMouseDelta(dx, dy);
if (dx == 0.0f && dy == 0.0f) return;
auto& tr = Transform();
const glm::quat cur = tr.GetRotationQuat();
// yaw:绕世界 up 左乘(不随俯仰改变旋转轴)
const glm::quat yaw =
glm::angleAxis(glm::radians(-dx * m_Sensitivity),
glm::vec3(0.0f, 1.0f, 0.0f));
// pitch:绕本地 X 右乘,钳制 ±89°(防过顶翻转)
const glm::vec3 fwd = cur * glm::vec3(0.0f, 0.0f, -1.0f);
const f32 pitch =
glm::asin(glm::clamp(fwd.y, -1.0f, 1.0f));
const f32 kPitchLimit = glm::radians(89.0f);
const f32 pitchTarget =
glm::clamp(pitch + glm::radians(-dy * m_Sensitivity),
-kPitchLimit, kPitchLimit);
const glm::quat pitchStep =
glm::angleAxis(pitchTarget - pitch,
glm::vec3(1.0f, 0.0f, 0.0f));
tr.SetRotationQuat(yaw * (cur * pitchStep));
}
void Move(f32 dt) {
glm::vec3 axis{0.0f};
if (Input::IsKeyDown(Input::Key::W))
axis.z += 1.0f;
if (Input::IsKeyDown(Input::Key::S))
axis.z -= 1.0f;
if (Input::IsKeyDown(Input::Key::D))
axis.x += 1.0f;
if (Input::IsKeyDown(Input::Key::A))
axis.x -= 1.0f;
if (Input::IsKeyDown(Input::Key::Space))
axis.y += 1.0f;
if (Input::IsKeyDown(Input::Key::LeftControl))
axis.y -= 1.0f;
if (glm::dot(axis, axis) < 1e-6f) return;
const glm::quat r = Transform().GetRotationQuat();
const glm::vec3 fwd = r * glm::vec3(0.0f, 0.0f, -1.0f);
const glm::vec3 right = r * glm::vec3(1.0f, 0.0f, 0.0f);
// 水平走视线投影(含俯仰 = 飞行感),升降用世界 Y
glm::vec3 move =
fwd * axis.z + right * axis.x
+ glm::vec3(0.0f, axis.y, 0.0f);
const f32 len = glm::length(move);
if (len < 1e-6f) return;
move /= len;
const f32 speed = Input::IsKeyDown(Input::Key::LeftShift)
? m_RunSpeed
: m_MoveSpeed;
auto& tr = Transform();
tr.SetPosition(tr.GetWorldPosition() + move * speed * dt);
}
f32 m_Sensitivity = 0.12f;
f32 m_MoveSpeed = 4.0f;
f32 m_RunSpeed = 8.0f;
bool m_CaptureOnStart = true;
bool m_LeftWasDown = false; // 重捕用的左键上升沿基准
};
ENGINE_REGISTER_SCRIPT(PlayerController)
} // namespace