Files
SpineParticlesWeb/Document/网页粒子系统阶段九.md
T
2026-09-02 10:45:10 +08:00

405 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 网页粒子系统 · 阶段九
> 阶段定位:**撤回与快捷键、编辑器配置持久化、可复用预设体系定版**
> 完成日期:2026-08-30
> 工程目录:`/Users/tianmokeji/Desktop/SpineParticle`
> 技术栈:Vue 3 + TypeScript + Pinia + PixiJS 7 + Spine Runtime 4.2 + Vite
---
## 一、阶段结论
阶段九在阶段八场景编辑、Spine 骨骼跟随和对象复制能力的基础上,补齐了编辑器日常使用所需的撤回、快捷键、工程保存、工程加载和预设加载流程。
编辑器现在可以把粒子系统、碰撞体、路径、Spine、系统设置、画布视图和动画归属等数据保存为可移植 JSON,并能把 Spine 骨架、Atlas 与多张纹理一并内嵌。配置重新加载后不需要再次选择 Spine 原始文件,画布、动画列表和骨骼树可以直接恢复。
本阶段主要完成:
1. 实现默认 20 步、最大 200 步的撤回历史;
2. 在系统设置中增加最大撤回次数设置;
3. 支持 `Ctrl/Cmd + Z` 撤回;
4. 增加画布工具、时间轴和保存配置快捷键;
5. 实现完整编辑器配置 JSON 下载保存;
6. 实现本地 JSON 配置加载和数据恢复;
7. 将 Spine 原始资源以内嵌 Data URL 形式纳入配置;
8. 修复 Spine 配置恢复后的运行时资源注册和渲染;
9. 实现 `public/Preset/` 预设目录与自动索引;
10. 实现预设列表、空状态和一键加载;
11. 建立纯粒子、路径、碰撞体、Spine 和空场景测试预设;
12. 修复包含 `+` 的预设文件名无法通过开发服务器读取的问题;
13. 为预设加载错误增加文件命名检查提示;
14. 修复同一配置第二次加载后停在第 0 帧的问题;
15. 完成普通配置和含 Spine 配置的保存—加载往返验证。
---
## 二、撤回功能
### 2.1 历史模型
编辑器通过快照记录可撤回数据。默认保留 20 步,用户可以在系统设置中修改,允许范围为 1~200 步。
快照覆盖:
- 全部粒子系统及其面板参数;
- 全部碰撞体;
- 全部路径与路径点;
- 全部 Spine 场景对象;
- 所属动画列表;
- 除撤回上限自身以外的系统设置;
- 对象显隐、背景图数据及背景偏移和透明度。
以下内容不作为普通撤回快照保存:
- 粒子逐帧录制缓存;
- PixiJS `Texture` 实例;
- 拖尾运行时纹理实例;
- 当前时间轴帧和正在播放状态;
- 撤回上限本身。
这些数据属于运行时缓存或撤回系统自身配置,恢复快照后由编辑器重新计算或重建。
### 2.2 操作合并
参数连续拖动或连续输入不会为每个微小变化创建独立历史。编辑器在最后一次变化后等待约 250ms,再把连续变化合并为一步操作。
该设计适用于:
- 滑块拖动;
- 数值连续输入;
- 曲线调整;
- 场景对象变换;
- 背景图偏移和透明度调整。
### 2.3 Spine 资源安全
Spine 场景对象的可序列化属性保存在快照中,已解析的 SkeletonData 和纹理通过资源注册表引用计数保留。
撤回删除、复制或资源替换操作时:
- 快照仍引用的 Spine 资源不会被提前销毁;
- 恢复快照时重新注册对应 Spine ID 的运行时资源;
- 超出撤回上限的旧快照会释放自己持有的资源引用;
- 粒子录制缓存清空并重新生成。
### 2.4 撤回后的状态修复
执行撤回后会:
1. 恢复场景对象和设置;
2. 修复当前选择,避免选择已不存在的对象;
3. 恢复粒子系统所属动画;
4. 清空旧录制帧;
5. 重新计算时间轴总长度;
6. 更新撤回按钮的剩余步数和可用状态。
当前阶段只实现“撤回”,尚未实现“重做”。
---
## 三、快捷键
### 3.1 快捷键表
| 快捷键 | 作用 | 生效范围 |
|---|---|---|
| `Ctrl/Cmd + Z` | 撤回上一步 | 全局 |
| `Ctrl/Cmd + S` | 下载保存当前编辑器配置 | 全局 |
| `Q` | 切换为画布拖动模式 | 画布已选中 |
| `W` | 切换位移工具 | 画布已选中 |
| `E` | 切换旋转工具 | 画布已选中 |
| `R` | 切换缩放工具 | 画布已选中 |
| `D` | 播放/暂停时间轴 | 全局非输入状态 |
| `S` | 回到时间轴第 0 帧 | 全局非输入状态 |
### 3.2 浏览器快捷键覆盖
`Ctrl/Cmd + S``Ctrl/Cmd + Z` 会阻止浏览器默认行为,分别交给编辑器保存和撤回,不再弹出浏览器网页保存或执行浏览器输入历史撤销。
### 3.3 输入控件保护
当焦点位于以下控件时,普通字母快捷键不会触发:
- `input`
- `textarea`
- `select`
- `contenteditable` 内容。
因此输入名称、搜索骨骼或编辑参数时,可以正常键入 `q/w/e/r/d/s`。带 `Ctrl/Cmd` 的保存与撤回仍按编辑器全局快捷键处理。
---
## 四、编辑器配置保存
### 4.1 保存入口
场景对象面板上方增加:
- `保存配置`
- `加载配置`
- `选择预设`
点击“保存配置”或按 `Ctrl/Cmd + S`,浏览器会下载:
```text
SpineParticle-YYYYMMDD-HHMMSS.json
```
### 4.2 文件格式
当前格式标识与版本:
```text
format: SpineParticle.EditorConfig
version: 1
```
顶层数据结构:
```text
editor 画布缩放与平移
settings 系统设置、背景图及撤回上限
timeline FPS、循环状态和所属动画列表
selection 当前场景对象类型与 ID
scene 粒子、碰撞体、路径和 Spine 数组
savedAt 保存时间
```
### 4.3 粒子与图片资源
粒子系统保存全部可编辑参数,包括:
- 发射模式、持续时间和延迟;
- 发射器形状和根变换;
- 生命周期、速度、缩放、旋转与曲线;
- 颜色、透明度、混合模式;
- 修改器;
- 碰撞、路径和骨骼跟随;
- 图片资源与拖尾资源;
- 对象显隐和所属动画。
PixiJS 纹理实例和粒子逐帧缓存不会写入 JSON。图片资源通过自身的预览 URL 或 Data URL 保存,配置加载时重新创建纹理。
### 4.4 Spine 原始资源内嵌
Spine 对象除属性、动画选择和骨骼元数据外,还保存原始资源副本:
```text
sourceBundle.skeleton
sourceBundle.atlas
sourceBundle.textures[]
```
每个资源同时保存原文件名和 Data URL。恢复时重新创建同名 `File`
- JSON 使用原 JSON 文件名;
- SKEL 使用原二进制文件名;
- Atlas 保留原 Atlas 文件名和内容;
- 纹理保留 Atlas 中引用的准确文件名。
保持文件名一致是 Atlas 再次匹配多张纹理的关键。Data URL 只是文件内容载体,不会替代资源之间的文件名引用关系。
Spine 面板在首次加载成功后异步生成 `sourceBundle`,避免内嵌资源转换干扰当前画布中的实时 Spine 解析结果。
---
## 五、编辑器配置加载
### 5.1 校验
加载本地文件时只接受 `.json`,并依次检查:
1. 是否为有效 JSON
2. `format` 是否为 `SpineParticle.EditorConfig`
3. 配置版本是否为 1
4. 场景是否包含粒子、碰撞体、路径和 Spine 数组。
失败时保持当前编辑器状态,并显示具体错误。
### 5.2 原子恢复流程
配置加载先在临时数据中完成资源准备:
1. 深度复制配置数据;
2. 补齐旧粒子参数默认值;
3. 重建粒子和拖尾纹理;
4. 还原 Spine 原始文件;
5. 解析骨架、Atlas 和多纹理;
6. 全部解析成功后再替换当前场景;
7. 注册新的 Spine 运行时资源;
8. 修复对象选择和所属动画;
9. 重新计算时间轴长度。
如果内嵌 Spine 资源解析失败,已临时创建的纹理会释放,不会把半完成场景覆盖到编辑器中。
### 5.3 Spine 运行时刷新
重复加载配置时,Spine 对象 ID 可能相同。加载流程会提升 `assetVersion`,确保运行时层识别为新资源并重新创建 Spine 显示对象,而不是继续使用旧实例。
资源加载完成后会恢复:
- Spine 画布渲染;
- 动画列表和动画时长;
- 当前选择的 Spine 动画;
- 骨骼层级树;
- 当前选中骨骼;
- 粒子系统保存的 Spine ID 与骨骼名称绑定。
### 5.4 加载后自动播放
配置和预设加载完成后统一执行:
```text
frame = 0
recorded = false
playing = true
```
因此首次加载和连续加载同一份配置都会从头自动播放,不再依赖场景深度监听是否检测到数据变化。
---
## 六、预设体系
### 6.1 预设目录
预设文件放置于:
```text
public/Preset/
```
每个预设都是与“保存配置”完全相同的 `SpineParticle.EditorConfig` JSON,因此预设和本地工程配置共用一套解析、校验和资源恢复流程。
### 6.2 自动索引
Vite 插件会扫描预设目录中的全部 `.json` 文件并自动生成:
```text
public/Preset/index.json
```
索引生成时:
- 排除 `index.json` 自身;
- 按中文文件名排序;
- 使用文件名去掉 `.json` 作为界面名称;
- 开发服务器监听文件新增和删除并刷新列表;
- 生产构建开始前重新生成索引。
目录中没有配置文件时,下拉框显示“无预设文件”并置灰。
### 6.3 当前预设
当前项目包含:
- `纯粒子.json`
- `纯粒子-路径.json`
- `纯粒子-碰撞.json`
- `纯粒子-spine.json`
- `空场景.json`
- `默认粒子.json`
带 Spine 的预设内嵌 `bingo.json``bingo.atlas``bingo.png``bingo_2.png`,加载后可直接显示 Spine、动画列表和骨骼树。
### 6.4 文件命名规则
阶段测试发现,文件名包含 `+` 时,经 URL 编码后开发服务器会返回应用 HTML,而不是目标 JSON,最终表现为“配置文件不是有效的 JSON”。
为确保开发环境和静态托管环境行为一致,组合预设统一使用连字符:
```text
推荐:纯粒子-路径.json
避免:纯粒子+路径.json
```
预设加载失败时,界面在原始错误后追加:
```text
请检查预设文件命名
```
---
## 七、代码结构
本阶段新增或重点调整:
| 文件 | 职责 |
|---|---|
| `src/editor/editorClone.ts` | 安全深度复制编辑器可序列化数据 |
| `src/editor/editorHistory.ts` | 撤回快照、合并、上限和 Spine 资源引用 |
| `src/editor/useEditorShortcuts.ts` | 全局快捷键、画布焦点和输入保护 |
| `src/editor/editorConfig.ts` | 配置创建、下载、校验、加载和资源恢复 |
| `src/spine/spineSourceBundle.ts` | Spine 原始文件 Data URL 内嵌与还原 |
| `src/spine/spineAssetRegistry.ts` | Spine 配置恢复和撤回所需的资源生命周期 |
| `src/views/ParticlePanel.vue` | 保存、加载、预设列表和结果提示 |
| `src/views/Stage.vue` | 快捷键接入、撤回按钮和加载后的运行时刷新 |
| `vite.config.ts` | 预设索引自动生成和 Spine 依赖去重 |
配置、历史与快捷键逻辑已从主画布和主属性面板中拆分,避免继续扩大单文件职责。
---
## 八、验证结果
已完成以下实际验证:
- `Ctrl/Cmd + S` 可以下载编辑器配置;
- 配置文件名按时间生成且 JSON 格式有效;
- 修改粒子名称后保存,再次修改并加载,名称恢复为保存值;
- 系统设置、背景图数据、画布视图和场景对象写入配置;
- 含 Spine 的配置保存后文件约 11MB,资源数据完整内嵌;
- 含 Spine 配置重新加载后,Spine 名称恢复;
- Spine 画布图像正常显示;
- 14 个 Spine 动画及“无”选项正常恢复;
- 骨骼层级树正常恢复;
- 页面未出现资源解析或渲染错误;
- `纯粒子.json` 加载成功;
- `纯粒子-路径.json` 加载成功,场景包含粒子与路径;
- `纯粒子-碰撞.json` 加载成功,场景包含粒子与碰撞体;
- `纯粒子-spine.json` 加载成功,场景包含粒子与 Spine;
- `空场景.json` 可以加载为零对象场景;
- `默认粒子.json` 加载成功;
- 同一 Spine 预设连续加载两次,两次都从第 0 帧自动播放;
- 第二次加载后帧数从 40 推进到 59,播放按钮保持“暂停”状态;
- 浏览器控制台无错误和警告;
- `npm run build` 生产构建通过。
构建仍存在 Vite 主产物超过 500kB 的提示,不影响功能和构建结果。
---
## 九、当前限制
1. 当前只支持单向撤回,尚未实现重做;
2. 撤回历史只存在于当前页面内存中,刷新页面后清空;
3. 撤回不保存当前播放帧、播放状态、画布选择和粒子录制缓存;
4. 配置格式当前为版本 1,尚未建立跨版本迁移器;
5. Spine 和本地图片使用 Data URL 内嵌,资源较大时配置文件体积明显增加;
6. 保存配置始终下载新文件,尚未提供覆盖保存、最近文件和自动保存;
7. 浏览器安全限制下无法记住原本地文件路径;
8. 预设依赖构建时生成的索引,纯静态部署后新增文件需要重新构建;
9. 预设命名目前通过规避 `+` 保证兼容,尚未建立完整的文件名字符校验;
10. 配置导入目前只接受 JSON,尚未支持 YAML;
11. 配置文件没有压缩,包含 Spine 多纹理时下载和解析成本较高;
12. 主包仍包含 Spine 运行时和主要编辑器模块,尚未动态拆包。
---
## 十、阶段十建议
1. 增加重做功能和 `Ctrl/Cmd + Shift + Z` 快捷键;
2. 增加配置格式迁移器,支持未来版本平滑升级;
3. 为预设文件名建立创建、校验和错误定位工具;
4. 提供自动保存、最近配置和页面异常恢复;
5. 支持压缩工程包,把 JSON 与 Spine、粒子图片资源拆分存储;
6. 增加配置导入前预览、差异对比和合并模式;
7. 为配置与预设建立自动化往返测试;
8. 对无效 ID、丢失骨骼、缺失纹理和旧字段提供迁移报告;
9. 增加工程名称、作者、备注和自定义元数据;
10. 开始设计正式导出结构,把所属动画、粒子系统和 Spine 骨骼绑定映射到导出数据;
11. 对 Spine 和编辑器主模块进行动态加载,降低初始包体积;
12. 增加配置资源大小统计和大文件保存提示。