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