Files
SpineParticlesWeb/Document/粒子系统开发阶段一.md
T
2026-09-02 10:45:10 +08:00

75 lines
6.6 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.
# 粒子系统开发 · 阶段一总结
定位:一个网页端粒子发射编辑器(Vue3 + Vite + TS + Pinia + PixiJS),负责「粒子发射系统的参数化编辑 + 实时预览」。**不依赖 Spine 运行时**,Spine 只是未来导出的目标格式,未做烘焙导出(按决定后置)。
目录:`/Users/tianmokeji/Desktop/SpineParticle`(dev server: `http://localhost:5173`)。
---
## 一、产出
### 核心文件
- `src/core/particleEmitter.ts` — 自研池化粒子发射器。排放模式(持续/爆发)、发射形状(点/圆/矩形/锥体)、速率、寿命、速度、缩放、旋转、颜色、混合、重力、风力、阻尼、随机种子、透明度曲线插值 `curveAt`
- `src/store/particleStore.ts` — Pinia 状态(多粒子系统、activeId 选中、时间轴、画布设置、`settings` 坐标轴配置)。
- `src/views/ParticlePanel.vue` — 左侧参数面板,7 个可折叠分组:场景对象/发射模式/发射器形状/粒子属性/外观与资源/修改器/导出设置(预留)。
- `src/views/Stage.vue` — Pixi 画布(网格背景、滚轮缩放、左键拖拽、无限坐标轴、系统设置面板、发射点标记)。
- `src/views/Timeline.vue` — 底部时间轴(播放/暂停/回到起点/循环、帧计数、滚轮缩放、每系统轨道条、拖动调延迟/时长)。
- `src/views/CurveEditor.vue` — 透明度生命周期曲线(横 0-1 时间、纵 0-1 透明度,节点拖动、双击新建/删除)。
- `src/views/NumSlider.vue` — 滑块+数字框复用控件。
- `public/particles/star.png` — 默认贴图。
### 已确认的关键行为
- Y 轴采用数学坐标系:**向上为正、向下为负**。
- 位置X/位置Y 是**锚点(黄点)**,偏移X/偏移Y 让**粒子相对黄点额外位移**,物理/力场源锚在锚点。
- 一个粒子系统 = 一个坐标点;无系统时画布无边线;选中系统高亮黄色,其余淡灰蓝。
- `totalFrames``delay + duration + lifeMax` 按生命周期自动算出,只在改这些属性时重算(签名监听,不卡)。
- 默认:发射速率 10/s、透明度用曲线(默认平台曲线 `(0,0)(0.2,1)(0.8,1)(1,0)`)、贴图 star.png、英文命名 ParticleSystem1 递增、画布默认 100%(最小 1%、无上限)、默认不显示骨骼连线、进入页面空白、默认循环播放。
- 设置面板「启用刻度」是坐标轴唯一主开关,默认关闭,内部含字号/线宽/颜色/显示刻度数值。
### 明确未做(预留)
导出 Spine JSON 烘焙、轨道路径/碰撞体/导出设置(界面占位)、真实 `.atlas+.png` 骨骼贴图。
---
## 二、踩过的坑
### 1. 方向性坑(代价最大)
- 一开始把 sample.json 当"要预览的素材",被纠正为"用来创建粒子系统",再被纠正为"用参数创建、json 是最终导出物",最后"不要强行匹配 spine,只负责粒子发射编辑器"。多轮方向错误导致大面积返工(一度引入 spine-pixi 依赖、做骨骼对象池架构)。
- 做了"加载示例骨骼"按钮,被否定(粒子系统创建应由编辑器参数决定)。
- 进页面自动建"系统1"、预置 item_11,被要求默认空白。
### 2. 技术坑
- **Pixi7 Color API**:`copyFrom``setValue(r,g,b)` 不存在,渐变插值需手动拼 RGB 再 `.toNumber()`
- **坐标轴文字放大变糊**:Text 放在被缩放的 world 容器会位图模糊;移到独立 `axisLabelLayer`(不随 world scale),用世界→屏幕坐标定位。
- **SVG 曲线编辑器点变椭圆/viewBox 拉伸**:`preserveAspectRatio="none"` 使 100×100 viewBox 拉成非正方形,圆变椭圆且命中区小;改为像素坐标系 + 加大命中圈。
- **曲线编辑器 `dblclick` 不触发**:透明命中圆上的 dblclick 被 pointer 捕获抑制;改为在 pointerdown 里检测两次点击(300ms 内、位移<8px)。
- **双击删除又新建**:删除节点后同一次双击的 dblclick 冒泡到 SVG 触发"双击空白新建";用删除抑制时间戳窗口解决。
- **录制→回放使面板改动不实时**:进入回放读旧帧,改参数(速率/颜色/曲线)不更新;把触发重录的 watch 改为对整个 config 做 `JSON.stringify`(排除 texture)的签名监听。
- **deep watch 引发每帧重算卡死**:之前 `watch(config, {deep:true})` 监听整个 config,emitter 每帧把 `_elapsed` 写进 config 导致深比较触发;修法:仅监听生命周期签名 + 把 `_elapsed` 移出 config 改为 emitter 私有字段。
- **发射点与位置X/Y 错位**:`setEmitterPos` 返回 centerX/centerY,而 `spawnOrigin` 又加一次 centerX,等于 `2×centerX+offsetX`;把锚点来源统一为 `_emitterPos()`,再加 offset。
- **Y 轴方向反了**:坐标轴标签是数学坐标(上正),world 用屏幕坐标(下正),位置Y 为正反而画向下;在发射点初始化处把锚点 Y 取负。
### 3. 协作/流程坑
- 反复来回挪同一设置面板里的选项(坐标轴颜色、显示刻度数值),属"反复折腾同一功能"。
- 有明确方向时仍多次用 ask_user_question 确认 A/B 方案,拖慢节奏。
---
## 三、经验
1. 先对齐"坐标系/数据模型"设计,再写编辑器代码。最贵的返工来自语义理解偏差,而非语法/API 问题。
2. 区分"一次功能 vs 一次架构"。小参数改动要最小侵入;方向级错误要敢于回滚,不要继续堆。
3. 性能敏感的循环里别 deep watch 可变的引用对象。粒子每帧改状态,任何 deep 监听都会拖垮帧率;用序列化签名 + 把每帧变化的场移到组件私有字段。
4. 坐标系不统一是渲染 bug 高发地。屏幕坐标(下正)与数学坐标(上正)混用,导致"位置反了/文字糊了/缩放不对";最好在数据入口一次转换,渲染层保持单一约定。
5. headless(puppeteer)自测有效。浏览器工具受限时,headless 截图 + `read_image` 能自主验证"位置/方向/颜色/数值是否生效"。
6. 事件优先级要兜底。曲线编辑器这类点击/拖动/双击/删除并存的小组件,事件易互相干扰(删了又建、拖了误删),需时间戳/位移阈值/抑制窗口做防抖。
---
## 四、现状与风险
- 还没做**导出**,一切围绕"调参 + 预览";导出 JSON(含烘焙 Spine)是后续大工程,现有"锚点 + 偏移 + 曲线 + 生命周期"数据模型已为此留接口。
- **发射方向(direction)/力场/移动噪声**这些修改器参数,物理方向在 Y 翻转后个别(发射方向角度、力场基准点 `base`)可能仍需按数学坐标复核;本次只改了黄点和粒子发射起点,`base`(力场)默认关闭未动,开启时需再验证。
- **爆发模式下 totalFrames 算法**(一次全出、无持续窗口)可能与预期不同,值得确认。
- 代码是反复迭代出来的,个别函数较长、命名一般;若有长期维护打算,建议做一轮小清理(非必须)。