新增脚本实体底座与碰撞事件:Spawn/Destroy + OnCollisionEnter/Exit + TestShoot 验收脚本

- ScriptBehavior::Spawn/Destroy:Scene::CreateEntity / 延迟销毁队列直达(实现下沉 ScriptRuntime.cpp,避 Application 不完整类型)
- ScriptRuntime::DispatchCollisions:帧首把 PhysicsWorld::GetEvents 派发到涉事实例(Persisted 跳过、禁用不收;回调内 spawn/destroy 安全)
- TestShoot:左键 spawn 动态球刚体子弹,OnCollisionEnter 命中点生成 ImpactFx 特效实体并自毁,超时防泄漏
This commit is contained in:
2026-10-08 21:45:10 +08:00
parent 26e222a9cf
commit b89f431896
4 changed files with 299 additions and 0 deletions
+53
View File
@@ -7,6 +7,9 @@
#include <Engine/Core/Application.h>
#include <Engine/Core/Log.h>
#include <Engine/ECS/Components.h>
#include <Engine/ECS/EntityHandle.h>
#include <Engine/Physics/PhysicsEvents.h>
#include <Engine/Physics/PhysicsWorld.h>
#include <algorithm>
@@ -19,6 +22,16 @@ namespace Engine {
return *m_App;
}
// ---- 场景实体 spawn/destroy 底座(声明在 Script.h,实现下沉
// 此处——Application 完整类型只在 cpp 可见)----
ECS::EntityHandle ScriptBehavior::Spawn(const std::string& name) {
return App().GetScene().CreateEntity(name);
}
void ScriptBehavior::Destroy(ECS::Entity e) {
App().GetScene().DestroyEntity(e);
}
// ---- 参数按名读写(ScriptBehavior 声明,经绑定表;写穿
// Item.params 由运行时 SetParam 完成)----
bool ScriptBehavior::WriteParam(const std::string& name,
@@ -41,7 +54,47 @@ namespace Engine {
return false;
}
// ---- 碰撞事件派发(Update 开头、Sync 之前):PhysicsWorld 最近
// 一次步进收集的事件转发到涉事实例。时序保证:Step 先于
// Update(帧循环序)→ 此处读到的是本帧物理结果;回调里
// spawn/destroy 安全——destroy 入延迟队列(帧尾 flush),
// spawn 不改 m_Instances(下一帧 Sync 对账建实例)。禁用
// 实例不收(Unity enabled 语义对齐);Persisted 每步都来,
// 直接跳过(Enter/Exit 已够 gameplay 用)
void ScriptRuntime::DispatchCollisions() {
if (!m_App) {
return;
}
const std::vector<CollisionEvent>& events =
m_App->GetPhysics().GetEvents();
for (const auto& ev : events) {
if (ev.kind == CollisionEvent::Kind::Persisted) {
continue;
}
const bool enter = ev.kind == CollisionEvent::Kind::Added;
for (const u32 self : {ev.a, ev.b}) {
const u32 other = (self == ev.a) ? ev.b : ev.a;
const auto it = m_Instances.find(self);
if (it == m_Instances.end()) {
continue;
}
for (auto& inst : it->second) {
if (!inst.behavior || !inst.enabled) {
continue;
}
if (enter) {
inst.behavior->OnCollisionEnter(
other, ev.point, ev.normal);
} else {
inst.behavior->OnCollisionExit(other);
}
}
}
}
}
void ScriptRuntime::Update(f32 dt) {
DispatchCollisions();
Sync();
auto& reg = m_Scene.GetRegistry();