- 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 横条为靶子)
121 lines
5.7 KiB
C++
121 lines
5.7 KiB
C++
//
|
||
// 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)
|