# 网页粒子系统 · 阶段十 > 阶段定位:**粒子图片序列帧与循环持续三段动画体系定版** > 完成日期:2026-08-31 > 工程目录:`/Users/tianmokeji/Desktop/SpineParticle` > 技术栈:Vue 3 + TypeScript + Pinia + PixiJS 7 + Spine Runtime 4.2 + Vite --- ## 一、阶段结论 阶段十在阶段九配置持久化、撤回和预设体系的基础上,扩展了粒子图片资源的序列帧能力,并完成了持续发射模式下“启动—循环—结束”三段动画的编辑和预览模型。 图片资源现在可以在固定图片和序列帧之间切换。每个序列帧资源仍属于同一个粒子和同一根粒子骨骼,只在播放过程中替换纹理,不会因为一组序列图而生成多根粒子骨骼。 持续发射模式新增“常规持续”和“循环持续”。循环持续通过稳定周期预演、确定性随机序列、完整帧缓存和假死粒子状态解决首尾衔接问题,并支持分别生成启动段、纯循环段和结束段。 本阶段主要完成: 1. 图片资源增加固定图片与序列帧两种模式; 2. 支持多选图片并按自然文件名顺序组成序列; 3. 支持单次尾帧消失、单次尾帧固定、正向循环和反向循环; 4. 支持独立序列帧播放帧率; 5. 序列帧状态纳入粒子录制、回放、保存、加载和撤回; 6. 持续发射增加常规持续与循环持续两种表现; 7. 循环时长使用独立整数帧参数,不覆盖常规持续秒数; 8. 实现启动段、纯循环段、结束段三种互斥表现; 9. 建立统一的循环衔接帧; 10. 使用周期预演避免末帧硬复制造成的运动突变; 11. 使用透明度为 0 的假死粒子保持纯循环段骨骼集合稳定; 12. 支持循环模式下的延迟时间与首帧保持; 13. 循环模式自动禁用并重置 Spine 骨骼跟随和路径跟随; 14. 修复循环重新计算期间缓存帧与实时状态交替造成的闪烁; 15. 时间轴支持选择包含结束端点的最后一帧; 16. 多粒子系统独立计算,整体时间轴继续取粒子和 Spine 中最长者; 17. 完成 TypeScript 与 Vite 生产构建验证。 --- ## 二、图片序列帧资源 ### 2.1 图片模式 每张粒子图片资源卡片增加“图片模式”: | 模式 | 说明 | |---|---| | 固定 | 粒子生命周期内始终使用同一张图片 | | 序列帧 | 按粒子出生后的时间依次切换多张图片 | 模式属于单个图片资源卡片。一个粒子系统可以同时存在多个图片资源,每个资源可以分别选择固定图片或序列帧,并继续使用原有权重随机选择逻辑。 资源卡片原有参数保持不变,包括: - 权重与权重锁定; - 缩放; - 锚点; - 颜色模式与颜色渐变; - 混合模式; - 独立透明度与透明度曲线。 ### 2.2 序列图片选择 选择序列帧时允许一次多选图片。编辑器会按文件名进行自然排序,而不是简单字符串排序。 例如: ```text diwen_1.png diwen_2.png diwen_10.png ``` 会按照 `1 → 2 → 10` 排列。 界面明确显示实际播放顺序: ```text 已选择 13 帧,按 diwen_000.png-diwen_012.png 顺序播放 ``` 阶段测试资源位于: ```text public/序列帧测试/sg/ ``` ### 2.3 播放模式 序列帧支持四种播放模式: | 模式 | 行为 | |---|---| | 单次-尾帧消失 | 正向播放一次,超过最后一张后隐藏粒子图片 | | 单次-尾帧固定 | 正向播放一次,之后保持最后一张图片 | | 正向循环 | 第一张播放到最后一张,再回到第一张 | | 反向循环 | 最后一张播放到第一张,再回到最后一张 | “尾帧消失”只隐藏粒子图片。粒子逻辑、粒子骨骼和拖尾仍可继续存在,直到粒子生命周期结束。 ### 2.4 播放帧率 每个序列帧资源拥有独立播放帧率: ```text sequenceFps ``` 有效范围为 1~120 FPS,默认 30 FPS。序列帧索引根据粒子实际出生时间计算,不依赖浏览器刷新次数。 ### 2.5 单粒子单骨骼原则 序列帧不会为每张图片创建独立骨骼。 运行规则为: ```text 一个粒子实例 = 一个粒子骨骼 = 一个 Sprite 多张序列图片 = 同一个 Sprite 在不同时间替换 Texture ``` 因此 13 张序列图片仍只使用一根粒子骨骼,避免序列帧数量直接放大骨骼数量。 ### 2.6 录制和持久化 粒子逐帧状态增加: ```text imageFrameIndex imageVisible ``` 录制和回放会恢复: - 当前序列帧索引; - 当前纹理; - 当前图片显隐; - 资源锚点; - 资源混合模式。 配置保存会保存序列帧文件名、预览数据和播放参数;加载时重新创建纹理。撤回快照也包含序列帧资源配置,因此选择图片、切换模式和调整播放方式均可撤回。 --- ## 三、持续发射表现模式 ### 3.1 两种表现 持续发射模式下增加: | 表现 | 说明 | |---|---| | 常规持续 | 保持原持续发射逻辑,结束发射后等待存活粒子死亡 | | 循环持续 | 生成可以拆分为启动、循环和结束的稳定周期动画 | 发射速率等已有参数继续共用。常规持续时长和循环持续时长分别保存,不会互相覆盖。 ### 3.2 独立时长数据 常规持续继续使用: ```text duration: number // 秒 ``` 循环持续新增: ```text loopDurationFrames: number // 整数帧 ``` 默认循环时长为 30f,可编辑范围为 1~1800f。播放仍固定按照: ```text 30f/s ``` 旧配置没有 `loopDurationFrames` 时,会把原持续秒数乘以 30 并向上取整作为迁移初值。此后两种时长完全独立。 例如: ```text 常规持续 = 1.00s 循环持续 = 54f ``` 在两种表现之间切换不会改变对方的数值。 --- ## 四、循环持续三段动画 ### 4.1 三种状态 循环持续面板包含两个附加开关: - 生成开始循环动画; - 生成结束循环动画。 两个开关互斥,不能同时开启。 | 开始开关 | 结束开关 | 当前生成内容 | |---|---|---| | 关 | 关 | 纯循环段 | | 开 | 关 | 启动—循环段 | | 关 | 开 | 循环—结束段 | ### 4.2 循环衔接帧 稳定循环状态的周期边界称为“循环衔接帧”。它包含: - 粒子骨骼集合; - 粒子位置、旋转和缩放; - 颜色与透明度; - 图片资源与序列帧索引; - 图片显隐; - 拖尾骨骼、宽度、颜色和透明度; - 修改器计算后的最终结果。 启动段末端、纯循环段周期边界和结束段起点使用同一套确定性计算规则。 ### 4.3 启动段 启动段规则: 1. 第一帧完全为空; 2. 粒子骨骼数量为 0; 3. 延迟期间保持空帧; 4. 延迟结束后开始正常生成粒子; 5. 粒子使用正常生命周期,可以在启动过程中死亡; 6. 系统自然预热到稳定循环状态; 7. 最后一帧到达循环衔接状态。 当最大粒子寿命跨越多个循环周期时,启动段会自动使用足够的预热周期,保证末端确实进入稳定循环分布。 ### 4.4 纯循环段 纯循环段规则: 1. 延迟期间保持循环衔接帧; 2. 延迟结束后播放一个完整循环周期; 3. 周期长度由 `loopDurationFrames` 决定; 4. 发射事件、随机参数和资源选择在每个周期使用相同确定性序列; 5. 周期末端由真实模拟自然到达下一周期起点; 6. 不再把末帧强制替换为首帧。 这一实现保证的不只是边界两个快照一致,还保证倒数帧到结束端点、结束端点到下一周期的运动连续,不会在最后两帧突然跳变或卡顿。 ### 4.5 结束段 结束段规则: 1. 第一帧为循环衔接状态; 2. 延迟期间保持该衔接状态; 3. 延迟结束后立即停止生成新粒子; 4. 已存在粒子继续按正常生命周期运行; 5. 拖尾随粒子继续更新; 6. 最后一帧所有粒子和拖尾消失。 结束段不使用发射时长作为消亡长度。长度根据衔接帧中粒子的最大剩余生命和拖尾状态自动计算。 --- ## 五、稳定循环计算 ### 5.1 完整周期预演 早期实现只把纯循环末帧复制为首帧。该方式虽然能让两个快照数值相同,却会使倒数帧直接跳到衔接状态,造成明显卡顿。 当前流程改为: 1. 根据循环时长计算每周期帧数; 2. 根据最大粒子寿命计算需要预演的周期数; 3. 从确定性随机种子开始模拟; 4. 每个新周期重置发射计时和随机序列; 5. 保留跨周期仍存活粒子的物理状态; 6. 预演到粒子分布稳定; 7. 记录下一完整周期及结束端点; 8. 时间轴循环时直接回放缓存结果。 ### 5.2 周期随机序列 每个周期重新开始: - 发射累计器; - 发射计时; - 粒子生成序号; - 全局随机源; - 与发射周期相关的吸附计时。 仍存活粒子不会在周期边界被重置,其运动会继续自然推进。 噪声相位、拖尾资源采样和吸附曲线方向改为使用周期内粒子生成序号,不再依赖粒子池槽位。即使粒子池复用了不同编号,也不会改变下一周期相同发射事件的视觉属性。 ### 5.3 假死粒子 纯循环段需要保持粒子骨骼集合稳定。某粒子在某些帧已按正常生命周期死亡时,录制缓存不会直接删除对应骨骼,而是写入假死状态: ```text active = true alpha = 0 imageVisible = false trailState = undefined ``` 因此: - 视觉上粒子已经死亡; - 图片和拖尾均不可见; - 逻辑上粒子骨骼仍存在; - 周期内不会因为骨骼突然增删破坏衔接; - 后续正常出现时仍可继续使用同一骨骼轨道。 假死只用于纯循环段。启动段和结束段仍使用正常粒子死亡逻辑。 ### 5.4 缓存帧闪烁修复 循环段会在录制首帧一次性生成完整缓存。此前在全局时间轴第一次录制结束前,固定帧之间仍会调用 `update(0)` 显示粒子内部实时状态,导致画面在以下两套状态之间交替: - 已计算好的循环缓存帧; - 周期预演结束后的内部状态。 表现为重新计算后粒子高频闪烁,直到时间轴完整运行一遍才恢复。 当前逻辑在循环缓存存在后立即全程读取缓存,不再夹杂实时状态。 --- ## 六、延迟时间 循环持续继续使用原“延迟时间”参数,三种状态均支持。 | 状态 | 延迟期间保持内容 | |---|---| | 启动段 | 空的第一帧 | | 纯循环段 | 循环衔接帧 | | 结束段 | 循环衔接帧 | 延迟结束后才开始推进对应动画。 时间轴中: - 粒子条左侧位置继续表示延迟; - 可以拖动粒子条调整延迟; - 整体播放长度包含延迟帧; - 延迟期间画布不是重复重新计算,而是保持第一帧缓存。 --- ## 七、跟随功能限制 循环持续不与 Spine 骨骼跟随或路径跟随联动。原因是外部目标动画或路径进度可能不具备相同周期,无法保证粒子周期边界稳定。 进入或退出循环持续时均弹出提示: ```text 粒子跟随设置会失效并恢复默认值 ``` 只有用户确认后才切换。 确认后重置: - 发射器跟随总开关; - 跟随模式; - 路径 ID; - Spine ID 与骨骼名; - 跟随空间和方向; - 路径进度曲线; - 位移、旋转和缩放偏移。 循环持续期间跟随控件不可重新开启。切回常规持续后控件恢复可用,但不会自动恢复进入循环前的旧跟随设置。 --- ## 八、时间轴规则 ### 8.1 结束端点 时间轴内部保存的是快照数量,界面显示的是最后一个可选帧编号。 例如动画长度为 54f: ```text 可选帧:0f~54f 快照数量:55 ``` 因此: - 可以拖动到第 54 帧; - “移动到最后一帧”会到达第 54 帧; - 后一帧按钮会正确限制在第 54 帧; - 非循环播放会停在第 54 帧。 ### 8.2 轨道显示 | 状态 | 时间轴表现 | |---|---| | 常规持续 | 绿色发射段 + 红色粒子存活尾段 | | 启动段 | 延迟偏移 + 启动预热发射段 | | 纯循环段 | 延迟偏移 + 一个完整循环周期 | | 结束段 | 延迟偏移 + 只有粒子存在/消亡段 | 结束段不显示可调整的绿色发射时长,因为该段不会产生新粒子。 ### 8.3 多系统与 Spine 每个粒子系统独立计算自己的: - 循环时长; - 预热周期; - 循环衔接状态; - 启动或结束长度; - 延迟帧。 整体时间轴仍取以下对象的最长结束时间: - 全部粒子系统; - 当前加载并选择动画的 Spine 对象; - 已存在的其他时间轴场景动画数据。 较短粒子系统到达末端后保持末帧,直到整体时间轴结束。 --- ## 九、配置、预设与撤回联动 阶段十新增字段均属于粒子系统配置: ```text streamBehavior loopDurationFrames generateLoopStartAnimation generateLoopEndAnimation imageMode sequencePlayback sequenceFps sequenceFrames ``` 因此它们自动纳入: - JSON 配置保存; - JSON 配置加载; - `public/Preset/` 预设加载; - 对象复制; - 编辑器撤回快照; - 模块重置。 加载旧配置时会补齐默认值,并处理: - 旧 `once` 序列模式迁移为 `once-hold`; - 旧 `loop` 序列模式迁移为 `loop-forward`; - 缺少循环时长时从旧持续秒数换算初值; - 启动和结束开关同时为真时自动保留启动段、关闭结束段; - 缺少序列帧字段时恢复固定图片模式。 粒子逐帧缓存不写入配置。配置加载、撤回或参数修改后会根据当前确定性配置重新计算。 --- ## 十、主要代码落点 | 文件 | 阶段十职责 | |---|---| | `src/core/particleEmitter.ts` | 序列帧纹理切换、循环配置字段、强制/停止发射控制、周期随机源重启 | | `src/views/ImageResourceCard.vue` | 图片模式、播放模式、播放帧率、序列文件和顺序提示 | | `src/views/ParticlePanel.vue` | 序列帧选择、循环持续面板、独立帧时长、互斥开关、跟随重置确认 | | `src/views/Stage.vue` | 三段动画烘焙、周期预演、衔接状态、假死粒子、缓存回放与闪烁修复 | | `src/views/Timeline.vue` | 循环轨道宽度、延迟偏移、结束段显示和末端帧选择 | | `src/store/particleStore.ts` | 三种循环状态总帧数、多系统和 Spine 最长时间计算 | | `src/editor/editorConfig.ts` | 序列图片数据保存、纹理重建和旧配置恢复 | --- ## 十一、验证结果 本阶段完成以下静态与构建验证: ```text npm run build ``` 结果: - `vue-tsc -b` 通过; - Vite 生产构建通过; - 548 个模块完成转换; - 无 TypeScript 错误; - 无构建错误; - 仅保留既有的大包体积提示。 交互修复过程中已覆盖: - 循环时长与常规持续时长独立; - 纯循环末端不再硬复制首帧; - 延迟期间保持第一帧; - 时间轴可以到达结束端点; - 重新计算期间不再交替显示内部实时状态; - 配置字段具备旧数据迁移默认值。 --- ## 十二、阶段十最终状态 阶段十完成后,编辑器已经具备: - 单图和序列帧混合资源; - 多种序列播放方式; - 确定性粒子序列帧录制; - 常规持续与独立循环持续; - 启动、循环、结束三段动画生成; - 稳定周期预演; - 假死粒子骨骼保持; - 延迟首帧保持; - 多系统时间轴对齐; - 配置、预设、复制和撤回联动。 至此,阶段十“序列帧资源与循环持续动画体系”完成落盘。