3D 粒子 特效 拖尾,概率性不显示. 解决方案.

ParticleBug.zip (899.1 KB)

以上是测试工程文件,
打开项目疯狂按下asd 有概率 不会触发特效
如同 3.8.8做的刀光拖尾粒子效果,有时后挥刀粒子不显示,概率性不显示,不知道为什么

引擎原理

粒子每帧执行:

time += dt;

然后 Burst 判断自己的触发时间是否位于本帧区间:

[上一帧时间, 当前帧时间)

const curFrameTime = time - startDelay;
const preFrameTime = curFrameTime - dt;

if (burstTime >= preFrameTime && burstTime < curFrameTime) {
emit();
}

粒子的配置如果是

startDelay = 0.05
Burst.time = 0

Burst.time=0 指“经过 startDelay 后的第 0 秒发射”。

以 40 FPS 为例:

dt = 1 / 40 = 0.025

数学上预期:

帧 ParticleSystem.time 行为
━━━━━ ━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1 0.025 未到延迟
───── ───────────────────── ────────────────────────────────────────
2 0.050 等于延迟,但引擎要求 time > startDelay
───── ───────────────────── ────────────────────────────────────────
3 0.075 应当检测区间 [0, 0.025) 并发射 Burst

但是 JavaScript 的 number 使用 IEEE-754 二进制浮点数,0.025、0.05、0.075 都无法被二
进制精确表示。引擎实际算出来的是:

time = 0.07500000000000001
curFrameTime = 0.02500000000000001
preFrameTime = 0.000000000000000006938893903907228
Burst.time = 0

于是原判断变成:

0 >= 0.000000000000000006938893903907228

结果是 false,因此没有发射。

到了下一帧,preFrameTime 已经变成约 0.025,而 Burst 时间仍然是 0,后面再也不可能进入
任何时间区间,所以这次播放永久没有粒子.

修复办法

找到引擎文件

加上26行
import { EPSILON, repeat } from ‘…/core/math’;
加上111行
if (this._curTime >= preFrameTime - EPSILON && this._curTime < curFrameTime) {

修改前


修改后

测试不会出现偶发情况 .

PR :
https://github.com/cocos/cocos-engine/pull/19204

希望能拉进去PR 我也想给cocos 添砖加瓦 万分感谢 !!!

@zxx43 希望能合并一次 PR :joy: