新增spine版本支持
@@ -2,7 +2,9 @@
|
||||
node_modules/
|
||||
# Build output (仅忽略根目录的 Vite 构建产物;不要用无锚点的 dist/,否则会误把
|
||||
# vendor/spine/*/dist 这类必需的第三方运行时文件一并忽略,导致 clone 后项目无法运行)
|
||||
/dist
|
||||
/release
|
||||
/release-tauri
|
||||
/src-tauri/target
|
||||
# TypeScript build cache
|
||||
*.tsbuildinfo
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"name": "粒子序列帧拖尾",
|
||||
"file": "粒子序列帧拖尾.json"
|
||||
}
|
||||
]
|
||||
|
Before Width: | Height: | Size: 3.1 MiB After Width: | Height: | Size: 3.1 MiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 527 B |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Spine Particle · 阶段1 Spike</title>
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; background: #111; color: #eee; font-family: system-ui, -apple-system, sans-serif; }
|
||||
#app { display: flex; flex-direction: column; height: 100vh; }
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/index-Dw7eU6re.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BPQ62DCC.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,286 @@
|
||||
|
||||
spineboy.png
|
||||
size: 1024,256
|
||||
format: RGBA8888
|
||||
filter: Linear,Linear
|
||||
repeat: none
|
||||
crosshair
|
||||
rotate: false
|
||||
xy: 352, 7
|
||||
size: 45, 45
|
||||
orig: 45, 45
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
eye-indifferent
|
||||
rotate: false
|
||||
xy: 862, 105
|
||||
size: 47, 45
|
||||
orig: 47, 45
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
eye-surprised
|
||||
rotate: false
|
||||
xy: 505, 79
|
||||
size: 47, 45
|
||||
orig: 47, 45
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-bracer
|
||||
rotate: false
|
||||
xy: 826, 66
|
||||
size: 29, 40
|
||||
orig: 29, 40
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-fist-closed
|
||||
rotate: false
|
||||
xy: 786, 65
|
||||
size: 38, 41
|
||||
orig: 38, 41
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-fist-open
|
||||
rotate: true
|
||||
xy: 710, 51
|
||||
size: 43, 44
|
||||
orig: 43, 44
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-foot
|
||||
rotate: false
|
||||
xy: 210, 6
|
||||
size: 63, 35
|
||||
orig: 63, 35
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-shin
|
||||
rotate: true
|
||||
xy: 665, 128
|
||||
size: 41, 92
|
||||
orig: 41, 92
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-thigh
|
||||
rotate: true
|
||||
xy: 2, 2
|
||||
size: 23, 56
|
||||
orig: 23, 56
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-upper-arm
|
||||
rotate: false
|
||||
xy: 250, 205
|
||||
size: 23, 49
|
||||
orig: 23, 49
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
goggles
|
||||
rotate: false
|
||||
xy: 665, 171
|
||||
size: 131, 83
|
||||
orig: 131, 83
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
gun
|
||||
rotate: false
|
||||
xy: 798, 152
|
||||
size: 105, 102
|
||||
orig: 105, 102
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
head
|
||||
rotate: false
|
||||
xy: 2, 27
|
||||
size: 136, 149
|
||||
orig: 136, 149
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
hoverboard-board
|
||||
rotate: false
|
||||
xy: 2, 178
|
||||
size: 246, 76
|
||||
orig: 246, 76
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
hoverboard-thruster
|
||||
rotate: true
|
||||
xy: 722, 96
|
||||
size: 30, 32
|
||||
orig: 30, 32
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
hoverglow-small
|
||||
rotate: false
|
||||
xy: 275, 81
|
||||
size: 137, 38
|
||||
orig: 137, 38
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
mouth-grind
|
||||
rotate: false
|
||||
xy: 614, 97
|
||||
size: 47, 30
|
||||
orig: 47, 30
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
mouth-oooo
|
||||
rotate: false
|
||||
xy: 612, 65
|
||||
size: 47, 30
|
||||
orig: 47, 30
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
mouth-smile
|
||||
rotate: false
|
||||
xy: 661, 64
|
||||
size: 47, 30
|
||||
orig: 47, 30
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle-glow
|
||||
rotate: false
|
||||
xy: 382, 54
|
||||
size: 25, 25
|
||||
orig: 25, 25
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle-ring
|
||||
rotate: true
|
||||
xy: 275, 54
|
||||
size: 25, 105
|
||||
orig: 25, 105
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle01
|
||||
rotate: true
|
||||
xy: 911, 95
|
||||
size: 67, 40
|
||||
orig: 67, 40
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle02
|
||||
rotate: false
|
||||
xy: 792, 108
|
||||
size: 68, 42
|
||||
orig: 68, 42
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle03
|
||||
rotate: true
|
||||
xy: 956, 171
|
||||
size: 83, 53
|
||||
orig: 83, 53
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle04
|
||||
rotate: false
|
||||
xy: 275, 7
|
||||
size: 75, 45
|
||||
orig: 75, 45
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle05
|
||||
rotate: false
|
||||
xy: 140, 3
|
||||
size: 68, 38
|
||||
orig: 68, 38
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
neck
|
||||
rotate: false
|
||||
xy: 250, 182
|
||||
size: 18, 21
|
||||
orig: 18, 21
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-bg
|
||||
rotate: false
|
||||
xy: 140, 43
|
||||
size: 133, 133
|
||||
orig: 133, 133
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-flare1
|
||||
rotate: false
|
||||
xy: 554, 65
|
||||
size: 56, 30
|
||||
orig: 56, 30
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-flare2
|
||||
rotate: true
|
||||
xy: 759, 112
|
||||
size: 57, 31
|
||||
orig: 57, 31
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-flare3
|
||||
rotate: false
|
||||
xy: 554, 97
|
||||
size: 58, 30
|
||||
orig: 58, 30
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-shade
|
||||
rotate: false
|
||||
xy: 275, 121
|
||||
size: 133, 133
|
||||
orig: 133, 133
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-streaks1
|
||||
rotate: false
|
||||
xy: 410, 126
|
||||
size: 126, 128
|
||||
orig: 126, 128
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-streaks2
|
||||
rotate: false
|
||||
xy: 538, 129
|
||||
size: 125, 125
|
||||
orig: 125, 125
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear-bracer
|
||||
rotate: false
|
||||
xy: 857, 67
|
||||
size: 28, 36
|
||||
orig: 28, 36
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear-foot
|
||||
rotate: false
|
||||
xy: 663, 96
|
||||
size: 57, 30
|
||||
orig: 57, 30
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear-shin
|
||||
rotate: true
|
||||
xy: 414, 86
|
||||
size: 38, 89
|
||||
orig: 38, 89
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear-thigh
|
||||
rotate: false
|
||||
xy: 756, 63
|
||||
size: 28, 47
|
||||
orig: 28, 47
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear-upper-arm
|
||||
rotate: true
|
||||
xy: 60, 5
|
||||
size: 20, 44
|
||||
orig: 20, 44
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
torso
|
||||
rotate: false
|
||||
xy: 905, 164
|
||||
size: 49, 90
|
||||
orig: 49, 90
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
|
After Width: | Height: | Size: 255 KiB |
@@ -0,0 +1,101 @@
|
||||
spineboy.png
|
||||
size: 1024, 256
|
||||
filter: Linear, Linear
|
||||
scale: 0.5
|
||||
crosshair
|
||||
bounds: 813, 160, 45, 45
|
||||
eye-indifferent
|
||||
bounds: 569, 2, 47, 45
|
||||
eye-surprised
|
||||
bounds: 643, 7, 47, 45
|
||||
rotate: 90
|
||||
front-bracer
|
||||
bounds: 811, 51, 29, 40
|
||||
front-fist-closed
|
||||
bounds: 807, 93, 38, 41
|
||||
front-fist-open
|
||||
bounds: 815, 210, 43, 44
|
||||
front-foot
|
||||
bounds: 706, 64, 63, 35
|
||||
rotate: 90
|
||||
front-shin
|
||||
bounds: 80, 11, 41, 92
|
||||
front-thigh
|
||||
bounds: 754, 12, 23, 56
|
||||
front-upper-arm
|
||||
bounds: 618, 5, 23, 49
|
||||
goggles
|
||||
bounds: 214, 20, 131, 83
|
||||
gun
|
||||
bounds: 347, 14, 105, 102
|
||||
rotate: 90
|
||||
head
|
||||
bounds: 80, 105, 136, 149
|
||||
hoverboard-board
|
||||
bounds: 2, 8, 246, 76
|
||||
rotate: 90
|
||||
hoverboard-thruster
|
||||
bounds: 478, 2, 30, 32
|
||||
hoverglow-small
|
||||
bounds: 218, 117, 137, 38
|
||||
rotate: 90
|
||||
mouth-grind
|
||||
bounds: 775, 80, 47, 30
|
||||
rotate: 90
|
||||
mouth-oooo
|
||||
bounds: 779, 31, 47, 30
|
||||
rotate: 90
|
||||
mouth-smile
|
||||
bounds: 783, 207, 47, 30
|
||||
rotate: 90
|
||||
muzzle-glow
|
||||
bounds: 779, 4, 25, 25
|
||||
muzzle-ring
|
||||
bounds: 451, 14, 25, 105
|
||||
muzzle01
|
||||
bounds: 664, 60, 67, 40
|
||||
rotate: 90
|
||||
muzzle02
|
||||
bounds: 580, 56, 68, 42
|
||||
rotate: 90
|
||||
muzzle03
|
||||
bounds: 478, 36, 83, 53
|
||||
rotate: 90
|
||||
muzzle04
|
||||
bounds: 533, 49, 75, 45
|
||||
rotate: 90
|
||||
muzzle05
|
||||
bounds: 624, 56, 68, 38
|
||||
rotate: 90
|
||||
neck
|
||||
bounds: 806, 8, 18, 21
|
||||
portal-bg
|
||||
bounds: 258, 121, 133, 133
|
||||
portal-flare1
|
||||
bounds: 690, 2, 56, 30
|
||||
rotate: 90
|
||||
portal-flare2
|
||||
bounds: 510, 3, 57, 31
|
||||
portal-flare3
|
||||
bounds: 722, 4, 58, 30
|
||||
rotate: 90
|
||||
portal-shade
|
||||
bounds: 393, 121, 133, 133
|
||||
portal-streaks1
|
||||
bounds: 528, 126, 126, 128
|
||||
portal-streaks2
|
||||
bounds: 656, 129, 125, 125
|
||||
rear-bracer
|
||||
bounds: 826, 13, 28, 36
|
||||
rear-foot
|
||||
bounds: 743, 70, 57, 30
|
||||
rotate: 90
|
||||
rear-shin
|
||||
bounds: 174, 14, 38, 89
|
||||
rear-thigh
|
||||
bounds: 783, 158, 28, 47
|
||||
rear-upper-arm
|
||||
bounds: 783, 136, 20, 44
|
||||
rotate: 90
|
||||
torso
|
||||
bounds: 123, 13, 49, 90
|
||||
|
After Width: | Height: | Size: 243 KiB |
@@ -0,0 +1,101 @@
|
||||
spineboy.png
|
||||
size: 1024, 256
|
||||
filter: Linear, Linear
|
||||
scale: 0.5
|
||||
crosshair
|
||||
bounds: 813, 160, 45, 45
|
||||
eye-indifferent
|
||||
bounds: 569, 2, 47, 45
|
||||
eye-surprised
|
||||
bounds: 643, 7, 47, 45
|
||||
rotate: 90
|
||||
front-bracer
|
||||
bounds: 811, 51, 29, 40
|
||||
front-fist-closed
|
||||
bounds: 807, 93, 38, 41
|
||||
front-fist-open
|
||||
bounds: 815, 210, 43, 44
|
||||
front-foot
|
||||
bounds: 706, 64, 63, 35
|
||||
rotate: 90
|
||||
front-shin
|
||||
bounds: 80, 11, 41, 92
|
||||
front-thigh
|
||||
bounds: 754, 12, 23, 56
|
||||
front-upper-arm
|
||||
bounds: 618, 5, 23, 49
|
||||
goggles
|
||||
bounds: 214, 20, 131, 83
|
||||
gun
|
||||
bounds: 347, 14, 105, 102
|
||||
rotate: 90
|
||||
head
|
||||
bounds: 80, 105, 136, 149
|
||||
hoverboard-board
|
||||
bounds: 2, 8, 246, 76
|
||||
rotate: 90
|
||||
hoverboard-thruster
|
||||
bounds: 478, 2, 30, 32
|
||||
hoverglow-small
|
||||
bounds: 218, 117, 137, 38
|
||||
rotate: 90
|
||||
mouth-grind
|
||||
bounds: 775, 80, 47, 30
|
||||
rotate: 90
|
||||
mouth-oooo
|
||||
bounds: 779, 31, 47, 30
|
||||
rotate: 90
|
||||
mouth-smile
|
||||
bounds: 783, 207, 47, 30
|
||||
rotate: 90
|
||||
muzzle-glow
|
||||
bounds: 779, 4, 25, 25
|
||||
muzzle-ring
|
||||
bounds: 451, 14, 25, 105
|
||||
muzzle01
|
||||
bounds: 664, 60, 67, 40
|
||||
rotate: 90
|
||||
muzzle02
|
||||
bounds: 580, 56, 68, 42
|
||||
rotate: 90
|
||||
muzzle03
|
||||
bounds: 478, 36, 83, 53
|
||||
rotate: 90
|
||||
muzzle04
|
||||
bounds: 533, 49, 75, 45
|
||||
rotate: 90
|
||||
muzzle05
|
||||
bounds: 624, 56, 68, 38
|
||||
rotate: 90
|
||||
neck
|
||||
bounds: 806, 8, 18, 21
|
||||
portal-bg
|
||||
bounds: 258, 121, 133, 133
|
||||
portal-flare1
|
||||
bounds: 690, 2, 56, 30
|
||||
rotate: 90
|
||||
portal-flare2
|
||||
bounds: 510, 3, 57, 31
|
||||
portal-flare3
|
||||
bounds: 722, 4, 58, 30
|
||||
rotate: 90
|
||||
portal-shade
|
||||
bounds: 393, 121, 133, 133
|
||||
portal-streaks1
|
||||
bounds: 528, 126, 126, 128
|
||||
portal-streaks2
|
||||
bounds: 656, 129, 125, 125
|
||||
rear-bracer
|
||||
bounds: 826, 13, 28, 36
|
||||
rear-foot
|
||||
bounds: 743, 70, 57, 30
|
||||
rotate: 90
|
||||
rear-shin
|
||||
bounds: 174, 14, 38, 89
|
||||
rear-thigh
|
||||
bounds: 783, 158, 28, 47
|
||||
rear-upper-arm
|
||||
bounds: 783, 136, 20, 44
|
||||
rotate: 90
|
||||
torso
|
||||
bounds: 123, 13, 49, 90
|
||||
|
After Width: | Height: | Size: 239 KiB |
@@ -0,0 +1,94 @@
|
||||
spineboy.png
|
||||
size: 1024, 256
|
||||
filter: Linear, Linear
|
||||
scale: 0.5
|
||||
crosshair
|
||||
bounds: 352, 7, 45, 45
|
||||
eye-indifferent
|
||||
bounds: 862, 105, 47, 45
|
||||
eye-surprised
|
||||
bounds: 505, 79, 47, 45
|
||||
front-bracer
|
||||
bounds: 826, 66, 29, 40
|
||||
front-fist-closed
|
||||
bounds: 786, 65, 38, 41
|
||||
front-fist-open
|
||||
bounds: 710, 51, 43, 44
|
||||
rotate: 90
|
||||
front-foot
|
||||
bounds: 210, 6, 63, 35
|
||||
front-shin
|
||||
bounds: 665, 128, 41, 92
|
||||
rotate: 90
|
||||
front-thigh
|
||||
bounds: 2, 2, 23, 56
|
||||
rotate: 90
|
||||
front-upper-arm
|
||||
bounds: 250, 205, 23, 49
|
||||
goggles
|
||||
bounds: 665, 171, 131, 83
|
||||
gun
|
||||
bounds: 798, 152, 105, 102
|
||||
head
|
||||
bounds: 2, 27, 136, 149
|
||||
hoverboard-board
|
||||
bounds: 2, 178, 246, 76
|
||||
hoverboard-thruster
|
||||
bounds: 722, 96, 30, 32
|
||||
rotate: 90
|
||||
hoverglow-small
|
||||
bounds: 275, 81, 137, 38
|
||||
mouth-grind
|
||||
bounds: 614, 97, 47, 30
|
||||
mouth-oooo
|
||||
bounds: 612, 65, 47, 30
|
||||
mouth-smile
|
||||
bounds: 661, 64, 47, 30
|
||||
muzzle-glow
|
||||
bounds: 382, 54, 25, 25
|
||||
muzzle-ring
|
||||
bounds: 275, 54, 25, 105
|
||||
rotate: 90
|
||||
muzzle01
|
||||
bounds: 911, 95, 67, 40
|
||||
rotate: 90
|
||||
muzzle02
|
||||
bounds: 792, 108, 68, 42
|
||||
muzzle03
|
||||
bounds: 956, 171, 83, 53
|
||||
rotate: 90
|
||||
muzzle04
|
||||
bounds: 275, 7, 75, 45
|
||||
muzzle05
|
||||
bounds: 140, 3, 68, 38
|
||||
neck
|
||||
bounds: 250, 182, 18, 21
|
||||
portal-bg
|
||||
bounds: 140, 43, 133, 133
|
||||
portal-flare1
|
||||
bounds: 554, 65, 56, 30
|
||||
portal-flare2
|
||||
bounds: 759, 112, 57, 31
|
||||
rotate: 90
|
||||
portal-flare3
|
||||
bounds: 554, 97, 58, 30
|
||||
portal-shade
|
||||
bounds: 275, 121, 133, 133
|
||||
portal-streaks1
|
||||
bounds: 410, 126, 126, 128
|
||||
portal-streaks2
|
||||
bounds: 538, 129, 125, 125
|
||||
rear-bracer
|
||||
bounds: 857, 67, 28, 36
|
||||
rear-foot
|
||||
bounds: 663, 96, 57, 30
|
||||
rear-shin
|
||||
bounds: 414, 86, 38, 89
|
||||
rotate: 90
|
||||
rear-thigh
|
||||
bounds: 756, 63, 28, 47
|
||||
rear-upper-arm
|
||||
bounds: 60, 5, 20, 44
|
||||
rotate: 90
|
||||
torso
|
||||
bounds: 905, 164, 49, 90
|
||||
|
After Width: | Height: | Size: 240 KiB |
@@ -0,0 +1,30 @@
|
||||
# Spine 多版本测试资源
|
||||
|
||||
这些资源来自 Esoteric Software 官方的
|
||||
[`spine-runtimes`](https://github.com/EsotericSoftware/spine-runtimes)
|
||||
仓库,用于测试本项目对 Spine 3.8、4.0、4.1、4.2 JSON 数据的加载、预览与动画联动。
|
||||
|
||||
## 目录结构
|
||||
|
||||
每个版本目录都包含同一套 Spineboy Pro 示例:
|
||||
|
||||
- `spineboy-pro.json`:骨骼与动画数据
|
||||
- `spineboy.atlas`:纹理图集
|
||||
- `spineboy.png`:图集贴图
|
||||
|
||||
| 目录 | JSON 中的实际 Spine 版本 | 浏览器访问路径 |
|
||||
| --- | --- | --- |
|
||||
| `3.8/` | `3.8.55` | `/spine-test/3.8/` |
|
||||
| `4.0/` | `4.0.31` | `/spine-test/4.0/` |
|
||||
| `4.1/` | `4.1.17` | `/spine-test/4.1/` |
|
||||
| `4.2/` | `4.2.22` | `/spine-test/4.2/` |
|
||||
|
||||
## 手动测试
|
||||
|
||||
1. 新建一个 Spine 场景对象。
|
||||
2. 依次选择对应版本目录中的 JSON、Atlas 和 PNG 文件。
|
||||
3. 点击“加载”。
|
||||
4. 检查资源版本、骨骼层级、动画列表、时间轴与粒子挂载联动。
|
||||
|
||||
测试时不要混用不同版本目录中的文件。资源版权和使用条件遵循
|
||||
[`spine-runtimes` License](https://github.com/EsotericSoftware/spine-runtimes/blob/4.2/LICENSE)。
|
||||
|
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 4.7 MiB After Width: | Height: | Size: 4.7 MiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@@ -1,492 +0,0 @@
|
||||
{
|
||||
"format": "SpineParticle.EditorConfig",
|
||||
"version": 1,
|
||||
"savedAt": "2026-08-31T09:38:45.071Z",
|
||||
"editor": {
|
||||
"viewScale": 6.866040888412048,
|
||||
"viewX": -86.9344445981659,
|
||||
"viewY": 14.683070674664151
|
||||
},
|
||||
"settings": {
|
||||
"tickEnabled": false,
|
||||
"axisFontSize": 12,
|
||||
"tickWidth": 1,
|
||||
"showAxisLabels": true,
|
||||
"axisColor": "#7a86ad",
|
||||
"undoLimit": 20,
|
||||
"backgroundX": 0,
|
||||
"backgroundY": 0,
|
||||
"backgroundOpacity": 1,
|
||||
"backgroundImageName": "",
|
||||
"backgroundImageData": "",
|
||||
"showEmitter": true,
|
||||
"showBones": true,
|
||||
"showSkinMesh": false,
|
||||
"showGrid": true,
|
||||
"exportSettings": {
|
||||
"imagesPath": "./images/",
|
||||
"spineVersion": "4.2",
|
||||
"keyframeCurve": "linear",
|
||||
"fps": 30,
|
||||
"omitFps": false,
|
||||
"integerFrameAlignment": true,
|
||||
"bonePool": true,
|
||||
"excludeEmptyAnimations": false,
|
||||
"fileName": "SpineParticle.json"
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"fps": 30,
|
||||
"loop": true,
|
||||
"animations": [
|
||||
"animation"
|
||||
]
|
||||
},
|
||||
"selection": {
|
||||
"type": "particle",
|
||||
"id": 1
|
||||
},
|
||||
"scene": {
|
||||
"systems": [
|
||||
{
|
||||
"id": 1,
|
||||
"visible": true,
|
||||
"animation": "animation",
|
||||
"config": {
|
||||
"imageResources": [
|
||||
{
|
||||
"id": 1,
|
||||
"textureName": "star",
|
||||
"textureFolder": "",
|
||||
"previewUrl": "/images/star.png",
|
||||
"imageMode": "fixed",
|
||||
"sequencePlayback": "loop-forward",
|
||||
"sequenceFps": 30,
|
||||
"sequenceFrames": [],
|
||||
"weight": 100,
|
||||
"locked": false,
|
||||
"scale": 1,
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
"colorMode": "fixed",
|
||||
"colorStart": "#ffffff",
|
||||
"colorEnd": "#ff4d4d",
|
||||
"colorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ff4d4d"
|
||||
}
|
||||
],
|
||||
"blend": "normal",
|
||||
"independentAlpha": "off",
|
||||
"alpha": 1,
|
||||
"alphaCurveMode": "跟随导出",
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 0.1,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 0.9,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"imageWeightVersion": 1,
|
||||
"name": "ParticleSystem1",
|
||||
"mode": "burst",
|
||||
"rate": 20,
|
||||
"streamBehavior": "normal",
|
||||
"loopDurationFrames": 30,
|
||||
"generateLoopStartAnimation": false,
|
||||
"generateLoopEndAnimation": false,
|
||||
"burstCount": 1,
|
||||
"burstLoop": false,
|
||||
"delay": 0,
|
||||
"duration": 1,
|
||||
"shape": "point",
|
||||
"radius": 30,
|
||||
"rectW": 60,
|
||||
"rectH": 40,
|
||||
"centerX": 0,
|
||||
"centerY": 0,
|
||||
"rootRotation": 0,
|
||||
"rootScaleX": 1,
|
||||
"rootScaleY": 1,
|
||||
"direction": 0,
|
||||
"spread": 360,
|
||||
"coneAngle": 60,
|
||||
"lifeMin": 1,
|
||||
"lifeMax": 1.5,
|
||||
"lifeMode": "fixed",
|
||||
"lifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"speedMin": 271,
|
||||
"speedMax": 307,
|
||||
"speedMode": "random",
|
||||
"speedCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleMin": 0.3,
|
||||
"scaleMax": 0.8,
|
||||
"scaleMode": "random",
|
||||
"scaleAxisMode": "uniform",
|
||||
"scaleYMin": 0.3,
|
||||
"scaleYMax": 0.8,
|
||||
"scaleCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleYCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleEndRatio": 0.3,
|
||||
"initialRotationMode": "random",
|
||||
"initialRotationMin": 0,
|
||||
"initialRotationMax": 360,
|
||||
"initialRotationCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"alpha": 0.9,
|
||||
"alphaEnd": 0,
|
||||
"rotationSpeedMin": -180,
|
||||
"rotationSpeedMax": 180,
|
||||
"speedOverLifeEnabled": false,
|
||||
"speedOverLifeMode": "fixed",
|
||||
"speedOverLifeMin": 1,
|
||||
"speedOverLifeMax": 1,
|
||||
"speedOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleOverLifeEnabled": false,
|
||||
"scaleOverLifeMode": "curve",
|
||||
"scaleOverLifeAxisMode": "uniform",
|
||||
"scaleOverLifeMin": 0,
|
||||
"scaleOverLifeMax": 1,
|
||||
"scaleYOverLifeMin": 0,
|
||||
"scaleYOverLifeMax": 1,
|
||||
"scaleOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleYOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"rotationOverLifeEnabled": false,
|
||||
"rotationOverLifeMode": "random",
|
||||
"rotationOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"gravity": 980,
|
||||
"gravityMode": "fixed",
|
||||
"gravityMin": 980,
|
||||
"gravityMax": 980,
|
||||
"gravityDirection": -90,
|
||||
"gravityCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"damping": 0,
|
||||
"seed": 0,
|
||||
"colorStart": "#ffffff",
|
||||
"colorEnd": "#ff4d4d",
|
||||
"colorOverLife": false,
|
||||
"blend": "add",
|
||||
"alphaMode": "curve",
|
||||
"curveMode": "线性",
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 0.2,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 0.8,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 0
|
||||
}
|
||||
],
|
||||
"textureName": "star",
|
||||
"textureFolder": "",
|
||||
"alphaScale": 1,
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
"independentAlpha": "off",
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"noise": false,
|
||||
"noiseAmt": 30,
|
||||
"noiseRange": 100,
|
||||
"noiseSpeed": 1,
|
||||
"useGravity": true,
|
||||
"wind": false,
|
||||
"windX": 0,
|
||||
"windY": 0,
|
||||
"windMode": "fixed",
|
||||
"windMin": 100,
|
||||
"windMax": 100,
|
||||
"windDirection": 0,
|
||||
"windCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"forceField": false,
|
||||
"forceStrength": 10,
|
||||
"forceRadius": 100,
|
||||
"forceCenterX": 0,
|
||||
"forceCenterY": 0,
|
||||
"forceFalloff": "linear",
|
||||
"attraction": false,
|
||||
"attractionCenterX": 200,
|
||||
"attractionCenterY": 0,
|
||||
"attractionRadius": 20,
|
||||
"attractionDuration": 0.5,
|
||||
"attractionDelay": 0.1,
|
||||
"attractionDelayMode": "particle",
|
||||
"attractionPath": "curve",
|
||||
"trail": true,
|
||||
"trailConfigVersion": 3,
|
||||
"trailResources": [
|
||||
{
|
||||
"id": 1,
|
||||
"textureName": "trail",
|
||||
"previewUrl": "/images/trail.png",
|
||||
"weight": 100,
|
||||
"locked": false,
|
||||
"rotation": 0,
|
||||
"colorMode": "particle",
|
||||
"color": "#ffffff",
|
||||
"colorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ffffff"
|
||||
}
|
||||
],
|
||||
"blend": "normal",
|
||||
"alphaMode": "particle",
|
||||
"alpha": 1,
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"boneCount": 5,
|
||||
"length": 100,
|
||||
"width": 100,
|
||||
"widthMode": "particle",
|
||||
"lifeLengthEnabled": false,
|
||||
"lifeLengthCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"shapeEnabled": true,
|
||||
"shapeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trailResourceVersion": 5,
|
||||
"trailTextureName": "trail",
|
||||
"trailPreviewUrl": "/images/trail.png",
|
||||
"trailColorMode": "particle",
|
||||
"trailColor": "#ffffff",
|
||||
"trailColorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ffffff"
|
||||
}
|
||||
],
|
||||
"trailAlphaMode": "particle",
|
||||
"trailAlpha": 1,
|
||||
"trailAlphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailBoneCount": 3,
|
||||
"trailLength": 100,
|
||||
"trailWidth": 100,
|
||||
"trailWidthMode": "particle",
|
||||
"trailLifeLengthEnabled": false,
|
||||
"trailLifeLengthCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailShapeEnabled": false,
|
||||
"trailShapeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailGridRows": 4,
|
||||
"trailGridCols": 5,
|
||||
"collision": false,
|
||||
"pathFollow": false,
|
||||
"emitterFollow": false,
|
||||
"emitterFollowMode": "none",
|
||||
"emitterFollowPathId": 0,
|
||||
"emitterFollowSpineId": 0,
|
||||
"emitterFollowBoneName": "",
|
||||
"emitterFollowBoneOffsetX": 0,
|
||||
"emitterFollowBoneOffsetY": 0,
|
||||
"emitterFollowBoneRotation": 0,
|
||||
"emitterFollowBoneScaleX": 1,
|
||||
"emitterFollowBoneScaleY": 1,
|
||||
"emitterAngleMode": "fixed",
|
||||
"emitterFollowCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"emitterFollowDuration": 2,
|
||||
"emitterFollowSpace": "world",
|
||||
"emitterFollowDirection": "forward",
|
||||
"emitterFollowOffset": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"colliders": [],
|
||||
"paths": [],
|
||||
"spines": []
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,10 @@
|
||||
[
|
||||
{
|
||||
"name": "纯粒子-路径",
|
||||
"file": "纯粒子-路径.json"
|
||||
"name": "粒子-序列帧-拖尾-碰撞-路径-spine",
|
||||
"file": "粒子-序列帧-拖尾-碰撞-路径-spine.json"
|
||||
},
|
||||
{
|
||||
"name": "纯粒子-碰撞",
|
||||
"file": "纯粒子-碰撞.json"
|
||||
},
|
||||
{
|
||||
"name": "纯粒子-spine",
|
||||
"file": "纯粒子-spine.json"
|
||||
},
|
||||
{
|
||||
"name": "纯粒子",
|
||||
"file": "纯粒子.json"
|
||||
},
|
||||
{
|
||||
"name": "空场景",
|
||||
"file": "空场景.json"
|
||||
},
|
||||
{
|
||||
"name": "默认粒子",
|
||||
"file": "默认粒子.json"
|
||||
},
|
||||
{
|
||||
"name": "TrailTest",
|
||||
"file": "TrailTest.json"
|
||||
},
|
||||
{
|
||||
"name": "yanhua",
|
||||
"file": "yanhua.json"
|
||||
"name": "粒子序列帧拖尾",
|
||||
"file": "粒子序列帧拖尾.json"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"format": "SpineParticle.EditorConfig",
|
||||
"version": 1,
|
||||
"savedAt": "2026-08-29T00:00:00.000Z",
|
||||
"editor": {
|
||||
"viewScale": 1,
|
||||
"viewX": 0,
|
||||
"viewY": 0
|
||||
},
|
||||
"settings": {
|
||||
"tickEnabled": false,
|
||||
"axisFontSize": 12,
|
||||
"tickWidth": 1,
|
||||
"showAxisLabels": true,
|
||||
"axisColor": "#7a86ad",
|
||||
"undoLimit": 20,
|
||||
"backgroundX": 0,
|
||||
"backgroundY": 0,
|
||||
"backgroundOpacity": 1,
|
||||
"backgroundImageName": "",
|
||||
"backgroundImageData": "",
|
||||
"showEmitter": true,
|
||||
"showBones": false,
|
||||
"showSkinMesh": false,
|
||||
"showGrid": true
|
||||
},
|
||||
"timeline": {
|
||||
"fps": 30,
|
||||
"loop": true,
|
||||
"animations": ["animation"]
|
||||
},
|
||||
"selection": {
|
||||
"type": "particle",
|
||||
"id": 0
|
||||
},
|
||||
"scene": {
|
||||
"systems": [],
|
||||
"colliders": [],
|
||||
"paths": [],
|
||||
"spines": []
|
||||
}
|
||||
}
|
||||
@@ -1,514 +0,0 @@
|
||||
{
|
||||
"format": "SpineParticle.EditorConfig",
|
||||
"version": 1,
|
||||
"savedAt": "2026-08-29T16:30:02.631Z",
|
||||
"editor": {
|
||||
"viewScale": 0.7971938775510203,
|
||||
"viewX": -195.50844387755103,
|
||||
"viewY": -83.49033163265301
|
||||
},
|
||||
"settings": {
|
||||
"tickEnabled": false,
|
||||
"axisFontSize": 12,
|
||||
"tickWidth": 1,
|
||||
"showAxisLabels": true,
|
||||
"axisColor": "#7a86ad",
|
||||
"undoLimit": 20,
|
||||
"backgroundX": 0,
|
||||
"backgroundY": 0,
|
||||
"backgroundOpacity": 1,
|
||||
"backgroundImageName": "",
|
||||
"backgroundImageData": "",
|
||||
"showEmitter": true,
|
||||
"showBones": false,
|
||||
"showSkinMesh": false,
|
||||
"showGrid": true
|
||||
},
|
||||
"timeline": {
|
||||
"fps": 30,
|
||||
"loop": true,
|
||||
"animations": [
|
||||
"animation"
|
||||
]
|
||||
},
|
||||
"selection": {
|
||||
"type": "collision",
|
||||
"id": 1
|
||||
},
|
||||
"scene": {
|
||||
"systems": [
|
||||
{
|
||||
"id": 1,
|
||||
"visible": true,
|
||||
"animation": "animation",
|
||||
"config": {
|
||||
"imageResources": [
|
||||
{
|
||||
"id": 1,
|
||||
"textureName": "star",
|
||||
"textureFolder": "",
|
||||
"previewUrl": "/particles/star.png",
|
||||
"weight": 100,
|
||||
"locked": false,
|
||||
"scale": 2,
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
"colorMode": "fixed",
|
||||
"colorStart": "#e83030",
|
||||
"colorEnd": "#ff4d4d",
|
||||
"colorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ff4d4d"
|
||||
}
|
||||
],
|
||||
"blend": "normal",
|
||||
"independentAlpha": "off",
|
||||
"alpha": 1,
|
||||
"alphaCurveMode": "跟随导出",
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 0.1,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 0.9,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"imageWeightVersion": 1,
|
||||
"name": "ParticleSystem1",
|
||||
"mode": "stream",
|
||||
"rate": 43,
|
||||
"burstCount": 50,
|
||||
"burstLoop": false,
|
||||
"delay": 0.1,
|
||||
"duration": 12.6333333333333,
|
||||
"shape": "point",
|
||||
"radius": 30,
|
||||
"rectW": 60,
|
||||
"rectH": 40,
|
||||
"centerX": 10,
|
||||
"centerY": -123,
|
||||
"rootRotation": 46,
|
||||
"rootScaleX": 1.95,
|
||||
"rootScaleY": 1.05,
|
||||
"direction": 7,
|
||||
"spread": 335,
|
||||
"coneAngle": 60,
|
||||
"lifeMin": 1,
|
||||
"lifeMax": 1,
|
||||
"lifeMode": "random",
|
||||
"lifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"speedMin": 106,
|
||||
"speedMax": 156,
|
||||
"speedMode": "random",
|
||||
"speedCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleMin": 0.65,
|
||||
"scaleMax": 1.4,
|
||||
"scaleMode": "random",
|
||||
"scaleAxisMode": "uniform",
|
||||
"scaleYMin": 0.3,
|
||||
"scaleYMax": 0.8,
|
||||
"scaleCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleYCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleEndRatio": 0.3,
|
||||
"initialRotationMode": "random",
|
||||
"initialRotationMin": 20,
|
||||
"initialRotationMax": 313,
|
||||
"initialRotationCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"alpha": 0.9,
|
||||
"alphaEnd": 0,
|
||||
"rotationSpeedMin": -310,
|
||||
"rotationSpeedMax": 370,
|
||||
"speedOverLifeEnabled": true,
|
||||
"speedOverLifeMode": "fixed",
|
||||
"speedOverLifeMin": 0.85,
|
||||
"speedOverLifeMax": 1,
|
||||
"speedOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleOverLifeEnabled": true,
|
||||
"scaleOverLifeMode": "curve",
|
||||
"scaleOverLifeAxisMode": "uniform",
|
||||
"scaleOverLifeMin": 0.15,
|
||||
"scaleOverLifeMax": 1.95,
|
||||
"scaleYOverLifeMin": 0,
|
||||
"scaleYOverLifeMax": 1,
|
||||
"scaleOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleYOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"rotationOverLifeEnabled": true,
|
||||
"rotationOverLifeMode": "random",
|
||||
"rotationOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"gravity": 980,
|
||||
"gravityMode": "fixed",
|
||||
"gravityMin": 200,
|
||||
"gravityMax": 980,
|
||||
"gravityDirection": -90,
|
||||
"gravityCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"damping": 0,
|
||||
"seed": 0,
|
||||
"colorStart": "#ffffff",
|
||||
"colorEnd": "#ff4d4d",
|
||||
"colorOverLife": false,
|
||||
"blend": "add",
|
||||
"alphaMode": "curve",
|
||||
"curveMode": "线性",
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 0.2,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 0.8,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 0
|
||||
}
|
||||
],
|
||||
"textureName": "star",
|
||||
"textureFolder": "",
|
||||
"alphaScale": 1,
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
"independentAlpha": "off",
|
||||
"offsetX": 15,
|
||||
"offsetY": -288,
|
||||
"noise": false,
|
||||
"noiseAmt": 30,
|
||||
"noiseRange": 100,
|
||||
"noiseSpeed": 1,
|
||||
"useGravity": true,
|
||||
"wind": true,
|
||||
"windX": 0,
|
||||
"windY": 0,
|
||||
"windMode": "fixed",
|
||||
"windMin": -200,
|
||||
"windMax": 100,
|
||||
"windDirection": 0,
|
||||
"windCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"forceField": false,
|
||||
"forceStrength": 10,
|
||||
"forceRadius": 100,
|
||||
"forceCenterX": 0,
|
||||
"forceCenterY": 0,
|
||||
"forceFalloff": "linear",
|
||||
"attraction": false,
|
||||
"attractionCenterX": 200,
|
||||
"attractionCenterY": 0,
|
||||
"attractionRadius": 20,
|
||||
"attractionDuration": 0.5,
|
||||
"attractionDelay": 0.1,
|
||||
"attractionDelayMode": "particle",
|
||||
"attractionPath": "curve",
|
||||
"trail": false,
|
||||
"trailConfigVersion": 3,
|
||||
"trailResources": [
|
||||
{
|
||||
"id": 1,
|
||||
"textureName": "trail",
|
||||
"previewUrl": "/trails/trail.png",
|
||||
"weight": 100,
|
||||
"locked": false,
|
||||
"rotation": 0,
|
||||
"colorMode": "particle",
|
||||
"color": "#ffffff",
|
||||
"colorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ffffff"
|
||||
}
|
||||
],
|
||||
"blend": "normal",
|
||||
"alphaMode": "particle",
|
||||
"alpha": 1,
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"boneCount": 3,
|
||||
"length": 100,
|
||||
"width": 100,
|
||||
"widthMode": "particle",
|
||||
"lifeLengthEnabled": false,
|
||||
"lifeLengthCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"shapeEnabled": false,
|
||||
"shapeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trailResourceVersion": 5,
|
||||
"trailTextureName": "trail",
|
||||
"trailPreviewUrl": "/trails/trail.png",
|
||||
"trailColorMode": "particle",
|
||||
"trailColor": "#ffffff",
|
||||
"trailColorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ffffff"
|
||||
}
|
||||
],
|
||||
"trailAlphaMode": "particle",
|
||||
"trailAlpha": 1,
|
||||
"trailAlphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailBoneCount": 3,
|
||||
"trailLength": 100,
|
||||
"trailWidth": 100,
|
||||
"trailWidthMode": "particle",
|
||||
"trailLifeLengthEnabled": false,
|
||||
"trailLifeLengthCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailShapeEnabled": false,
|
||||
"trailShapeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailGridRows": 4,
|
||||
"trailGridCols": 4,
|
||||
"collision": false,
|
||||
"pathFollow": false,
|
||||
"emitterFollow": false,
|
||||
"emitterFollowMode": "none",
|
||||
"emitterFollowPathId": 0,
|
||||
"emitterFollowSpineId": 0,
|
||||
"emitterFollowBoneName": "",
|
||||
"emitterFollowBoneOffsetX": 0,
|
||||
"emitterFollowBoneOffsetY": 0,
|
||||
"emitterFollowBoneRotation": 0,
|
||||
"emitterFollowBoneScaleX": 1,
|
||||
"emitterFollowBoneScaleY": 1,
|
||||
"emitterAngleMode": "fixed",
|
||||
"emitterFollowCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"emitterFollowDuration": 2,
|
||||
"emitterFollowSpace": "world",
|
||||
"emitterFollowDirection": "forward",
|
||||
"emitterFollowOffset": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"colliders": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Collider1",
|
||||
"visible": true,
|
||||
"tags": [
|
||||
"Default"
|
||||
],
|
||||
"selectedTag": "Default",
|
||||
"shape": "circle",
|
||||
"enabled": true,
|
||||
"x": -97.84312343749997,
|
||||
"y": -448.23894609375,
|
||||
"rotation": 61,
|
||||
"scaleX": 1,
|
||||
"scaleY": 1,
|
||||
"radius": 227,
|
||||
"radiusX": 70,
|
||||
"radiusY": 45,
|
||||
"width": 120,
|
||||
"height": 80,
|
||||
"sides": 6,
|
||||
"response": "physics",
|
||||
"elasticity": 0.8,
|
||||
"friction": 0.3,
|
||||
"followPath": false,
|
||||
"followPathId": 0,
|
||||
"followDuration": 2,
|
||||
"followPathRotation": false,
|
||||
"followCurveMode": "跟随导出",
|
||||
"followCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"paths": [],
|
||||
"spines": []
|
||||
}
|
||||
}
|
||||
@@ -1,522 +0,0 @@
|
||||
{
|
||||
"format": "SpineParticle.EditorConfig",
|
||||
"version": 1,
|
||||
"savedAt": "2026-08-29T16:31:20.445Z",
|
||||
"editor": {
|
||||
"viewScale": 0.7971938775510203,
|
||||
"viewX": -200.17506985411353,
|
||||
"viewY": -140.15701864437176
|
||||
},
|
||||
"settings": {
|
||||
"tickEnabled": false,
|
||||
"axisFontSize": 12,
|
||||
"tickWidth": 1,
|
||||
"showAxisLabels": true,
|
||||
"axisColor": "#7a86ad",
|
||||
"undoLimit": 20,
|
||||
"backgroundX": 0,
|
||||
"backgroundY": 0,
|
||||
"backgroundOpacity": 1,
|
||||
"backgroundImageName": "",
|
||||
"backgroundImageData": "",
|
||||
"showEmitter": true,
|
||||
"showBones": false,
|
||||
"showSkinMesh": false,
|
||||
"showGrid": true
|
||||
},
|
||||
"timeline": {
|
||||
"fps": 30,
|
||||
"loop": true,
|
||||
"animations": [
|
||||
"animation"
|
||||
]
|
||||
},
|
||||
"selection": {
|
||||
"type": "path",
|
||||
"id": 1
|
||||
},
|
||||
"scene": {
|
||||
"systems": [
|
||||
{
|
||||
"id": 1,
|
||||
"visible": true,
|
||||
"animation": "animation",
|
||||
"config": {
|
||||
"imageResources": [
|
||||
{
|
||||
"id": 1,
|
||||
"textureName": "star",
|
||||
"textureFolder": "",
|
||||
"previewUrl": "/particles/star.png",
|
||||
"weight": 100,
|
||||
"locked": false,
|
||||
"scale": 2,
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
"colorMode": "fixed",
|
||||
"colorStart": "#e83030",
|
||||
"colorEnd": "#ff4d4d",
|
||||
"colorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ff4d4d"
|
||||
}
|
||||
],
|
||||
"blend": "normal",
|
||||
"independentAlpha": "off",
|
||||
"alpha": 1,
|
||||
"alphaCurveMode": "跟随导出",
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 0.1,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 0.9,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"imageWeightVersion": 1,
|
||||
"name": "ParticleSystem1",
|
||||
"mode": "stream",
|
||||
"rate": 43,
|
||||
"burstCount": 50,
|
||||
"burstLoop": false,
|
||||
"delay": 0.1,
|
||||
"duration": 12.6333333333333,
|
||||
"shape": "point",
|
||||
"radius": 30,
|
||||
"rectW": 60,
|
||||
"rectH": 40,
|
||||
"centerX": 10,
|
||||
"centerY": -123,
|
||||
"rootRotation": 46,
|
||||
"rootScaleX": 1.95,
|
||||
"rootScaleY": 1.05,
|
||||
"direction": 7,
|
||||
"spread": 335,
|
||||
"coneAngle": 60,
|
||||
"lifeMin": 1,
|
||||
"lifeMax": 1,
|
||||
"lifeMode": "random",
|
||||
"lifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"speedMin": 106,
|
||||
"speedMax": 156,
|
||||
"speedMode": "random",
|
||||
"speedCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleMin": 0.65,
|
||||
"scaleMax": 1.4,
|
||||
"scaleMode": "random",
|
||||
"scaleAxisMode": "uniform",
|
||||
"scaleYMin": 0.3,
|
||||
"scaleYMax": 0.8,
|
||||
"scaleCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleYCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleEndRatio": 0.3,
|
||||
"initialRotationMode": "random",
|
||||
"initialRotationMin": 20,
|
||||
"initialRotationMax": 313,
|
||||
"initialRotationCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"alpha": 0.9,
|
||||
"alphaEnd": 0,
|
||||
"rotationSpeedMin": -310,
|
||||
"rotationSpeedMax": 370,
|
||||
"speedOverLifeEnabled": true,
|
||||
"speedOverLifeMode": "fixed",
|
||||
"speedOverLifeMin": 0.85,
|
||||
"speedOverLifeMax": 1,
|
||||
"speedOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleOverLifeEnabled": true,
|
||||
"scaleOverLifeMode": "curve",
|
||||
"scaleOverLifeAxisMode": "uniform",
|
||||
"scaleOverLifeMin": 0.15,
|
||||
"scaleOverLifeMax": 1.95,
|
||||
"scaleYOverLifeMin": 0,
|
||||
"scaleYOverLifeMax": 1,
|
||||
"scaleOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleYOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"rotationOverLifeEnabled": true,
|
||||
"rotationOverLifeMode": "random",
|
||||
"rotationOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"gravity": 980,
|
||||
"gravityMode": "fixed",
|
||||
"gravityMin": 200,
|
||||
"gravityMax": 980,
|
||||
"gravityDirection": -90,
|
||||
"gravityCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"damping": 0,
|
||||
"seed": 0,
|
||||
"colorStart": "#ffffff",
|
||||
"colorEnd": "#ff4d4d",
|
||||
"colorOverLife": false,
|
||||
"blend": "add",
|
||||
"alphaMode": "curve",
|
||||
"curveMode": "线性",
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 0.2,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 0.8,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 0
|
||||
}
|
||||
],
|
||||
"textureName": "star",
|
||||
"textureFolder": "",
|
||||
"alphaScale": 1,
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
"independentAlpha": "off",
|
||||
"offsetX": 15,
|
||||
"offsetY": -288,
|
||||
"noise": false,
|
||||
"noiseAmt": 30,
|
||||
"noiseRange": 100,
|
||||
"noiseSpeed": 1,
|
||||
"useGravity": true,
|
||||
"wind": true,
|
||||
"windX": 0,
|
||||
"windY": 0,
|
||||
"windMode": "fixed",
|
||||
"windMin": -200,
|
||||
"windMax": 100,
|
||||
"windDirection": 0,
|
||||
"windCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"forceField": false,
|
||||
"forceStrength": 10,
|
||||
"forceRadius": 100,
|
||||
"forceCenterX": 0,
|
||||
"forceCenterY": 0,
|
||||
"forceFalloff": "linear",
|
||||
"attraction": false,
|
||||
"attractionCenterX": 200,
|
||||
"attractionCenterY": 0,
|
||||
"attractionRadius": 20,
|
||||
"attractionDuration": 0.5,
|
||||
"attractionDelay": 0.1,
|
||||
"attractionDelayMode": "particle",
|
||||
"attractionPath": "curve",
|
||||
"trail": false,
|
||||
"trailConfigVersion": 3,
|
||||
"trailResources": [
|
||||
{
|
||||
"id": 1,
|
||||
"textureName": "trail",
|
||||
"previewUrl": "/trails/trail.png",
|
||||
"weight": 100,
|
||||
"locked": false,
|
||||
"rotation": 0,
|
||||
"colorMode": "particle",
|
||||
"color": "#ffffff",
|
||||
"colorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ffffff"
|
||||
}
|
||||
],
|
||||
"blend": "normal",
|
||||
"alphaMode": "particle",
|
||||
"alpha": 1,
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"boneCount": 3,
|
||||
"length": 100,
|
||||
"width": 100,
|
||||
"widthMode": "particle",
|
||||
"lifeLengthEnabled": false,
|
||||
"lifeLengthCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"shapeEnabled": false,
|
||||
"shapeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trailResourceVersion": 5,
|
||||
"trailTextureName": "trail",
|
||||
"trailPreviewUrl": "/trails/trail.png",
|
||||
"trailColorMode": "particle",
|
||||
"trailColor": "#ffffff",
|
||||
"trailColorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ffffff"
|
||||
}
|
||||
],
|
||||
"trailAlphaMode": "particle",
|
||||
"trailAlpha": 1,
|
||||
"trailAlphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailBoneCount": 3,
|
||||
"trailLength": 100,
|
||||
"trailWidth": 100,
|
||||
"trailWidthMode": "particle",
|
||||
"trailLifeLengthEnabled": false,
|
||||
"trailLifeLengthCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailShapeEnabled": false,
|
||||
"trailShapeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailGridRows": 4,
|
||||
"trailGridCols": 4,
|
||||
"collision": false,
|
||||
"pathFollow": false,
|
||||
"emitterFollow": false,
|
||||
"emitterFollowMode": "none",
|
||||
"emitterFollowPathId": 0,
|
||||
"emitterFollowSpineId": 0,
|
||||
"emitterFollowBoneName": "",
|
||||
"emitterFollowBoneOffsetX": 0,
|
||||
"emitterFollowBoneOffsetY": 0,
|
||||
"emitterFollowBoneRotation": 0,
|
||||
"emitterFollowBoneScaleX": 1,
|
||||
"emitterFollowBoneScaleY": 1,
|
||||
"emitterAngleMode": "fixed",
|
||||
"emitterFollowCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"emitterFollowDuration": 2,
|
||||
"emitterFollowSpace": "world",
|
||||
"emitterFollowDirection": "forward",
|
||||
"emitterFollowOffset": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"colliders": [],
|
||||
"paths": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Path1",
|
||||
"visible": true,
|
||||
"enabled": true,
|
||||
"x": -320.2901078125,
|
||||
"y": 86.97174609375001,
|
||||
"rotation": 55,
|
||||
"scaleX": 1,
|
||||
"scaleY": 2,
|
||||
"closed": true,
|
||||
"color": "#ff933e",
|
||||
"preset": "square",
|
||||
"points": [
|
||||
{
|
||||
"x": -100,
|
||||
"y": -100,
|
||||
"inX": 0,
|
||||
"inY": 0,
|
||||
"outX": 0,
|
||||
"outY": 0
|
||||
},
|
||||
{
|
||||
"x": 100,
|
||||
"y": -100,
|
||||
"inX": 0,
|
||||
"inY": 0,
|
||||
"outX": 0,
|
||||
"outY": 0
|
||||
},
|
||||
{
|
||||
"x": 100,
|
||||
"y": 100,
|
||||
"inX": 0,
|
||||
"inY": 0,
|
||||
"outX": 0,
|
||||
"outY": 0
|
||||
},
|
||||
{
|
||||
"x": -100,
|
||||
"y": 100,
|
||||
"inX": 0,
|
||||
"inY": 0,
|
||||
"outX": 0,
|
||||
"outY": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"spines": []
|
||||
}
|
||||
}
|
||||
@@ -1,473 +0,0 @@
|
||||
{
|
||||
"format": "SpineParticle.EditorConfig",
|
||||
"version": 1,
|
||||
"savedAt": "2026-08-29T16:29:28.329Z",
|
||||
"editor": {
|
||||
"viewScale": 0.7971938775510203,
|
||||
"viewX": -195.50844387755103,
|
||||
"viewY": -83.49033163265301
|
||||
},
|
||||
"settings": {
|
||||
"tickEnabled": false,
|
||||
"axisFontSize": 12,
|
||||
"tickWidth": 1,
|
||||
"showAxisLabels": true,
|
||||
"axisColor": "#7a86ad",
|
||||
"undoLimit": 20,
|
||||
"backgroundX": 0,
|
||||
"backgroundY": 0,
|
||||
"backgroundOpacity": 1,
|
||||
"backgroundImageName": "",
|
||||
"backgroundImageData": "",
|
||||
"showEmitter": true,
|
||||
"showBones": false,
|
||||
"showSkinMesh": false,
|
||||
"showGrid": true
|
||||
},
|
||||
"timeline": {
|
||||
"fps": 30,
|
||||
"loop": true,
|
||||
"animations": [
|
||||
"animation"
|
||||
]
|
||||
},
|
||||
"selection": {
|
||||
"type": "particle",
|
||||
"id": 1
|
||||
},
|
||||
"scene": {
|
||||
"systems": [
|
||||
{
|
||||
"id": 1,
|
||||
"visible": true,
|
||||
"animation": "animation",
|
||||
"config": {
|
||||
"imageResources": [
|
||||
{
|
||||
"id": 1,
|
||||
"textureName": "star",
|
||||
"textureFolder": "",
|
||||
"previewUrl": "/particles/star.png",
|
||||
"weight": 100,
|
||||
"locked": false,
|
||||
"scale": 2,
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
"colorMode": "fixed",
|
||||
"colorStart": "#e83030",
|
||||
"colorEnd": "#ff4d4d",
|
||||
"colorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ff4d4d"
|
||||
}
|
||||
],
|
||||
"blend": "normal",
|
||||
"independentAlpha": "off",
|
||||
"alpha": 1,
|
||||
"alphaCurveMode": "跟随导出",
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 0.1,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 0.9,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"imageWeightVersion": 1,
|
||||
"name": "ParticleSystem1",
|
||||
"mode": "stream",
|
||||
"rate": 43,
|
||||
"burstCount": 50,
|
||||
"burstLoop": false,
|
||||
"delay": 0.1,
|
||||
"duration": 12.6333333333333,
|
||||
"shape": "point",
|
||||
"radius": 30,
|
||||
"rectW": 60,
|
||||
"rectH": 40,
|
||||
"centerX": 10,
|
||||
"centerY": -123,
|
||||
"rootRotation": 46,
|
||||
"rootScaleX": 1.95,
|
||||
"rootScaleY": 1.05,
|
||||
"direction": 7,
|
||||
"spread": 335,
|
||||
"coneAngle": 60,
|
||||
"lifeMin": 1,
|
||||
"lifeMax": 1,
|
||||
"lifeMode": "random",
|
||||
"lifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"speedMin": 106,
|
||||
"speedMax": 156,
|
||||
"speedMode": "random",
|
||||
"speedCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleMin": 0.65,
|
||||
"scaleMax": 1.4,
|
||||
"scaleMode": "random",
|
||||
"scaleAxisMode": "uniform",
|
||||
"scaleYMin": 0.3,
|
||||
"scaleYMax": 0.8,
|
||||
"scaleCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleYCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleEndRatio": 0.3,
|
||||
"initialRotationMode": "random",
|
||||
"initialRotationMin": 20,
|
||||
"initialRotationMax": 313,
|
||||
"initialRotationCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"alpha": 0.9,
|
||||
"alphaEnd": 0,
|
||||
"rotationSpeedMin": -310,
|
||||
"rotationSpeedMax": 370,
|
||||
"speedOverLifeEnabled": true,
|
||||
"speedOverLifeMode": "fixed",
|
||||
"speedOverLifeMin": 0.85,
|
||||
"speedOverLifeMax": 1,
|
||||
"speedOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleOverLifeEnabled": true,
|
||||
"scaleOverLifeMode": "curve",
|
||||
"scaleOverLifeAxisMode": "uniform",
|
||||
"scaleOverLifeMin": 0.15,
|
||||
"scaleOverLifeMax": 1.95,
|
||||
"scaleYOverLifeMin": 0,
|
||||
"scaleYOverLifeMax": 1,
|
||||
"scaleOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleYOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"rotationOverLifeEnabled": true,
|
||||
"rotationOverLifeMode": "random",
|
||||
"rotationOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"gravity": 980,
|
||||
"gravityMode": "fixed",
|
||||
"gravityMin": 200,
|
||||
"gravityMax": 980,
|
||||
"gravityDirection": -90,
|
||||
"gravityCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"damping": 0,
|
||||
"seed": 0,
|
||||
"colorStart": "#ffffff",
|
||||
"colorEnd": "#ff4d4d",
|
||||
"colorOverLife": false,
|
||||
"blend": "add",
|
||||
"alphaMode": "curve",
|
||||
"curveMode": "线性",
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 0.2,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 0.8,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 0
|
||||
}
|
||||
],
|
||||
"textureName": "star",
|
||||
"textureFolder": "",
|
||||
"alphaScale": 1,
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
"independentAlpha": "off",
|
||||
"offsetX": 15,
|
||||
"offsetY": -288,
|
||||
"noise": false,
|
||||
"noiseAmt": 30,
|
||||
"noiseRange": 100,
|
||||
"noiseSpeed": 1,
|
||||
"useGravity": true,
|
||||
"wind": true,
|
||||
"windX": 0,
|
||||
"windY": 0,
|
||||
"windMode": "fixed",
|
||||
"windMin": -200,
|
||||
"windMax": 100,
|
||||
"windDirection": 0,
|
||||
"windCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"forceField": false,
|
||||
"forceStrength": 10,
|
||||
"forceRadius": 100,
|
||||
"forceCenterX": 0,
|
||||
"forceCenterY": 0,
|
||||
"forceFalloff": "linear",
|
||||
"attraction": false,
|
||||
"attractionCenterX": 200,
|
||||
"attractionCenterY": 0,
|
||||
"attractionRadius": 20,
|
||||
"attractionDuration": 0.5,
|
||||
"attractionDelay": 0.1,
|
||||
"attractionDelayMode": "particle",
|
||||
"attractionPath": "curve",
|
||||
"trail": false,
|
||||
"trailConfigVersion": 3,
|
||||
"trailResources": [
|
||||
{
|
||||
"id": 1,
|
||||
"textureName": "trail",
|
||||
"previewUrl": "/trails/trail.png",
|
||||
"weight": 100,
|
||||
"locked": false,
|
||||
"rotation": 0,
|
||||
"colorMode": "particle",
|
||||
"color": "#ffffff",
|
||||
"colorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ffffff"
|
||||
}
|
||||
],
|
||||
"blend": "normal",
|
||||
"alphaMode": "particle",
|
||||
"alpha": 1,
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"boneCount": 3,
|
||||
"length": 100,
|
||||
"width": 100,
|
||||
"widthMode": "particle",
|
||||
"lifeLengthEnabled": false,
|
||||
"lifeLengthCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"shapeEnabled": false,
|
||||
"shapeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trailResourceVersion": 5,
|
||||
"trailTextureName": "trail",
|
||||
"trailPreviewUrl": "/trails/trail.png",
|
||||
"trailColorMode": "particle",
|
||||
"trailColor": "#ffffff",
|
||||
"trailColorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ffffff"
|
||||
}
|
||||
],
|
||||
"trailAlphaMode": "particle",
|
||||
"trailAlpha": 1,
|
||||
"trailAlphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailBoneCount": 3,
|
||||
"trailLength": 100,
|
||||
"trailWidth": 100,
|
||||
"trailWidthMode": "particle",
|
||||
"trailLifeLengthEnabled": false,
|
||||
"trailLifeLengthCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailShapeEnabled": false,
|
||||
"trailShapeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailGridRows": 4,
|
||||
"trailGridCols": 4,
|
||||
"collision": false,
|
||||
"pathFollow": false,
|
||||
"emitterFollow": false,
|
||||
"emitterFollowMode": "none",
|
||||
"emitterFollowPathId": 0,
|
||||
"emitterFollowSpineId": 0,
|
||||
"emitterFollowBoneName": "",
|
||||
"emitterFollowBoneOffsetX": 0,
|
||||
"emitterFollowBoneOffsetY": 0,
|
||||
"emitterFollowBoneRotation": 0,
|
||||
"emitterFollowBoneScaleX": 1,
|
||||
"emitterFollowBoneScaleY": 1,
|
||||
"emitterAngleMode": "fixed",
|
||||
"emitterFollowCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"emitterFollowDuration": 2,
|
||||
"emitterFollowSpace": "world",
|
||||
"emitterFollowDirection": "forward",
|
||||
"emitterFollowOffset": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"colliders": [],
|
||||
"paths": [],
|
||||
"spines": []
|
||||
}
|
||||
}
|
||||
@@ -1,473 +0,0 @@
|
||||
{
|
||||
"format": "SpineParticle.EditorConfig",
|
||||
"version": 1,
|
||||
"savedAt": "2026-08-29T14:25:58.695Z",
|
||||
"editor": {
|
||||
"viewScale": 1.12,
|
||||
"viewX": -7.944298618861609,
|
||||
"viewY": -12.270927472795819
|
||||
},
|
||||
"settings": {
|
||||
"tickEnabled": false,
|
||||
"axisFontSize": 12,
|
||||
"tickWidth": 1,
|
||||
"showAxisLabels": true,
|
||||
"axisColor": "#7a86ad",
|
||||
"undoLimit": 20,
|
||||
"backgroundX": 0,
|
||||
"backgroundY": 0,
|
||||
"backgroundOpacity": 1,
|
||||
"backgroundImageName": "",
|
||||
"backgroundImageData": "",
|
||||
"showEmitter": true,
|
||||
"showBones": false,
|
||||
"showSkinMesh": false,
|
||||
"showGrid": true
|
||||
},
|
||||
"timeline": {
|
||||
"fps": 30,
|
||||
"loop": true,
|
||||
"animations": [
|
||||
"animation"
|
||||
]
|
||||
},
|
||||
"selection": {
|
||||
"type": "particle",
|
||||
"id": 2
|
||||
},
|
||||
"scene": {
|
||||
"systems": [
|
||||
{
|
||||
"id": 2,
|
||||
"visible": true,
|
||||
"animation": "animation",
|
||||
"config": {
|
||||
"imageResources": [
|
||||
{
|
||||
"id": 1,
|
||||
"textureName": "star",
|
||||
"textureFolder": "",
|
||||
"previewUrl": "/particles/star.png",
|
||||
"weight": 100,
|
||||
"locked": false,
|
||||
"scale": 1,
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
"colorMode": "fixed",
|
||||
"colorStart": "#ffffff",
|
||||
"colorEnd": "#ff4d4d",
|
||||
"colorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ff4d4d"
|
||||
}
|
||||
],
|
||||
"blend": "normal",
|
||||
"independentAlpha": "off",
|
||||
"alpha": 1,
|
||||
"alphaCurveMode": "跟随导出",
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 0.1,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 0.9,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"imageWeightVersion": 1,
|
||||
"name": "ParticleSystem1",
|
||||
"mode": "stream",
|
||||
"rate": 20,
|
||||
"burstCount": 50,
|
||||
"burstLoop": false,
|
||||
"delay": 0,
|
||||
"duration": 1,
|
||||
"shape": "point",
|
||||
"radius": 30,
|
||||
"rectW": 60,
|
||||
"rectH": 40,
|
||||
"centerX": 0,
|
||||
"centerY": 0,
|
||||
"rootRotation": 0,
|
||||
"rootScaleX": 1,
|
||||
"rootScaleY": 1,
|
||||
"direction": 0,
|
||||
"spread": 360,
|
||||
"coneAngle": 60,
|
||||
"lifeMin": 0.6,
|
||||
"lifeMax": 1.8,
|
||||
"lifeMode": "random",
|
||||
"lifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"speedMin": 30,
|
||||
"speedMax": 140,
|
||||
"speedMode": "random",
|
||||
"speedCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleMin": 0.3,
|
||||
"scaleMax": 0.8,
|
||||
"scaleMode": "random",
|
||||
"scaleAxisMode": "uniform",
|
||||
"scaleYMin": 0.3,
|
||||
"scaleYMax": 0.8,
|
||||
"scaleCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleYCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleEndRatio": 0.3,
|
||||
"initialRotationMode": "random",
|
||||
"initialRotationMin": 0,
|
||||
"initialRotationMax": 360,
|
||||
"initialRotationCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"alpha": 0.9,
|
||||
"alphaEnd": 0,
|
||||
"rotationSpeedMin": -180,
|
||||
"rotationSpeedMax": 180,
|
||||
"speedOverLifeEnabled": false,
|
||||
"speedOverLifeMode": "fixed",
|
||||
"speedOverLifeMin": 1,
|
||||
"speedOverLifeMax": 1,
|
||||
"speedOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleOverLifeEnabled": false,
|
||||
"scaleOverLifeMode": "curve",
|
||||
"scaleOverLifeAxisMode": "uniform",
|
||||
"scaleOverLifeMin": 0,
|
||||
"scaleOverLifeMax": 1,
|
||||
"scaleYOverLifeMin": 0,
|
||||
"scaleYOverLifeMax": 1,
|
||||
"scaleOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"scaleYOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"rotationOverLifeEnabled": false,
|
||||
"rotationOverLifeMode": "random",
|
||||
"rotationOverLifeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"gravity": 980,
|
||||
"gravityMode": "fixed",
|
||||
"gravityMin": 980,
|
||||
"gravityMax": 980,
|
||||
"gravityDirection": -90,
|
||||
"gravityCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"damping": 0,
|
||||
"seed": 0,
|
||||
"colorStart": "#ffffff",
|
||||
"colorEnd": "#ff4d4d",
|
||||
"colorOverLife": false,
|
||||
"blend": "add",
|
||||
"alphaMode": "curve",
|
||||
"curveMode": "线性",
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 0.2,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 0.8,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 0
|
||||
}
|
||||
],
|
||||
"textureName": "star",
|
||||
"textureFolder": "",
|
||||
"alphaScale": 1,
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
"independentAlpha": "off",
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"noise": false,
|
||||
"noiseAmt": 30,
|
||||
"noiseRange": 100,
|
||||
"noiseSpeed": 1,
|
||||
"useGravity": false,
|
||||
"wind": false,
|
||||
"windX": 0,
|
||||
"windY": 0,
|
||||
"windMode": "fixed",
|
||||
"windMin": 100,
|
||||
"windMax": 100,
|
||||
"windDirection": 0,
|
||||
"windCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"forceField": false,
|
||||
"forceStrength": 10,
|
||||
"forceRadius": 100,
|
||||
"forceCenterX": 0,
|
||||
"forceCenterY": 0,
|
||||
"forceFalloff": "linear",
|
||||
"attraction": false,
|
||||
"attractionCenterX": 200,
|
||||
"attractionCenterY": 0,
|
||||
"attractionRadius": 20,
|
||||
"attractionDuration": 0.5,
|
||||
"attractionDelay": 0.1,
|
||||
"attractionDelayMode": "particle",
|
||||
"attractionPath": "curve",
|
||||
"trail": false,
|
||||
"trailConfigVersion": 3,
|
||||
"trailResources": [
|
||||
{
|
||||
"id": 1,
|
||||
"textureName": "trail",
|
||||
"previewUrl": "/trails/trail.png",
|
||||
"weight": 100,
|
||||
"locked": false,
|
||||
"rotation": 0,
|
||||
"colorMode": "particle",
|
||||
"color": "#ffffff",
|
||||
"colorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ffffff"
|
||||
}
|
||||
],
|
||||
"blend": "normal",
|
||||
"alphaMode": "particle",
|
||||
"alpha": 1,
|
||||
"alphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"boneCount": 3,
|
||||
"length": 100,
|
||||
"width": 100,
|
||||
"widthMode": "particle",
|
||||
"lifeLengthEnabled": false,
|
||||
"lifeLengthCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"shapeEnabled": false,
|
||||
"shapeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"trailResourceVersion": 5,
|
||||
"trailTextureName": "trail",
|
||||
"trailPreviewUrl": "/trails/trail.png",
|
||||
"trailColorMode": "particle",
|
||||
"trailColor": "#ffffff",
|
||||
"trailColorGradient": [
|
||||
{
|
||||
"position": 0,
|
||||
"color": "#ffffff"
|
||||
},
|
||||
{
|
||||
"position": 1,
|
||||
"color": "#ffffff"
|
||||
}
|
||||
],
|
||||
"trailAlphaMode": "particle",
|
||||
"trailAlpha": 1,
|
||||
"trailAlphaCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailBoneCount": 3,
|
||||
"trailLength": 100,
|
||||
"trailWidth": 100,
|
||||
"trailWidthMode": "particle",
|
||||
"trailLifeLengthEnabled": false,
|
||||
"trailLifeLengthCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailShapeEnabled": false,
|
||||
"trailShapeCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 1
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"trailGridRows": 4,
|
||||
"trailGridCols": 4,
|
||||
"collision": false,
|
||||
"pathFollow": false,
|
||||
"emitterFollow": false,
|
||||
"emitterFollowMode": "none",
|
||||
"emitterFollowPathId": 0,
|
||||
"emitterFollowSpineId": 0,
|
||||
"emitterFollowBoneName": "",
|
||||
"emitterFollowBoneOffsetX": 0,
|
||||
"emitterFollowBoneOffsetY": 0,
|
||||
"emitterFollowBoneRotation": 0,
|
||||
"emitterFollowBoneScaleX": 1,
|
||||
"emitterFollowBoneScaleY": 1,
|
||||
"emitterAngleMode": "fixed",
|
||||
"emitterFollowCurve": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
{
|
||||
"x": 1,
|
||||
"y": 1
|
||||
}
|
||||
],
|
||||
"emitterFollowDuration": 2,
|
||||
"emitterFollowSpace": "world",
|
||||
"emitterFollowDirection": "forward",
|
||||
"emitterFollowOffset": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"colliders": [],
|
||||
"paths": [],
|
||||
"spines": []
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,286 @@
|
||||
|
||||
spineboy.png
|
||||
size: 1024,256
|
||||
format: RGBA8888
|
||||
filter: Linear,Linear
|
||||
repeat: none
|
||||
crosshair
|
||||
rotate: false
|
||||
xy: 352, 7
|
||||
size: 45, 45
|
||||
orig: 45, 45
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
eye-indifferent
|
||||
rotate: false
|
||||
xy: 862, 105
|
||||
size: 47, 45
|
||||
orig: 47, 45
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
eye-surprised
|
||||
rotate: false
|
||||
xy: 505, 79
|
||||
size: 47, 45
|
||||
orig: 47, 45
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-bracer
|
||||
rotate: false
|
||||
xy: 826, 66
|
||||
size: 29, 40
|
||||
orig: 29, 40
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-fist-closed
|
||||
rotate: false
|
||||
xy: 786, 65
|
||||
size: 38, 41
|
||||
orig: 38, 41
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-fist-open
|
||||
rotate: true
|
||||
xy: 710, 51
|
||||
size: 43, 44
|
||||
orig: 43, 44
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-foot
|
||||
rotate: false
|
||||
xy: 210, 6
|
||||
size: 63, 35
|
||||
orig: 63, 35
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-shin
|
||||
rotate: true
|
||||
xy: 665, 128
|
||||
size: 41, 92
|
||||
orig: 41, 92
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-thigh
|
||||
rotate: true
|
||||
xy: 2, 2
|
||||
size: 23, 56
|
||||
orig: 23, 56
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
front-upper-arm
|
||||
rotate: false
|
||||
xy: 250, 205
|
||||
size: 23, 49
|
||||
orig: 23, 49
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
goggles
|
||||
rotate: false
|
||||
xy: 665, 171
|
||||
size: 131, 83
|
||||
orig: 131, 83
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
gun
|
||||
rotate: false
|
||||
xy: 798, 152
|
||||
size: 105, 102
|
||||
orig: 105, 102
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
head
|
||||
rotate: false
|
||||
xy: 2, 27
|
||||
size: 136, 149
|
||||
orig: 136, 149
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
hoverboard-board
|
||||
rotate: false
|
||||
xy: 2, 178
|
||||
size: 246, 76
|
||||
orig: 246, 76
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
hoverboard-thruster
|
||||
rotate: true
|
||||
xy: 722, 96
|
||||
size: 30, 32
|
||||
orig: 30, 32
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
hoverglow-small
|
||||
rotate: false
|
||||
xy: 275, 81
|
||||
size: 137, 38
|
||||
orig: 137, 38
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
mouth-grind
|
||||
rotate: false
|
||||
xy: 614, 97
|
||||
size: 47, 30
|
||||
orig: 47, 30
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
mouth-oooo
|
||||
rotate: false
|
||||
xy: 612, 65
|
||||
size: 47, 30
|
||||
orig: 47, 30
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
mouth-smile
|
||||
rotate: false
|
||||
xy: 661, 64
|
||||
size: 47, 30
|
||||
orig: 47, 30
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle-glow
|
||||
rotate: false
|
||||
xy: 382, 54
|
||||
size: 25, 25
|
||||
orig: 25, 25
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle-ring
|
||||
rotate: true
|
||||
xy: 275, 54
|
||||
size: 25, 105
|
||||
orig: 25, 105
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle01
|
||||
rotate: true
|
||||
xy: 911, 95
|
||||
size: 67, 40
|
||||
orig: 67, 40
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle02
|
||||
rotate: false
|
||||
xy: 792, 108
|
||||
size: 68, 42
|
||||
orig: 68, 42
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle03
|
||||
rotate: true
|
||||
xy: 956, 171
|
||||
size: 83, 53
|
||||
orig: 83, 53
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle04
|
||||
rotate: false
|
||||
xy: 275, 7
|
||||
size: 75, 45
|
||||
orig: 75, 45
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
muzzle05
|
||||
rotate: false
|
||||
xy: 140, 3
|
||||
size: 68, 38
|
||||
orig: 68, 38
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
neck
|
||||
rotate: false
|
||||
xy: 250, 182
|
||||
size: 18, 21
|
||||
orig: 18, 21
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-bg
|
||||
rotate: false
|
||||
xy: 140, 43
|
||||
size: 133, 133
|
||||
orig: 133, 133
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-flare1
|
||||
rotate: false
|
||||
xy: 554, 65
|
||||
size: 56, 30
|
||||
orig: 56, 30
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-flare2
|
||||
rotate: true
|
||||
xy: 759, 112
|
||||
size: 57, 31
|
||||
orig: 57, 31
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-flare3
|
||||
rotate: false
|
||||
xy: 554, 97
|
||||
size: 58, 30
|
||||
orig: 58, 30
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-shade
|
||||
rotate: false
|
||||
xy: 275, 121
|
||||
size: 133, 133
|
||||
orig: 133, 133
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-streaks1
|
||||
rotate: false
|
||||
xy: 410, 126
|
||||
size: 126, 128
|
||||
orig: 126, 128
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
portal-streaks2
|
||||
rotate: false
|
||||
xy: 538, 129
|
||||
size: 125, 125
|
||||
orig: 125, 125
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear-bracer
|
||||
rotate: false
|
||||
xy: 857, 67
|
||||
size: 28, 36
|
||||
orig: 28, 36
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear-foot
|
||||
rotate: false
|
||||
xy: 663, 96
|
||||
size: 57, 30
|
||||
orig: 57, 30
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear-shin
|
||||
rotate: true
|
||||
xy: 414, 86
|
||||
size: 38, 89
|
||||
orig: 38, 89
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear-thigh
|
||||
rotate: false
|
||||
xy: 756, 63
|
||||
size: 28, 47
|
||||
orig: 28, 47
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
rear-upper-arm
|
||||
rotate: true
|
||||
xy: 60, 5
|
||||
size: 20, 44
|
||||
orig: 20, 44
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
torso
|
||||
rotate: false
|
||||
xy: 905, 164
|
||||
size: 49, 90
|
||||
orig: 49, 90
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
|
After Width: | Height: | Size: 255 KiB |
@@ -0,0 +1,101 @@
|
||||
spineboy.png
|
||||
size: 1024, 256
|
||||
filter: Linear, Linear
|
||||
scale: 0.5
|
||||
crosshair
|
||||
bounds: 813, 160, 45, 45
|
||||
eye-indifferent
|
||||
bounds: 569, 2, 47, 45
|
||||
eye-surprised
|
||||
bounds: 643, 7, 47, 45
|
||||
rotate: 90
|
||||
front-bracer
|
||||
bounds: 811, 51, 29, 40
|
||||
front-fist-closed
|
||||
bounds: 807, 93, 38, 41
|
||||
front-fist-open
|
||||
bounds: 815, 210, 43, 44
|
||||
front-foot
|
||||
bounds: 706, 64, 63, 35
|
||||
rotate: 90
|
||||
front-shin
|
||||
bounds: 80, 11, 41, 92
|
||||
front-thigh
|
||||
bounds: 754, 12, 23, 56
|
||||
front-upper-arm
|
||||
bounds: 618, 5, 23, 49
|
||||
goggles
|
||||
bounds: 214, 20, 131, 83
|
||||
gun
|
||||
bounds: 347, 14, 105, 102
|
||||
rotate: 90
|
||||
head
|
||||
bounds: 80, 105, 136, 149
|
||||
hoverboard-board
|
||||
bounds: 2, 8, 246, 76
|
||||
rotate: 90
|
||||
hoverboard-thruster
|
||||
bounds: 478, 2, 30, 32
|
||||
hoverglow-small
|
||||
bounds: 218, 117, 137, 38
|
||||
rotate: 90
|
||||
mouth-grind
|
||||
bounds: 775, 80, 47, 30
|
||||
rotate: 90
|
||||
mouth-oooo
|
||||
bounds: 779, 31, 47, 30
|
||||
rotate: 90
|
||||
mouth-smile
|
||||
bounds: 783, 207, 47, 30
|
||||
rotate: 90
|
||||
muzzle-glow
|
||||
bounds: 779, 4, 25, 25
|
||||
muzzle-ring
|
||||
bounds: 451, 14, 25, 105
|
||||
muzzle01
|
||||
bounds: 664, 60, 67, 40
|
||||
rotate: 90
|
||||
muzzle02
|
||||
bounds: 580, 56, 68, 42
|
||||
rotate: 90
|
||||
muzzle03
|
||||
bounds: 478, 36, 83, 53
|
||||
rotate: 90
|
||||
muzzle04
|
||||
bounds: 533, 49, 75, 45
|
||||
rotate: 90
|
||||
muzzle05
|
||||
bounds: 624, 56, 68, 38
|
||||
rotate: 90
|
||||
neck
|
||||
bounds: 806, 8, 18, 21
|
||||
portal-bg
|
||||
bounds: 258, 121, 133, 133
|
||||
portal-flare1
|
||||
bounds: 690, 2, 56, 30
|
||||
rotate: 90
|
||||
portal-flare2
|
||||
bounds: 510, 3, 57, 31
|
||||
portal-flare3
|
||||
bounds: 722, 4, 58, 30
|
||||
rotate: 90
|
||||
portal-shade
|
||||
bounds: 393, 121, 133, 133
|
||||
portal-streaks1
|
||||
bounds: 528, 126, 126, 128
|
||||
portal-streaks2
|
||||
bounds: 656, 129, 125, 125
|
||||
rear-bracer
|
||||
bounds: 826, 13, 28, 36
|
||||
rear-foot
|
||||
bounds: 743, 70, 57, 30
|
||||
rotate: 90
|
||||
rear-shin
|
||||
bounds: 174, 14, 38, 89
|
||||
rear-thigh
|
||||
bounds: 783, 158, 28, 47
|
||||
rear-upper-arm
|
||||
bounds: 783, 136, 20, 44
|
||||
rotate: 90
|
||||
torso
|
||||
bounds: 123, 13, 49, 90
|
||||
|
After Width: | Height: | Size: 243 KiB |
@@ -0,0 +1,101 @@
|
||||
spineboy.png
|
||||
size: 1024, 256
|
||||
filter: Linear, Linear
|
||||
scale: 0.5
|
||||
crosshair
|
||||
bounds: 813, 160, 45, 45
|
||||
eye-indifferent
|
||||
bounds: 569, 2, 47, 45
|
||||
eye-surprised
|
||||
bounds: 643, 7, 47, 45
|
||||
rotate: 90
|
||||
front-bracer
|
||||
bounds: 811, 51, 29, 40
|
||||
front-fist-closed
|
||||
bounds: 807, 93, 38, 41
|
||||
front-fist-open
|
||||
bounds: 815, 210, 43, 44
|
||||
front-foot
|
||||
bounds: 706, 64, 63, 35
|
||||
rotate: 90
|
||||
front-shin
|
||||
bounds: 80, 11, 41, 92
|
||||
front-thigh
|
||||
bounds: 754, 12, 23, 56
|
||||
front-upper-arm
|
||||
bounds: 618, 5, 23, 49
|
||||
goggles
|
||||
bounds: 214, 20, 131, 83
|
||||
gun
|
||||
bounds: 347, 14, 105, 102
|
||||
rotate: 90
|
||||
head
|
||||
bounds: 80, 105, 136, 149
|
||||
hoverboard-board
|
||||
bounds: 2, 8, 246, 76
|
||||
rotate: 90
|
||||
hoverboard-thruster
|
||||
bounds: 478, 2, 30, 32
|
||||
hoverglow-small
|
||||
bounds: 218, 117, 137, 38
|
||||
rotate: 90
|
||||
mouth-grind
|
||||
bounds: 775, 80, 47, 30
|
||||
rotate: 90
|
||||
mouth-oooo
|
||||
bounds: 779, 31, 47, 30
|
||||
rotate: 90
|
||||
mouth-smile
|
||||
bounds: 783, 207, 47, 30
|
||||
rotate: 90
|
||||
muzzle-glow
|
||||
bounds: 779, 4, 25, 25
|
||||
muzzle-ring
|
||||
bounds: 451, 14, 25, 105
|
||||
muzzle01
|
||||
bounds: 664, 60, 67, 40
|
||||
rotate: 90
|
||||
muzzle02
|
||||
bounds: 580, 56, 68, 42
|
||||
rotate: 90
|
||||
muzzle03
|
||||
bounds: 478, 36, 83, 53
|
||||
rotate: 90
|
||||
muzzle04
|
||||
bounds: 533, 49, 75, 45
|
||||
rotate: 90
|
||||
muzzle05
|
||||
bounds: 624, 56, 68, 38
|
||||
rotate: 90
|
||||
neck
|
||||
bounds: 806, 8, 18, 21
|
||||
portal-bg
|
||||
bounds: 258, 121, 133, 133
|
||||
portal-flare1
|
||||
bounds: 690, 2, 56, 30
|
||||
rotate: 90
|
||||
portal-flare2
|
||||
bounds: 510, 3, 57, 31
|
||||
portal-flare3
|
||||
bounds: 722, 4, 58, 30
|
||||
rotate: 90
|
||||
portal-shade
|
||||
bounds: 393, 121, 133, 133
|
||||
portal-streaks1
|
||||
bounds: 528, 126, 126, 128
|
||||
portal-streaks2
|
||||
bounds: 656, 129, 125, 125
|
||||
rear-bracer
|
||||
bounds: 826, 13, 28, 36
|
||||
rear-foot
|
||||
bounds: 743, 70, 57, 30
|
||||
rotate: 90
|
||||
rear-shin
|
||||
bounds: 174, 14, 38, 89
|
||||
rear-thigh
|
||||
bounds: 783, 158, 28, 47
|
||||
rear-upper-arm
|
||||
bounds: 783, 136, 20, 44
|
||||
rotate: 90
|
||||
torso
|
||||
bounds: 123, 13, 49, 90
|
||||
|
After Width: | Height: | Size: 239 KiB |
@@ -0,0 +1,94 @@
|
||||
spineboy.png
|
||||
size: 1024, 256
|
||||
filter: Linear, Linear
|
||||
scale: 0.5
|
||||
crosshair
|
||||
bounds: 352, 7, 45, 45
|
||||
eye-indifferent
|
||||
bounds: 862, 105, 47, 45
|
||||
eye-surprised
|
||||
bounds: 505, 79, 47, 45
|
||||
front-bracer
|
||||
bounds: 826, 66, 29, 40
|
||||
front-fist-closed
|
||||
bounds: 786, 65, 38, 41
|
||||
front-fist-open
|
||||
bounds: 710, 51, 43, 44
|
||||
rotate: 90
|
||||
front-foot
|
||||
bounds: 210, 6, 63, 35
|
||||
front-shin
|
||||
bounds: 665, 128, 41, 92
|
||||
rotate: 90
|
||||
front-thigh
|
||||
bounds: 2, 2, 23, 56
|
||||
rotate: 90
|
||||
front-upper-arm
|
||||
bounds: 250, 205, 23, 49
|
||||
goggles
|
||||
bounds: 665, 171, 131, 83
|
||||
gun
|
||||
bounds: 798, 152, 105, 102
|
||||
head
|
||||
bounds: 2, 27, 136, 149
|
||||
hoverboard-board
|
||||
bounds: 2, 178, 246, 76
|
||||
hoverboard-thruster
|
||||
bounds: 722, 96, 30, 32
|
||||
rotate: 90
|
||||
hoverglow-small
|
||||
bounds: 275, 81, 137, 38
|
||||
mouth-grind
|
||||
bounds: 614, 97, 47, 30
|
||||
mouth-oooo
|
||||
bounds: 612, 65, 47, 30
|
||||
mouth-smile
|
||||
bounds: 661, 64, 47, 30
|
||||
muzzle-glow
|
||||
bounds: 382, 54, 25, 25
|
||||
muzzle-ring
|
||||
bounds: 275, 54, 25, 105
|
||||
rotate: 90
|
||||
muzzle01
|
||||
bounds: 911, 95, 67, 40
|
||||
rotate: 90
|
||||
muzzle02
|
||||
bounds: 792, 108, 68, 42
|
||||
muzzle03
|
||||
bounds: 956, 171, 83, 53
|
||||
rotate: 90
|
||||
muzzle04
|
||||
bounds: 275, 7, 75, 45
|
||||
muzzle05
|
||||
bounds: 140, 3, 68, 38
|
||||
neck
|
||||
bounds: 250, 182, 18, 21
|
||||
portal-bg
|
||||
bounds: 140, 43, 133, 133
|
||||
portal-flare1
|
||||
bounds: 554, 65, 56, 30
|
||||
portal-flare2
|
||||
bounds: 759, 112, 57, 31
|
||||
rotate: 90
|
||||
portal-flare3
|
||||
bounds: 554, 97, 58, 30
|
||||
portal-shade
|
||||
bounds: 275, 121, 133, 133
|
||||
portal-streaks1
|
||||
bounds: 410, 126, 126, 128
|
||||
portal-streaks2
|
||||
bounds: 538, 129, 125, 125
|
||||
rear-bracer
|
||||
bounds: 857, 67, 28, 36
|
||||
rear-foot
|
||||
bounds: 663, 96, 57, 30
|
||||
rear-shin
|
||||
bounds: 414, 86, 38, 89
|
||||
rotate: 90
|
||||
rear-thigh
|
||||
bounds: 756, 63, 28, 47
|
||||
rear-upper-arm
|
||||
bounds: 60, 5, 20, 44
|
||||
rotate: 90
|
||||
torso
|
||||
bounds: 905, 164, 49, 90
|
||||
|
After Width: | Height: | Size: 240 KiB |
@@ -0,0 +1,30 @@
|
||||
# Spine 多版本测试资源
|
||||
|
||||
这些资源来自 Esoteric Software 官方的
|
||||
[`spine-runtimes`](https://github.com/EsotericSoftware/spine-runtimes)
|
||||
仓库,用于测试本项目对 Spine 3.8、4.0、4.1、4.2 JSON 数据的加载、预览与动画联动。
|
||||
|
||||
## 目录结构
|
||||
|
||||
每个版本目录都包含同一套 Spineboy Pro 示例:
|
||||
|
||||
- `spineboy-pro.json`:骨骼与动画数据
|
||||
- `spineboy.atlas`:纹理图集
|
||||
- `spineboy.png`:图集贴图
|
||||
|
||||
| 目录 | JSON 中的实际 Spine 版本 | 浏览器访问路径 |
|
||||
| --- | --- | --- |
|
||||
| `3.8/` | `3.8.55` | `/spine-test/3.8/` |
|
||||
| `4.0/` | `4.0.31` | `/spine-test/4.0/` |
|
||||
| `4.1/` | `4.1.17` | `/spine-test/4.1/` |
|
||||
| `4.2/` | `4.2.22` | `/spine-test/4.2/` |
|
||||
|
||||
## 手动测试
|
||||
|
||||
1. 新建一个 Spine 场景对象。
|
||||
2. 依次选择对应版本目录中的 JSON、Atlas 和 PNG 文件。
|
||||
3. 点击“加载”。
|
||||
4. 检查资源版本、骨骼层级、动画列表、时间轴与粒子挂载联动。
|
||||
|
||||
测试时不要混用不同版本目录中的文件。资源版权和使用条件遵循
|
||||
[`spine-runtimes` License](https://github.com/EsotericSoftware/spine-runtimes/blob/4.2/LICENSE)。
|
||||
@@ -186,7 +186,10 @@ export async function applyEditorConfig(store: EditorStore, input: EditorConfigF
|
||||
const colliders = cloneEditorValue(config.scene.colliders) as unknown as CollisionBody[]
|
||||
const paths = cloneEditorValue(config.scene.paths) as unknown as ScenePath[]
|
||||
const spines = cloneEditorValue(config.scene.spines) as unknown as SpineSceneObject[]
|
||||
for (const spine of spines) if (spine.sourceBundle == null) spine.sourceBundle = null
|
||||
for (const spine of spines) {
|
||||
if (spine.sourceBundle == null) spine.sourceBundle = null
|
||||
if (spine.dataVersion == null) spine.dataVersion = ''
|
||||
}
|
||||
|
||||
await hydrateParticleResources(systems)
|
||||
const parsedSpines = await parseEmbeddedSpines(spines)
|
||||
@@ -221,6 +224,7 @@ export async function applyEditorConfig(store: EditorStore, input: EditorConfigF
|
||||
continue
|
||||
}
|
||||
registerSpineAsset(spine.id, parsed)
|
||||
spine.dataVersion = parsed.dataVersion
|
||||
spine.animations = parsed.animations
|
||||
spine.bones = parsed.bones
|
||||
if (!parsed.animations.some((animation) => animation.name === spine.selectedAnimation)) {
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
import type { SpineJsonDocument, SpineJsonMap } from './spineJsonTypes'
|
||||
|
||||
/** 按编辑器导出设置保留简洁的 Spine 3.8 版本标识。 */
|
||||
export const SPINE_38_JSON_VERSION = '3.8'
|
||||
|
||||
function rename(target: SpineJsonMap, nextName: string, oldName: string) {
|
||||
if (target[nextName] == null && target[oldName] != null) target[nextName] = target[oldName]
|
||||
delete target[oldName]
|
||||
}
|
||||
|
||||
function removeArrayCurves(value: unknown) {
|
||||
if (!value || typeof value !== 'object') return
|
||||
if (Array.isArray(value)) {
|
||||
for (const item of value) removeArrayCurves(item)
|
||||
return
|
||||
}
|
||||
const record = value as SpineJsonMap
|
||||
// Spine 3.8 只有一组归一化贝塞尔控制点,无法表达 4.x 的逐通道绝对控制点。
|
||||
// 导出器在 3.8 模式下会重新生成线性精简关键帧;这里也为未来新增时间轴兜底。
|
||||
if (Array.isArray(record.curve)) delete record.curve
|
||||
for (const child of Object.values(record)) removeArrayCurves(child)
|
||||
}
|
||||
|
||||
function downgradeSetup(document: SpineJsonDocument) {
|
||||
for (const bone of document.bones) rename(bone, 'transform', 'inherit')
|
||||
for (const constraint of (document as any).transform || []) {
|
||||
rename(constraint, 'rotateMix', 'mixRotate')
|
||||
if (constraint.translateMix == null) constraint.translateMix = constraint.mixX ?? constraint.mixY
|
||||
if (constraint.scaleMix == null) constraint.scaleMix = constraint.mixScaleX ?? constraint.mixScaleY
|
||||
rename(constraint, 'shearMix', 'mixShearY')
|
||||
delete constraint.mixX
|
||||
delete constraint.mixY
|
||||
delete constraint.mixScaleX
|
||||
delete constraint.mixScaleY
|
||||
}
|
||||
for (const constraint of (document as any).path || []) {
|
||||
rename(constraint, 'rotateMix', 'mixRotate')
|
||||
if (constraint.translateMix == null) constraint.translateMix = constraint.mixX ?? constraint.mixY
|
||||
delete constraint.mixX
|
||||
delete constraint.mixY
|
||||
}
|
||||
for (const skin of document.skins) {
|
||||
for (const slot of Object.values<SpineJsonMap>(skin.attachments || {})) {
|
||||
for (const attachment of Object.values<SpineJsonMap>(slot || {})) {
|
||||
if (attachment.parent != null) rename(attachment, 'deform', 'timelines')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function downgradeSlots(animation: SpineJsonMap) {
|
||||
for (const slot of Object.values<SpineJsonMap>(animation.slots || {})) {
|
||||
rename(slot, 'color', 'rgba')
|
||||
rename(slot, 'twoColor', 'rgba2')
|
||||
}
|
||||
}
|
||||
|
||||
function downgradeBones(animation: SpineJsonMap) {
|
||||
for (const bone of Object.values<SpineJsonMap>(animation.bones || {})) {
|
||||
for (const frame of bone.rotate || []) rename(frame, 'angle', 'value')
|
||||
}
|
||||
}
|
||||
|
||||
function downgradeTransformConstraints(animation: SpineJsonMap) {
|
||||
for (const frames of Object.values<SpineJsonMap[]>(animation.transform || {})) {
|
||||
for (const frame of frames) {
|
||||
rename(frame, 'rotateMix', 'mixRotate')
|
||||
if (frame.translateMix == null) frame.translateMix = frame.mixX ?? frame.mixY
|
||||
if (frame.scaleMix == null) frame.scaleMix = frame.mixScaleX ?? frame.mixScaleY
|
||||
rename(frame, 'shearMix', 'mixShearY')
|
||||
delete frame.mixX
|
||||
delete frame.mixY
|
||||
delete frame.mixScaleX
|
||||
delete frame.mixScaleY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function downgradePathConstraints(animation: SpineJsonMap) {
|
||||
for (const constraint of Object.values<SpineJsonMap>(animation.path || {})) {
|
||||
for (const timelineName of ['position', 'spacing']) {
|
||||
for (const frame of constraint[timelineName] || []) rename(frame, timelineName, 'value')
|
||||
}
|
||||
for (const frame of constraint.mix || []) {
|
||||
rename(frame, 'rotateMix', 'mixRotate')
|
||||
if (frame.translateMix == null) frame.translateMix = frame.mixX ?? frame.mixY
|
||||
delete frame.mixX
|
||||
delete frame.mixY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function downgradeDeforms(animation: SpineJsonMap) {
|
||||
if (!animation.attachments) return
|
||||
const deform = animation.deform || (animation.deform = {})
|
||||
for (const [skinName, skin] of Object.entries<SpineJsonMap>(animation.attachments)) {
|
||||
const targetSkin = deform[skinName] || (deform[skinName] = {})
|
||||
for (const [slotName, slot] of Object.entries<SpineJsonMap>(skin)) {
|
||||
const targetSlot = targetSkin[slotName] || (targetSkin[slotName] = {})
|
||||
for (const [attachmentName, timelines] of Object.entries<SpineJsonMap>(slot)) {
|
||||
if (timelines.deform) targetSlot[attachmentName] = timelines.deform
|
||||
}
|
||||
}
|
||||
}
|
||||
delete animation.attachments
|
||||
}
|
||||
|
||||
/** 把编辑器内部生成的 4.x 公共结构降级为 Spine 3.8 软件可导入的 JSON。 */
|
||||
export function downgradeSpineJsonTo38(document: SpineJsonDocument) {
|
||||
document.skeleton.spine = SPINE_38_JSON_VERSION
|
||||
downgradeSetup(document)
|
||||
for (const animation of Object.values(document.animations)) {
|
||||
downgradeSlots(animation)
|
||||
downgradeBones(animation)
|
||||
downgradeTransformConstraints(animation)
|
||||
downgradePathConstraints(animation)
|
||||
downgradeDeforms(animation)
|
||||
}
|
||||
removeArrayCurves(document.animations)
|
||||
return document
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
export type SpineExportVersion = '4.2'
|
||||
import { normalizeSpineVersion, type SupportedSpineVersion } from '../spine/spineVersion'
|
||||
|
||||
export type SpineExportVersion = SupportedSpineVersion
|
||||
export type SpineExportKeyframeCurve = 'linear' | 'bezier'
|
||||
|
||||
/** Spine JSON 导出的全局参数。实际 JSON 生成逻辑将在后续阶段接入。 */
|
||||
@@ -32,7 +34,7 @@ export function defaultSpineExportSettings(): SpineExportSettings {
|
||||
export function ensureSpineExportSettings(value?: Partial<SpineExportSettings> | null): SpineExportSettings {
|
||||
const settings = Object.assign(defaultSpineExportSettings(), value || {})
|
||||
settings.imagesPath = String(settings.imagesPath || './images/')
|
||||
settings.spineVersion = '4.2'
|
||||
settings.spineVersion = normalizeSpineVersion(settings.spineVersion) || '4.2'
|
||||
settings.keyframeCurve = settings.keyframeCurve === 'bezier' ? 'bezier' : 'linear'
|
||||
settings.fps = Math.min(240, Math.max(1, Math.round(Number(settings.fps) || 30)))
|
||||
settings.omitFps = settings.omitFps === true
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { EmitterConfig, ParticleImageResource, ParticleState, TrailImageRes
|
||||
import type { ParticleSystem, TimelineState } from '../store/particleStore'
|
||||
import type { SpineExportSettings } from './spineExportSettings'
|
||||
import type { SpineExportResult, SpineExportWarning, SpineJsonDocument, SpineJsonMap } from './spineJsonTypes'
|
||||
import { downgradeSpineJsonTo38 } from './spine38JsonExporter'
|
||||
import { reduceBezierSamples, reduceNumericSamples, roundSpine, unwrapDegrees, type NumericSample } from './spineKeyframeReducer'
|
||||
import { buildWeightedTrailMesh } from './spineMeshBuilder'
|
||||
|
||||
@@ -111,7 +112,7 @@ function resolvedTimelineCurve(mode: '跟随导出' | '线性' | '贝塞尔' | u
|
||||
|
||||
function numericTimeline(samples: NumericSample[], fps: number, names: string[], tolerances: number[], settings: SpineExportSettings, forcedFrames: Set<number> = new Set(), curveMode: TimelineCurveMode = settings.keyframeCurve) {
|
||||
if (!samples.length) return []
|
||||
const fitted = curveMode === 'bezier'
|
||||
const fitted = curveMode === 'bezier' && settings.spineVersion !== '3.8'
|
||||
? reduceBezierSamples(samples, tolerances, forcedFrames)
|
||||
: { samples: reduceNumericSamples(samples, tolerances, forcedFrames), controls: [] }
|
||||
const keys = fitted.samples.map((sample) => {
|
||||
@@ -212,7 +213,7 @@ function rgbaTimeline(colors: number[][], attachments: Array<string | null>, fps
|
||||
// RGB 保持单通道 1/255,透明度使用 0.01 的视觉容差。
|
||||
const samples: NumericSample[] = colors.map((values, frame) => ({ frame, values }))
|
||||
const rgbTolerance = 1 / 255
|
||||
const fitted = curveMode === 'bezier'
|
||||
const fitted = curveMode === 'bezier' && settings.spineVersion !== '3.8'
|
||||
? reduceBezierSamples(samples, [rgbTolerance, rgbTolerance, rgbTolerance, 0.01], forcedFrames)
|
||||
: { samples: reduceNumericSamples(samples, [rgbTolerance, rgbTolerance, rgbTolerance, 0.01], forcedFrames), controls: [] }
|
||||
const keys = fitted.samples.map((sample) => ({ time: time(sample.frame, fps), color: `${byte(sample.values[0])}${byte(sample.values[1])}${byte(sample.values[2])}${byte(sample.values[3])}` } as SpineJsonMap))
|
||||
@@ -232,7 +233,9 @@ function rgbaTimeline(colors: number[][], attachments: Array<string | null>, fps
|
||||
|
||||
function addSlotAnimation(animation: SpineJsonMap, slotName: string, attachments: Array<string | null>, colors: number[][], fps: number, settings: SpineExportSettings, curveMode: TimelineCurveMode = settings.keyframeCurve) {
|
||||
const slot = animation.slots[slotName] ||= {}
|
||||
const attachment = discreteTimeline(attachments, fps, (name, frame) => name == null ? { time: time(frame, fps) } : { time: time(frame, fps), name })
|
||||
// Spine 3.8 编辑器要求附件时间轴的每一帧都存在 name;隐藏附件必须显式写 null,
|
||||
// 省略字段会在导入时触发 “Named value not found: name”。4.x 同样接受该标准写法。
|
||||
const attachment = discreteTimeline(attachments, fps, (name, frame) => ({ time: time(frame, fps), name: name ?? null }))
|
||||
if (attachment.length) slot.attachment = attachment
|
||||
const rgba = rgbaTimeline(colors, attachments, fps, settings, curveMode)
|
||||
if (rgba.length) slot.rgba = rgba
|
||||
@@ -247,7 +250,8 @@ export function buildSpineJson(input: ExportInput): SpineExportResult {
|
||||
const warnings: SpineExportWarning[] = []
|
||||
const visibleSystems = input.systems.filter((system) => system.visible !== false)
|
||||
const document: SpineJsonDocument = {
|
||||
skeleton: { hash: '', spine: '4.2', x: 0, y: 0, width: 0, height: 0, images: settings.imagesPath || './images/' },
|
||||
// 先生成当前运行时使用的公共结构;3.8 会在最终序列化前降级字段与时间轴格式。
|
||||
skeleton: { hash: '', spine: settings.spineVersion, x: 0, y: 0, width: 0, height: 0, images: settings.imagesPath || './images/' },
|
||||
bones: [{ name: 'root' }], slots: [], skins: [{ name: 'default', attachments: {} }], animations: {},
|
||||
}
|
||||
if (!settings.omitFps) document.skeleton.fps = targetFps
|
||||
@@ -426,8 +430,9 @@ export function buildSpineJson(input: ExportInput): SpineExportResult {
|
||||
}
|
||||
|
||||
if (!Object.keys(document.animations).length && !settings.excludeEmptyAnimations) document.animations.animation = { bones: {}, slots: {} }
|
||||
const text = JSON.stringify(document, null, 2)
|
||||
return { json: document, text, warnings, particleSystemCount: visibleSystems.length, animationCount: Object.keys(document.animations).length, boneCount: document.bones.length }
|
||||
const output = settings.spineVersion === '3.8' ? downgradeSpineJsonTo38(document) : document
|
||||
const text = JSON.stringify(output, null, 2)
|
||||
return { json: output, text, warnings, particleSystemCount: visibleSystems.length, animationCount: Object.keys(output.animations).length, boneCount: output.bones.length }
|
||||
}
|
||||
|
||||
export function downloadSpineJson(result: SpineExportResult, fileName: string) {
|
||||
|
||||
@@ -9,6 +9,9 @@ import {
|
||||
type AttachmentLoader,
|
||||
type Skin,
|
||||
} from '@esotericsoftware/spine-core'
|
||||
import { normalizeSpine38JsonFor42 } from '../spine/spine38Compatibility'
|
||||
import { normalizeSpineVersion, supportedSpineVersionsText, type SupportedSpineVersion } from '../spine/spineVersion'
|
||||
import type { SpineJsonMap } from './spineJsonTypes'
|
||||
|
||||
class ExportValidationAttachmentLoader implements AttachmentLoader {
|
||||
newRegionAttachment(_skin: Skin, name: string, path: string, _sequence: any) { return new RegionAttachment(name, path) }
|
||||
@@ -59,12 +62,12 @@ function validateMesh(mesh: Record<string, any>, attachmentName: string, boneCou
|
||||
if (offset !== vertices.length || decodedVertices !== vertexCount) throw new Error(`拖尾网格“${attachmentName}”的顶点数量与 UV 不一致`)
|
||||
}
|
||||
|
||||
function validateEditorImportStructure(root: Record<string, any>) {
|
||||
function validateEditorImportStructure(root: Record<string, any>, version: SupportedSpineVersion) {
|
||||
const bones = Array.isArray(root.bones) ? root.bones : []
|
||||
const boneByName = new Map(bones.map((bone) => [String(bone.name || ''), bone]))
|
||||
const weightedMeshSlots = new Set<string>()
|
||||
for (const bone of bones) {
|
||||
if (bone.inherit != null && !VALID_INHERIT.has(bone.inherit)) throw new Error(`骨骼“${bone.name || ''}”的 inherit 值“${bone.inherit}”不符合 Spine 4.2 JSON 格式`)
|
||||
if (bone.inherit != null && !VALID_INHERIT.has(bone.inherit)) throw new Error(`骨骼“${bone.name || ''}”的 inherit 值“${bone.inherit}”不符合 Spine ${version} JSON 格式`)
|
||||
if (/_particle_\d+_trail_/.test(String(bone.name || ''))) {
|
||||
const parent = boneByName.get(String(bone.parent || ''))
|
||||
if (!parent || /_particle_\d+_trail_/.test(String(parent.name || ''))) {
|
||||
@@ -94,12 +97,47 @@ function validateEditorImportStructure(root: Record<string, any>) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 下载前使用项目内置 Spine 4.2 Runtime 做一次结构解析,提前拦截无效 JSON。 */
|
||||
export function validateSpineJson(text: string) {
|
||||
const root = JSON.parse(text)
|
||||
validateEditorImportStructure(root)
|
||||
const reader = new SkeletonJson(new ExportValidationAttachmentLoader())
|
||||
const data = reader.readSkeletonData(root)
|
||||
if (!data.bones.length) throw new Error('导出结果缺少骨骼')
|
||||
return { bones: data.bones.length, slots: data.slots.length, animations: data.animations.length }
|
||||
function validateSpine38Structure(root: Record<string, any>) {
|
||||
if (String(root?.skeleton?.spine || '') !== '3.8') throw new Error('Spine 3.8 导出的版本标识必须为 3.8')
|
||||
for (const bone of root.bones || []) {
|
||||
if (bone.inherit != null) throw new Error(`Spine 3.8 骨骼“${bone.name || ''}”应使用 transform,不能使用 inherit`)
|
||||
}
|
||||
for (const animation of Object.values(root.animations || {}) as SpineJsonMap[]) {
|
||||
for (const slot of Object.values(animation.slots || {}) as SpineJsonMap[]) {
|
||||
if (slot.rgba || slot.rgba2) throw new Error('Spine 3.8 插槽颜色时间轴必须使用 color / twoColor')
|
||||
for (const frame of slot.attachment || []) {
|
||||
if (!Object.prototype.hasOwnProperty.call(frame, 'name')) throw new Error('Spine 3.8 附件时间轴的隐藏帧必须显式写入 name: null')
|
||||
}
|
||||
}
|
||||
for (const bone of Object.values(animation.bones || {}) as SpineJsonMap[]) {
|
||||
for (const frame of bone.rotate || []) {
|
||||
if (frame.value != null || frame.angle == null) throw new Error('Spine 3.8 旋转时间轴必须使用 angle')
|
||||
}
|
||||
}
|
||||
const stack: unknown[] = [animation]
|
||||
while (stack.length) {
|
||||
const value = stack.pop()
|
||||
if (!value || typeof value !== 'object') continue
|
||||
if (!Array.isArray(value) && Array.isArray((value as SpineJsonMap).curve)) throw new Error('Spine 3.8 不支持 4.x 数组曲线格式')
|
||||
stack.push(...Object.values(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载前使用项目内置运行时解析共同结构,提前拦截无效 JSON。
|
||||
* 目标版本由 skeleton.spine 决定;校验不会改写导出的版本字段。
|
||||
*/
|
||||
export function validateSpineJson(text: string, expectedVersion?: SupportedSpineVersion) {
|
||||
const root = JSON.parse(text)
|
||||
const version = normalizeSpineVersion(root?.skeleton?.spine)
|
||||
if (!version) throw new Error(`导出版本不受支持,仅支持 Spine ${supportedSpineVersionsText()}`)
|
||||
if (expectedVersion && version !== expectedVersion) throw new Error(`导出版本不一致:设置为 Spine ${expectedVersion},JSON 标记为 Spine ${version}`)
|
||||
validateEditorImportStructure(root, version)
|
||||
if (version === '3.8') validateSpine38Structure(root)
|
||||
const runtimeRoot = version === '3.8' ? normalizeSpine38JsonFor42(JSON.parse(JSON.stringify(root))) : root
|
||||
const reader = new SkeletonJson(new ExportValidationAttachmentLoader())
|
||||
const data = reader.readSkeletonData(runtimeRoot)
|
||||
if (!data.bones.length) throw new Error('导出结果缺少骨骼')
|
||||
return { version, bones: data.bones.length, slots: data.slots.length, animations: data.animations.length }
|
||||
}
|
||||
|
||||
@@ -38,7 +38,10 @@
|
||||
</button>
|
||||
<button class="clear" @click="clearBundle">清除</button>
|
||||
</div>
|
||||
<div class="runtime-note">Spine 4.2.119 · 官方 PixiJS 7 运行时 · 本地离线</div>
|
||||
<div class="runtime-note">
|
||||
支持 Spine 3.8 / 4.0 / 4.1 / 4.2 JSON · 4.2.119 预览运行时 · 本地离线
|
||||
<span v-if="spineObject.dataVersion"> · 当前资源 {{ spineObject.dataVersion }}</span>
|
||||
</div>
|
||||
<div v-if="spineObject.error" class="error">{{ spineObject.error }}</div>
|
||||
|
||||
<div class="section-box">
|
||||
@@ -125,6 +128,7 @@ const textureFiles = ref<File[]>([])
|
||||
// 兼容热更新或旧场景数据;骨骼选择默认保持为空。
|
||||
if (props.spineObject.selectedBone == null) props.spineObject.selectedBone = ''
|
||||
if (props.spineObject.sourceBundle == null) props.spineObject.sourceBundle = null
|
||||
if (props.spineObject.dataVersion == null) props.spineObject.dataVersion = ''
|
||||
|
||||
const skeletonName = computed(() => skeletonFile.value?.name || props.spineObject.skeletonFileName)
|
||||
const atlasName = computed(() => atlasFile.value?.name || props.spineObject.atlasFileName)
|
||||
@@ -221,6 +225,7 @@ async function loadBundle() {
|
||||
props.spineObject.skeletonFileName = skeleton.name
|
||||
props.spineObject.atlasFileName = atlas.name
|
||||
props.spineObject.textureFileNames = textureFiles.value.map((file) => file.name)
|
||||
props.spineObject.dataVersion = parsed.dataVersion
|
||||
props.spineObject.animations = parsed.animations
|
||||
props.spineObject.bones = parsed.bones
|
||||
props.spineObject.selectedBone = ''
|
||||
@@ -257,6 +262,7 @@ function clearBundle() {
|
||||
props.spineObject.skeletonFileName = ''
|
||||
props.spineObject.atlasFileName = ''
|
||||
props.spineObject.textureFileNames = []
|
||||
props.spineObject.dataVersion = ''
|
||||
props.spineObject.sourceBundle = null
|
||||
props.spineObject.animations = []
|
||||
props.spineObject.bones = []
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
type JsonRecord = Record<string, any>
|
||||
|
||||
function valueOf(frame: JsonRecord, key: string, fallback: number) {
|
||||
const value = Number(frame[key])
|
||||
return Number.isFinite(value) ? value : fallback
|
||||
}
|
||||
|
||||
function setRenamedValue(frame: JsonRecord, target: string, source: string, fallback: number) {
|
||||
if (frame[target] == null) frame[target] = valueOf(frame, source, fallback)
|
||||
}
|
||||
|
||||
function legacyCurveToArray(
|
||||
frame: JsonRecord,
|
||||
next: JsonRecord,
|
||||
values: Array<[number, number]>,
|
||||
) {
|
||||
if (typeof frame.curve !== 'number') return
|
||||
const time1 = valueOf(frame, 'time', 0)
|
||||
const time2 = valueOf(next, 'time', 0)
|
||||
const timeRange = time2 - time1
|
||||
const x1 = frame.curve
|
||||
const y1 = valueOf(frame, 'c2', 0)
|
||||
const x2 = valueOf(frame, 'c3', 1)
|
||||
const y2 = valueOf(frame, 'c4', 1)
|
||||
frame.curve = values.flatMap(([start, end]) => [
|
||||
time1 + timeRange * x1,
|
||||
start + (end - start) * y1,
|
||||
time1 + timeRange * x2,
|
||||
start + (end - start) * y2,
|
||||
])
|
||||
delete frame.c2
|
||||
delete frame.c3
|
||||
delete frame.c4
|
||||
}
|
||||
|
||||
function convertTimelineCurves(
|
||||
frames: JsonRecord[] | undefined,
|
||||
channels: Array<{ key: string; fallback: number }>,
|
||||
) {
|
||||
if (!Array.isArray(frames)) return
|
||||
for (let index = 0; index < frames.length - 1; index++) {
|
||||
const frame = frames[index]
|
||||
const next = frames[index + 1]
|
||||
legacyCurveToArray(frame, next, channels.map(({ key, fallback }) => [
|
||||
valueOf(frame, key, fallback),
|
||||
valueOf(next, key, fallback),
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
||||
function convertNormalizedTimelineCurves(frames: JsonRecord[] | undefined) {
|
||||
if (!Array.isArray(frames)) return
|
||||
for (let index = 0; index < frames.length - 1; index++) {
|
||||
legacyCurveToArray(frames[index], frames[index + 1], [[0, 1]])
|
||||
}
|
||||
}
|
||||
|
||||
function colorChannels(value: unknown, includeAlpha: boolean) {
|
||||
const input = typeof value === 'string' ? value.replace(/^#/, '') : ''
|
||||
const normalized = input.length === 6 ? `${input}ff` : input.padEnd(8, 'f').slice(0, 8)
|
||||
const channels = [0, 2, 4, 6].map((offset) => Number.parseInt(normalized.slice(offset, offset + 2), 16) / 255)
|
||||
return includeAlpha ? channels : channels.slice(0, 3)
|
||||
}
|
||||
|
||||
function convertColorTimelineCurves(frames: JsonRecord[] | undefined, twoColor: boolean) {
|
||||
if (!Array.isArray(frames)) return
|
||||
for (let index = 0; index < frames.length - 1; index++) {
|
||||
const frame = frames[index]
|
||||
const next = frames[index + 1]
|
||||
const start = twoColor
|
||||
? [...colorChannels(frame.light, true), ...colorChannels(frame.dark, false)]
|
||||
: colorChannels(frame.color, true)
|
||||
const end = twoColor
|
||||
? [...colorChannels(next.light, true), ...colorChannels(next.dark, false)]
|
||||
: colorChannels(next.color, true)
|
||||
legacyCurveToArray(frame, next, start.map((value, channel) => [value, end[channel]]))
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeConstraintSetup(root: JsonRecord) {
|
||||
for (const bone of root.bones || []) {
|
||||
if (bone.inherit == null && bone.transform != null) bone.inherit = bone.transform
|
||||
}
|
||||
for (const constraint of root.transform || []) {
|
||||
setRenamedValue(constraint, 'mixRotate', 'rotateMix', 1)
|
||||
setRenamedValue(constraint, 'mixX', 'translateMix', 1)
|
||||
if (constraint.mixY == null) constraint.mixY = constraint.mixX
|
||||
setRenamedValue(constraint, 'mixScaleX', 'scaleMix', 1)
|
||||
if (constraint.mixScaleY == null) constraint.mixScaleY = constraint.mixScaleX
|
||||
setRenamedValue(constraint, 'mixShearY', 'shearMix', 1)
|
||||
}
|
||||
for (const constraint of root.path || []) {
|
||||
setRenamedValue(constraint, 'mixRotate', 'rotateMix', 1)
|
||||
setRenamedValue(constraint, 'mixX', 'translateMix', 1)
|
||||
if (constraint.mixY == null) constraint.mixY = constraint.mixX
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeLinkedMeshes(root: JsonRecord) {
|
||||
for (const skin of root.skins || []) {
|
||||
for (const slot of Object.values<JsonRecord>(skin.attachments || {})) {
|
||||
for (const attachment of Object.values<JsonRecord>(slot || {})) {
|
||||
if (attachment.parent != null && attachment.timelines == null && attachment.deform != null) {
|
||||
attachment.timelines = attachment.deform
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeSlotTimelines(animation: JsonRecord) {
|
||||
for (const slot of Object.values<JsonRecord>(animation.slots || {})) {
|
||||
if (slot.color && !slot.rgba) {
|
||||
slot.rgba = slot.color
|
||||
delete slot.color
|
||||
}
|
||||
if (slot.twoColor && !slot.rgba2) {
|
||||
slot.rgba2 = slot.twoColor
|
||||
delete slot.twoColor
|
||||
}
|
||||
convertColorTimelineCurves(slot.rgba, false)
|
||||
convertColorTimelineCurves(slot.rgba2, true)
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeBoneTimelines(animation: JsonRecord) {
|
||||
for (const bone of Object.values<JsonRecord>(animation.bones || {})) {
|
||||
for (const frame of bone.rotate || []) setRenamedValue(frame, 'value', 'angle', 0)
|
||||
convertTimelineCurves(bone.rotate, [{ key: 'value', fallback: 0 }])
|
||||
convertTimelineCurves(bone.translate, [{ key: 'x', fallback: 0 }, { key: 'y', fallback: 0 }])
|
||||
convertTimelineCurves(bone.scale, [{ key: 'x', fallback: 1 }, { key: 'y', fallback: 1 }])
|
||||
convertTimelineCurves(bone.shear, [{ key: 'x', fallback: 0 }, { key: 'y', fallback: 0 }])
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeIkTimelines(animation: JsonRecord) {
|
||||
for (const frames of Object.values<JsonRecord[]>(animation.ik || {})) {
|
||||
convertTimelineCurves(frames, [{ key: 'mix', fallback: 1 }, { key: 'softness', fallback: 0 }])
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeTransformTimelines(animation: JsonRecord) {
|
||||
for (const frames of Object.values<JsonRecord[]>(animation.transform || {})) {
|
||||
for (const frame of frames) {
|
||||
setRenamedValue(frame, 'mixRotate', 'rotateMix', 1)
|
||||
setRenamedValue(frame, 'mixX', 'translateMix', 1)
|
||||
if (frame.mixY == null) frame.mixY = frame.mixX
|
||||
setRenamedValue(frame, 'mixScaleX', 'scaleMix', 1)
|
||||
if (frame.mixScaleY == null) frame.mixScaleY = frame.mixScaleX
|
||||
setRenamedValue(frame, 'mixShearY', 'shearMix', 1)
|
||||
}
|
||||
convertTimelineCurves(frames, [
|
||||
{ key: 'mixRotate', fallback: 1 },
|
||||
{ key: 'mixX', fallback: 1 },
|
||||
{ key: 'mixY', fallback: 1 },
|
||||
{ key: 'mixScaleX', fallback: 1 },
|
||||
{ key: 'mixScaleY', fallback: 1 },
|
||||
{ key: 'mixShearY', fallback: 1 },
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
function normalizePathTimelines(animation: JsonRecord) {
|
||||
for (const constraint of Object.values<JsonRecord>(animation.path || {})) {
|
||||
for (const timelineName of ['position', 'spacing'] as const) {
|
||||
const frames = constraint[timelineName] as JsonRecord[] | undefined
|
||||
for (const frame of frames || []) setRenamedValue(frame, 'value', timelineName, 0)
|
||||
convertTimelineCurves(frames, [{ key: 'value', fallback: 0 }])
|
||||
}
|
||||
const mixFrames = constraint.mix as JsonRecord[] | undefined
|
||||
for (const frame of mixFrames || []) {
|
||||
setRenamedValue(frame, 'mixRotate', 'rotateMix', 1)
|
||||
setRenamedValue(frame, 'mixX', 'translateMix', 1)
|
||||
if (frame.mixY == null) frame.mixY = frame.mixX
|
||||
}
|
||||
convertTimelineCurves(mixFrames, [
|
||||
{ key: 'mixRotate', fallback: 1 },
|
||||
{ key: 'mixX', fallback: 1 },
|
||||
{ key: 'mixY', fallback: 1 },
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeDeformTimelines(animation: JsonRecord) {
|
||||
if (!animation.deform) return
|
||||
const attachments = animation.attachments || (animation.attachments = {})
|
||||
for (const [skinName, skin] of Object.entries<JsonRecord>(animation.deform)) {
|
||||
const targetSkin = attachments[skinName] || (attachments[skinName] = {})
|
||||
for (const [slotName, slot] of Object.entries<JsonRecord>(skin)) {
|
||||
const targetSlot = targetSkin[slotName] || (targetSkin[slotName] = {})
|
||||
for (const [attachmentName, frames] of Object.entries<JsonRecord[]>(slot)) {
|
||||
const targetAttachment = targetSlot[attachmentName] || (targetSlot[attachmentName] = {})
|
||||
targetAttachment.deform = frames
|
||||
convertNormalizedTimelineCurves(frames)
|
||||
}
|
||||
}
|
||||
}
|
||||
delete animation.deform
|
||||
}
|
||||
|
||||
/**
|
||||
* Spine 3.8 的曲线、旋转值和约束字段名与 4.x 不同。当前预览层统一使用
|
||||
* Spine 4.2 Runtime,因此只在内存中把 3.8 JSON 转成 4.2 Runtime 可识别的等价结构。
|
||||
* 原始文件、保存配置中的源文件以及 skeleton.spine 版本标识均保持不变。
|
||||
*/
|
||||
export function normalizeSpine38JsonFor42(source: JsonRecord) {
|
||||
normalizeConstraintSetup(source)
|
||||
normalizeLinkedMeshes(source)
|
||||
for (const animation of Object.values<JsonRecord>(source.animations || {})) {
|
||||
normalizeSlotTimelines(animation)
|
||||
normalizeBoneTimelines(animation)
|
||||
normalizeIkTimelines(animation)
|
||||
normalizeTransformTimelines(animation)
|
||||
normalizePathTimelines(animation)
|
||||
normalizeDeformTimelines(animation)
|
||||
if (!animation.drawOrder && animation.draworder) animation.drawOrder = animation.draworder
|
||||
}
|
||||
return source
|
||||
}
|
||||
@@ -9,10 +9,13 @@ import { SpineTexture } from '@esotericsoftware/spine-pixi-v7'
|
||||
import { ALPHA_MODES, Texture } from 'pixi.js'
|
||||
import type { LoadedSpineAsset } from './spineAssetRegistry'
|
||||
import type { SpineAnimationInfo, SpineBoneInfo } from './spineTypes'
|
||||
import { normalizeSpine38JsonFor42 } from './spine38Compatibility'
|
||||
import { normalizeSpineVersion, supportedSpineVersionsText, type SupportedSpineVersion } from './spineVersion'
|
||||
|
||||
export interface ParsedSpineBundle extends LoadedSpineAsset {
|
||||
animations: SpineAnimationInfo[]
|
||||
bones: SpineBoneInfo[]
|
||||
dataVersion: SupportedSpineVersion
|
||||
}
|
||||
|
||||
function basename(path: string) {
|
||||
@@ -56,17 +59,30 @@ export async function parseSpineBundle(skeletonFile: File, atlasFile: File, text
|
||||
|
||||
const attachmentLoader = new AtlasAttachmentLoader(atlas)
|
||||
let skeletonData: SkeletonData
|
||||
let dataVersion: SupportedSpineVersion | null = null
|
||||
if (/\.skel$/i.test(skeletonFile.name)) {
|
||||
const reader = new SkeletonBinary(attachmentLoader)
|
||||
skeletonData = reader.readSkeletonData(await skeletonFile.arrayBuffer())
|
||||
dataVersion = normalizeSpineVersion(skeletonData.version)
|
||||
} else {
|
||||
let source: any
|
||||
try {
|
||||
source = JSON.parse(await skeletonFile.text())
|
||||
} catch {
|
||||
throw new Error('Spine JSON 文件格式无效')
|
||||
}
|
||||
dataVersion = normalizeSpineVersion(source?.skeleton?.spine)
|
||||
if (!dataVersion) throw new Error(`Spine JSON 版本不受支持,仅支持 ${supportedSpineVersionsText()}`)
|
||||
if (dataVersion === '3.8') normalizeSpine38JsonFor42(source)
|
||||
const reader = new SkeletonJson(attachmentLoader)
|
||||
skeletonData = reader.readSkeletonData(await skeletonFile.text())
|
||||
skeletonData = reader.readSkeletonData(source)
|
||||
}
|
||||
if (!dataVersion) throw new Error(`Spine 数据版本不受支持,仅支持 ${supportedSpineVersionsText()}`)
|
||||
|
||||
return {
|
||||
skeletonData,
|
||||
textures,
|
||||
dataVersion,
|
||||
animations: skeletonData.animations.map((animation) => ({ name: animation.name, duration: animation.duration })),
|
||||
bones: boneMetadata(skeletonData),
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { SpineSourceBundle } from './spineSourceBundle'
|
||||
import type { SupportedSpineVersion } from './spineVersion'
|
||||
|
||||
export interface SpineAnimationInfo {
|
||||
name: string
|
||||
@@ -25,6 +26,8 @@ export interface SpineSceneObject {
|
||||
skeletonFileName: string
|
||||
atlasFileName: string
|
||||
textureFileNames: string[]
|
||||
/** 当前已加载资源的 Spine 主版本。 */
|
||||
dataVersion: SupportedSpineVersion | ''
|
||||
/** 保存配置时使用的可移植原始 Spine 文件。 */
|
||||
sourceBundle: SpineSourceBundle | null
|
||||
selectedAnimation: string
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
export const SUPPORTED_SPINE_VERSIONS = ['3.8', '4.0', '4.1', '4.2'] as const
|
||||
|
||||
export type SupportedSpineVersion = typeof SUPPORTED_SPINE_VERSIONS[number]
|
||||
|
||||
export function normalizeSpineVersion(value: unknown): SupportedSpineVersion | null {
|
||||
const version = String(value || '').trim()
|
||||
return SUPPORTED_SPINE_VERSIONS.find((candidate) => version === candidate || version.startsWith(`${candidate}.`)) || null
|
||||
}
|
||||
|
||||
export function isSupportedSpineVersion(value: unknown): value is SupportedSpineVersion {
|
||||
return normalizeSpineVersion(value) !== null
|
||||
}
|
||||
|
||||
export function supportedSpineVersionsText() {
|
||||
return SUPPORTED_SPINE_VERSIONS.join(' / ')
|
||||
}
|
||||
@@ -314,6 +314,7 @@ export const useParticleStore = defineStore('particle', {
|
||||
skeletonFileName: '',
|
||||
atlasFileName: '',
|
||||
textureFileNames: [],
|
||||
dataVersion: '',
|
||||
sourceBundle: null,
|
||||
selectedAnimation: '',
|
||||
selectedBone: '',
|
||||
|
||||
@@ -828,6 +828,9 @@
|
||||
<label class="export-field">
|
||||
<span>Spine 版本</span>
|
||||
<select v-model="exportSettings.spineVersion" class="inp export-input">
|
||||
<option value="3.8">Spine 3.8</option>
|
||||
<option value="4.0">Spine 4.0</option>
|
||||
<option value="4.1">Spine 4.1</option>
|
||||
<option value="4.2">Spine 4.2</option>
|
||||
</select>
|
||||
</label>
|
||||
@@ -840,6 +843,7 @@
|
||||
</select>
|
||||
</label>
|
||||
<div class="export-help">平滑贝塞尔会在误差允许范围内拟合连续运动;出生、死亡、附件切换和突变仍使用阶跃关键帧。</div>
|
||||
<div v-if="exportSettings.spineVersion === '3.8'" class="export-help">Spine 3.8 不支持 4.x 的逐通道数组贝塞尔,导出时会转换为经过容差精简的分段线性关键帧。</div>
|
||||
|
||||
<div class="export-fps-row">
|
||||
<label class="export-field export-fps-field">
|
||||
@@ -869,7 +873,7 @@
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<button type="button" class="export-spine-json" :disabled="exportBusy" :title="exportBusy ? '正在重新计算并烘焙动画' : '导出可重新导入 Spine 4.2 的 JSON'" @click="exportSpineJson">
|
||||
<button type="button" class="export-spine-json" :disabled="exportBusy" :title="exportBusy ? '正在重新计算并烘焙动画' : `导出 Spine ${exportSettings.spineVersion} JSON`" @click="exportSpineJson">
|
||||
{{ exportBusy ? '正在准备导出…' : '导出Spine Json' }}
|
||||
</button>
|
||||
<div v-if="exportMessage" class="export-message" :class="{ error: exportError }">{{ exportMessage }}</div>
|
||||
@@ -1000,10 +1004,10 @@ async function exportSpineJson() {
|
||||
try {
|
||||
await prepareExportFrames()
|
||||
const result = buildSpineJson({ systems: store.systems as unknown as ParticleSystem[], timeline: store.timeline, settings: exportSettings.value })
|
||||
validateSpineJson(result.text)
|
||||
validateSpineJson(result.text, exportSettings.value.spineVersion)
|
||||
downloadSpineJson(result, exportSettings.value.fileName)
|
||||
const warning = result.warnings.length ? `;${result.warnings.length} 条资源提示(缺图仍已导出)` : ''
|
||||
exportMessage.value = `已导出 ${result.particleSystemCount} 个粒子系统、${result.animationCount} 个动画、${result.boneCount} 根骨骼${warning}`
|
||||
exportMessage.value = `已导出 Spine ${exportSettings.value.spineVersion}:${result.particleSystemCount} 个粒子系统、${result.animationCount} 个动画、${result.boneCount} 根骨骼${warning}`
|
||||
} catch (error) {
|
||||
exportError.value = true
|
||||
exportMessage.value = error instanceof Error ? error.message : String(error)
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
<li><b>创建对象:</b>在左侧“场景对象”中添加粒子、碰撞、路径或 Spine。</li>
|
||||
<li><b>编辑粒子:</b>选中粒子系统,依次调整发射、形状、属性、外观资源和修改器。</li>
|
||||
<li><b>查看效果:</b>使用底部时间轴播放、暂停或拖动到指定帧;修改参数后会自动重新计算。</li>
|
||||
<li><b>保存成果:</b>配置文件用于继续编辑;“导出 Spine Json”用于导入 Spine 4.2。</li>
|
||||
<li><b>保存成果:</b>配置文件用于继续编辑;“导出 Spine Json”支持 Spine 3.8、4.0、4.1 和 4.2。</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
|
||||