75 lines
6.6 KiB
Markdown
75 lines
6.6 KiB
Markdown
# 粒子系统开发 · 阶段一总结
|
||
|
||
定位:一个网页端粒子发射编辑器(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 算法**(一次全出、无持续窗口)可能与预期不同,值得确认。
|
||
- 代码是反复迭代出来的,个别函数较长、命名一般;若有长期维护打算,建议做一轮小清理(非必须)。
|