Files
HelloVulkan/App/scripts/Target.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

121 lines
5.7 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.
//
// Target.cpp:打靶场玻璃靶子脚本(侧线"玩法原型验证")。
//
// 职责(挂靶子实体:MeshRenderer 玻璃立方 + RigidBody Static Box +
// 本脚本;通常由 GameDirector 运行时成批 spawn,也可编辑器手动摆):
// OnCollisionEnter → 玻璃外观套用(半透明 + 靶色自发光)→
// Fracture::Burst::TryFire(一次性保护 + Dynamic 速度校验 +
// 藏靶 + Voronoi 切分 + spawn 玻璃碎片群,共享库内完成)
// ReportScore:向 Director 实体的 GameDirector 脚本报分(Score +1,
// 写穿 Item.params,PIE Inspector 实时反映);Director=0 表示
// 独立靶不计分;导演 AcceptHits=false(回合已结束)不报
// OnUpdate/OnDestroy → Burst::Tick/Shutdown(碎片施速/寿命/回收)
//
// 覆盖的引擎设施:跨脚本参数访问(ScriptRuntime::GetParam/SetParam,
// GameDirector ↔ Target 的计分通道)、共享碎裂库(FractureLib.h,
// 与 WallFracture 同一条碎片路径)、玻璃材质(透明队列 + 自发光)。
//
// 演示步骤:任意实体挂 GameDirector → Play → 左键射击靶阵:
// 靶子玻璃式碎裂 + 计分,60 秒倒计时,时间到结算,R 重开。
//
#include <Engine/Scripting/Script.h>
#include <Engine/Scripting/ScriptRuntime.h> // GetScripts() 跨脚本参数访问
#include <Engine/Core/Types.h>
#include "FractureLib.h"
using namespace Engine; // i32/f32/u32 基础类型(同 WallFracture)
namespace {
// ---- 玻璃靶子 ----
class Target final : public Engine::Scripting::ScriptBehavior {
public:
const char* Name() const override { return "Target"; }
void DeclareParams(Engine::Scripting::ParamBuilder& pb) override {
// 击碎报分去向:Director 实体 bits(0 = 独立靶不计分);
// GameDirector spawn 时写进脚本项参数
pb.Field("Director", &m_Director, 0);
// 靶色(玻璃染色 + 自发光基色;碎片同色系)
pb.Field("Color", &m_Color,
glm::vec3{1.0f, 0.3f, 0.25f});
// 碎裂参数(同 WallFracture 语义;靶面小 → 种子更密)
pb.Field("Count", &m_Burst.p.count, 22);
pb.Field("SeedRadius", &m_Burst.p.seedRadius, 0.35f);
pb.Field("MinSeedDist", &m_Burst.p.minSeedDist, 0.07f);
pb.Field("BurstSpeed", &m_Burst.p.burstSpeed, 1.6f);
pb.Field("Falloff", &m_Burst.p.falloff, 2.0f);
pb.Field("NormalPop", &m_Burst.p.normalPop, 0.6f);
pb.Field("UpBias", &m_Burst.p.upBias, 0.4f);
pb.Field("Lifetime", &m_Burst.p.lifetime, 6.0f);
pb.Field("MaxFragments", &m_Burst.p.maxFragments, 96);
pb.Field("MinImpactSpeed", &m_Burst.p.minImpactSpeed, 2.0f);
}
void OnCollisionEnter(u32 other, const glm::vec3& point,
const glm::vec3& normal) override {
// 玻璃外观:半透明 + 靶色自发光(Fire 前套用,碎片沿用;
// 每次覆写代价可忽略,且吃 Inspector 实时改色)。
// alpha 0.85(与靶体 BuildGlassCube 同步:0.45 时代碎片
// 在亮背景里几乎隐形)
m_Burst.look.baseColor = glm::vec4{m_Color, 0.85f};
m_Burst.look.transparent = true;
m_Burst.look.emissive = m_Color * 0.7f;
m_Burst.look.emissiveStrength = 3.0f;
if (m_Burst.TryFire(HV(), other, point, normal)) {
ReportScore();
}
}
void OnUpdate(f32 dt) override { m_Burst.Tick(HV(), dt); }
// 靶销毁(PIE stop / 重开 / 手动删除):碎片模型批量回收
void OnDestroy() override { m_Burst.Shutdown(HV()); }
private:
// 库桥接:本成员函数内可访问 protected 基类设施(App/Spawn/
// Destroy),库内只走公共 API——见 FractureLib.h HostView 注
Engine::Fracture::HostView HV() {
return {App(), EntityBits(),
[this](const std::string& n) { return Spawn(n); },
[this](Engine::ECS::Entity e) { Destroy(e); }};
}
// 击碎报分:读导演 AcceptHits 门(回合结束不报)→ Score +1。
// 参数层 = 跨脚本通信协议(与序列化同一条路,C# 反射缺失下
// 的按名消息);导演实例未建(罕见:同帧开局碰撞)时忽略
void ReportScore() {
if (m_Director == 0) return;
auto& scripts = App().GetScripts();
const u32 director = static_cast<u32>(m_Director);
// 参数层按名访问(ScriptRuntime 只认 ParamValue 变体,
// 取值自行 std::get_if 校型)
using Engine::Scripting::ParamValue;
ParamValue v{true};
if (scripts.GetParam(director, "GameDirector",
"AcceptHits", v)) {
if (const auto* b = std::get_if<bool>(&v.v); b && !*b) {
return; // 回合已结束(Director 收靶前的漏网命中)
}
}
i32 score = 0;
if (scripts.GetParam(director, "GameDirector", "Score", v)) {
if (const auto* s = std::get_if<i32>(&v.v)) {
score = *s;
}
}
scripts.SetParam(director, "GameDirector", "Score",
ParamValue{static_cast<i32>(score + 1)});
}
i32 m_Director = 0; // 导演实体 bits(0 = 独立靶)
glm::vec3 m_Color{1.0f, 0.3f, 0.25f};
Engine::Fracture::Burst m_Burst; // 碎片簿记(look 每次命中前套)
};
} // namespace
ENGINE_REGISTER_SCRIPT(Target)