From bca50976f3a2fa8de75a8749e24c7f56d201148d Mon Sep 17 00:00:00 2001 From: atdunbg Date: Thu, 8 Oct 2026 22:43:36 +0800 Subject: [PATCH] =?UTF-8?q?WallFracture=20=E7=A2=8E=E8=A3=82=E6=89=8B?= =?UTF-8?q?=E6=84=9F=E4=BF=AE=E6=AD=A3=EF=BC=9A=E7=88=86=E7=82=B8=E9=A3=9E?= =?UTF-8?q?=E6=95=A3=20=E2=86=92=20=E7=8E=BB=E7=92=83=E5=BC=8F=E7=A2=8E?= =?UTF-8?q?=E8=A3=82=EF=BC=88=E5=88=9D=E9=80=9F=E8=B7=9D=E7=A6=BB=E8=A1=B0?= =?UTF-8?q?=E5=87=8F=20+=20=E6=B3=95=E7=BA=BF=E5=89=A5=E8=90=BD=E5=A4=96?= =?UTF-8?q?=E6=8E=A8=20+=20=E7=BD=91=E6=A0=BC=E5=88=87=E7=BB=86=E8=87=B3?= =?UTF-8?q?=208=C3=976=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/scripts/WallFracture.cpp | 67 +++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/App/scripts/WallFracture.cpp b/App/scripts/WallFracture.cpp index 8b41387..dbf41c5 100644 --- a/App/scripts/WallFracture.cpp +++ b/App/scripts/WallFracture.cpp @@ -1,6 +1,12 @@ // // WallFracture.cpp:侧线A 验收脚本——可碎墙 + 碎片刚体群 + 寿命清理。 // +// 碎裂语义 = 玻璃/陶瓷式("碎掉"),非爆炸飞散: +// 碎片沿裂纹网格分离,初速 = 径向 × 距离指数衰减(只有命中点 +// 周边的碎片被推动,远处几乎原地悬置)+ 沿命中法线轻微外推 +// (朝弹侧剥落)+ 微弱上抛——重力是塌落的主导,整体呈 +// "裂纹分离 → 孔洞塌落 → 碎块堆在墙脚"的观感。 +// // WallFracture(挂墙实体:Static Box 刚体 + MeshRenderer 立方体): // OnCollisionEnter(Dynamic 体以足够速度命中)→ 触发一次: // 藏墙(MeshRenderer/RigidBody.active = false,PhysicsWorld 对账 @@ -8,8 +14,8 @@ // 实体(共享一份程序化立方体模型 + Dynamic Box 刚体),初速记入 // 待办表 // OnUpdate:碎片簿记——body 建好(下一帧 Step 对账,同 Bullet -// OnCreate 施速的时序契约)即统一施加径向初速(命中点→碎片方向 + -// 向上偏置);寿命到期统一 Destroy;总量上限防泄漏 +// OnCreate 施速的时序契约)即统一施加初速;寿命到期统一 Destroy; +// 总量上限防泄漏 // // 碎片不挂脚本:单一 WallFracture 集中管理全部碎片的施速/寿命/ // 清理(一帧 spawn 几十个实体,每颗一个脚本实例纯属浪费—— @@ -37,6 +43,7 @@ #include #include +#include #include using namespace Engine; // u32/f32/Entity 等基础类型 + 门面(同 TestShoot) @@ -62,21 +69,24 @@ namespace { void DeclareParams(Engine::Scripting::ParamBuilder& pb) override { // 碎片网格:每轴切几刀(总碎片 = x*y*z;占位档位 = 每碎片 - // 一实体,网格 6*4*1=24 起步,中等规模才考虑 instanced draw) - pb.Field("GridX", &m_GridX, 6); - pb.Field("GridY", &m_GridY, 4); + // 一实体,网格 8*6*1=48 起步,中等规模才考虑 instanced draw) + pb.Field("GridX", &m_GridX, 8); + pb.Field("GridY", &m_GridY, 6); pb.Field("GridZ", &m_GridZ, 1); - pb.Field("BurstSpeed", &m_BurstSpeed, 4.5f); // 径向初速 m/s - pb.Field("UpBias", &m_UpBias, 2.0f); // 向上偏置 m/s + // 玻璃/陶瓷式碎裂(裂纹分离 + 重力塌落),非爆炸飞散: + // 初速 = 命中点径向 × 距离指数衰减(近动远不动)+ 法线 + // 轻微外推(剥落)+ 微弱上抛;重力是塌落的主导 + pb.Field("BurstSpeed", &m_BurstSpeed, 1.2f); // 近点径向初速 m/s + pb.Field("Falloff", &m_Falloff, 1.0f); // 距离衰减率 1/m + pb.Field("NormalPop", &m_NormalPop, 0.4f); // 法线外推 m/s + pb.Field("UpBias", &m_UpBias, 0.3f); // 上抛偏置 m/s pb.Field("Lifetime", &m_Lifetime, 6.0f); // 碎片寿命(秒) - pb.Field("MaxFragments", &m_MaxFragments, 96); // 活碎片上限 + pb.Field("MaxFragments", &m_MaxFragments, 128); // 活碎片上限 pb.Field("MinImpactSpeed", &m_MinImpactSpeed, 2.0f); // 触发阈值 } void OnCollisionEnter(u32 other, const glm::vec3& point, const glm::vec3& normal) override { - (void)normal; // 法线留给将来定向喷射 - if (m_Fired) return; // 触发条件:对方是活的 Dynamic 刚体且速度够快(过滤 @@ -96,7 +106,7 @@ namespace { App().GetPhysics().GetLinearVelocity(other)); if (speed < m_MinImpactSpeed) return; - Fire(point); + Fire(point, normal); } void OnUpdate(f32 dt) override { @@ -106,8 +116,9 @@ namespace { private: // ---- 触发碎裂:藏墙 + 切网格 + spawn 碎片群 ---- - void Fire(const glm::vec3& hitPoint) { + void Fire(const glm::vec3& hitPoint, const glm::vec3& hitNormal) { m_Fired = true; + m_HitNormal = hitNormal; // 藏墙:渲染/拾取跳过 + body 对账销毁(组件级 active, // 与 Unity Renderer.enabled + Rigidbody 摘除同语义) @@ -145,9 +156,9 @@ namespace { (j + 0.5f) * fragSize.y - wallSize.y * 0.5f, (k + 0.5f) * fragSize.z - wallSize.z * 0.5f}; const glm::vec3 jitter{ - Rand(-0.2f, 0.2f) * fragSize.x, - Rand(-0.2f, 0.2f) * fragSize.y, - Rand(-0.2f, 0.2f) * fragSize.z}; + Rand(-0.3f, 0.3f) * fragSize.x, + Rand(-0.3f, 0.3f) * fragSize.y, + Rand(-0.3f, 0.3f) * fragSize.z}; const glm::vec3 pos = wallPos + wallRot * (cell + jitter); @@ -180,8 +191,10 @@ namespace { frb.friction = 0.7f; frb.restitution = 0.05f; - // 初速待办:body 下一帧建好,OnUpdate 统一施加 - //(同 Bullet OnCreate 施速的时序契约) + // 碎裂初速(玻璃式,非爆炸):离命中点越远越 + // 接近静止(指数衰减)——只有孔洞周边的碎片被 + // 冲击波推动,整体呈"裂纹分离→重力塌落"; + // 法线外推让碎片朝弹侧剥出,而非向墙内挤压 glm::vec3 dir = pos - hitPoint; const f32 len = glm::length(dir); if (len < 1e-3f) { @@ -190,9 +203,12 @@ namespace { } else { dir /= len; } + const f32 falloff = std::exp(-len * m_Falloff); const glm::vec3 vel = - dir * m_BurstSpeed * Rand(0.6f, 1.3f) + - glm::vec3{0.0f, m_UpBias * Rand(0.5f, 1.0f), + dir * m_BurstSpeed * falloff * + Rand(0.4f, 1.1f) + + hitNormal * m_NormalPop * Rand(0.3f, 0.8f) + + glm::vec3{0.0f, m_UpBias * Rand(0.0f, 0.5f), 0.0f}; // 总量上限:超限立即回收最老碎片(防泄漏的 @@ -258,15 +274,18 @@ namespace { bool applied = false; // 初速已注入 }; - int m_GridX = 6; - int m_GridY = 4; + int m_GridX = 8; + int m_GridY = 6; int m_GridZ = 1; - f32 m_BurstSpeed = 4.5f; - f32 m_UpBias = 2.0f; + f32 m_BurstSpeed = 1.2f; + f32 m_Falloff = 1.0f; + f32 m_NormalPop = 0.4f; + f32 m_UpBias = 0.3f; f32 m_Lifetime = 6.0f; - int m_MaxFragments = 96; + int m_MaxFragments = 128; f32 m_MinImpactSpeed = 2.0f; + glm::vec3 m_HitNormal{0.0f, 0.0f, 1.0f}; // 命中法线(剥落方向) bool m_Fired = false; // 一次性触发保护 std::vector m_Fragments; // 活碎片簿记 };