新增 Prefab 系统:实体子树存取 + 编辑器 Save As Prefab/拖入实例化 + 脚本 Instantiate
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// PrefabTest.cpp:阶段2 验收脚本——脚本侧 Instantiate(prefab) 运行时
|
||||
// 实例化链路。
|
||||
//
|
||||
// PrefabTest(挂任意空实体,作为实例化锚点):
|
||||
// OnStart 按参数路径实例化一次 prefab;Interval > 0 时周期性再实例化
|
||||
// (多实例验收:每次 UUID 全量再生、物理体独立、沿 X 向排开下落)。
|
||||
//
|
||||
// 覆盖的引擎设施:
|
||||
// - ScriptBehavior::Instantiate(path, pos, rot)(Unity Object.
|
||||
// Instantiate 同位)→ SceneSerializer::InstantiatePrefab
|
||||
// - prefab 子树含 RigidBody/ScriptComponent 时由 PhysicsWorld/
|
||||
// ScriptRuntime 下一帧对账消化(与 Spawn 同语义)
|
||||
//
|
||||
// 验收步骤:
|
||||
// 1. 编辑器搭一个实体子树(如 Dynamic 盒刚体 + MeshRenderer 的箱子,
|
||||
// 可再挂个子实体验证层级一起走)→ Outliner 右键 Save As Prefab
|
||||
// (落盘 assets/prefabs/<名字>.prefab)
|
||||
// 2. 建空实体挂 PrefabTest,参数 PrefabPath 填该路径 → Play:
|
||||
// 锚点处出现实例;Interval 设 1.0 可看连续多实例物理下落互不串扰
|
||||
// 3. 编辑态也可从 Content Browser 把 .prefab 拖进 Outliner(节点=
|
||||
// 挂其下,空白区=挂根)或双击直接实例化——UUID 独立、资产引用有效
|
||||
//
|
||||
|
||||
#include <Engine/Scripting/Script.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
using namespace Engine; // f32 / ScriptBehavior 等免前缀(对齐 TestShoot)
|
||||
|
||||
namespace {
|
||||
|
||||
using Engine::Scripting::ParamBuilder;
|
||||
|
||||
class PrefabTest final : public Engine::Scripting::ScriptBehavior {
|
||||
public:
|
||||
const char* Name() const override { return "PrefabTest"; }
|
||||
|
||||
void DeclareParams(ParamBuilder& pb) override {
|
||||
// prefab 资产路径(工作目录相对,同场景/资产管理约定)
|
||||
pb.Field("PrefabPath", &m_PrefabPath,
|
||||
std::string{"assets/prefabs/crate.prefab"});
|
||||
// 周期实例化间隔(秒;<=0 = 仅 OnStart 实例化一次)
|
||||
pb.Field("Interval", &m_Interval, 0.0f);
|
||||
// 相邻实例的 X 向排开间距(多实例不叠在一起)
|
||||
pb.Field("SpreadX", &m_SpreadX, 2.0f);
|
||||
}
|
||||
|
||||
void OnStart() override {
|
||||
m_Timer = m_Interval;
|
||||
SpawnInstance();
|
||||
}
|
||||
|
||||
void OnUpdate(f32 dt) override {
|
||||
if (m_Interval <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
m_Timer -= dt;
|
||||
if (m_Timer <= 0.0f) {
|
||||
m_Timer = m_Interval;
|
||||
SpawnInstance();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void SpawnInstance() {
|
||||
// 锚点实体位姿 + 排开偏移;旋转 = 锚点自身旋转
|
||||
const auto& tr = Transform();
|
||||
const glm::vec3 pos =
|
||||
tr.GetPosition() + glm::vec3{m_SpreadX * f32(m_Count),
|
||||
0.0f, 0.0f};
|
||||
const glm::quat rot = tr.GetRotationQuat();
|
||||
if (Instantiate(m_PrefabPath, pos, rot) == entt::null) {
|
||||
return; // 路径无效/解析失败:日志已在序列化器里打过
|
||||
}
|
||||
++m_Count;
|
||||
}
|
||||
|
||||
std::string m_PrefabPath;
|
||||
f32 m_Interval = 0.0f;
|
||||
f32 m_SpreadX = 2.0f;
|
||||
f32 m_Timer = 0.0f;
|
||||
int m_Count = 0; // 已实例化份数(排开偏移基准)
|
||||
};
|
||||
|
||||
ENGINE_REGISTER_SCRIPT(PrefabTest)
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user