13 KiB
网页粒子系统 · 阶段六
阶段定位:场景对象、碰撞体、路径编辑与发射器路径跟随定版
完成日期:2026-08-29
工程目录:/Users/tianmokeji/Desktop/SpineParticle
技术栈:Vue 3 + TypeScript + Pinia + PixiJS 7 + Vite
一、阶段结论
阶段六完成了碰撞功能所需的场景对象基础,并把粒子系统、碰撞体和路径统一纳入同一套场景对象树。碰撞体已经参与粒子运行时计算;路径具备可视化锚点、贝塞尔手柄和预设形状编辑能力;粒子系统新增发射器路径跟随修改器。
本阶段主要完成:
- 统一场景对象创建入口和对象列表;
- 新增碰撞体对象、属性面板、画布显示和实时碰撞响应;
- 新增路径对象、锚点及贝塞尔手柄编辑;
- 新增圆形、方形、多边形和星形路径预设;
- 新增发射器路径跟随修改器;
- 支持局部空间和世界空间两种跟随方式;
- 整理画布左上角系统设置入口;
- 修复新模块与既有粒子属性、固定帧缓存和时间轴的兼容问题;
- 修复时间轴粒子条拖动时反复重置模拟的问题。
Spine 骨架创建入口在本阶段仅保留占位,尚未创建实际骨架对象。碰撞体面板中的“跟随轨道移动”也保留为后续碰撞体动画接口,本阶段未接入路径采样。
二、场景对象统一管理
2.1 创建入口
原编辑器顶部的“+系统”入口已合并到“场景对象”模块。场景对象标题右侧提供:
+粒子:创建粒子系统;+碰撞:创建碰撞体;+路径:创建路径;+骨架:Spine 骨架占位入口。
即使场景中没有粒子系统,场景对象模块仍可独立创建碰撞体或路径。
2.2 对象树
创建后的对象统一显示在场景对象树中,不再保留顶部独立的粒子系统列表。对象树支持:
- 粒子系统、碰撞体和路径混合显示;
- 点击对象切换当前属性面板;
- 当前对象高亮;
- 单独删除对象;
- 删除当前对象后自动选择可用的回退对象。
默认对象名称使用英文编号:
| 对象类型 | 默认名称 |
|---|---|
| 粒子系统 | ParticleSystem1 |
| 碰撞体 | Collider1 |
| 路径 | Path1 |
三、碰撞体对象
3.1 默认参数
| 参数 | 默认值 |
|---|---|
| 名称 | Collider1 |
| 标签 | Default |
| 类型 | 圆形 |
| 启用 | 开启 |
| X / Y | 0 / 0 |
| 旋转 | 0° |
| 半径 | 50 |
| 椭圆 X / Y 半径 | 70 / 45 |
| 矩形宽 / 高 | 120 / 80 |
| 多边形边数 | 6 |
| 碰撞响应 | 物理 |
| 弹性 | 0.8 |
| 摩擦 | 0.3 |
| 跟随轨道移动 | 关闭,后续接入 |
3.2 类型
碰撞体支持五种类型:
- 圆形;
- 椭圆;
- 矩形;
- 多边形;
- 自定义。
圆形使用半径;椭圆使用 X/Y 半径;矩形、多边形和自定义形状使用宽高,多边形与自定义形状还可设置 3~16 的边数。
当前“自定义”采用可调边数的规则多边形作为运行时轮廓,为后续接入自由顶点编辑保留类型。
3.3 标签
- 新建碰撞体默认拥有
Default标签; - 点击标签可设为当前标签;
- 点击
+自动创建Tag N; - 标签数据归属于各碰撞体对象。
本阶段标签已完成编辑和存储,尚未作为粒子碰撞过滤条件。
3.4 碰撞响应
| 响应 | 行为 |
|---|---|
| 物理(弹跳/摩擦) | 把粒子推出碰撞体,根据法线反射速度,并应用弹性和切向摩擦 |
| 暂停(停止不动) | 粒子停留在碰撞边界,速度清零,但自身生命周期继续消耗 |
| 消失(立即销毁) | 粒子进入碰撞体后立即死亡并回收到粒子池 |
弹性和摩擦限制在 0~1:
- 弹性
1表示完全弹跳,0表示不保留法线反弹速度; - 摩擦
1表示停止切向滑动,0表示保留切向速度。
3.5 坐标与运行时
碰撞体使用场景世界坐标。每帧把粒子局部位置和速度转换到世界空间完成碰撞检测,再把修正后的位置和速度变换回粒子系统局部空间。因此粒子系统经过位移、旋转、缩放或发射器路径跟随后,仍能与固定世界碰撞体正确交互。
原修改器面板中的全局“碰撞体开关”已移除。是否参与碰撞由每个碰撞体自己的“启用”属性控制。
四、路径对象与画布编辑
4.1 路径属性
每条路径独立保存:
- 英文名称
PathN; - 启用状态;
- 对象位置和旋转;
- 是否闭合;
- 轨道颜色;
- 锚点及入/出贝塞尔手柄;
- 当前预设类型。
路径使用三次贝塞尔曲线连接相邻锚点。闭合路径会额外连接最后一个锚点与第一个锚点。
4.2 锚点操作
- 双击空白处或曲线:新建锚点;
- 双击锚点:删除节点;
- 双击第二下按住拖动:新建锚点并拉出对称手柄;
- 拖动锚点:移动节点;
- 拖动手柄:调整曲线;
Shift + 拖动手柄:两侧手柄长度与方向完全对称;Alt + 拖动手柄:独立控制单侧手柄;Ctrl/Command + 点击或框选:加选节点;Alt + 点击或框选:减选节点;Alt + 单击空白处:清空选择;- 选中多个节点后拖动:整体移动所选节点。
路径锚点、手柄、连线和选择状态均直接绘制在画布中。
4.3 路径预设
| 预设 | 生成结果 |
|---|---|
| 圆形 | 4 个锚点和贝塞尔手柄组成的闭合圆 |
| 方形 | 4 个直线锚点组成的闭合方形 |
| 多边形 | 6 个锚点组成的闭合规则多边形 |
| 星形 | 10 个交替半径锚点组成的闭合星形 |
“应用预设”会替换当前路径锚点,“清空锚点”只清除节点,不删除路径对象。
五、发射器路径跟随
5.1 默认状态
| 参数 | 默认值 |
|---|---|
| 开启发射器跟随 | 关闭 |
| 跟随模式 | 无 |
| 跟随轨道 | 无 |
| 发射器角度模式 | 固定角度 |
| 移动进度曲线 | 0→1 线性 |
| 移动时长 | 2 秒 |
| 跟随空间 | 世界空间 |
| 移动方向 | 正向 |
| 偏移起始点 | 0 |
开启修改器后,跟随模式仍默认为“无”;只有主动选择“跟随轨道”并指定有效路径后,发射器才开始移动。
5.2 移动进度
路径按实际采样长度计算进度,避免不同长度曲线段使用相同参数步长后产生明显速度差异。
归一化时间 = 当前时间 / 移动时长
路径进度 = 移动进度曲线(归一化时间)
偏移起始点限制在 0~1,用于跳过路径开头部分。反向模式从终点向起点采样,并反转移动方向角度。
5.3 发射器角度
| 模式 | 行为 |
|---|---|
| 固定角度 | 保持粒子系统原有根旋转 |
| 跟随移动方向 | 根据路径当前位置前后的采样点计算切线方向 |
角度会继续叠加到粒子的发射方向和锥形散布计算中。
5.4 跟随空间
| 空间 | 行为 |
|---|---|
| 局部空间(GEN 移动) | 移动整个发射器容器,已经出生的粒子随发射器整体移动 |
| 世界空间(粒子生成点移动) | 只移动新粒子的出生点,已经出生的粒子保留在原世界位置 |
碰撞、力场和吸附等使用世界坐标的模块同步使用当前模拟变换,避免启用路径跟随后发生坐标错位。
六、系统设置与画布辅助显示
原画布左上角的“发射点、骨骼连线、蒙皮网格”三个复选项已移动到系统设置面板。系统设置入口移动到画布左上角,并直接显示文字“系统设置”。
系统设置当前包括:
- 发射点显示,默认开启;
- 骨骼连线显示,默认关闭;
- 蒙皮网格显示,默认关闭;
- 坐标轴刻度开关;
- 刻度文字大小;
- 刻度线粗细;
- 坐标轴颜色;
- 刻度数值显示。
6.1 模块级重置
以下面板标题右侧统一增加“重置”按钮:
- 发射模式;
- 发射器形状;
- 粒子属性;
- 外观与资源;
- 修改器;
- 导出设置占位。
重置只恢复当前模块在 defaultConfig() 中的默认参数,不修改粒子系统名称、场景位置、旋转、缩放、随机种子或其他模块。外观与资源会恢复默认 star.png 资源,修改器会恢复全部关闭状态及默认 trail.png 拖尾资源。点击重置按钮不会改变面板当前的展开或折叠状态。
七、兼容性与时间轴修复
7.1 帧率基准
编辑器固定帧率统一为 30 FPS,与 Spine 默认时间基准对齐:
1 秒 = 30 帧
固定模拟步长 = 1 / 30 秒
时间轴显示、秒数与帧数换算、拖动吸附、总帧数计算、粒子固定步长模拟和发射器路径跟随均读取同一个帧率配置,不再单独写死 60 FPS。
时间轴视口默认显示 0~120f,相当于 4 秒可视范围;实际系统总帧数仍根据发射时长和最长粒子生命动态计算,滚轮可继续缩放显示范围。
7.2 粒子属性与时间轴总长度
时间轴总帧数根据各粒子系统最晚消失时间计算:
总时长 = 延迟时间 + 发射持续时间 + 当前模式下的最大粒子生命
- 固定生命周期使用
lifeMin; - 随机生命周期使用
lifeMin、lifeMax中的较大值; - 多个粒子系统取最晚结束时间。
修复前固定生命周期仍按 lifeMax 计算,时间轴可能提前循环,使生命周期、速度、缩放等参数看起来没有生效。
7.3 时间轴粒子条语义
时间轴粒子条使用一个延迟段和两层叠加色条:
- 左侧空白:发射延迟
delay; - 红色底条:整个粒子系统仍有粒子存在的总时长,不可直接缩放;
- 绿色覆盖层:持续发射时长
duration,仅持续模式显示,可拖动。
持续发射时长默认 1 秒,即 30f;拖动绿色层到 60f 表示持续发射 2 秒。持续模式下,红色底条长度为“绿色发射时长 + 最长粒子生命”,绿色覆盖红色底条的前半段,停止发射后露出的红色尾段表示剩余粒子继续存活的时间。因此红色底条一定比绿色层长。
爆发模式没有持续发射窗口,因此不显示绿色覆盖层,红色底条长度就是最长粒子生命。
红色生命段根据粒子属性模式自动计算:固定模式使用固定生命值,随机模式使用上下限中的较大值。用户修改生命参数后,红色段和总帧数同步更新。
拖动整个叠加条仍用于修改发射延迟。持续发射的最短时长为 1 帧。
7.4 拖动重算修复
修复前,鼠标每次移动都会直接写入配置,触发固定帧缓存清空和粒子模拟重置,造成粒子跳动、数量异常或短暂停止。
现在的处理流程为:
- 按下并拖动时只更新本地条带预览;
- 粒子运行时保持当前模拟,不反复清空;
- 松开鼠标后一次性提交最终值;
- 固定帧缓存只重建一次;
- 取消拖动不修改配置;
- 拖长操作不再被修改前的总帧数错误限制。
切换持续/爆发模式不再承担“恢复异常状态”的作用;模式切换仅按当前配置正常重新模拟。
八、数据与迁移
粒子系统配置新增发射器跟随字段,旧配置通过 ensureEmitterConfig() 自动补齐默认值:
emitterFollow;emitterFollowMode;emitterFollowPathId;emitterAngleMode;emitterFollowCurve;emitterFollowDuration;emitterFollowSpace;emitterFollowDirection;emitterFollowOffset。
碰撞体和路径存储在 Pinia 场景状态中,和粒子系统共同参与配置变化监听。对象、路径锚点或碰撞参数改变后会清空旧固定帧并从第 0 帧重新生成。
九、验证结果
本阶段完成以下验证:
- 粒子系统、碰撞体和路径的创建、选择、删除与英文默认命名;
- 圆形、椭圆、矩形和规则多边形碰撞检测;
- 物理、暂停和销毁三种碰撞响应;
- 路径预设、锚点新增删除、多选移动和手柄调整;
- 发射器跟随默认“无”及有效路径选择;
- 30 FPS 时间基准,确认 1 秒对应 30 帧;
- 正向/反向、固定角度/移动方向;
- 局部空间和世界空间跟随;
- 路径跟随与粒子初始生命周期、速度、缩放、旋转的组合;
- 固定生命周期与时间轴总帧数联动;
- 时间轴延迟拖动和持续时间缩放只在松手后重建缓存;
- 各模块重置按钮的默认值恢复与面板展开状态保持;
- 页面运行无可见错误;
npm run build生产构建通过。
十、阶段七建议
- 实现碰撞体自由顶点编辑,使“自定义”类型拥有独立轮廓;
- 把碰撞标签接入粒子系统过滤规则;
- 实现碰撞体跟随路径移动;
- 支持路径循环、往返和超出移动时长后的行为设置;
- 增加碰撞事件输出,为音效、子粒子或动画触发提供接口;
- 开始接入 Spine 骨架场景对象和骨架资源管理;
- 为场景对象、路径和碰撞体补充保存、导入与导出格式。