修复打靶场射击链路:发射源/玩家控制走 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 横条为靶子)
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
//
|
||||
// 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
|
||||
Reference in New Issue
Block a user