Compare commits
46 Commits
923d81c2a0
...
new2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbb6cc72cc | ||
|
|
4be5252cc4 | ||
|
|
04cea0fbb2 | ||
|
|
0db3404481 | ||
|
|
8c7748436b | ||
|
|
311b8ebb54 | ||
|
|
5d398d0a29 | ||
|
|
9c9cc99e64 | ||
|
|
1bb275607a | ||
|
|
95bf2a4e17 | ||
|
|
3f2989ab55 | ||
|
|
577a62193c | ||
|
|
8f89dd11fa | ||
|
|
c10e24709d | ||
|
|
f92502f4f5 | ||
|
|
fa58f699d9 | ||
|
|
90e8a4a284 | ||
|
|
39de30b9b4 | ||
|
|
8707316032 | ||
|
|
fdcd81c083 | ||
|
|
cd9e7296a1 | ||
|
|
be6d941b90 | ||
|
|
51256a2813 | ||
|
|
0ea0434087 | ||
|
|
1634f6a528 | ||
|
|
c183ae464a | ||
|
|
d140645aab | ||
|
|
c610829661 | ||
|
|
580a5ad131 | ||
|
|
c282adcf3b | ||
|
|
4900911cfc | ||
|
|
45e3e8712b | ||
|
|
f4150bd33c | ||
|
|
707e25e73f | ||
|
|
f53c4293df | ||
|
|
f67f8a4aa0 | ||
|
|
16854ab1b8 | ||
|
|
287989b425 | ||
|
|
63a9f6cba5 | ||
|
|
93dc59a616 | ||
|
|
8c8810bb7e | ||
|
|
7640957325 | ||
|
|
2dc44b2393 | ||
|
|
f2a4926c49 | ||
|
|
5583dca2b6 | ||
|
|
b63572c383 |
@@ -56,7 +56,7 @@ description: "Guides users through filling the official software copyright (计
|
||||
- 软件环境(操作系统 / 平台)
|
||||
- 编程语言
|
||||
- 源程序量(行数)
|
||||
- 主要功能(200-300 字)
|
||||
- 主要功能(申请表字段要求 500 字以上,覆盖各功能模块;设计说明书概述章节可用 200-300 字摘要版)
|
||||
- 技术特点(150-250 字,可选)
|
||||
|
||||
**功能模块(ManualModule[])**
|
||||
@@ -72,6 +72,7 @@ description: "Guides users through filling the official software copyright (计
|
||||
3. **设计说明书 / 用户操作手册**:调用 `buildManual` 的章节模板,可选其一:
|
||||
- 设计说明书:引言 / 运行环境 / 功能模块设计 / 数据结构与接口设计 / 安全与异常处理 / 联系方式
|
||||
- 用户操作手册:引言 / 运行环境 / 安装与启动 / 功能操作说明 / 常见问题 / 联系方式
|
||||
4. **填表指引**(用户需要时):见下方"填表指引文档"章节
|
||||
|
||||
### 源程序专项
|
||||
|
||||
@@ -80,10 +81,10 @@ description: "Guides users through filling the official software copyright (计
|
||||
#### 提交要求(来自登记规范)
|
||||
|
||||
- 取前 30 页 + 后 30 页,不足 60 页时全部提交
|
||||
- 每页不少于 50 行有效代码
|
||||
- 每页不少于 50 行有效代码(默认每页 50 行;用户要求更高密度时可调,如 60 行/页,但不得低于 50)
|
||||
- 页眉:左侧标注 `软件全称 版本号`,右侧标注 `第 N 页 共 M 页`
|
||||
- 9.5pt 等宽字体,每行不超过 84 字符(A4 折行限制)
|
||||
- 文件名示例:`软件全称_V1.0_源程序.pdf`
|
||||
- 9.5pt 等宽字体,每行不超过 84 字符(A4 折行限制;按显示宽度计:ASCII 记 1 列,中文/全角记 2 列)
|
||||
- 文件名示例:`软件全称_V1.0_源程序.pdf`;用户需要 docx/PDF 成品时按下方「docx 版本生成」章节产出
|
||||
|
||||
#### 三种生成方式(按用户掌握情况选用)
|
||||
|
||||
@@ -92,11 +93,17 @@ description: "Guides users through filling the official software copyright (计
|
||||
让用户提供源代码文件路径或粘贴代码文本,Skill 直接执行 `paginateCode` 逻辑:
|
||||
|
||||
```text
|
||||
1. 把 \r\n 替换为 \n,\t 替换为 4 空格
|
||||
2. 按每页 50 行切分,得到 N 页
|
||||
3. 若 N > 60:保留前 30 页 + 后 30 页,丢弃中间
|
||||
4. 给每页加上统一页眉
|
||||
5. 用 A4 纸张打印 / 导出 PDF
|
||||
1. 与用户确认源代码根目录范围(只采集约定目录,如 assets/script)
|
||||
2. 排除非源码:.md/.csv 等文档、.d.ts 声明文件、着色器/材质、空文件、
|
||||
构建产物、第三方框架目录(如 extensions/ 下的开源插件框架)
|
||||
3. 清理文件头(前 40 行)的第三方署名与版权行:他人 ID/昵称、QQ 号、
|
||||
第三方框架作者的 @Author/@LastEditors/@Date/@LastEditTime、引擎 Copyright
|
||||
声明;生成后必须 grep 复验清理干净
|
||||
4. 入口文件(如 Main.ts)优先排序,其余按路径字母序;文件间加注释分隔行
|
||||
5. 把 \r\n 替换为 \n,\t 替换为 4 空格
|
||||
6. 按每页 N 行切分(N ≥ 50,默认 50,可按用户要求调整),得到总页数
|
||||
7. 若总页数 > 60:保留前 30 页 + 后 30 页,丢弃中间
|
||||
8. 给每页加上统一页眉;建议沉淀为可重跑脚本(代码变更后重新生成)
|
||||
```
|
||||
|
||||
输出格式示例:
|
||||
@@ -148,7 +155,7 @@ description: "Guides users through filling the official software copyright (计
|
||||
| 3 | 注释行占比 > 40% | info | 建议补充有效代码 |
|
||||
| 4 | 含第三方 License / Copyright 声明且与著作权人不一致 | error | 必须删除或修改 |
|
||||
| 5 | 实际行数与速查表"源程序量"相差 > 10% | warn | 同步修改申请表 |
|
||||
| 6 | 单行字符数 > 84 | warn | 折行换段 |
|
||||
| 6 | 单行显示宽度 > 84 列(中文记 2 列) | warn | 折行换段,续行缩进 4 空格;生成 docx 时必须主动折行,勿依赖 Word 自动换行 |
|
||||
| 7 | 含与著作权人无关的手机号 / 邮箱 | info | 脱敏后提交 |
|
||||
| 8 | 混入 package-lock.json / node_modules / .min.js 等构建产物 | warn | 移除后再上传 |
|
||||
|
||||
@@ -158,6 +165,24 @@ description: "Guides users through filling the official software copyright (计
|
||||
- ⚠️ **建议修改**:无 error,有 warn,列出具体项
|
||||
- ❌ **必须修改**:有 error,阻断提交
|
||||
|
||||
#### docx 版本生成(用户需要成品文件时)
|
||||
|
||||
用 Node + `docx` 库(v9)把 txt/md 排成规范 docx,关键实践:
|
||||
|
||||
- **页眉用 Word 域自动页码**:`PageNumber.CURRENT` / `PageNumber.TOTAL_PAGES`,
|
||||
配右对齐 Tab 位;勿在正文硬编码"共 M 页"——折行增多页数时域自动跟随
|
||||
- **精确分页**:每 N 行代码一页,下一页首段用 `pageBreakBefore: true`,
|
||||
保证"每页行数"与规范声明一致
|
||||
- **主动折行**:超 84 显示列的行在生成时折断(续行缩进 4 空格);
|
||||
依赖 Word 自动换行会导致每页物理行数失控、分页错位
|
||||
- **排版**:A4;边距上下 1.27cm、左右 1.5cm;代码 9.5pt Consolas
|
||||
(中文回退宋体);行距适度压缩(如 230/240)确保每页行数放得下
|
||||
- **依赖隔离**:在材料目录建独立 `package.json` 再 `npm install docx`;
|
||||
中文目录名会导致 `npm init -y` 失败(Invalid name),需手写合法 name;
|
||||
不隔离会污染用户项目根依赖(装错后必须还原 package.json 并删除误装的包)
|
||||
- **文件占用**:写入报 `EBUSY` 说明用户正在 Word 中打开该 docx,
|
||||
提示关闭后重试,勿反复盲试
|
||||
|
||||
## 设计说明书与用户操作手册(详细)
|
||||
|
||||
Skill 必须能根据"功能模块"列表生成完整的说明书文档,章节结构与项目代码 `buildManual` 一致:
|
||||
@@ -256,6 +281,32 @@ Skill 必须能根据"功能模块"列表生成完整的说明书文档,章节
|
||||
|
||||
输出"通过 / 建议修改 / 必须修改"三档结论,列出问题清单。
|
||||
|
||||
## 填表指引文档
|
||||
|
||||
用户要求生成"填表指引/调表指引"时,按在线申请表「软件开发信息」的 12 个系统字段
|
||||
逐项输出(字段名以中国版权保护中心系统实际为准),每项含
|
||||
「可直接粘贴的填写内容 + 填写要点」:
|
||||
|
||||
1. 开发的硬件环境(开发机配置,按实际开发电脑填写)
|
||||
2. 运行的硬件环境(目标设备,要求写低一些以扩大兼容范围)
|
||||
3. 开发该软件的操作系统
|
||||
4. 软件开发环境 / 开发工具(引擎编辑器、IDE、平台调试工具等,列主要项即可)
|
||||
5. 该软件的运行平台 / 操作系统
|
||||
6. 软件运行支撑环境 / 支持软件(如宿主 App、云服务)
|
||||
7. 编程语言(主语言;勿把 JSON/配置格式算作语言)
|
||||
8. 源程序量(与提交材料逻辑一致)
|
||||
9. 开发目的(如实填写,不夸大商业目标)
|
||||
10. 面向领域 / 行业(按系统下拉选项就近选择,游戏软件归文化娱乐类)
|
||||
11. 软件的主要功能(500 字以上,系统要求;覆盖各功能模块,游戏术语、书面语)
|
||||
12. 软件的技术特点(150-250 字)
|
||||
|
||||
**易错提示(必须写进指引)**:第 1/2 项(开发 vs 运行硬件)、第 3/5 项(开发 vs
|
||||
运行操作系统)是两对容易填反的字段,审查员会核对逻辑一致性。
|
||||
|
||||
指引还应包含:办理入口与实名认证、在线填报步骤、鉴别材料上传要求与 PDF 命名规范、
|
||||
提交前自检清单(checkbox)、常见退回原因与规避(已处理项标 ✅)、时间线参考、
|
||||
材料重新生成命令。
|
||||
|
||||
## 关键规则
|
||||
|
||||
- 所有对外材料一律使用「本软件」指代软件本身,不出现具体产品名
|
||||
|
||||
@@ -1781,7 +1781,7 @@
|
||||
"propertyPath": [
|
||||
"_active"
|
||||
],
|
||||
"value": true
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.TargetInfo",
|
||||
@@ -1800,7 +1800,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -30,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
@@ -1821,7 +1821,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 150,
|
||||
"height": 95.5
|
||||
"height": 35.5
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1838,7 +1838,7 @@
|
||||
"propertyPath": [
|
||||
"_active"
|
||||
],
|
||||
"value": true
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.TargetInfo",
|
||||
@@ -1869,7 +1869,7 @@
|
||||
"propertyPath": [
|
||||
"_top"
|
||||
],
|
||||
"value": -8.2625
|
||||
"value": 6.737500000000001
|
||||
},
|
||||
{
|
||||
"__type__": "cc.TargetInfo",
|
||||
@@ -1885,7 +1885,7 @@
|
||||
"propertyPath": [
|
||||
"_bottom"
|
||||
],
|
||||
"value": -7.237500000000001
|
||||
"value": 7.762499999999999
|
||||
},
|
||||
{
|
||||
"__type__": "CCPropertyOverrideInfo",
|
||||
@@ -1933,7 +1933,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 2.75,
|
||||
"y": 17.75,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
@@ -3659,7 +3659,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -30,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -3766,7 +3766,7 @@
|
||||
"__id__": 202
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_active": false,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 208
|
||||
@@ -4202,7 +4202,7 @@
|
||||
"__id__": 220
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_active": false,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 226
|
||||
@@ -4217,7 +4217,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 2.75,
|
||||
"y": 17.75,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -4635,7 +4635,7 @@
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 150,
|
||||
"height": 95.5
|
||||
"height": 35.5
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -4664,8 +4664,8 @@
|
||||
"_target": null,
|
||||
"_left": 0,
|
||||
"_right": 0,
|
||||
"_top": -8.2625,
|
||||
"_bottom": -7.237500000000001,
|
||||
"_top": 21.7375,
|
||||
"_bottom": 22.7625,
|
||||
"_horizontalCenter": 0,
|
||||
"_verticalCenter": 0,
|
||||
"_isAbsLeft": true,
|
||||
|
||||
@@ -11,29 +11,32 @@
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"enableTrsBlending": false,
|
||||
"_duration": 0.6,
|
||||
"_duration": 0.65,
|
||||
"_hash": 500763545,
|
||||
"_tracks": [
|
||||
{
|
||||
"__id__": 1
|
||||
},
|
||||
{
|
||||
"__id__": 7
|
||||
}
|
||||
],
|
||||
"_exoticAnimation": null,
|
||||
"_events": [
|
||||
{
|
||||
"frame": 0.2,
|
||||
"frame": 0.3,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.2,
|
||||
"frame": 0.3,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
}
|
||||
],
|
||||
"_embeddedPlayers": [],
|
||||
"_additiveSettings": {
|
||||
"__id__": 7
|
||||
"__id__": 13
|
||||
},
|
||||
"_auxiliaryCurveEntries": []
|
||||
},
|
||||
@@ -90,7 +93,8 @@
|
||||
0.4,
|
||||
0.45,
|
||||
0.5,
|
||||
0.55
|
||||
0.55,
|
||||
0.6
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
@@ -140,7 +144,98 @@
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5d13a",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
}
|
||||
},
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.ObjectTrack",
|
||||
"_binding": {
|
||||
"__type__": "cc.animation.TrackBinding",
|
||||
"path": {
|
||||
"__id__": 8
|
||||
},
|
||||
"proxy": null
|
||||
},
|
||||
"_channel": {
|
||||
"__id__": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.TrackPath",
|
||||
"_paths": [
|
||||
{
|
||||
"__id__": 9
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
"spriteFrame"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.HierarchyPath",
|
||||
"path": "slash-horizontal1"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.ComponentPath",
|
||||
"component": "cc.Sprite"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.ObjectCurve",
|
||||
"_times": [
|
||||
0.15,
|
||||
0.2,
|
||||
0.25,
|
||||
0.3,
|
||||
0.35,
|
||||
0.4,
|
||||
0.45,
|
||||
0.5,
|
||||
0.55,
|
||||
0.6
|
||||
],
|
||||
"_values": [
|
||||
null,
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d5755",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d5755",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@34609",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@35b2b",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@0e377",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@cb59a",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5adf0",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6c6f6",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -11,29 +11,32 @@
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"enableTrsBlending": false,
|
||||
"_duration": 0.4583333333333333,
|
||||
"_duration": 0.5833333333333334,
|
||||
"_hash": 500763545,
|
||||
"_tracks": [
|
||||
{
|
||||
"__id__": 1
|
||||
},
|
||||
{
|
||||
"__id__": 7
|
||||
}
|
||||
],
|
||||
"_exoticAnimation": null,
|
||||
"_events": [
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"frame": 0.16666666666666666,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"frame": 0.16666666666666666,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
}
|
||||
],
|
||||
"_embeddedPlayers": [],
|
||||
"_additiveSettings": {
|
||||
"__id__": 7
|
||||
"__id__": 13
|
||||
},
|
||||
"_auxiliaryCurveEntries": []
|
||||
},
|
||||
@@ -89,7 +92,8 @@
|
||||
0.2916666666666667,
|
||||
0.3333333333333333,
|
||||
0.375,
|
||||
0.4166666666666667
|
||||
0.4166666666666667,
|
||||
0.4583333333333333
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
@@ -135,7 +139,95 @@
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@21b99",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
}
|
||||
},
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.ObjectTrack",
|
||||
"_binding": {
|
||||
"__type__": "cc.animation.TrackBinding",
|
||||
"path": {
|
||||
"__id__": 8
|
||||
},
|
||||
"proxy": null
|
||||
},
|
||||
"_channel": {
|
||||
"__id__": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.TrackPath",
|
||||
"_paths": [
|
||||
{
|
||||
"__id__": 9
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
"spriteFrame"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.HierarchyPath",
|
||||
"path": "slash-horizontal1"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.ComponentPath",
|
||||
"component": "cc.Sprite"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.ObjectCurve",
|
||||
"_times": [
|
||||
0,
|
||||
0.20833333333333334,
|
||||
0.25,
|
||||
0.2916666666666667,
|
||||
0.3333333333333333,
|
||||
0.375,
|
||||
0.4166666666666667,
|
||||
0.4583333333333333,
|
||||
0.5,
|
||||
0.5416666666666666
|
||||
],
|
||||
"_values": [
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d5755",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@34609",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@35b2b",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@0e377",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@cb59a",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5adf0",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6c6f6",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -11,29 +11,32 @@
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"enableTrsBlending": false,
|
||||
"_duration": 0.4166666666666667,
|
||||
"_duration": 0.7083333333333334,
|
||||
"_hash": 500763545,
|
||||
"_tracks": [
|
||||
{
|
||||
"__id__": 1
|
||||
},
|
||||
{
|
||||
"__id__": 7
|
||||
}
|
||||
],
|
||||
"_exoticAnimation": null,
|
||||
"_events": [
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"frame": 0.16666666666666666,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.08333333333333333,
|
||||
"frame": 0.16666666666666666,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
}
|
||||
],
|
||||
"_embeddedPlayers": [],
|
||||
"_additiveSettings": {
|
||||
"__id__": 7
|
||||
"__id__": 13
|
||||
},
|
||||
"_auxiliaryCurveEntries": []
|
||||
},
|
||||
@@ -88,7 +91,8 @@
|
||||
0.25,
|
||||
0.2916666666666667,
|
||||
0.3333333333333333,
|
||||
0.375
|
||||
0.375,
|
||||
0.4166666666666667
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
@@ -130,7 +134,115 @@
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@daa57",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
}
|
||||
},
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.ObjectTrack",
|
||||
"_binding": {
|
||||
"__type__": "cc.animation.TrackBinding",
|
||||
"path": {
|
||||
"__id__": 8
|
||||
},
|
||||
"proxy": null
|
||||
},
|
||||
"_channel": {
|
||||
"__id__": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.TrackPath",
|
||||
"_paths": [
|
||||
{
|
||||
"__id__": 9
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
"spriteFrame"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.HierarchyPath",
|
||||
"path": "fire-slash-horizontal1"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.ComponentPath",
|
||||
"component": "cc.Sprite"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.ObjectCurve",
|
||||
"_times": [
|
||||
0,
|
||||
0.16666666666666666,
|
||||
0.20833333333333334,
|
||||
0.25,
|
||||
0.2916666666666667,
|
||||
0.3333333333333333,
|
||||
0.375,
|
||||
0.4166666666666667,
|
||||
0.4583333333333333,
|
||||
0.5,
|
||||
0.5416666666666666,
|
||||
0.5833333333333334,
|
||||
0.625,
|
||||
0.6666666666666666
|
||||
],
|
||||
"_values": [
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@38937",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@31859",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@33f97",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@0ff1b",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@4953c",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@cb80d",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d0b5c",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@4ce52",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@90cfe",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@17d94",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@64baf",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -11,39 +11,32 @@
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"enableTrsBlending": false,
|
||||
"_duration": 0.625,
|
||||
"_duration": 0.75,
|
||||
"_hash": 500763545,
|
||||
"_tracks": [
|
||||
{
|
||||
"__id__": 1
|
||||
},
|
||||
{
|
||||
"__id__": 7
|
||||
}
|
||||
],
|
||||
"_exoticAnimation": null,
|
||||
"_events": [
|
||||
{
|
||||
"frame": 0.20833333333333334,
|
||||
"frame": 0.375,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.20833333333333334,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.4583333333333333,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.4583333333333333,
|
||||
"frame": 0.375,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
}
|
||||
],
|
||||
"_embeddedPlayers": [],
|
||||
"_additiveSettings": {
|
||||
"__id__": 7
|
||||
"__id__": 13
|
||||
},
|
||||
"_auxiliaryCurveEntries": []
|
||||
},
|
||||
@@ -103,7 +96,8 @@
|
||||
0.4583333333333333,
|
||||
0.5,
|
||||
0.5416666666666666,
|
||||
0.5833333333333334
|
||||
0.5833333333333334,
|
||||
0.625
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
@@ -165,7 +159,115 @@
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@1b470",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
}
|
||||
},
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.ObjectTrack",
|
||||
"_binding": {
|
||||
"__type__": "cc.animation.TrackBinding",
|
||||
"path": {
|
||||
"__id__": 8
|
||||
},
|
||||
"proxy": null
|
||||
},
|
||||
"_channel": {
|
||||
"__id__": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.TrackPath",
|
||||
"_paths": [
|
||||
{
|
||||
"__id__": 9
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
"spriteFrame"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.HierarchyPath",
|
||||
"path": "electric-slash-horizontal1"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.ComponentPath",
|
||||
"component": "cc.Sprite"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.ObjectCurve",
|
||||
"_times": [
|
||||
0,
|
||||
0.20833333333333334,
|
||||
0.25,
|
||||
0.2916666666666667,
|
||||
0.3333333333333333,
|
||||
0.375,
|
||||
0.4166666666666667,
|
||||
0.4583333333333333,
|
||||
0.5,
|
||||
0.5416666666666666,
|
||||
0.5833333333333334,
|
||||
0.625,
|
||||
0.6666666666666666,
|
||||
0.7083333333333334
|
||||
],
|
||||
"_values": [
|
||||
null,
|
||||
null,
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@f6490",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6c874",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5b5e5",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5cc03",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@161b8",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@01fef",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@70d19",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@34499",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@9ec10",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@9e7f6",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@99406",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
null
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -89,30 +89,33 @@
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5cbcb",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@3981b",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@1837a",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@341ea",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@494bc",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@494bc",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
null
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
921
assets/resources/game/skill/anm/atk/fb-8.anim
Normal file
@@ -0,0 +1,921 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "fb-8",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {
|
||||
"embeddedPlayerGroups": []
|
||||
},
|
||||
"_native": "",
|
||||
"sample": 20,
|
||||
"speed": 1,
|
||||
"wrapMode": 1,
|
||||
"enableTrsBlending": false,
|
||||
"_duration": 1.4,
|
||||
"_hash": 500763545,
|
||||
"_tracks": [
|
||||
{
|
||||
"__id__": 1
|
||||
},
|
||||
{
|
||||
"__id__": 7
|
||||
},
|
||||
{
|
||||
"__id__": 13
|
||||
},
|
||||
{
|
||||
"__id__": 24
|
||||
}
|
||||
],
|
||||
"_exoticAnimation": null,
|
||||
"_events": [
|
||||
{
|
||||
"frame": 0,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.6,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 0.6,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 1.2,
|
||||
"func": "",
|
||||
"params": []
|
||||
},
|
||||
{
|
||||
"frame": 1.2,
|
||||
"func": "atk",
|
||||
"params": []
|
||||
}
|
||||
],
|
||||
"_embeddedPlayers": [],
|
||||
"_additiveSettings": {
|
||||
"__id__": 35
|
||||
},
|
||||
"_auxiliaryCurveEntries": []
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.ObjectTrack",
|
||||
"_binding": {
|
||||
"__type__": "cc.animation.TrackBinding",
|
||||
"path": {
|
||||
"__id__": 2
|
||||
},
|
||||
"proxy": null
|
||||
},
|
||||
"_channel": {
|
||||
"__id__": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.TrackPath",
|
||||
"_paths": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 4
|
||||
},
|
||||
"spriteFrame"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.HierarchyPath",
|
||||
"path": "Node"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.ComponentPath",
|
||||
"component": "cc.Sprite"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 6
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.ObjectCurve",
|
||||
"_times": [
|
||||
0,
|
||||
0.05,
|
||||
0.1,
|
||||
0.15,
|
||||
0.2,
|
||||
0.25,
|
||||
0.3,
|
||||
0.35,
|
||||
0.4,
|
||||
0.45,
|
||||
0.5,
|
||||
0.55,
|
||||
0.6,
|
||||
0.65,
|
||||
0.7,
|
||||
0.75,
|
||||
0.8,
|
||||
0.85,
|
||||
0.9,
|
||||
0.95,
|
||||
1,
|
||||
1.05,
|
||||
1.1,
|
||||
1.15,
|
||||
1.2,
|
||||
1.25,
|
||||
1.3,
|
||||
1.35
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.ObjectTrack",
|
||||
"_binding": {
|
||||
"__type__": "cc.animation.TrackBinding",
|
||||
"path": {
|
||||
"__id__": 8
|
||||
},
|
||||
"proxy": null
|
||||
},
|
||||
"_channel": {
|
||||
"__id__": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.TrackPath",
|
||||
"_paths": [
|
||||
{
|
||||
"__id__": 9
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
"spriteFrame"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.HierarchyPath",
|
||||
"path": "Node-001"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.ComponentPath",
|
||||
"component": "cc.Sprite"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.ObjectCurve",
|
||||
"_times": [
|
||||
0,
|
||||
0.05,
|
||||
0.1,
|
||||
0.15,
|
||||
0.2,
|
||||
0.25,
|
||||
0.3,
|
||||
0.35,
|
||||
0.4,
|
||||
0.45,
|
||||
0.5,
|
||||
0.55,
|
||||
0.6,
|
||||
0.65,
|
||||
0.7,
|
||||
0.75,
|
||||
0.8,
|
||||
0.85,
|
||||
0.9,
|
||||
0.95,
|
||||
1,
|
||||
1.05,
|
||||
1.1,
|
||||
1.15,
|
||||
1.2,
|
||||
1.25,
|
||||
1.3,
|
||||
1.35
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@2ac32",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@a38c9",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@005f7",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@d585f",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@740a0",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@6b34e",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.VectorTrack",
|
||||
"_binding": {
|
||||
"__type__": "cc.animation.TrackBinding",
|
||||
"path": {
|
||||
"__id__": 14
|
||||
},
|
||||
"proxy": null
|
||||
},
|
||||
"_channels": [
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
},
|
||||
{
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_nComponents": 3
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.TrackPath",
|
||||
"_paths": [
|
||||
{
|
||||
"__id__": 15
|
||||
},
|
||||
"position"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.HierarchyPath",
|
||||
"path": "Node"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 17
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealCurve",
|
||||
"_times": [
|
||||
0,
|
||||
0.65,
|
||||
1.35
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -70,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": 70,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -70,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"preExtrapolation": 1,
|
||||
"postExtrapolation": 1
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealCurve",
|
||||
"_times": [
|
||||
0,
|
||||
0.3,
|
||||
0.65,
|
||||
1,
|
||||
1.35
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -60,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -70,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -60,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -50,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -60,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"preExtrapolation": 1,
|
||||
"postExtrapolation": 1
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 21
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealCurve",
|
||||
"_times": [],
|
||||
"_values": [],
|
||||
"preExtrapolation": 1,
|
||||
"postExtrapolation": 1
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 23
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealCurve",
|
||||
"_times": [],
|
||||
"_values": [],
|
||||
"preExtrapolation": 1,
|
||||
"postExtrapolation": 1
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.VectorTrack",
|
||||
"_binding": {
|
||||
"__type__": "cc.animation.TrackBinding",
|
||||
"path": {
|
||||
"__id__": 25
|
||||
},
|
||||
"proxy": null
|
||||
},
|
||||
"_channels": [
|
||||
{
|
||||
"__id__": 27
|
||||
},
|
||||
{
|
||||
"__id__": 29
|
||||
},
|
||||
{
|
||||
"__id__": 31
|
||||
},
|
||||
{
|
||||
"__id__": 33
|
||||
}
|
||||
],
|
||||
"_nComponents": 3
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.TrackPath",
|
||||
"_paths": [
|
||||
{
|
||||
"__id__": 26
|
||||
},
|
||||
"position"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.HierarchyPath",
|
||||
"path": "Node-001"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 28
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealCurve",
|
||||
"_times": [
|
||||
0,
|
||||
0.65,
|
||||
1.35
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": 70,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -70,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": 70,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"preExtrapolation": 1,
|
||||
"postExtrapolation": 1
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 30
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealCurve",
|
||||
"_times": [
|
||||
0,
|
||||
0.3,
|
||||
0.65,
|
||||
1,
|
||||
1.35
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -60,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -50,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -60,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -70,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": -60,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"preExtrapolation": 1,
|
||||
"postExtrapolation": 1
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 32
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealCurve",
|
||||
"_times": [
|
||||
0,
|
||||
0.65,
|
||||
1.35
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": 0,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": 0,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": 0,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"broken": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"preExtrapolation": 1,
|
||||
"postExtrapolation": 1
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 34
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealCurve",
|
||||
"_times": [],
|
||||
"_values": [],
|
||||
"preExtrapolation": 1,
|
||||
"postExtrapolation": 1
|
||||
},
|
||||
{
|
||||
"__type__": "cc.AnimationClipAdditiveSettings",
|
||||
"enabled": false,
|
||||
"refClip": null
|
||||
}
|
||||
]
|
||||
13
assets/resources/game/skill/anm/atk/fb-8.anim.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "2.0.3",
|
||||
"importer": "animation-clip",
|
||||
"imported": true,
|
||||
"uuid": "b0bec9a1-c3c7-412f-b6de-e27ec78dcc86",
|
||||
"files": [
|
||||
".cconb"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"name": "fb-8"
|
||||
}
|
||||
}
|
||||
@@ -76,23 +76,23 @@
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@2cfc2",
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@03bc8",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@1ca40",
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@acc42",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@66637",
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@aaff4",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@cf65d",
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@05059",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@1e597",
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@4b51f",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -76,23 +76,23 @@
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@94f10",
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@03bc8",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@ab87c",
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@acc42",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@7c2ba",
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@aaff4",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@d6871",
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@05059",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
{
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@4cd95",
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@4b51f",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -20,28 +20,31 @@
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 8
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 12
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
},
|
||||
{
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 18
|
||||
"__id__": 24
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -211,6 +214,139 @@
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "slash-horizontal1",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 9
|
||||
},
|
||||
{
|
||||
"__id__": 11
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 13
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 2,
|
||||
"y": 2,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 10
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 95,
|
||||
"height": 48
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "0aybWnCBJDBb3WOXwo/YxC"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": null,
|
||||
"_type": 0,
|
||||
"_fillType": 0,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": null,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "45iYWOPyBCNKkmXE+dmADF"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "bdI0RFo3VCNKhgFojxldzA",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
@@ -221,7 +357,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
"__id__": 15
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -249,7 +385,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
"__id__": 17
|
||||
},
|
||||
"atk_x": 20,
|
||||
"atk_y": 40,
|
||||
@@ -261,6 +397,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 1,
|
||||
"summon_target_mode": 0,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 0,
|
||||
"_id": ""
|
||||
},
|
||||
@@ -278,7 +418,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 13
|
||||
"__id__": 19
|
||||
},
|
||||
"enabledContactListener": true,
|
||||
"bullet": false,
|
||||
@@ -312,7 +452,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 15
|
||||
"__id__": 21
|
||||
},
|
||||
"tag": 0,
|
||||
"_group": 1,
|
||||
@@ -346,7 +486,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
"__id__": 23
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
|
||||
@@ -20,28 +20,31 @@
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 8
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 12
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
},
|
||||
{
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 18
|
||||
"__id__": 24
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -211,6 +214,139 @@
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "slash-horizontal1",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 9
|
||||
},
|
||||
{
|
||||
"__id__": 11
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 13
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 2,
|
||||
"y": 2,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 10
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 95,
|
||||
"height": 48
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "82TGDP+iVBv4P1whT99OBW"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": null,
|
||||
"_type": 0,
|
||||
"_fillType": 0,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": null,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "daC3XwzZFG4JHd5pqsR70r"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "e8yfxZXCJCU6wnX0/ttDjH",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
@@ -221,7 +357,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
"__id__": 15
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -249,7 +385,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
"__id__": 17
|
||||
},
|
||||
"atk_x": 20,
|
||||
"atk_y": 40,
|
||||
@@ -261,6 +397,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 1,
|
||||
"summon_target_mode": 0,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 0,
|
||||
"_id": ""
|
||||
},
|
||||
@@ -278,7 +418,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 13
|
||||
"__id__": 19
|
||||
},
|
||||
"enabledContactListener": true,
|
||||
"bullet": false,
|
||||
@@ -312,7 +452,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 15
|
||||
"__id__": 21
|
||||
},
|
||||
"tag": 0,
|
||||
"_group": 1,
|
||||
@@ -346,7 +486,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
"__id__": 23
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
|
||||
@@ -20,28 +20,31 @@
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 8
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 12
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
},
|
||||
{
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 18
|
||||
"__id__": 24
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -173,7 +176,7 @@
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@13b06",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@7e6d7",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
@@ -211,6 +214,139 @@
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "fire-slash-horizontal1",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 9
|
||||
},
|
||||
{
|
||||
"__id__": 11
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 13
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 29.777,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 2,
|
||||
"y": 2,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 10
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 95,
|
||||
"height": 48
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "61GNVJPatIJoTFQpCuL1tc"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": null,
|
||||
"_type": 0,
|
||||
"_fillType": 0,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": null,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "64tuHxFsxBMK3c6Rl+GQll"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "05Mo/yQRtK5YAX1chbWL76",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
@@ -221,7 +357,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
"__id__": 15
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -249,7 +385,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
"__id__": 17
|
||||
},
|
||||
"atk_x": 20,
|
||||
"atk_y": 40,
|
||||
@@ -261,6 +397,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 1,
|
||||
"summon_target_mode": 0,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 0,
|
||||
"_id": ""
|
||||
},
|
||||
@@ -278,7 +418,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 13
|
||||
"__id__": 19
|
||||
},
|
||||
"enabledContactListener": true,
|
||||
"bullet": false,
|
||||
@@ -312,7 +452,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 15
|
||||
"__id__": 21
|
||||
},
|
||||
"tag": 0,
|
||||
"_group": 1,
|
||||
@@ -346,7 +486,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
"__id__": 23
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
|
||||
@@ -20,28 +20,31 @@
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 8
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
},
|
||||
{
|
||||
"__id__": 12
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
},
|
||||
{
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 18
|
||||
"__id__": 24
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -211,6 +214,142 @@
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "electric-slash-horizontal1",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 9
|
||||
},
|
||||
{
|
||||
"__id__": 11
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 13
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 25.352,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 2,
|
||||
"y": 2,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 10
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 95,
|
||||
"height": 48
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "598QTUIYhAD5NxyPBcSrlV"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@f6490",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
"_fillType": 0,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": null,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "79xdyqEqhFdZmXNHgUvUaA"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "d1hgL10YVE8a0CvDCyOdTd",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
@@ -221,7 +360,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
"__id__": 15
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
@@ -249,7 +388,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
"__id__": 17
|
||||
},
|
||||
"atk_x": 20,
|
||||
"atk_y": 40,
|
||||
@@ -261,6 +400,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 1,
|
||||
"summon_target_mode": 0,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 0,
|
||||
"_id": ""
|
||||
},
|
||||
@@ -278,7 +421,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 13
|
||||
"__id__": 19
|
||||
},
|
||||
"enabledContactListener": true,
|
||||
"bullet": false,
|
||||
@@ -312,7 +455,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 15
|
||||
"__id__": 21
|
||||
},
|
||||
"tag": 0,
|
||||
"_group": 1,
|
||||
@@ -346,7 +489,7 @@
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
"__id__": 23
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
|
||||
@@ -35,10 +35,13 @@
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 16
|
||||
"__id__": 18
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -92,8 +95,8 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 6.77,
|
||||
"y": 0,
|
||||
"x": 0,
|
||||
"y": -60,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -105,8 +108,8 @@
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.3,
|
||||
"y": 0.3,
|
||||
"x": 1.4,
|
||||
"y": 2,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
@@ -133,13 +136,13 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 90,
|
||||
"height": 90
|
||||
"width": 128,
|
||||
"height": 128
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
@@ -170,7 +173,7 @@
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@4d4df",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
@@ -222,13 +225,13 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"height": 40
|
||||
"width": 20,
|
||||
"height": 100
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
@@ -248,13 +251,26 @@
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"atk_x": 10,
|
||||
"atk_y": 15,
|
||||
"atk_x": 0,
|
||||
"atk_y": 0,
|
||||
"runType": 3,
|
||||
"endType": 0,
|
||||
"speed": 720,
|
||||
"time": 0,
|
||||
"distance": 0,
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 1,
|
||||
"summon_target_mode": 0,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "60LInmZXxDtKu79AshRG9j"
|
||||
"fileId": "35nW0iQNBH2bqkWAr3MVkQ"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RigidBody2D",
|
||||
@@ -288,7 +304,7 @@
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "e1yBA625RLwLhzo6bLYW7j"
|
||||
"fileId": "57cr7S0YpK4oEZCavwXtIX"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.BoxCollider2D",
|
||||
@@ -315,14 +331,43 @@
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"height": 40
|
||||
"width": 20,
|
||||
"height": 100
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "43ZDJfXX9AX73gyytKQZWm"
|
||||
"fileId": "ebw5mObxNGGKxnJXDgX5gl"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Animation",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
{
|
||||
"__uuid__": "45605d53-4dca-4529-819d-4a0d98c3a47c",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
}
|
||||
],
|
||||
"_defaultClip": {
|
||||
"__uuid__": "45605d53-4dca-4529-819d-4a0d98c3a47c",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "20U0hP/NZErJJXRCEib1lq"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "fc32700f-bf4a-47ce-b619-6497b7280fde",
|
||||
"uuid": "7edb8215-1344-4215-8172-7a50a72da8bb",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
|
||||
@@ -35,10 +35,13 @@
|
||||
},
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 16
|
||||
"__id__": 18
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
@@ -92,7 +95,7 @@
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 6.77,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
@@ -100,13 +103,13 @@
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
"z": 0.706489444943837,
|
||||
"w": 0.7077235789366842
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.3,
|
||||
"y": 0.3,
|
||||
"x": -1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
@@ -115,7 +118,7 @@
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
"z": 89.9
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
@@ -133,8 +136,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 90,
|
||||
"height": 90
|
||||
"width": 85,
|
||||
"height": 119
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -170,7 +173,7 @@
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@179ff",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@59ec8",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
@@ -222,8 +225,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"height": 40
|
||||
"width": 50,
|
||||
"height": 50
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -248,13 +251,25 @@
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"atk_x": 10,
|
||||
"atk_y": 15,
|
||||
"atk_x": 20,
|
||||
"atk_y": 20,
|
||||
"runType": 0,
|
||||
"endType": 2,
|
||||
"speed": 720,
|
||||
"time": 0,
|
||||
"distance": 0,
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 1,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "60LInmZXxDtKu79AshRG9j"
|
||||
"fileId": "35nW0iQNBH2bqkWAr3MVkQ"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RigidBody2D",
|
||||
@@ -288,7 +303,7 @@
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "e1yBA625RLwLhzo6bLYW7j"
|
||||
"fileId": "57cr7S0YpK4oEZCavwXtIX"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.BoxCollider2D",
|
||||
@@ -315,14 +330,43 @@
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 30,
|
||||
"height": 40
|
||||
"width": 50,
|
||||
"height": 150
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "43ZDJfXX9AX73gyytKQZWm"
|
||||
"fileId": "ebw5mObxNGGKxnJXDgX5gl"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Animation",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
{
|
||||
"__uuid__": "45385cba-7334-4ff4-a548-578262417f58",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
}
|
||||
],
|
||||
"_defaultClip": {
|
||||
"__uuid__": "45385cba-7334-4ff4-a548-578262417f58",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "20U0hP/NZErJJXRCEib1lq"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "5a0c6727-c741-4a33-b6f2-b2c56e3fc540",
|
||||
"uuid": "7c7ff7a4-17d5-4c4a-8fee-68b73af250e5",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
|
||||
519
assets/resources/game/skill/atk/m5.prefab
Normal file
@@ -0,0 +1,519 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "m5",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "m5",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 8
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
},
|
||||
{
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 24
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "Node",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 5
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -0.5,
|
||||
"y": 0.5,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 277,
|
||||
"height": 250
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "93pNmvtQlLSqtTgIepyEmA"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@260b5",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
"_fillType": 0,
|
||||
"_sizeMode": 0,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20",
|
||||
"__expectedType__": "cc.SpriteAtlas"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "12eKc8gltBz50frJCS5+ww"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "3arqAMBz1MvoXBzeDaL5M/",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "Node-001",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 9
|
||||
},
|
||||
{
|
||||
"__id__": 11
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 13
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": -0.5,
|
||||
"y": 0.5,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 10
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 122,
|
||||
"height": 68
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "4blcTDlixIRI3qtyERLs2E"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": null,
|
||||
"_type": 0,
|
||||
"_fillType": 0,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": null,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "e6QtagQwZA/50lsdWvOjb0"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "ed54OCubBD853t6+5pUPLQ",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 15
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 50,
|
||||
"height": 100
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "63NP9yq3hEUKD/OZZZ5t7x"
|
||||
},
|
||||
{
|
||||
"__type__": "57aabs7TE1J5obTAZczc+64",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
},
|
||||
"atk_x": 0,
|
||||
"atk_y": 0,
|
||||
"runType": 0,
|
||||
"endType": 2,
|
||||
"speed": 720,
|
||||
"time": 0,
|
||||
"distance": 0,
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 1,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "35nW0iQNBH2bqkWAr3MVkQ"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RigidBody2D",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 19
|
||||
},
|
||||
"enabledContactListener": true,
|
||||
"bullet": false,
|
||||
"awakeOnLoad": true,
|
||||
"_group": 1,
|
||||
"_type": 1,
|
||||
"_allowSleep": false,
|
||||
"_gravityScale": 1,
|
||||
"_linearDamping": 0,
|
||||
"_angularDamping": 0,
|
||||
"_linearVelocity": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_angularVelocity": 0,
|
||||
"_fixedRotation": false,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "57cr7S0YpK4oEZCavwXtIX"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.BoxCollider2D",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 21
|
||||
},
|
||||
"tag": 0,
|
||||
"_group": 1,
|
||||
"_density": 1,
|
||||
"_sensor": true,
|
||||
"_friction": 0.2,
|
||||
"_restitution": 0,
|
||||
"_offset": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 50
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 50,
|
||||
"height": 100
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "ebw5mObxNGGKxnJXDgX5gl"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Animation",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 23
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
{
|
||||
"__uuid__": "a71379d4-b14d-4070-96ee-e7c889f25bbd",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
}
|
||||
],
|
||||
"_defaultClip": {
|
||||
"__uuid__": "a71379d4-b14d-4070-96ee-e7c889f25bbd",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "20U0hP/NZErJJXRCEib1lq"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
@@ -2,12 +2,12 @@
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "91e5e3e3-d2f1-4522-9f82-649e9bc8f8db",
|
||||
"uuid": "8dc65122-222f-4bd3-b89c-62e7f8eefe78",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "up_red"
|
||||
"syncNodeName": "m5"
|
||||
}
|
||||
}
|
||||
@@ -293,6 +293,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 4,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -293,6 +293,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 6,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -261,6 +261,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 3,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -397,6 +397,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 3,
|
||||
"summon_target_mode": 0,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0.2,
|
||||
"height_offset": 0,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -30,
|
||||
"y": -90,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -108,8 +108,8 @@
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0.9,
|
||||
"y": 1,
|
||||
"x": 1.5,
|
||||
"y": 2,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
@@ -136,8 +136,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 65,
|
||||
"height": 330
|
||||
"width": 128,
|
||||
"height": 128
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -173,7 +173,7 @@
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@5cbcb",
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
@@ -261,6 +261,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 5,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 0,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -261,6 +261,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 3,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0.5,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -261,6 +261,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 3,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
@@ -261,6 +261,10 @@
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 3,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0,
|
||||
"height_offset": 100,
|
||||
"_id": ""
|
||||
},
|
||||
|
||||
526
assets/resources/game/skill/atk/maxm7.prefab
Normal file
@@ -0,0 +1,526 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "maxm7",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "maxm7",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
},
|
||||
{
|
||||
"__id__": 8
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 14
|
||||
},
|
||||
{
|
||||
"__id__": 16
|
||||
},
|
||||
{
|
||||
"__id__": 18
|
||||
},
|
||||
{
|
||||
"__id__": 20
|
||||
},
|
||||
{
|
||||
"__id__": 22
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 24
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "Node",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 5
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -30,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 2,
|
||||
"y": 2,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 128,
|
||||
"height": 128
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "93pNmvtQlLSqtTgIepyEmA"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
"_fillType": 0,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20",
|
||||
"__expectedType__": "cc.SpriteAtlas"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "12eKc8gltBz50frJCS5+ww"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "3arqAMBz1MvoXBzeDaL5M/",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "Node-001",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 9
|
||||
},
|
||||
{
|
||||
"__id__": 11
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 13
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -30,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 2,
|
||||
"y": 2,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1073741824,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 10
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 128,
|
||||
"height": 128
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "cbS/mBx7hFKK1RlGcpOgD1"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 8
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20@55402",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
"_fillType": 0,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0,
|
||||
"_fillRange": 0,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": {
|
||||
"__uuid__": "2842dc10-d89e-4ff6-8a11-6d09bf48cf20",
|
||||
"__expectedType__": "cc.SpriteAtlas"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "eah7cf5S5FCrmP7CHX5e38"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "f9cYdo2HdAp7KWposjmIcg",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 15
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 200,
|
||||
"height": 100
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0.3
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "63NP9yq3hEUKD/OZZZ5t7x"
|
||||
},
|
||||
{
|
||||
"__type__": "57aabs7TE1J5obTAZczc+64",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 17
|
||||
},
|
||||
"atk_x": 0,
|
||||
"atk_y": 0,
|
||||
"runType": 3,
|
||||
"endType": 0,
|
||||
"speed": 720,
|
||||
"time": 0,
|
||||
"distance": 0,
|
||||
"forceStartX": -1,
|
||||
"forceStartY": -1,
|
||||
"summon_count": 1,
|
||||
"summon_target_mode": 2,
|
||||
"summon_x_offset": 0,
|
||||
"summon_y_offset": 0,
|
||||
"summon_interval": 0.5,
|
||||
"height_offset": 0,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "35nW0iQNBH2bqkWAr3MVkQ"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RigidBody2D",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 19
|
||||
},
|
||||
"enabledContactListener": true,
|
||||
"bullet": false,
|
||||
"awakeOnLoad": true,
|
||||
"_group": 1,
|
||||
"_type": 1,
|
||||
"_allowSleep": false,
|
||||
"_gravityScale": 1,
|
||||
"_linearDamping": 0,
|
||||
"_angularDamping": 0,
|
||||
"_linearVelocity": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_angularVelocity": 0,
|
||||
"_fixedRotation": false,
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "57cr7S0YpK4oEZCavwXtIX"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.BoxCollider2D",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 21
|
||||
},
|
||||
"tag": 0,
|
||||
"_group": 1,
|
||||
"_density": 1,
|
||||
"_sensor": true,
|
||||
"_friction": 0.2,
|
||||
"_restitution": 0,
|
||||
"_offset": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_size": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 200,
|
||||
"height": 100
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "ebw5mObxNGGKxnJXDgX5gl"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Animation",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 23
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
{
|
||||
"__uuid__": "b0bec9a1-c3c7-412f-b6de-e27ec78dcc86",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
}
|
||||
],
|
||||
"_defaultClip": {
|
||||
"__uuid__": "b0bec9a1-c3c7-412f-b6de-e27ec78dcc86",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "20U0hP/NZErJJXRCEib1lq"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
@@ -2,12 +2,12 @@
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "55e98478-734f-4d85-92b2-0a62a52c494c",
|
||||
"uuid": "2316d214-bb61-434e-a056-48793e72dcce",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "up_blue"
|
||||
"syncNodeName": "maxm7"
|
||||
}
|
||||
}
|
||||
@@ -158,13 +158,13 @@
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"r": 10,
|
||||
"g": 206,
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@2cfc2",
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@03bc8",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
|
||||
@@ -159,12 +159,12 @@
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"g": 12,
|
||||
"b": 12,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@94f10",
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@03bc8",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 0,
|
||||
|
||||
@@ -1,274 +0,0 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "up_blue",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "up_blue",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "skill",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 5
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1.3,
|
||||
"y": 1.3,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 77,
|
||||
"height": 77
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "b4sNQPJWFKha7x75SWXmRj"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 206
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@e7e9c",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 1,
|
||||
"_fillType": 1,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0.2,
|
||||
"_fillRange": 1,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6",
|
||||
"__expectedType__": "cc.SpriteAtlas"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "9a+65VIghBm4HQxuHPQ/mg"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "7a5LvbdlxEc6FKa7cun2oB",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 80,
|
||||
"height": 110
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "63NP9yq3hEUKD/OZZZ5t7x"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Animation",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
{
|
||||
"__uuid__": "81e87781-7328-4283-a747-060707c41880",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
}
|
||||
],
|
||||
"_defaultClip": {
|
||||
"__uuid__": "81e87781-7328-4283-a747-060707c41880",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "c6LOemuvJKyYCqlF/yUJcr"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
@@ -1,274 +0,0 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "up_green",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "up_green",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "skill",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 5
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1.3,
|
||||
"y": 1.3,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 77,
|
||||
"height": 77
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "b4sNQPJWFKha7x75SWXmRj"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 206
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@e7e9c",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 1,
|
||||
"_fillType": 1,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0.2,
|
||||
"_fillRange": 1,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6",
|
||||
"__expectedType__": "cc.SpriteAtlas"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "9a+65VIghBm4HQxuHPQ/mg"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "7a5LvbdlxEc6FKa7cun2oB",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 80,
|
||||
"height": 110
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "63NP9yq3hEUKD/OZZZ5t7x"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Animation",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
{
|
||||
"__uuid__": "01337a12-a04d-41f5-8f1f-efbf16989fb3",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
}
|
||||
],
|
||||
"_defaultClip": {
|
||||
"__uuid__": "01337a12-a04d-41f5-8f1f-efbf16989fb3",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "c6LOemuvJKyYCqlF/yUJcr"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
@@ -1,274 +0,0 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "up_red",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "up_red",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "skill",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 5
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1.3,
|
||||
"y": 1.3,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 77,
|
||||
"height": 77
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "b4sNQPJWFKha7x75SWXmRj"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 206
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@e7e9c",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 1,
|
||||
"_fillType": 1,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0.2,
|
||||
"_fillRange": 1,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6",
|
||||
"__expectedType__": "cc.SpriteAtlas"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "9a+65VIghBm4HQxuHPQ/mg"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "7a5LvbdlxEc6FKa7cun2oB",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 80,
|
||||
"height": 110
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "63NP9yq3hEUKD/OZZZ5t7x"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Animation",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
{
|
||||
"__uuid__": "0f9dab25-82b0-4b96-b649-7c6162deafa0",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
}
|
||||
],
|
||||
"_defaultClip": {
|
||||
"__uuid__": "0f9dab25-82b0-4b96-b649-7c6162deafa0",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "c6LOemuvJKyYCqlF/yUJcr"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
@@ -1,274 +0,0 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "up_blue",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "up_blue",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "skill",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 5
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -7.953,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1.3,
|
||||
"y": 1.3,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 77,
|
||||
"height": 77
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "b4sNQPJWFKha7x75SWXmRj"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 206
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@e7e9c",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 1,
|
||||
"_fillType": 1,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0.2,
|
||||
"_fillRange": 1,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6",
|
||||
"__expectedType__": "cc.SpriteAtlas"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "9a+65VIghBm4HQxuHPQ/mg"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "7a5LvbdlxEc6FKa7cun2oB",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 80,
|
||||
"height": 110
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "63NP9yq3hEUKD/OZZZ5t7x"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Animation",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
{
|
||||
"__uuid__": "81e87781-7328-4283-a747-060707c41880",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
}
|
||||
],
|
||||
"_defaultClip": {
|
||||
"__uuid__": "81e87781-7328-4283-a747-060707c41880",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "c6LOemuvJKyYCqlF/yUJcr"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
{"ver":"1.1.50","importer":"prefab","imported":true,"uuid":"1b44e122-28a1-4b56-964c-718f6f68737f","files":[".json"],"subMetas":{},"userData":{"syncNodeName":"up_blue"}}
|
||||
@@ -1,274 +0,0 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "up_green",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "up_green",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "skill",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 5
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -5.121,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1.3,
|
||||
"y": 1.3,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 77,
|
||||
"height": 77
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "b4sNQPJWFKha7x75SWXmRj"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 206
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@e7e9c",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 1,
|
||||
"_fillType": 1,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0.2,
|
||||
"_fillRange": 1,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6",
|
||||
"__expectedType__": "cc.SpriteAtlas"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "9a+65VIghBm4HQxuHPQ/mg"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "7a5LvbdlxEc6FKa7cun2oB",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 80,
|
||||
"height": 110
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "63NP9yq3hEUKD/OZZZ5t7x"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Animation",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
{
|
||||
"__uuid__": "01337a12-a04d-41f5-8f1f-efbf16989fb3",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
}
|
||||
],
|
||||
"_defaultClip": {
|
||||
"__uuid__": "01337a12-a04d-41f5-8f1f-efbf16989fb3",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "c6LOemuvJKyYCqlF/yUJcr"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
{"ver":"1.1.50","importer":"prefab","imported":true,"uuid":"dd573541-6f27-4dc4-9e86-c98caf79a58d","files":[".json"],"subMetas":{},"userData":{"syncNodeName":"up_green"}}
|
||||
@@ -1,274 +0,0 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.Prefab",
|
||||
"_name": "up_red",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_native": "",
|
||||
"data": {
|
||||
"__id__": 1
|
||||
},
|
||||
"optimizationPolicy": 0,
|
||||
"persistent": false
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "up_red",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": null,
|
||||
"_children": [
|
||||
{
|
||||
"__id__": 2
|
||||
}
|
||||
],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 8
|
||||
},
|
||||
{
|
||||
"__id__": 10
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 12
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Node",
|
||||
"_name": "skill",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"_parent": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_children": [],
|
||||
"_active": true,
|
||||
"_components": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 5
|
||||
}
|
||||
],
|
||||
"_prefab": {
|
||||
"__id__": 7
|
||||
},
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": -7.795,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
"__type__": "cc.Quat",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"_lscale": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 1.3,
|
||||
"y": 1.3,
|
||||
"z": 1
|
||||
},
|
||||
"_mobility": 0,
|
||||
"_layer": 1,
|
||||
"_euler": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 4
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 77,
|
||||
"height": 77
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "b4sNQPJWFKha7x75SWXmRj"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Sprite",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 6
|
||||
},
|
||||
"_customMaterial": null,
|
||||
"_srcBlendFactor": 2,
|
||||
"_dstBlendFactor": 4,
|
||||
"_color": {
|
||||
"__type__": "cc.Color",
|
||||
"r": 255,
|
||||
"g": 255,
|
||||
"b": 255,
|
||||
"a": 206
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6@e7e9c",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_type": 1,
|
||||
"_fillType": 1,
|
||||
"_sizeMode": 1,
|
||||
"_fillCenter": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"_fillStart": 0.2,
|
||||
"_fillRange": 1,
|
||||
"_isTrimmedMode": true,
|
||||
"_useGrayscale": false,
|
||||
"_atlas": {
|
||||
"__uuid__": "3d46f945-3f07-477e-a95a-b49557d552c6",
|
||||
"__expectedType__": "cc.SpriteAtlas"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "9a+65VIghBm4HQxuHPQ/mg"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "7a5LvbdlxEc6FKa7cun2oB",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
"__type__": "cc.UITransform",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 9
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 80,
|
||||
"height": 110
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
"x": 0.5,
|
||||
"y": 0
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "63NP9yq3hEUKD/OZZZ5t7x"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.Animation",
|
||||
"_name": "",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {},
|
||||
"node": {
|
||||
"__id__": 1
|
||||
},
|
||||
"_enabled": true,
|
||||
"__prefab": {
|
||||
"__id__": 11
|
||||
},
|
||||
"playOnLoad": true,
|
||||
"_clips": [
|
||||
{
|
||||
"__uuid__": "0f9dab25-82b0-4b96-b649-7c6162deafa0",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
}
|
||||
],
|
||||
"_defaultClip": {
|
||||
"__uuid__": "0f9dab25-82b0-4b96-b649-7c6162deafa0",
|
||||
"__expectedType__": "cc.AnimationClip"
|
||||
},
|
||||
"_id": ""
|
||||
},
|
||||
{
|
||||
"__type__": "cc.CompPrefabInfo",
|
||||
"fileId": "c6LOemuvJKyYCqlF/yUJcr"
|
||||
},
|
||||
{
|
||||
"__type__": "cc.PrefabInfo",
|
||||
"root": {
|
||||
"__id__": 1
|
||||
},
|
||||
"asset": {
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "c46/YsCPVOJYA4mWEpNYRx",
|
||||
"instance": null,
|
||||
"targetOverrides": null
|
||||
}
|
||||
]
|
||||
@@ -1 +0,0 @@
|
||||
{"ver":"1.1.50","importer":"prefab","imported":true,"uuid":"34fd7720-511b-4935-a1c6-d23e9e095faa","files":[".json"],"subMetas":{},"userData":{"syncNodeName":"up_red"}}
|
||||
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 948 KiB |
213
assets/resources/gui/anim/iround.anim
Normal file
@@ -0,0 +1,213 @@
|
||||
[
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "iround",
|
||||
"_objFlags": 0,
|
||||
"__editorExtras__": {
|
||||
"embeddedPlayerGroups": []
|
||||
},
|
||||
"_native": "",
|
||||
"sample": 5,
|
||||
"speed": 1,
|
||||
"wrapMode": 38,
|
||||
"enableTrsBlending": false,
|
||||
"_duration": 2.4,
|
||||
"_hash": 500763545,
|
||||
"_tracks": [
|
||||
{
|
||||
"__id__": 1
|
||||
}
|
||||
],
|
||||
"_exoticAnimation": null,
|
||||
"_events": [],
|
||||
"_embeddedPlayers": [],
|
||||
"_additiveSettings": {
|
||||
"__id__": 11
|
||||
},
|
||||
"_auxiliaryCurveEntries": []
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.VectorTrack",
|
||||
"_binding": {
|
||||
"__type__": "cc.animation.TrackBinding",
|
||||
"path": {
|
||||
"__id__": 2
|
||||
},
|
||||
"proxy": null
|
||||
},
|
||||
"_channels": [
|
||||
{
|
||||
"__id__": 3
|
||||
},
|
||||
{
|
||||
"__id__": 5
|
||||
},
|
||||
{
|
||||
"__id__": 7
|
||||
},
|
||||
{
|
||||
"__id__": 9
|
||||
}
|
||||
],
|
||||
"_nComponents": 3
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.TrackPath",
|
||||
"_paths": [
|
||||
"eulerAngles"
|
||||
]
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealCurve",
|
||||
"_times": [
|
||||
0,
|
||||
2.4
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": 0,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"tangentMode": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": 0,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"tangentMode": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"preExtrapolation": 1,
|
||||
"postExtrapolation": 1
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 6
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealCurve",
|
||||
"_times": [
|
||||
0,
|
||||
2.4
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": 0,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"tangentMode": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": 0,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"tangentMode": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"preExtrapolation": 1,
|
||||
"postExtrapolation": 1
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealCurve",
|
||||
"_times": [
|
||||
0,
|
||||
2.4
|
||||
],
|
||||
"_values": [
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": 0,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"tangentMode": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealKeyframeValue",
|
||||
"interpolationMode": 0,
|
||||
"tangentWeightMode": 0,
|
||||
"value": 360,
|
||||
"rightTangent": 0,
|
||||
"rightTangentWeight": 1,
|
||||
"leftTangent": 0,
|
||||
"leftTangentWeight": 1,
|
||||
"easingMethod": 0,
|
||||
"__editorExtras__": {
|
||||
"tangentMode": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"preExtrapolation": 1,
|
||||
"postExtrapolation": 1
|
||||
},
|
||||
{
|
||||
"__type__": "cc.animation.Channel",
|
||||
"_curve": {
|
||||
"__id__": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "cc.RealCurve",
|
||||
"_times": [],
|
||||
"_values": [],
|
||||
"preExtrapolation": 1,
|
||||
"postExtrapolation": 1
|
||||
},
|
||||
{
|
||||
"__type__": "cc.AnimationClipAdditiveSettings",
|
||||
"enabled": false,
|
||||
"refClip": null
|
||||
}
|
||||
]
|
||||
13
assets/resources/gui/anim/iround.anim.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "2.0.3",
|
||||
"importer": "animation-clip",
|
||||
"imported": true,
|
||||
"uuid": "3466f525-e22b-4574-80ff-9c55fdc8c481",
|
||||
"files": [
|
||||
".cconb"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"name": "iround"
|
||||
}
|
||||
}
|
||||
5172
assets/resources/gui/element/TIBox.prefab
Normal file
@@ -2,12 +2,12 @@
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "deb4a1bb-3f47-4c7c-9be1-352518675a16",
|
||||
"uuid": "e2394eb1-27f0-4b7c-ace3-cfb3453eef99",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "up_green"
|
||||
"syncNodeName": "TIBox"
|
||||
}
|
||||
}
|
||||
@@ -257,7 +257,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 75,
|
||||
"y": 80,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
@@ -338,8 +338,8 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 160.26666666666668,
|
||||
"height": 200
|
||||
"width": 200.26666666666665,
|
||||
"height": 213.33333333333334
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -358,8 +358,8 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 160.26666666666668,
|
||||
"height": 200
|
||||
"width": 200.26666666666665,
|
||||
"height": 213.33333333333334
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -379,8 +379,8 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 160.26666666666668,
|
||||
"height": 200
|
||||
"width": 200.26666666666665,
|
||||
"height": 213.33333333333334
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -400,7 +400,7 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 152.26666666666668,
|
||||
"width": 192.26666666666665,
|
||||
"height": 150
|
||||
}
|
||||
},
|
||||
@@ -422,7 +422,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 21,
|
||||
"y": 27.66666666666667,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
@@ -443,7 +443,7 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 152.26666666666668,
|
||||
"width": 192.26666666666665,
|
||||
"height": 24
|
||||
}
|
||||
},
|
||||
@@ -465,7 +465,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 84,
|
||||
"y": 90.66666666666667,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
@@ -486,7 +486,7 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 140.26666666666668,
|
||||
"width": 180.26666666666665,
|
||||
"height": 150
|
||||
}
|
||||
},
|
||||
@@ -508,7 +508,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 21,
|
||||
"y": 27.66666666666667,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
@@ -529,8 +529,8 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 160.26666666666668,
|
||||
"height": 200
|
||||
"width": 200.26666666666665,
|
||||
"height": 213.33333333333334
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -550,8 +550,8 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 160.26666666666668,
|
||||
"height": 200
|
||||
"width": 200.26666666666665,
|
||||
"height": 213.33333333333334
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -571,7 +571,7 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 152.26666666666668,
|
||||
"width": 192.26666666666665,
|
||||
"height": 150
|
||||
}
|
||||
},
|
||||
@@ -593,7 +593,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 21,
|
||||
"y": 27.66666666666667,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
@@ -614,7 +614,7 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 152.26666666666668,
|
||||
"width": 192.26666666666665,
|
||||
"height": 24
|
||||
}
|
||||
},
|
||||
@@ -636,7 +636,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 84,
|
||||
"y": 90.66666666666667,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
@@ -657,7 +657,7 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 140.26666666666668,
|
||||
"width": 180.26666666666665,
|
||||
"height": 150
|
||||
}
|
||||
},
|
||||
@@ -679,7 +679,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 21,
|
||||
"y": 27.66666666666667,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
@@ -752,8 +752,8 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 160.26666666666668,
|
||||
"height": 200
|
||||
"width": 200.26666666666665,
|
||||
"height": 213.33333333333334
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -773,8 +773,8 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 160.26666666666668,
|
||||
"height": 200
|
||||
"width": 200.26666666666665,
|
||||
"height": 213.33333333333334
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -794,7 +794,7 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 152.26666666666668,
|
||||
"width": 192.26666666666665,
|
||||
"height": 150
|
||||
}
|
||||
},
|
||||
@@ -816,7 +816,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 21,
|
||||
"y": 27.66666666666667,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
@@ -837,7 +837,7 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 152.26666666666668,
|
||||
"width": 192.26666666666665,
|
||||
"height": 24
|
||||
}
|
||||
},
|
||||
@@ -859,7 +859,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 84,
|
||||
"y": 90.66666666666667,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
@@ -880,7 +880,7 @@
|
||||
],
|
||||
"value": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 140.26666666666668,
|
||||
"width": 180.26666666666665,
|
||||
"height": 150
|
||||
}
|
||||
},
|
||||
@@ -902,7 +902,7 @@
|
||||
"value": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 21,
|
||||
"y": 27.66666666666667,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
@@ -937,7 +937,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 50.892,
|
||||
"y": 59.957,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -1083,7 +1083,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 89.47899999999998,
|
||||
"y": 96.661,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -1244,6 +1244,8 @@
|
||||
"__id__": 0
|
||||
},
|
||||
"fileId": "08p7XmUnpCJKHgFSs+XBKi",
|
||||
"instance": null,
|
||||
"targetOverrides": null,
|
||||
"nestedPrefabInstanceRoots": null
|
||||
},
|
||||
{
|
||||
@@ -1260,8 +1262,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 90,
|
||||
"height": 79.99999999999997
|
||||
"width": 120,
|
||||
"height": 90
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
@@ -1312,8 +1314,8 @@
|
||||
"_target": null,
|
||||
"_left": 15,
|
||||
"_right": 15,
|
||||
"_top": 20.521,
|
||||
"_bottom": 49.479000000000006,
|
||||
"_top": 18.339,
|
||||
"_bottom": 51.66100000000001,
|
||||
"_horizontalCenter": 0,
|
||||
"_verticalCenter": 0,
|
||||
"_isAbsLeft": true,
|
||||
@@ -1418,7 +1420,7 @@
|
||||
"_lpos": {
|
||||
"__type__": "cc.Vec3",
|
||||
"x": 0,
|
||||
"y": 131.674,
|
||||
"y": 141.674,
|
||||
"z": 0
|
||||
},
|
||||
"_lrot": {
|
||||
@@ -3037,8 +3039,8 @@
|
||||
},
|
||||
"_contentSize": {
|
||||
"__type__": "cc.Size",
|
||||
"width": 120,
|
||||
"height": 150
|
||||
"width": 150,
|
||||
"height": 160
|
||||
},
|
||||
"_anchorPoint": {
|
||||
"__type__": "cc.Vec2",
|
||||
|
||||
15693
assets/resources/gui/element/heroInfo.prefab
Normal file
13
assets/resources/gui/element/heroInfo.prefab.meta
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "620ee559-61bc-470d-b85d-e881bac42067",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "heroInfo"
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,1095},{616,182}}</string>
|
||||
<string>{{675,1669},{616,182}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -51,7 +51,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{675,1775},{672,92}}</string>
|
||||
<string>{{675,1853},{672,92}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -68,9 +68,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{675,1869},{672,76}}</string>
|
||||
<string>{{1931,675},{672,76}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>0l5_mountains.png</key>
|
||||
<dict>
|
||||
@@ -102,7 +102,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1,1589},{672,162}}</string>
|
||||
<string>{{675,1193},{672,162}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -119,9 +119,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{675,1507},{672,138}}</string>
|
||||
<string>{{1663,675},{672,138}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>0l8_ground.png</key>
|
||||
<dict>
|
||||
@@ -136,9 +136,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,381},{672,216}}</string>
|
||||
<string>{{1729,1},{672,216}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>1l1_wall.png</key>
|
||||
<dict>
|
||||
@@ -221,9 +221,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,1279},{662,90}}</string>
|
||||
<string>{{1349,1349},{662,90}}</string>
|
||||
<key>textureRotated</key>
|
||||
<true/>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>1l6_ground.png</key>
|
||||
<dict>
|
||||
@@ -238,9 +238,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1441,1279},{672,76}}</string>
|
||||
<string>{{1293,1699},{672,76}}</string>
|
||||
<key>textureRotated</key>
|
||||
<true/>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>3l1_sky.png</key>
|
||||
<dict>
|
||||
@@ -272,9 +272,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{675,1353},{672,152}}</string>
|
||||
<string>{{1509,675},{672,152}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>3l3_pyramid.png</key>
|
||||
<dict>
|
||||
@@ -289,9 +289,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1621,1279},{528,154}}</string>
|
||||
<string>{{1349,1543},{528,154}}</string>
|
||||
<key>textureRotated</key>
|
||||
<true/>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>3l4_bg-ground01.png</key>
|
||||
<dict>
|
||||
@@ -306,7 +306,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1,1753},{672,156}}</string>
|
||||
<string>{{675,1357},{672,156}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -323,7 +323,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,599},{672,180}}</string>
|
||||
<string>{{1,1589},{672,180}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -340,9 +340,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{675,1647},{672,126}}</string>
|
||||
<string>{{1803,675},{672,126}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>3l7_ground.png</key>
|
||||
<dict>
|
||||
@@ -357,7 +357,24 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,941},{672,152}}</string>
|
||||
<string>{{675,1515},{672,152}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>Icon_Battle.png</key>
|
||||
<dict>
|
||||
<key>aliases</key>
|
||||
<array/>
|
||||
<key>anchor</key>
|
||||
<string>{0.5,0.5}</string>
|
||||
<key>spriteOffset</key>
|
||||
<string>{0,0}</string>
|
||||
<key>spriteSize</key>
|
||||
<string>{64,57}</string>
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{64,57}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,1894},{64,57}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -374,9 +391,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{68,51}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1777,1626},{68,51}}</string>
|
||||
<string>{{1879,1629},{68,51}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Stone_A_04.png</key>
|
||||
<dict>
|
||||
@@ -391,9 +408,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{60,51}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1850,1562},{60,51}}</string>
|
||||
<string>{{1293,1777},{60,51}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Stone_A_07.png</key>
|
||||
<dict>
|
||||
@@ -408,9 +425,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{107,51}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1621,1809},{107,51}}</string>
|
||||
<string>{{1947,1},{107,51}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Stone_B_01.png</key>
|
||||
<dict>
|
||||
@@ -425,7 +442,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{68,70}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1519,1865},{68,70}}</string>
|
||||
<string>{{1935,1441},{68,70}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -442,7 +459,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{66,45}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1777,1679},{66,45}}</string>
|
||||
<string>{{1415,1894},{66,45}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -459,7 +476,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{35,22}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1730,1809},{35,22}}</string>
|
||||
<string>{{1293,1669},{35,22}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -476,9 +493,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{71,62}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1777,1562},{71,62}}</string>
|
||||
<string>{{1899,1777},{71,62}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Stone_B_05.png</key>
|
||||
<dict>
|
||||
@@ -493,7 +510,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{84,43}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1967,1095},{84,43}}</string>
|
||||
<string>{{1879,1543},{84,43}}</string>
|
||||
<key>textureRotated</key>
|
||||
<true/>
|
||||
</dict>
|
||||
@@ -510,7 +527,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{31,15}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1519,1937},{31,15}}</string>
|
||||
<string>{{1947,110},{31,15}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -527,7 +544,41 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{44,16}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1,1911},{44,16}}</string>
|
||||
<string>{{1,1931},{44,16}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>Title_01_NoDeco_Orange.Png</key>
|
||||
<dict>
|
||||
<key>aliases</key>
|
||||
<array/>
|
||||
<key>anchor</key>
|
||||
<string>{0.5,0.5}</string>
|
||||
<key>spriteOffset</key>
|
||||
<string>{0,0}</string>
|
||||
<key>spriteSize</key>
|
||||
<string>{273,115}</string>
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{273,115}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,1777},{273,115}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>Title_01_NoDeco_Tangerine.Png</key>
|
||||
<dict>
|
||||
<key>aliases</key>
|
||||
<array/>
|
||||
<key>anchor</key>
|
||||
<string>{0.5,0.5}</string>
|
||||
<key>spriteOffset</key>
|
||||
<string>{0,0}</string>
|
||||
<key>spriteSize</key>
|
||||
<string>{273,115}</string>
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{273,115}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1624,1777},{273,115}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -546,7 +597,7 @@
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,1},{672,378}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>l2_mountains.png</key>
|
||||
<dict>
|
||||
@@ -578,9 +629,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1519,1279},{584,100}}</string>
|
||||
<string>{{1349,1441},{584,100}}</string>
|
||||
<key>textureRotated</key>
|
||||
<true/>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>l4_bg-ground01.png</key>
|
||||
<dict>
|
||||
@@ -595,9 +646,9 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{675,1193},{672,158}}</string>
|
||||
<string>{{1349,675},{672,158}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>l5_bg-ground02.png</key>
|
||||
<dict>
|
||||
@@ -612,7 +663,7 @@
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{672,378}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1349,781},{672,158}}</string>
|
||||
<string>{{1,1771},{672,158}}</string>
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
@@ -633,23 +684,6 @@
|
||||
<key>textureRotated</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>logo2.png</key>
|
||||
<dict>
|
||||
<key>aliases</key>
|
||||
<array/>
|
||||
<key>anchor</key>
|
||||
<string>{0.5,0.5}</string>
|
||||
<key>spriteOffset</key>
|
||||
<string>{1,2}</string>
|
||||
<key>spriteSize</key>
|
||||
<string>{281,231}</string>
|
||||
<key>spriteSourceSize</key>
|
||||
<string>{307,307}</string>
|
||||
<key>textureRect</key>
|
||||
<string>{{1777,1279},{281,231}}</string>
|
||||
<key>textureRotated</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>metadata</key>
|
||||
<dict>
|
||||
@@ -662,9 +696,9 @@
|
||||
<key>realTextureFileName</key>
|
||||
<string>mps.png</string>
|
||||
<key>size</key>
|
||||
<string>{2022,1953}</string>
|
||||
<string>{2012,1952}</string>
|
||||
<key>smartupdate</key>
|
||||
<string>$TexturePacker:SmartUpdate:c995e79e2727f3d5b64d2e4345b903e7:ff13e6153e38a1ee043318ccbb0a835f:4c0e3901f0d5fcb2cf0cd4dcba1c7f8b$</string>
|
||||
<string>$TexturePacker:SmartUpdate:afc599cf42d3db8475edd4bf42d848d7:62891583945cafa92fc112c0ecd848ee:4c0e3901f0d5fcb2cf0cd4dcba1c7f8b$</string>
|
||||
<key>textureFileName</key>
|
||||
<string>mps.png</string>
|
||||
</dict>
|
||||
|
||||
@@ -7,6 +7,52 @@
|
||||
".json"
|
||||
],
|
||||
"subMetas": {
|
||||
"57674": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "81af97ed-7940-45e6-91a1-21bd0df1a343@57674",
|
||||
"displayName": "",
|
||||
"id": "57674",
|
||||
"name": "Icon_Battle",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1349,
|
||||
"trimY": 1894,
|
||||
"width": 64,
|
||||
"height": 57,
|
||||
"rawWidth": 64,
|
||||
"rawHeight": 57,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [],
|
||||
"indexes": [],
|
||||
"uv": [],
|
||||
"nuv": [],
|
||||
"minPos": [],
|
||||
"maxPos": []
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "ca2b26a5-8d54-49ec-bdaf-e9f777afc9cb@6c48a",
|
||||
"atlasUuid": "81af97ed-7940-45e6-91a1-21bd0df1a343",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"58094": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "81af97ed-7940-45e6-91a1-21bd0df1a343@58094",
|
||||
@@ -53,6 +99,98 @@
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"63222": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "81af97ed-7940-45e6-91a1-21bd0df1a343@63222",
|
||||
"displayName": "",
|
||||
"id": "63222",
|
||||
"name": "Title_01_NoDeco_Tangerine",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1624,
|
||||
"trimY": 1777,
|
||||
"width": 273,
|
||||
"height": 115,
|
||||
"rawWidth": 273,
|
||||
"rawHeight": 115,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [],
|
||||
"indexes": [],
|
||||
"uv": [],
|
||||
"nuv": [],
|
||||
"minPos": [],
|
||||
"maxPos": []
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "ca2b26a5-8d54-49ec-bdaf-e9f777afc9cb@6c48a",
|
||||
"atlasUuid": "81af97ed-7940-45e6-91a1-21bd0df1a343",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"86850": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "81af97ed-7940-45e6-91a1-21bd0df1a343@86850",
|
||||
"displayName": "",
|
||||
"id": "86850",
|
||||
"name": "Title_01_NoDeco_Orange",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1349,
|
||||
"trimY": 1777,
|
||||
"width": 273,
|
||||
"height": 115,
|
||||
"rawWidth": 273,
|
||||
"rawHeight": 115,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 135,
|
||||
"borderRight": 138,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [],
|
||||
"indexes": [],
|
||||
"uv": [],
|
||||
"nuv": [],
|
||||
"minPos": [],
|
||||
"maxPos": []
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "ca2b26a5-8d54-49ec-bdaf-e9f777afc9cb@6c48a",
|
||||
"atlasUuid": "81af97ed-7940-45e6-91a1-21bd0df1a343",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"4f746": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "81af97ed-7940-45e6-91a1-21bd0df1a343@4f746",
|
||||
@@ -110,8 +248,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": -4,
|
||||
"offsetY": 82,
|
||||
"trimX": 1349,
|
||||
"trimY": 1095,
|
||||
"trimX": 675,
|
||||
"trimY": 1669,
|
||||
"width": 616,
|
||||
"height": 182,
|
||||
"rawWidth": 672,
|
||||
@@ -157,7 +295,7 @@
|
||||
"offsetX": 0,
|
||||
"offsetY": -3,
|
||||
"trimX": 675,
|
||||
"trimY": 1775,
|
||||
"trimY": 1853,
|
||||
"width": 672,
|
||||
"height": 92,
|
||||
"rawWidth": 672,
|
||||
@@ -199,11 +337,11 @@
|
||||
"name": "0l4_clouds02",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 122,
|
||||
"trimX": 675,
|
||||
"trimY": 1869,
|
||||
"trimX": 1931,
|
||||
"trimY": 675,
|
||||
"width": 672,
|
||||
"height": 76,
|
||||
"rawWidth": 672,
|
||||
@@ -294,8 +432,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -108,
|
||||
"trimX": 1,
|
||||
"trimY": 1589,
|
||||
"trimX": 675,
|
||||
"trimY": 1193,
|
||||
"width": 672,
|
||||
"height": 162,
|
||||
"rawWidth": 672,
|
||||
@@ -337,11 +475,11 @@
|
||||
"name": "0l7_ground02",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": -120,
|
||||
"trimX": 675,
|
||||
"trimY": 1507,
|
||||
"trimX": 1663,
|
||||
"trimY": 675,
|
||||
"width": 672,
|
||||
"height": 138,
|
||||
"rawWidth": 672,
|
||||
@@ -383,11 +521,11 @@
|
||||
"name": "0l8_ground",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": -81,
|
||||
"trimX": 1349,
|
||||
"trimY": 381,
|
||||
"trimX": 1729,
|
||||
"trimY": 1,
|
||||
"width": 672,
|
||||
"height": 216,
|
||||
"rawWidth": 672,
|
||||
@@ -613,11 +751,11 @@
|
||||
"name": "1l5_crystals",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"rotated": false,
|
||||
"offsetX": -2,
|
||||
"offsetY": -85,
|
||||
"trimX": 1349,
|
||||
"trimY": 1279,
|
||||
"trimY": 1349,
|
||||
"width": 662,
|
||||
"height": 90,
|
||||
"rawWidth": 672,
|
||||
@@ -659,11 +797,11 @@
|
||||
"name": "1l6_ground",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -151,
|
||||
"trimX": 1441,
|
||||
"trimY": 1279,
|
||||
"trimX": 1293,
|
||||
"trimY": 1699,
|
||||
"width": 672,
|
||||
"height": 76,
|
||||
"rawWidth": 672,
|
||||
@@ -705,11 +843,11 @@
|
||||
"name": "3l2_clouds",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": -48,
|
||||
"trimX": 675,
|
||||
"trimY": 1353,
|
||||
"trimX": 1509,
|
||||
"trimY": 675,
|
||||
"width": 672,
|
||||
"height": 152,
|
||||
"rawWidth": 672,
|
||||
@@ -751,11 +889,11 @@
|
||||
"name": "3l3_pyramid",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"rotated": false,
|
||||
"offsetX": 2,
|
||||
"offsetY": -7,
|
||||
"trimX": 1621,
|
||||
"trimY": 1279,
|
||||
"trimX": 1349,
|
||||
"trimY": 1543,
|
||||
"width": 528,
|
||||
"height": 154,
|
||||
"rawWidth": 672,
|
||||
@@ -800,8 +938,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -111,
|
||||
"trimX": 1,
|
||||
"trimY": 1753,
|
||||
"trimX": 675,
|
||||
"trimY": 1357,
|
||||
"width": 672,
|
||||
"height": 156,
|
||||
"rawWidth": 672,
|
||||
@@ -846,8 +984,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -99,
|
||||
"trimX": 1349,
|
||||
"trimY": 599,
|
||||
"trimX": 1,
|
||||
"trimY": 1589,
|
||||
"width": 672,
|
||||
"height": 180,
|
||||
"rawWidth": 672,
|
||||
@@ -889,11 +1027,11 @@
|
||||
"name": "3l6_bg-ground03",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": -126,
|
||||
"trimX": 675,
|
||||
"trimY": 1647,
|
||||
"trimX": 1803,
|
||||
"trimY": 675,
|
||||
"width": 672,
|
||||
"height": 126,
|
||||
"rawWidth": 672,
|
||||
@@ -938,8 +1076,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -113,
|
||||
"trimX": 1349,
|
||||
"trimY": 941,
|
||||
"trimX": 675,
|
||||
"trimY": 1515,
|
||||
"width": 672,
|
||||
"height": 152,
|
||||
"rawWidth": 672,
|
||||
@@ -981,11 +1119,11 @@
|
||||
"name": "Stone_A_01",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1777,
|
||||
"trimY": 1626,
|
||||
"trimX": 1879,
|
||||
"trimY": 1629,
|
||||
"width": 68,
|
||||
"height": 51,
|
||||
"rawWidth": 68,
|
||||
@@ -1027,11 +1165,11 @@
|
||||
"name": "Stone_A_04",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1850,
|
||||
"trimY": 1562,
|
||||
"trimX": 1293,
|
||||
"trimY": 1777,
|
||||
"width": 60,
|
||||
"height": 51,
|
||||
"rawWidth": 60,
|
||||
@@ -1073,11 +1211,11 @@
|
||||
"name": "Stone_A_07",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1621,
|
||||
"trimY": 1809,
|
||||
"trimX": 1947,
|
||||
"trimY": 1,
|
||||
"width": 107,
|
||||
"height": 51,
|
||||
"rawWidth": 107,
|
||||
@@ -1122,8 +1260,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1519,
|
||||
"trimY": 1865,
|
||||
"trimX": 1935,
|
||||
"trimY": 1441,
|
||||
"width": 68,
|
||||
"height": 70,
|
||||
"rawWidth": 68,
|
||||
@@ -1168,8 +1306,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1777,
|
||||
"trimY": 1679,
|
||||
"trimX": 1415,
|
||||
"trimY": 1894,
|
||||
"width": 66,
|
||||
"height": 45,
|
||||
"rawWidth": 66,
|
||||
@@ -1214,8 +1352,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1730,
|
||||
"trimY": 1809,
|
||||
"trimX": 1293,
|
||||
"trimY": 1669,
|
||||
"width": 35,
|
||||
"height": 22,
|
||||
"rawWidth": 35,
|
||||
@@ -1257,11 +1395,11 @@
|
||||
"name": "Stone_B_04",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1777,
|
||||
"trimY": 1562,
|
||||
"trimX": 1899,
|
||||
"trimY": 1777,
|
||||
"width": 71,
|
||||
"height": 62,
|
||||
"rawWidth": 71,
|
||||
@@ -1306,8 +1444,8 @@
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1967,
|
||||
"trimY": 1095,
|
||||
"trimX": 1879,
|
||||
"trimY": 1543,
|
||||
"width": 84,
|
||||
"height": 43,
|
||||
"rawWidth": 84,
|
||||
@@ -1352,8 +1490,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1519,
|
||||
"trimY": 1937,
|
||||
"trimX": 1947,
|
||||
"trimY": 110,
|
||||
"width": 31,
|
||||
"height": 15,
|
||||
"rawWidth": 31,
|
||||
@@ -1399,7 +1537,7 @@
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1,
|
||||
"trimY": 1911,
|
||||
"trimY": 1931,
|
||||
"width": 44,
|
||||
"height": 16,
|
||||
"rawWidth": 44,
|
||||
@@ -1441,7 +1579,7 @@
|
||||
"name": "l1_sky",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"trimX": 1349,
|
||||
@@ -1533,11 +1671,11 @@
|
||||
"name": "l3_clouds",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"rotated": false,
|
||||
"offsetX": -6,
|
||||
"offsetY": 89,
|
||||
"trimX": 1519,
|
||||
"trimY": 1279,
|
||||
"trimX": 1349,
|
||||
"trimY": 1441,
|
||||
"width": 584,
|
||||
"height": 100,
|
||||
"rawWidth": 672,
|
||||
@@ -1579,11 +1717,11 @@
|
||||
"name": "l4_bg-ground01",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"rotated": true,
|
||||
"offsetX": 0,
|
||||
"offsetY": -110,
|
||||
"trimX": 675,
|
||||
"trimY": 1193,
|
||||
"trimX": 1349,
|
||||
"trimY": 675,
|
||||
"width": 672,
|
||||
"height": 158,
|
||||
"rawWidth": 672,
|
||||
@@ -1628,8 +1766,8 @@
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": -110,
|
||||
"trimX": 1349,
|
||||
"trimY": 781,
|
||||
"trimX": 1,
|
||||
"trimY": 1771,
|
||||
"width": 672,
|
||||
"height": 158,
|
||||
"rawWidth": 672,
|
||||
@@ -1708,52 +1846,6 @@
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
},
|
||||
"14c74": {
|
||||
"importer": "sprite-frame",
|
||||
"uuid": "81af97ed-7940-45e6-91a1-21bd0df1a343@14c74",
|
||||
"displayName": "",
|
||||
"id": "14c74",
|
||||
"name": "logo2",
|
||||
"userData": {
|
||||
"trimThreshold": 1,
|
||||
"rotated": true,
|
||||
"offsetX": 1,
|
||||
"offsetY": 2,
|
||||
"trimX": 1777,
|
||||
"trimY": 1279,
|
||||
"width": 281,
|
||||
"height": 231,
|
||||
"rawWidth": 307,
|
||||
"rawHeight": 307,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
"pivotY": 0.5,
|
||||
"meshType": 0,
|
||||
"vertices": {
|
||||
"rawPosition": [],
|
||||
"indexes": [],
|
||||
"uv": [],
|
||||
"nuv": [],
|
||||
"minPos": [],
|
||||
"maxPos": []
|
||||
},
|
||||
"isUuid": true,
|
||||
"imageUuidOrDatabaseUri": "ca2b26a5-8d54-49ec-bdaf-e9f777afc9cb@6c48a",
|
||||
"atlasUuid": "81af97ed-7940-45e6-91a1-21bd0df1a343",
|
||||
"trimType": "auto"
|
||||
},
|
||||
"ver": "1.0.12",
|
||||
"imported": true,
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {}
|
||||
}
|
||||
},
|
||||
"userData": {
|
||||
|
||||
|
Before Width: | Height: | Size: 469 KiB After Width: | Height: | Size: 396 KiB |
|
Before Width: | Height: | Size: 962 KiB After Width: | Height: | Size: 1.0 MiB |
@@ -116,8 +116,8 @@
|
||||
"height": 54,
|
||||
"rawWidth": 89,
|
||||
"rawHeight": 54,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderTop": 26,
|
||||
"borderBottom": 26,
|
||||
"borderLeft": 44,
|
||||
"borderRight": 44,
|
||||
"packable": true,
|
||||
@@ -576,8 +576,8 @@
|
||||
"height": 45,
|
||||
"rawWidth": 52,
|
||||
"rawHeight": 45,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderTop": 22,
|
||||
"borderBottom": 23,
|
||||
"borderLeft": 26,
|
||||
"borderRight": 26,
|
||||
"packable": true,
|
||||
@@ -4992,8 +4992,8 @@
|
||||
"height": 45,
|
||||
"rawWidth": 81,
|
||||
"rawHeight": 45,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderTop": 22,
|
||||
"borderBottom": 22,
|
||||
"borderLeft": 40,
|
||||
"borderRight": 40,
|
||||
"packable": true,
|
||||
@@ -6096,10 +6096,10 @@
|
||||
"height": 39,
|
||||
"rawWidth": 37,
|
||||
"rawHeight": 39,
|
||||
"borderTop": 0,
|
||||
"borderBottom": 0,
|
||||
"borderLeft": 0,
|
||||
"borderRight": 0,
|
||||
"borderTop": 19,
|
||||
"borderBottom": 18,
|
||||
"borderLeft": 19,
|
||||
"borderRight": 18,
|
||||
"packable": true,
|
||||
"pixelsToUnit": 100,
|
||||
"pivotX": 0.5,
|
||||
|
||||
@@ -81,11 +81,13 @@ const PLACEHOLDER_PATTERN = /\{(\w+)\}/g;
|
||||
* atking/atked 为周期循环触发(运行时按次数取模判定),拼为"每攻击N次"/"每受击N次"
|
||||
* 表达循环语义(N=1 时退化为"每次攻击"/"每次受击");其余类型直接用触发名(召唤/死亡后/回合开始)。
|
||||
*/
|
||||
function buildTriggerLabel(type: SkillTriggerType, tNum: number): string {
|
||||
function buildTriggerLabel(type: SkillTriggerType, tNum: number, chance?: number): string {
|
||||
if (type === SkillTriggerType.Atking || type === SkillTriggerType.Atked) {
|
||||
// 配置了 t_chance 且 < 100 时追加概率说明(保底叠加为隐藏机制,不在文案展示)
|
||||
const chanceSeg = chance !== undefined && chance < 100 ? `(${valueRich(Math.round(chance))}%概率)` : "";
|
||||
return tNum <= 1
|
||||
? `每次${SkillTriggerName[type]}`
|
||||
: `每${SkillTriggerName[type]}${valueRich(tNum)}次`;
|
||||
? `每次${SkillTriggerName[type]}${chanceSeg}`
|
||||
: `每${SkillTriggerName[type]}${valueRich(tNum)}次${chanceSeg}`;
|
||||
}
|
||||
return SkillTriggerName[type];
|
||||
}
|
||||
@@ -137,18 +139,25 @@ function getBuffValue(skill: SkillConfig): number {
|
||||
* Why: 数值不写死在模板里,overrides 调整档位数值时文案自动同步。
|
||||
* @param tmpl 描述模板(含占位符)
|
||||
* @param skill mergeSkillParams 合并后的技能配置
|
||||
* @param extra 条目级参数占位符(触发技能的 t_chance/pity_add 不在 SkillConfig,由调用方透传;优先于技能字段)
|
||||
*/
|
||||
function renderDesc(tmpl: string, skill: SkillConfig): string {
|
||||
function renderDesc(tmpl: string, skill: SkillConfig, extra?: Record<string, number>): string {
|
||||
return tmpl.replace(PLACEHOLDER_PATTERN, (raw, key: string) => {
|
||||
if (key === "target") return buildTargetDesc(skill);
|
||||
if (key === "dur") return valueRich(getBuffDuration(skill));
|
||||
if (key === "buff_value") return valueRich(getBuffValue(skill));
|
||||
if (extra && key in extra) return valueRich(String(extra[key]));
|
||||
const v = (skill as unknown as Record<string, unknown>)[key];
|
||||
// 未定义数值字段按 0 渲染,避免面板出现 undefined(模板与配置不匹配的兜底)
|
||||
return v === undefined ? valueRich(0) : valueRich(String(v));
|
||||
});
|
||||
}
|
||||
|
||||
/** 触发档位的条目级占位符上下文(普攻/大招档位无此层参数,返回 undefined 走技能字段) */
|
||||
function tierExtras(t: ISkillTierInfo): Record<string, number> | undefined {
|
||||
return t.tChance === undefined ? undefined : { t_chance: t.tChance, pity_add: t.pityAdd ?? 0 };
|
||||
}
|
||||
|
||||
/** 无模板时兜底:回退底座技能的 info 备注 */
|
||||
function fallbackDesc(skill: SkillConfig): string {
|
||||
return String(skill.info ?? "");
|
||||
@@ -224,9 +233,12 @@ export function buildHeroSkillDesc(heroUuid: number, showName: boolean = true, s
|
||||
if (e.lv <= lv && e.desc) tmpl = e.desc;
|
||||
}
|
||||
tmpl = tmpl ?? entries[0]?.desc;
|
||||
const text = tmpl ? renderDesc(tmpl, skill) : fallbackDesc(skill);
|
||||
const text = tmpl
|
||||
? renderDesc(tmpl, skill, { t_chance: item.t_chance ?? 100, pity_add: item.pity_add ?? 0 })
|
||||
: fallbackDesc(skill);
|
||||
// 触发语境:"每攻击N次"循环语义(buildTriggerLabel),逗号衔接效果文本
|
||||
const trig = buildTriggerLabel(type, item.t_num);
|
||||
// 模板已显式使用 {t_chance} 时不再自动追加概率后缀,避免同一行重复展示
|
||||
const trig = buildTriggerLabel(type, item.t_num, tmpl?.includes("{t_chance}") ? undefined : item.t_chance);
|
||||
parts.push(`${trig}, ${text}`);
|
||||
}
|
||||
// dead 组内的复活效果(revive_hp / revive_count)并入同一行
|
||||
@@ -279,12 +291,17 @@ interface ISkillTierInfo {
|
||||
ownDesc?: string;
|
||||
/** 触发技能档位的触发次数(普攻无) */
|
||||
tNum: number;
|
||||
/** 触发技能档位的触发概率百分点(普攻无;缺省 100 必触发) */
|
||||
tChance?: number;
|
||||
/** 触发技能档位的保底叠加百分点(普攻无;缺省 0) */
|
||||
pityAdd?: number;
|
||||
}
|
||||
|
||||
/** 相邻档 diff 参与展示的字段(排除动画/弹道/特效等玩家无感字段),t_num 为触发技能专有 */
|
||||
const DIFF_KEYS: string[] = [
|
||||
"ap", "hit_count", "num", "summon_count", "crt", "frz", "stun", "para",
|
||||
"bck", "bck_chance", "buff_duration", "buff_value", "t_num", "timed_buff_id",
|
||||
"t_chance", "pity_add",
|
||||
];
|
||||
|
||||
/** diff 字段的称谓与单位("新增/漂移"描述共用) */
|
||||
@@ -302,11 +319,15 @@ const DIFF_META: Record<string, { label: string; unit: string }> = {
|
||||
buff_duration: { label: "持续", unit: "秒" },
|
||||
buff_value: { label: "增益强度", unit: "" },
|
||||
t_num: { label: "触发次数", unit: "次" },
|
||||
t_chance: { label: "触发概率", unit: "%" },
|
||||
pity_add: { label: "保底叠加", unit: "%" },
|
||||
};
|
||||
|
||||
/** 读取档位某展示字段的实时值(t_num/buff_value 走专用取值) */
|
||||
/** 读取档位某展示字段的实时值(t_num/t_chance/pity_add/buff_value 走专用取值) */
|
||||
function getTierValue(tier: ISkillTierInfo, key: string): number {
|
||||
if (key === "t_num") return tier.tNum;
|
||||
if (key === "t_chance") return tier.tChance ?? 100;
|
||||
if (key === "pity_add") return tier.pityAdd ?? 0;
|
||||
if (key === "buff_value") return getBuffValue(tier.skill);
|
||||
const v = (tier.skill as unknown as Record<string, unknown>)[key];
|
||||
return typeof v === "number" ? v : 0;
|
||||
@@ -497,9 +518,13 @@ function collectTriggerTiers(hero: heroInfo, type: SkillTriggerType, skillUuid:
|
||||
desc: e.desc ?? inherit,
|
||||
ownDesc: e.desc,
|
||||
tNum: e.t_num,
|
||||
tChance: e.t_chance ?? 100,
|
||||
pityAdd: e.pity_add ?? 0,
|
||||
};
|
||||
});
|
||||
const label = buildTriggerLabel(type, sorted[0].t_num);
|
||||
// slv1 模板已显式使用 {t_chance} 时不再自动追加概率后缀,避免同一行重复展示
|
||||
const firstTmpl = tiers[0]?.desc;
|
||||
const label = buildTriggerLabel(type, sorted[0].t_num, firstTmpl?.includes("{t_chance}") ? undefined : sorted[0].t_chance);
|
||||
return { tiers, label };
|
||||
}
|
||||
|
||||
@@ -510,11 +535,11 @@ function buildTierLines(tiers: ISkillTierInfo[], triggerLabel: string): HeroSkil
|
||||
const t = tiers[i];
|
||||
if (i === 0) {
|
||||
// 技能 1 级:完整能力 + 数值
|
||||
const text = t.desc ? renderDesc(t.desc, t.skill) : fallbackDesc(t.skill);
|
||||
const text = t.desc ? renderDesc(t.desc, t.skill, tierExtras(t)) : fallbackDesc(t.skill);
|
||||
lines.push({ sLv: t.sLv, heroLv: t.heroLv, text: triggerLabel ? `${triggerLabel}, ${text}` : text });
|
||||
} else if (t.ownDesc) {
|
||||
// 提升档:该档显式配置了模板(如护盾/治疗等 diff 标签语义不达的技能),策划表述优先
|
||||
lines.push({ sLv: t.sLv, heroLv: t.heroLv, text: renderDesc(t.ownDesc, t.skill) });
|
||||
lines.push({ sLv: t.sLv, heroLv: t.heroLv, text: renderDesc(t.ownDesc, t.skill, tierExtras(t)) });
|
||||
} else {
|
||||
// 提升档:未配置模板,给相对上一级的提升
|
||||
const diff = buildTierDiff(tiers[i - 1], t);
|
||||
|
||||
@@ -9,7 +9,7 @@ import { GameScoreStats } from "./config/HeroAttrs";
|
||||
import { mLogger } from "./Logger";
|
||||
import { gameDataSync } from "./GameDataSync";
|
||||
import { HERO_UPGRADE_NEED_FRAGMENTS } from "./config/GameSet";
|
||||
import { TalentSet, TALENT_LEVEL_MAX, getTalentLevelExp, getTalentUpgradeCost, isTalentTierUnlocked } from "./config/TalentSet";
|
||||
import { TalentSet, TALENT_LEVEL_MAX, getTalentLevelExp, isTalentPrereqMet, isTalentTierUnlocked } from "./config/TalentSet";
|
||||
import { ScoreRankList, ScoreTier, getRankByScore } from "./config/ScoreRankSet";
|
||||
import { RANK_REWARDS, STAGE_REWARDS, RewardItem, pickRandomHeroUuid } from "./config/RewardSet";
|
||||
|
||||
@@ -48,11 +48,9 @@ export interface GameDate {
|
||||
talent_lv?: number,
|
||||
/** 天赋当前等级已累计的经验值 */
|
||||
talent_exp?: number,
|
||||
/** 关卡进度存档:当前章节-关-节 */
|
||||
/** 关卡进度存档:当前关卡号(无限关模式只记关卡号,回合恒从 1 开始) */
|
||||
stage_progress?: {
|
||||
chapter: number,
|
||||
stage: number,
|
||||
section: number,
|
||||
},
|
||||
/** 奖励领取状态:段位/闯关首达奖励的已领取标记(玩家点击领取) */
|
||||
reward_claimed?: {
|
||||
@@ -61,7 +59,7 @@ export interface GameDate {
|
||||
/** 已领取的大关号 */
|
||||
stage: number[],
|
||||
},
|
||||
/** 已通关大关的显式标记(覆盖存档停留场景,如第 10 关通关后进度停留 1-10-10) */
|
||||
/** 已通关大关的显式标记(历史遗留字段,无限关模式不再写入;仅用于兼容读取旧存档) */
|
||||
passed_stages?: number[],
|
||||
}
|
||||
export interface CloudData {
|
||||
@@ -152,11 +150,9 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
talent_lv: 0,
|
||||
/** 当前等级已累计经验 */
|
||||
talent_exp: 0,
|
||||
/** 关卡进度存档:默认从 1-1-1 开始 */
|
||||
/** 关卡进度存档:默认从第 1 关开始 */
|
||||
stage_progress: {
|
||||
chapter: 1,
|
||||
stage: 1,
|
||||
section: 1,
|
||||
},
|
||||
/** 奖励领取状态(玩家点击领取,跨局保留) */
|
||||
reward_claimed: {
|
||||
@@ -238,9 +234,7 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
switch_music: true, // 音乐开关(MVVM绑定字段)
|
||||
/** 关卡进度(MVVM绑定字段,镜像 data.stage_progress,供 HUD 实时显示) */
|
||||
stage_progress: {
|
||||
chapter: 1,
|
||||
stage: 1,
|
||||
section: 1,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -352,26 +346,26 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
* 将 data 层的关卡进度镜像到 vmdata 视图层(MVVM 绑定字段)。
|
||||
* Why: data.stage_progress 为云端持久权威源,vmdata.stage_progress 仅供 HUD 绑定展示;
|
||||
* 登录覆盖、关卡推进后都必须调用本方法保持镜像一致。
|
||||
* 旧版三段存档(chapter/stage/section)在同步时归一化为 stage 单字段。
|
||||
*/
|
||||
public syncStageProgressToView(): void {
|
||||
const p = this.data.stage_progress;
|
||||
// 就地更新字段而非整体替换对象:oops VM(JsonOb)只通知被赋值属性的精确路径,
|
||||
// 整体替换仅派发 VC:data.stage_progress,不会触发 HUD 绑定的
|
||||
// data.stage_progress.section 等嵌套末端路径刷新,导致进度显示停留在老节
|
||||
const view = this.vmdata.stage_progress;
|
||||
view.chapter = p?.chapter ?? 1;
|
||||
view.stage = p?.stage ?? 1;
|
||||
view.section = p?.section ?? 1;
|
||||
// 旧存档归一化:兼容历史 chapter/stage/section 三段结构,仅提取 stage
|
||||
const stage = Math.max(1, Math.floor(p?.stage ?? 1));
|
||||
if (p && (p.stage !== stage || (p as any).chapter !== undefined || (p as any).section !== undefined)) {
|
||||
this.data.stage_progress = { stage };
|
||||
}
|
||||
this.vmdata.stage_progress.stage = stage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新关卡进度(权威源 data + 视图镜像 vmdata),并派发事件刷新 UI。
|
||||
* Why: 替代直接赋值 smc.data.stage_progress,保证视图层实时同步。
|
||||
* @param progress 新的关卡进度(章节/大关/小节均从 1 开始)
|
||||
* @param progress 新的关卡进度(仅关卡号,从 1 开始)
|
||||
* @param is_sync 是否标记脏并触发云端/本地同步
|
||||
*/
|
||||
public updateStageProgress(progress: { chapter: number; stage: number; section: number }, is_sync: boolean = true): void {
|
||||
this.data.stage_progress = { ...progress };
|
||||
public updateStageProgress(progress: { stage: number }, is_sync: boolean = true): void {
|
||||
this.data.stage_progress = { stage: Math.max(1, Math.floor(progress.stage)) };
|
||||
this.syncStageProgressToView();
|
||||
if (is_sync) {
|
||||
gameDataSync.markDataDirty();
|
||||
@@ -452,20 +446,18 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记大关已通关(通关点调用,覆盖存档停留场景)
|
||||
* Why: 第 10 关通关后存档停留 1-10-10,无法从 stage_progress 推导已通状态,
|
||||
* 需在通关时显式写入。
|
||||
* @param stage 大关号
|
||||
* 标记大关已通关(历史遗留入口)
|
||||
* Why: 旧版本第 10 关通关后存档停留,无法从 stage_progress 推导已通状态,需显式标记;
|
||||
* 无限关模式存档永远推进,判定已通可直接由 stage_progress 推导,无需再写入。
|
||||
* 保留空实现以避免破坏外部调用方(若有旧存档读取场景走 passed_stages 兼容)。
|
||||
* @param _stage 大关号(未使用,保留签名兼容)
|
||||
* @deprecated 无限关模式无需调用,保留仅为兼容旧代码引用
|
||||
*/
|
||||
public markStagePassed(stage: number): void {
|
||||
if (!this.data.passed_stages) this.data.passed_stages = [];
|
||||
if (!this.data.passed_stages.includes(stage)) {
|
||||
this.data.passed_stages.push(stage);
|
||||
gameDataSync.markDataDirty();
|
||||
}
|
||||
public markStagePassed(_stage: number): void {
|
||||
// 无限关模式不再写入 passed_stages
|
||||
}
|
||||
|
||||
/** 判定大关是否已通关:显式标记优先,存档推进兜底(已进入后续关即已通关) */
|
||||
/** 判定大关是否已通关:旧存档显式标记兼容,无限关以存档关卡号推导(已进入后续关即已通关) */
|
||||
private isStagePassed(stage: number): boolean {
|
||||
if ((this.data.passed_stages ?? []).includes(stage)) return true;
|
||||
return (this.data.stage_progress?.stage ?? 1) > stage;
|
||||
@@ -694,7 +686,7 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
/**
|
||||
* 消耗天赋点升级天赋(升级即激活,下一局生效)
|
||||
* @param uuid 天赋 uuid
|
||||
* @returns 是否升级成功(天赋不存在/已满级/阶位未解锁/点数不足时返回 false)
|
||||
* @returns 是否升级成功(天赋不存在/已满级/层位未解锁/前置未满足/点数不足时返回 false)
|
||||
*/
|
||||
upgradeTalent(uuid: number): boolean {
|
||||
const cfg = TalentSet[uuid];
|
||||
@@ -702,11 +694,13 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
if (!this.data.talents) this.data.talents = {};
|
||||
const curLv = this.getTalentLv(uuid);
|
||||
if (curLv >= cfg.max_lv) return false;
|
||||
// 阶位解锁:二/三阶天赋要求前一阶累计投入点数达标(一阶恒解锁)
|
||||
// 层位解锁:第 N 层天赋要求第 N-1 层累计投入点数达标(第 1 层恒解锁)
|
||||
if (!isTalentTierUnlocked(this.data.talents, cfg.tier)) return false;
|
||||
const cost = getTalentUpgradeCost(cfg.tier);
|
||||
if (cost < 0 || this.getTalentPoints() < cost) return false;
|
||||
this.data.talent_points -= cost;
|
||||
// 软前置:前置天赋等级需达标(仅限制加点)
|
||||
if (!isTalentPrereqMet(this.data.talents, cfg)) return false;
|
||||
// 统一 1 点/级
|
||||
if (this.getTalentPoints() < 1) return false;
|
||||
this.data.talent_points -= 1;
|
||||
this.data.talents[uuid] = curLv + 1;
|
||||
gameDataSync.markDataDirty();
|
||||
oops.message.dispatchEvent(GameEvent.TALENT_UPDATE);
|
||||
@@ -715,17 +709,13 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
|
||||
/**
|
||||
* 重置所有天赋等级并退还全部已消耗天赋点(看广告入口)
|
||||
* Why: 退还点数按"升到当前等级的累计消耗"计算,与升级消耗表严格对账,避免点数膨胀/缩水。
|
||||
* Why: 统一 1 点/级后退还点数 = 等级总和,与升级消耗严格对账,避免点数膨胀/缩水。
|
||||
*/
|
||||
resetTalents(): void {
|
||||
if (!this.data.talents) this.data.talents = {};
|
||||
let refund = 0;
|
||||
for (const key in this.data.talents) {
|
||||
const lv = this.data.talents[key];
|
||||
for (let i = 0; i < lv; i++) {
|
||||
const c = getTalentUpgradeCost(i);
|
||||
if (c > 0) refund += c;
|
||||
}
|
||||
refund += this.data.talents[key];
|
||||
}
|
||||
this.data.talents = {};
|
||||
this.data.talent_points = (this.data.talent_points ?? 0) + refund;
|
||||
|
||||
@@ -104,15 +104,15 @@ export enum GameEvent {
|
||||
STAGE_PROGRESS_UPDATE = "STAGE_PROGRESS_UPDATE",
|
||||
/** 奖励领取完成(payload 为空,UI 刷新待领取列表/红点) */
|
||||
REWARD_CLAIMED = "REWARD_CLAIMED",
|
||||
/** 小节开始(payload: { chapter, stage, section },MissionMonComp 据此生成怪物) */
|
||||
/** 回合开始(payload: { stage, section },MissionMonComp 据此生成怪物) */
|
||||
SectionStart = "SectionStart",
|
||||
/** 小节结束(payload: { chapter, stage, section },玩家点击"下一节"后推进) */
|
||||
/** @deprecated 已废弃:无限关模式无节间结算,回合自动推进,勿再监听 */
|
||||
SectionEnd = "SectionEnd",
|
||||
/** 大关结束(payload: { chapter, stage },10 节打完) */
|
||||
/** @deprecated 已废弃:无限关模式无大关结算,勿再监听 */
|
||||
StageEnd = "StageEnd",
|
||||
/** 章节结束(payload: { chapter },10 关打完) */
|
||||
/** @deprecated 已废弃:无限关模式无章节概念,勿再监听 */
|
||||
ChapterEnd = "ChapterEnd",
|
||||
/** 结算弹窗点击"下一节"(payload 为空,MissionComp 据此推进到下一小节) */
|
||||
/** @deprecated 已废弃:无限关模式无"下一节"手动推进,勿再监听 */
|
||||
NextSection = "NextSection",
|
||||
/** 结算弹窗点击"再来一次"(payload 为空,MissionComp 据此重开本关) */
|
||||
RestartMission = "RestartMission",
|
||||
|
||||
@@ -47,7 +47,7 @@ export enum FightSet {
|
||||
/** 英雄属性随等级成长的倍率(ap/hp = base * MULTIPLIER^(lv-1)) */
|
||||
HERO_LV_MULTIPLIER = 2,
|
||||
// BACK_RANG=30,//后退范围
|
||||
BACK_RANG = 20,//后退范围
|
||||
BACK_RANG = 30,//后退范围
|
||||
FiIGHT_TIME = 30,//战斗时间
|
||||
FROST_TIME = 3,//冰冻时间
|
||||
STUN_TIME = 1,//击晕时间(短控:施加瞬间 CD 削减,期间 CD 停止增长)
|
||||
|
||||
@@ -25,6 +25,10 @@ export enum UIID {
|
||||
Mission,
|
||||
/** 技能信息弹窗(技能小图标点击弹出) */
|
||||
SInfo,
|
||||
/** 英雄详情弹窗(图鉴卡片点击弹出:含属性/技能/升级/前后切换) */
|
||||
HeroInfo,
|
||||
/** 天赋详情弹窗(天赋迷你卡点击弹出:图标/等级/前置/条幅说明/加点按钮) */
|
||||
TIBox,
|
||||
}
|
||||
|
||||
/** 打开界面方式的配置数据 */
|
||||
@@ -41,5 +45,7 @@ export var UIConfigData: { [key: number]: UIConfig } = {
|
||||
// [UIID.Talents]: { layer: LayerType.UI, prefab: "gui/element/talents" },
|
||||
[UIID.Mission]: { layer: LayerType.UI, prefab: "gui/element/mission" },
|
||||
[UIID.SInfo]: { layer: LayerType.PopUp, prefab: "gui/element/SInfoBox" },
|
||||
[UIID.HeroInfo]: { layer: LayerType.PopUp, prefab: "gui/element/heroInfo", bundle: "resources" },
|
||||
[UIID.TIBox]: { layer: LayerType.PopUp, prefab: "gui/element/TIBox", bundle: "resources" },
|
||||
|
||||
}
|
||||
@@ -65,6 +65,16 @@ export enum EType {
|
||||
timeEnd = 1, //碰撞够也不消失,时间到才消失
|
||||
collision = 2, //碰撞次数够就消失
|
||||
}
|
||||
|
||||
/**
|
||||
* 召唤类技能(summon_count>1)多次施放的目标选择模式(由技能 prefab 上 SkillView 配置)。
|
||||
* 仅对敌方目标技能生效;友方/自身技能不走该逻辑。
|
||||
*/
|
||||
export enum SummonTMode {
|
||||
same = 0, // 同一敌人:所有召唤物锁定施法时选定的目标(默认,原行为)
|
||||
random = 1, // 随机敌人:每次出手时从射程内敌人中随机锁定一个
|
||||
unique = 2, // 避免相同敌人:优先锁定本轮尚未选过的敌人,一轮选完后重置再选
|
||||
}
|
||||
//debuff类型
|
||||
|
||||
|
||||
@@ -72,31 +82,40 @@ export enum EType {
|
||||
=== 技能配置系统使用说明 ===
|
||||
|
||||
1. 基础属性:
|
||||
- uuid: 技能唯一ID
|
||||
- name: 技能名称
|
||||
- uuid: 技能唯一ID(6001~6013 单体普攻、6100~6204 群体大招、6301~6302 治疗护盾、
|
||||
6401~6416 永久强化、6501~6519 计时强化/特殊、7001~7024 驻场光环)
|
||||
- name: 技能名称(内部底座代号;英雄语境对外名由 heroSet 侧 name 字段覆写)
|
||||
- sp_name: 特效名称
|
||||
- AtkedName: 攻击类型
|
||||
- path: 图片资源路径
|
||||
- icon: 图标ID
|
||||
|
||||
2. 目标和效果:
|
||||
- TGroup: 目标群体 (敌方、友方等)
|
||||
- SType: 技能类型 (伤害、治疗、护盾等)
|
||||
- TGroup: 目标群体(Self 自身 / Ally 全体友方含自己 / Team 全体友方 / Enemy 敌方 / All 全部)
|
||||
- kind: 主效果类型(Damage 伤害 / Heal 治疗 / Shield 护盾 / Support 强化)
|
||||
|
||||
3. 执行参数:
|
||||
- act: 角色执行的动画
|
||||
- DTType: 伤害类型 (单体、范围)
|
||||
- EType: 结束条件
|
||||
- fname: 特效文件名
|
||||
- act: 角色执行的动画
|
||||
- DTType: 伤害类型(single 单体 / range 范围)
|
||||
- EType: 结束条件(动画结束/时间结束/碰撞次数)
|
||||
- RType: 弹道类型(linear 直线 / bezier 贝塞尔 / fixed 固定起点 / fixedEnd 固定终点)
|
||||
- with: 暂时无用
|
||||
|
||||
4. 数值参数:
|
||||
- ap: 攻击力百分比
|
||||
- cd: 冷却时间
|
||||
- hit_count: 可命中次数
|
||||
- t_num: 目标数量
|
||||
- hitcd: 持续伤害的伤害间隔
|
||||
- speed: 移动速度
|
||||
- cost: 消耗值
|
||||
- ap: 伤害/治疗为攻击力百分比;护盾为生命最大值百分比;强化技能为修饰数值
|
||||
- cd: 冷却时间(普攻 cd 即攻击间隔)
|
||||
- hit_count: 可命中目标数(伤害技能=弹道穿透数;辅助技能=作用目标数)
|
||||
- hitcd: 持续伤害的伤害间隔(秒)
|
||||
- speed: 弹道移动速度
|
||||
- summon_count: 单次施法召唤的弹道/实体个数(>1 视为召唤类技能)
|
||||
|
||||
5. 增益/减益:
|
||||
- buff_type + ap: 永久强化(直接累加到属性,无时长)
|
||||
- timed_buff_id + buff_value/buff_duration/buff_chance/buff_target: 计时强化(走 BuffList)
|
||||
- timed_debuff_id + debuff_value/debuff_duration/debuff_chance: 命中敌方后挂的计时减益
|
||||
- proc_skill: 施法后概率触发额外技能(技能级触发器,无视 CD)
|
||||
|
||||
6. 文案约定:
|
||||
- info 仅作语义描述,禁止写死数值;数值由 heroSet/卡片 overrides 注入,
|
||||
UI 文案由 SkillDescSet / HeroSkillText 按合并后实时配置动态生成
|
||||
*/
|
||||
export enum DType {
|
||||
ATK = 0, // 物理
|
||||
@@ -140,8 +159,8 @@ export interface SkillConfig {
|
||||
TGroup: TGroup, // 目标群体(敌方/友方/自身等)
|
||||
act: string, // 角色执行的动画
|
||||
DTType: DTType, // 伤害类型(单体/范围)
|
||||
ap: number, // 伤害/治疗技能为攻击百分比,护盾技能为免疫次数
|
||||
hit_count: number, // 可命中次数
|
||||
ap: number, // 伤害/治疗为攻击力百分比;护盾为生命最大值百分比;永久强化为修饰数值
|
||||
hit_count: number, // 可命中目标数(伤害技能=弹道穿透数;辅助技能=作用目标数,>1 生效)
|
||||
hitcd: number, // 持续伤害的伤害间隔(秒)
|
||||
speed: number, // 移动速度
|
||||
with: number, // 宽度(暂时无用)
|
||||
@@ -318,6 +337,21 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true,
|
||||
RType: RType.bezier, EType: EType.collision, info: "红瓶抛射物",
|
||||
},
|
||||
6013: {
|
||||
uuid: 6013, name: "闪电", sp_name: "m3", icon: "109-Red-Potion", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true,
|
||||
RType: RType.fixedEnd, EType: EType.collision, info: "单体雷击(固定终点落雷),可附加麻痹",
|
||||
},
|
||||
6014: {
|
||||
uuid: 6014, name: "小火球", sp_name: "m4", icon: "109-Red-Potion", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true,
|
||||
RType: RType.fixedEnd, EType: EType.collision, info: "小火球(固定终点),可附加灼烧/易伤",
|
||||
},
|
||||
6015: {
|
||||
uuid: 6015, name: "小飓风", sp_name: "m5", icon: "109-Red-Potion", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true,
|
||||
RType: RType.fixedEnd, EType: EType.collision, info: "小飓风(固定终点),直线穿透",
|
||||
},
|
||||
// ==================== 群体大招(按职业分段:6100-6149 坦克/战士、6150-6199 刺客/射手、6200-6249 法师/辅助) ====================
|
||||
// 坦克/战士群体攻击大招
|
||||
6100: {
|
||||
@@ -336,8 +370,8 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
RType: RType.bezier, EType: EType.collision, info: "火焰斩动画",//英雄配置技能的时候,可以叠加暴击debuff
|
||||
},
|
||||
6103: {
|
||||
uuid: 6103, name: "闪电斩", sp_name: "atk5", icon: "100-Enchant-Magic", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max0",
|
||||
DTType: DTType.single, para: 30, ap: 150, hit_count: 5, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true,
|
||||
uuid: 6103, name: "闪电斩", sp_name: "atk6", icon: "100-Enchant-Magic", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max0",
|
||||
DTType: DTType.single, ap: 150, hit_count: 5, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.Melee, is_accel: true,
|
||||
RType: RType.bezier, EType: EType.collision, info: "闪电斩动画",//英雄配置技能的时候,可以疲惫触发闪电系追加技能
|
||||
},
|
||||
6104: {
|
||||
@@ -358,52 +392,52 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
},
|
||||
// 法师/辅助群体攻击大招
|
||||
6200: {
|
||||
uuid: 6200, name: "火球术", sp_name: "maxm1", icon: "31-Fire", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max0",
|
||||
uuid: 6200, name: "火球术", sp_name: "maxm1", icon: "31-Fire", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1",
|
||||
DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
||||
RType: RType.bezier, EType: EType.collision, bezier_start_y: 20, bezier_mid_y: 140, bezier_arc: 1.05, info: "一个大火球",
|
||||
},
|
||||
6201: {
|
||||
uuid: 6201, name: "飓风", sp_name: "maxm2", icon: "98-Enchant-Wind", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1",
|
||||
DTType: DTType.single, ap: 100, hit_count: 2, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
||||
DTType: DTType.single, ap: 100, hit_count: 99, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
||||
RType: RType.linear, EType: EType.collision, info: "一个飓风",
|
||||
},
|
||||
6202: {
|
||||
uuid: 6202, name: "毒气弹", sp_name: "maxm4", icon: "o_warlock_hyzy_skill", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1",
|
||||
DTType: DTType.single, ap: 100, hit_count: 2, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
||||
DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
||||
RType: RType.linear, EType: EType.collision, bezier_start_y: 20, bezier_mid_y: 140, bezier_arc: 1.05, info: "一个大毒气弹",
|
||||
},
|
||||
6203: {
|
||||
uuid: 6203, name: "能量波", sp_name: "maxm5", icon: "b_priest_kx_skill", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1",
|
||||
DTType: DTType.single, ap: 100, hit_count: 2, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
||||
DTType: DTType.single, ap: 100, hit_count: 1, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
||||
RType: RType.linear, EType: EType.collision, bezier_start_y: 20, bezier_mid_y: 140, bezier_arc: 1.05, info: "一个能量波",
|
||||
},
|
||||
6204: {
|
||||
uuid: 6204, name: "多毒气弹", sp_name: "maxm6", icon: "o_warlock_hyzy_skill", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1",
|
||||
DTType: DTType.single, ap: 100, hit_count: 2, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
||||
RType: RType.linear, EType: EType.collision, bezier_start_y: 20, bezier_mid_y: 140, bezier_arc: 1.05, info: "一个大毒气弹",
|
||||
uuid: 6204, name: "雷暴", sp_name: "maxm7", icon: "o_warlock_hyzy_skill", TGroup: TGroup.Enemy, readyAnm: "", endAnm: "", act: "max1",
|
||||
DTType: DTType.single, ap: 100, hit_count: 99, hitcd: 0.3, speed: 720, with: 90, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.remote,
|
||||
RType: RType.linear, EType: EType.collision, bezier_start_y: 20, bezier_mid_y: 140, bezier_arc: 1.05, info: "雷暴多段打击(hit_count=99 直线穿透),可附加麻痹",
|
||||
},
|
||||
|
||||
//============================= ====== 辅助技能 回合技能 ====== ==========================
|
||||
6301: {
|
||||
uuid: 6301, name: "护盾", sp_name: "buff_wind", icon: "28-Electric-Wave", TGroup: TGroup.Self, readyAnm: "up_blue", endAnm: "", act: "atk",
|
||||
uuid: 6301, name: "护盾", sp_name: "buff_wind", icon: "28-Electric-Wave", TGroup: TGroup.Self, readyAnm: "up_blue", endAnm: "", act: "max1",
|
||||
DTType: DTType.single, kind: SkillKind.Shield, ap: 30, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support, shield_duration: 7,
|
||||
RType: RType.fixed, EType: EType.animationEnd, info: "获得施法者最大生命30%的护盾, 持续7秒",
|
||||
RType: RType.fixed, EType: EType.animationEnd, info: "获得施法者最大生命一定比例的护盾,持续7秒(ap=百分比)",
|
||||
},
|
||||
6302: {
|
||||
uuid: 6302, name: "治疗", sp_name: "buff_wind", icon: "g_priest_zldy_skill", TGroup: TGroup.Team, readyAnm: "up_green", endAnm: "", act: "atk",
|
||||
uuid: 6302, name: "治疗", sp_name: "buff_wind", icon: "g_priest_zldy_skill", TGroup: TGroup.Team, readyAnm: "up_green", endAnm: "", act: "max1",
|
||||
DTType: DTType.single, kind: SkillKind.Heal, ap: 300, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, info: "治疗伙伴/自己",
|
||||
RType: RType.fixed, EType: EType.animationEnd, info: "治疗友方目标,回复量=目标最大生命×ap%",
|
||||
},
|
||||
//==========================buff 技能=====================
|
||||
6401: {
|
||||
uuid: 6401, name: "攻击强化", sp_name: "buff_wind", icon: "36-Guardian-Stance", TGroup: TGroup.Team, readyAnm: "up_ap", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Support, ap: 5, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.ap, info: "全体友方攻击力提升5%, 持续1次",
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.ap, info: "全体友方攻击力永久提升(ap=百分比,单次施加)",
|
||||
},
|
||||
6402: {
|
||||
uuid: 6402, name: "生命强化", sp_name: "buff_wind", icon: "29-Endure", TGroup: TGroup.Team, readyAnm: "up_hp", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Support, ap: 20, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.hp_max, info: "全体友方最大生命值提升20%, 持续1次",
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.hp_max, info: "全体友方最大生命值永久提升(ap=百分比,单次施加)",
|
||||
},
|
||||
6403: {
|
||||
uuid: 6403, name: "暴击强化", sp_name: "buff_wind", icon: "5-Apply-Burn", TGroup: TGroup.Team, readyAnm: "up_ap", endAnm: "", act: "atk",
|
||||
@@ -456,7 +490,7 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
6412: {
|
||||
uuid: 6412, name: "防御强化", sp_name: "buff_wind", icon: "46-Iron-Clad", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Support, ap: 50, hit_count: 1, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.defense, info: "全体友方防御提升50点, 持续1次",
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.defense, info: "全体友方防御永久提升(ap=固定点数,单次施加)",
|
||||
},
|
||||
6413: {
|
||||
uuid: 6413, name: "反伤强化", sp_name: "buff_wind", icon: "75-Shield-Stun", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
|
||||
@@ -514,7 +548,7 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
6507: {
|
||||
uuid: 6507, name: "攻速爆发", sp_name: "buff_wind", icon: "147-Chronomancy", TGroup: TGroup.Team, readyAnm: "up_ap", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 3, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.speed, timed_buff_id: 7015, info: "全体友方攻击速度提升40%, 持续5秒",
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.speed, timed_buff_id: 7015, info: "全体友方攻击速度提升(buff_value=百分比,默认5秒)",
|
||||
},
|
||||
// 风怒机制已停用: 6508 风怒爆发技能已移除
|
||||
/*
|
||||
@@ -568,7 +602,7 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
6517: {
|
||||
uuid: 6517, name: "生命爆发", sp_name: "buff_wind", icon: "29-Endure", TGroup: TGroup.Team, readyAnm: "up_green", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 3, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.hp_max, timed_buff_id: 7029, info: "全体友方最大生命值提升30%, 持续5秒",
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.hp_max, timed_buff_id: 7029, info: "全体友方最大生命值提升(buff_value=百分比,默认5秒)",
|
||||
},
|
||||
6518: {
|
||||
uuid: 6518, name: "闪避爆发", sp_name: "buff_wind", icon: "98-Enchant-Wind", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
|
||||
@@ -576,9 +610,9 @@ export const SkillSet: Record<number, SkillConfig> = {
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.dodge, timed_buff_id: 7030, info: "全体友方闪避概率提升20%, 持续5秒",
|
||||
},
|
||||
6519: {
|
||||
uuid: 6519, name: "命中强化", sp_name: "buff_wind", icon: "27-Hawkeye", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
|
||||
uuid: 6519, name: "命中爆发", sp_name: "buff_wind", icon: "27-Hawkeye", TGroup: TGroup.Team, readyAnm: "up_blue", endAnm: "", act: "atk",
|
||||
DTType: DTType.single, kind: SkillKind.Support, ap: 0, hit_count: 3, hitcd: 0.2, speed: 720, with: 0, ready: 0.2, EAnm: 0, DAnm: "", IType: IType.support,
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.accuracy, timed_buff_id: 7031, info: "全体友方命中概率提升20%, 持续5秒",
|
||||
RType: RType.fixed, EType: EType.animationEnd, buff_type: Attrs.accuracy, timed_buff_id: 7031, info: "全体友方命中概率提升(buff_value=百分比,默认5秒)",
|
||||
}
|
||||
};
|
||||
//***************驻场技能配置***************
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
/**
|
||||
* @file StageSet.ts
|
||||
* @description 关卡系统配置(章节-关-节三级结构)
|
||||
* @description 关卡系统配置(无限关卡·单线推进)
|
||||
*
|
||||
* 设计要点:
|
||||
* - 1 章 = 10 关,每关 = 5 小节(一关一局,节间自动推进),共 50 个小节
|
||||
* - 每关节点固定:1~3 节普通(3 小怪)、第 4 节精英(3 精英)、第 5 节 Boss(1 Boss + 2 小怪)
|
||||
* - 怪物等级 = 关卡号(1-1 的怪为 Lv1,1-5 的怪为 Lv5)
|
||||
* - 怪物属性 = 基础 × 开局系数 × (1 + 成长斜率 × (lv-1)) × 类型倍率
|
||||
* - 无限关卡:从第 1 关起无上限推进,每关 = 5 回合(一关一局,回合间自动推进)
|
||||
* - 第 1~4 回合为普通怪,属性逐回合轻量增强(SECTION_RAMP_STEP)
|
||||
* - 第 5 回合为单 Boss 回合(无护卫),Boss 采用超厚血量(BOSS_HP_MUL)
|
||||
* - 怪物等级 = 关卡号(第 N 关的怪为 LvN,随关卡无限成长)
|
||||
* - 小节配置按需动态生成,不再依赖章节静态表
|
||||
*
|
||||
* 数值基准:
|
||||
* - 开局系数 0.8(1 级小怪略弱于英雄)
|
||||
* - 成长斜率 +5%/级(10 级 ≈ 1.45 倍)
|
||||
* - 精英倍率 × 1.5,Boss 倍率 × 3.0(精英 × 2)
|
||||
* - 成长斜率 +5%/级(无限线性成长,曲线平缓可控)
|
||||
* - 回合增强 +12%/回合(第 4 回合 ≈ 1.36 倍)
|
||||
* - Boss:HP × 12(超厚血量)/ AP × 2.0(攻击克制,避免 Boss 秒杀英雄)
|
||||
*
|
||||
* 核心公式:
|
||||
* 怪物属性 = 基础 × MON_START_COEF × (1 + MON_GROW_SLOPE×(lv-1)) × 回合增强 × 类型倍率
|
||||
*/
|
||||
|
||||
import { MonType } from "./heroSet";
|
||||
@@ -20,82 +25,54 @@ import { MonType } from "./heroSet";
|
||||
|
||||
/** 怪物开局系数:1 级小怪略弱于英雄(0.8 倍) */
|
||||
export const MON_START_COEF = 0.8;
|
||||
/** 怪物成长斜率:每级 +5% 基础属性 */
|
||||
/** 怪物成长斜率:每级 +5% 基础属性(无限线性成长) */
|
||||
export const MON_GROW_SLOPE = 0.05;
|
||||
/** 精英属性倍率:同级普通怪的 1.5 倍 */
|
||||
export const ELITE_MUL = 1.5;
|
||||
/** Boss 属性倍率:同级普通怪的 3.0 倍(精英 × 2) */
|
||||
export const BOSS_MUL = 3.0;
|
||||
/** 每关小节总数(一关一局,节间自动推进) */
|
||||
/** 回合内轻量增强步长:第 1→4 回合每回合 +12% 属性 */
|
||||
export const SECTION_RAMP_STEP = 0.12;
|
||||
/** Boss 血量倍率:同级普通怪的 12 倍(超厚血量,拖长 Boss 战节奏) */
|
||||
export const BOSS_HP_MUL = 12;
|
||||
/** Boss 攻击倍率:同级普通怪的 2.0 倍(显著低于血量倍率,避免 Boss 秒杀英雄) */
|
||||
export const BOSS_AP_MUL = 2.0;
|
||||
/** 每关回合总数(一关一局,回合间自动推进) */
|
||||
export const SECTIONS_PER_STAGE = 5;
|
||||
/** 精英节号(每关第 4 节为精英节) */
|
||||
export const ELITE_SECTION = 4;
|
||||
/** Boss 节号(每关第 5 节为 Boss 节,即末节) */
|
||||
/** Boss 回合号(每关第 5 回合,即末回合) */
|
||||
export const BOSS_SECTION = 5;
|
||||
/** 普通节小怪数量(一关一局压缩后单节 3 只) */
|
||||
/** 普通回合小怪数量 */
|
||||
export const NORMAL_MON_COUNT = 3;
|
||||
/** 普通节开局立即刷出数量(3 只全部立即刷出) */
|
||||
/** 普通回合开局立即刷出数量(3 只全部立即刷出) */
|
||||
export const NORMAL_FIRST_SPAWN = 3;
|
||||
/** 普通节后续刷怪间隔(秒):保留配置位(3 只全立即刷,当前无后续批次) */
|
||||
/** 普通回合后续刷怪间隔(秒):保留配置位(3 只全立即刷,当前无后续批次) */
|
||||
export const NORMAL_SPAWN_INTERVAL = 2;
|
||||
/** 精英节精英数量 */
|
||||
export const ELITE_COUNT = 3;
|
||||
/** Boss 节护卫小怪数量 */
|
||||
export const BOSS_ELITE_COUNT = 2;
|
||||
/** Boss 节 Boss 延迟刷出时间(秒) */
|
||||
/** Boss 回合 Boss 延迟刷出时间(秒) */
|
||||
export const BOSS_DELAY = 1;
|
||||
|
||||
// ======================== 类型定义 ========================
|
||||
|
||||
/** 小节类型 */
|
||||
/** 回合类型 */
|
||||
export enum SectionType {
|
||||
Normal = 0, // 普通节:3 小怪
|
||||
Elite = 1, // 精英节:3 精英
|
||||
Boss = 2, // Boss 节:1 Boss + 2 小怪
|
||||
Normal = 0, // 普通回合:3 小怪(逐回合轻量增强)
|
||||
Boss = 2, // Boss 回合:1 Boss(超厚血量,无护卫)
|
||||
}
|
||||
|
||||
/** 小节配置 */
|
||||
/** 回合配置 */
|
||||
export interface SectionConfig {
|
||||
/** 小节类型 */
|
||||
/** 回合类型 */
|
||||
type: SectionType;
|
||||
/** 怪物等级(驱动线性成长) */
|
||||
/** 怪物等级(= 关卡号,驱动线性成长) */
|
||||
monLv: number;
|
||||
/** 精英数量(精英关/Boss 关用) */
|
||||
eliteCount?: number;
|
||||
/** Boss UUID(Boss 关用,可选,缺省随机) */
|
||||
bossUuid?: number;
|
||||
/** 怪物类型池(普通关用,缺省随机) */
|
||||
/** 回合增强系数(第 n 回合 = 1 + SECTION_RAMP_STEP×(n-1),仅普通回合生效) */
|
||||
ramp: number;
|
||||
/** 怪物类型池(普通回合用,缺省随机) */
|
||||
monTypes?: MonType[];
|
||||
}
|
||||
|
||||
/** 大关配置(1-1 ~ 1-10),每关 SECTIONS_PER_STAGE 个小节 */
|
||||
export interface StageConfig {
|
||||
/** 章节号 */
|
||||
chapter: number;
|
||||
/** 关卡号 1~10 */
|
||||
stage: number;
|
||||
/** 小节列表(长度 = SECTIONS_PER_STAGE) */
|
||||
sections: SectionConfig[];
|
||||
}
|
||||
|
||||
/** 章节配置 */
|
||||
export interface ChapterConfig {
|
||||
/** 章节号 */
|
||||
chapter: number;
|
||||
/** 章节名称 */
|
||||
name: string;
|
||||
/** 10 个大关 */
|
||||
stages: StageConfig[];
|
||||
}
|
||||
|
||||
// ======================== 工具函数 ========================
|
||||
|
||||
/**
|
||||
* 计算怪物最终属性
|
||||
* 计算怪物最终属性(Boss 血/攻倍率分离:超厚血 + 克制攻)
|
||||
* @param baseHp 基础 HP
|
||||
* @param baseAp 基础 AP
|
||||
* @param lv 怪物等级
|
||||
* @param isElite 是否精英
|
||||
* @param isBoss 是否 Boss
|
||||
* @returns 最终 HP/AP
|
||||
*/
|
||||
@@ -103,159 +80,70 @@ export function calcMonsterAttrs(
|
||||
baseHp: number,
|
||||
baseAp: number,
|
||||
lv: number,
|
||||
isElite: boolean = false,
|
||||
isBoss: boolean = false
|
||||
): { hp: number; ap: number } {
|
||||
const growCoef = 1 + MON_GROW_SLOPE * (lv - 1);
|
||||
let typeMul = 1;
|
||||
if (isBoss) {
|
||||
typeMul = BOSS_MUL;
|
||||
} else if (isElite) {
|
||||
typeMul = ELITE_MUL;
|
||||
}
|
||||
const hp = Math.max(1, Math.round(baseHp * MON_START_COEF * growCoef * typeMul));
|
||||
const ap = Math.max(1, Math.round(baseAp * MON_START_COEF * growCoef * typeMul));
|
||||
const hp = Math.max(1, Math.round(baseHp * MON_START_COEF * growCoef * (isBoss ? BOSS_HP_MUL : 1)));
|
||||
const ap = Math.max(1, Math.round(baseAp * MON_START_COEF * growCoef * (isBoss ? BOSS_AP_MUL : 1)));
|
||||
return { hp, ap };
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定关卡的怪物等级
|
||||
* @param stage 关卡号(1~10)
|
||||
* 获取指定关卡的怪物等级(无限关:等级 = 关卡号,无上限)
|
||||
* @param stage 关卡号(1~∞)
|
||||
* @returns 怪物等级
|
||||
*/
|
||||
export function getMonsterLv(stage: number): number {
|
||||
return Math.max(1, Math.min(10, stage));
|
||||
return Math.max(1, Math.floor(stage));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为精英节(每关第 ELITE_SECTION 节)
|
||||
* @param section 小节号(1~SECTIONS_PER_STAGE)
|
||||
*/
|
||||
export function isEliteSection(section: number): boolean {
|
||||
return section === ELITE_SECTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为 Boss 节(每关第 BOSS_SECTION 节,即末节)
|
||||
* @param section 小节号(1~SECTIONS_PER_STAGE)
|
||||
* 判断是否为 Boss 回合(每关第 BOSS_SECTION 回合,即末回合)
|
||||
* @param section 回合号(1~SECTIONS_PER_STAGE)
|
||||
*/
|
||||
export function isBossSection(section: number): boolean {
|
||||
return section === BOSS_SECTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取小节类型(按节号区分:1~3 普通 / 4 精英 / 5 Boss)
|
||||
* @param section 小节号(1~SECTIONS_PER_STAGE)
|
||||
* 获取回合类型(按回合号区分:1~4 普通 / 5 Boss)
|
||||
* @param section 回合号(1~SECTIONS_PER_STAGE)
|
||||
*/
|
||||
export function getSectionType(section: number): SectionType {
|
||||
if (isBossSection(section)) return SectionType.Boss;
|
||||
if (isEliteSection(section)) return SectionType.Elite;
|
||||
return SectionType.Normal;
|
||||
return isBossSection(section) ? SectionType.Boss : SectionType.Normal;
|
||||
}
|
||||
|
||||
// ======================== 第 1 章配置 ========================
|
||||
|
||||
/** 生成单个大关的 SECTIONS_PER_STAGE 个小节配置(1~3 普通 / 4 精英 / 5 Boss) */
|
||||
function makeStageSections(stage: number): SectionConfig[] {
|
||||
const monLv = getMonsterLv(stage);
|
||||
const sections: SectionConfig[] = [];
|
||||
|
||||
for (let i = 1; i <= SECTIONS_PER_STAGE; i++) {
|
||||
const type = getSectionType(i);
|
||||
const section: SectionConfig = { type, monLv };
|
||||
|
||||
if (type === SectionType.Elite) {
|
||||
section.eliteCount = ELITE_COUNT;
|
||||
} else if (type === SectionType.Boss) {
|
||||
section.eliteCount = BOSS_ELITE_COUNT;
|
||||
// bossUuid 缺省随机,由生成引擎从 Boss 池抽取
|
||||
} else {
|
||||
// 普通节:近战为主,穿插远程/重型
|
||||
section.monTypes = [MonType.Melee, MonType.Melee, MonType.Melee, MonType.Heavy, MonType.Long];
|
||||
}
|
||||
|
||||
sections.push(section);
|
||||
}
|
||||
return sections;
|
||||
}
|
||||
|
||||
/** 第 1 章配置 */
|
||||
export const Chapter1: ChapterConfig = {
|
||||
chapter: 1,
|
||||
name: "兽人入侵",
|
||||
stages: [],
|
||||
};
|
||||
|
||||
// 初始化第 1 章 10 个大关
|
||||
for (let stage = 1; stage <= 10; stage++) {
|
||||
Chapter1.stages.push({
|
||||
chapter: 1,
|
||||
stage,
|
||||
sections: makeStageSections(stage),
|
||||
});
|
||||
}
|
||||
|
||||
/** 所有章节配置表(当前仅第 1 章,后续扩展) */
|
||||
export const ChapterSet: Record<number, ChapterConfig> = {
|
||||
1: Chapter1,
|
||||
};
|
||||
|
||||
// ======================== 查询接口 ========================
|
||||
|
||||
/**
|
||||
* 获取小节配置
|
||||
* @param chapter 章节号
|
||||
* @param stage 关卡号
|
||||
* @param section 小节号(1~SECTIONS_PER_STAGE)
|
||||
* @returns 小节配置,不存在时返回 null
|
||||
* 获取回合配置(无限关:按需动态生成,不再依赖章节静态表)
|
||||
* @param stage 关卡号(1~∞)
|
||||
* @param section 回合号(1~SECTIONS_PER_STAGE)
|
||||
* @returns 回合配置,回合号越界时返回 null
|
||||
*/
|
||||
export function getSectionConfig(chapter: number, stage: number, section: number): SectionConfig | null {
|
||||
const ch = ChapterSet[chapter];
|
||||
if (!ch) return null;
|
||||
const st = ch.stages.find(s => s.stage === stage);
|
||||
if (!st) return null;
|
||||
if (section < 1 || section > st.sections.length) return null;
|
||||
return st.sections[section - 1];
|
||||
export function getSectionConfig(stage: number, section: number): SectionConfig | null {
|
||||
if (section < 1 || section > SECTIONS_PER_STAGE) return null;
|
||||
|
||||
const type = getSectionType(section);
|
||||
const cfg: SectionConfig = {
|
||||
type,
|
||||
monLv: getMonsterLv(stage),
|
||||
ramp: 1 + SECTION_RAMP_STEP * (section - 1),
|
||||
};
|
||||
|
||||
if (type !== SectionType.Boss) {
|
||||
// 普通回合:近战为主,穿插远程/重型
|
||||
cfg.monTypes = [MonType.Melee, MonType.Melee, MonType.Melee, MonType.Heavy, MonType.Long];
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取大关配置
|
||||
* @param chapter 章节号
|
||||
* 获取当前进度显示文本(无限关:只展示 关-回合)
|
||||
* @param stage 关卡号
|
||||
* @returns 大关配置,不存在时返回 null
|
||||
* @param section 回合号
|
||||
* @returns 格式化文本,如 "5-3"
|
||||
*/
|
||||
export function getStageConfig(chapter: number, stage: number): StageConfig | null {
|
||||
const ch = ChapterSet[chapter];
|
||||
if (!ch) return null;
|
||||
return ch.stages.find(s => s.stage === stage) ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取章节配置
|
||||
* @param chapter 章节号
|
||||
* @returns 章节配置,不存在时返回 null
|
||||
*/
|
||||
export function getChapterConfig(chapter: number): ChapterConfig | null {
|
||||
return ChapterSet[chapter] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前进度显示文本
|
||||
* @param chapter 章节号
|
||||
* @param stage 关卡号
|
||||
* @param section 小节号
|
||||
* @returns 格式化文本,如 "1-5-3"
|
||||
*/
|
||||
export function getProgressText(chapter: number, stage: number, section: number): string {
|
||||
return `${chapter}-${stage}-${section}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取大关显示文本
|
||||
* @param chapter 章节号
|
||||
* @param stage 关卡号
|
||||
* @returns 格式化文本,如 "1-5"
|
||||
*/
|
||||
export function getStageText(chapter: number, stage: number): string {
|
||||
return `${chapter}-${stage}`;
|
||||
export function getProgressText(stage: number, section: number): string {
|
||||
return `${stage}-${section}`;
|
||||
}
|
||||
|
||||
@@ -4,13 +4,15 @@ import { HRole } from "./heroSet";
|
||||
/**
|
||||
* 天赋系统配置(局外成长:升级即激活,战斗中对英雄属性常驻加成)。
|
||||
*
|
||||
* 三阶结构(阶位逐级解锁,门槛见 TALENT_TIER_UNLOCK_THRESHOLD):
|
||||
* - 一阶·基础天赋(9001-9099):全局生效,对所有英雄叠加;
|
||||
* - 二阶·专精天赋(9101-9199):按 HRole 职业过滤,仅对匹配职业的英雄生效;
|
||||
* - 三阶·超强天赋(9201-9219):全局(9201-9209)+ 职业(9211-9219)混合,数值幅度约为前两阶的 2 倍。
|
||||
* 五层递进结构(逐层解锁,门槛见 TALENT_TIER_UNLOCK_THRESHOLD):
|
||||
* - 第 1 层(9001-9099):恒解锁,建议放置全局基础属性;
|
||||
* - 第 2 层(9101-9199):第 1 层累计投入 ≥5 点解锁;
|
||||
* - 第 3 层(9201-9299):第 2 层累计投入 ≥5 点解锁;
|
||||
* - 第 4 层(9301-9399):第 3 层累计投入 ≥5 点解锁;
|
||||
* - 第 5 层(9401-9499):第 4 层累计投入 ≥5 点解锁。
|
||||
*
|
||||
* 解锁规则:一阶恒可升级;二阶需一阶累计投入 ≥10 点;三阶需二阶累计投入 ≥10 点。
|
||||
* 专精/超强职业天赋不再有独立前置天赋,仅受阶位解锁约束。
|
||||
* 解锁规则:第 1 层恒可升级;第 N 层需第 N-1 层累计投入 ≥5 点。
|
||||
* 前置天赋(prereq_uuid/prereq_lv)为软前置:仅限制加点,不影响已有点数的战斗结算。
|
||||
*
|
||||
* 结算口径(与项目 buff 规范一致):
|
||||
* - percent 模式:按英雄基础值(base_ap/base_hp/hero.def)相对放大;
|
||||
@@ -23,14 +25,18 @@ export enum TalentValueMode {
|
||||
Flat = 1,
|
||||
}
|
||||
|
||||
/** 天赋阶位:一阶基础 / 二阶专精 / 三阶超强 */
|
||||
/** 天赋层位:第 1 层 ~ 第 5 层递进解锁 */
|
||||
export enum TalentTier {
|
||||
/** 一阶:基础天赋,全局生效 */
|
||||
Basic = 1,
|
||||
/** 二阶:专精天赋,按职业过滤 */
|
||||
Specialized = 2,
|
||||
/** 三阶:超强天赋,全局 + 职业混合 */
|
||||
Super = 3,
|
||||
/** 第 1 层:恒解锁 */
|
||||
L1 = 1,
|
||||
/** 第 2 层:第 1 层投入 5 点解锁 */
|
||||
L2 = 2,
|
||||
/** 第 3 层:第 2 层投入 5 点解锁 */
|
||||
L3 = 3,
|
||||
/** 第 4 层:第 3 层投入 5 点解锁 */
|
||||
L4 = 4,
|
||||
/** 第 5 层:第 4 层投入 5 点解锁 */
|
||||
L5 = 5,
|
||||
}
|
||||
|
||||
/** 单条属性加成词条 */
|
||||
@@ -47,7 +53,7 @@ export interface TalentAttrBonus {
|
||||
export interface TalentConfig {
|
||||
/** 天赋 uuid(段位见 TalentSet 注释) */
|
||||
uuid: number;
|
||||
/** 所属阶位(升级校验:升下一阶天赋需前一阶累计投入点数达标) */
|
||||
/** 所属层位(升级校验:升下一层天赋需前一层累计投入点数达标) */
|
||||
tier: TalentTier;
|
||||
/** 天赋名称 */
|
||||
name: string;
|
||||
@@ -59,8 +65,16 @@ export interface TalentConfig {
|
||||
bonuses: TalentAttrBonus[];
|
||||
/** 最大等级 */
|
||||
max_lv: number;
|
||||
/** 专精/超强职业天赋:仅对该职业英雄生效;全局天赋省略此字段 */
|
||||
/** 专精/职业天赋:仅对该职业英雄生效;全局天赋省略此字段 */
|
||||
role?: HRole;
|
||||
/** 软前置:前置天赋 uuid(与 prereq_lv 成对出现;缺省视为无前置) */
|
||||
prereq_uuid?: number;
|
||||
/** 软前置:前置天赋要求达到的等级(仅限制加点,不影响已有点数的结算) */
|
||||
prereq_lv?: number;
|
||||
/** L4 触发修正:触发类技能计数阈值减少量(每级,下限 1;与 bonuses 互斥) */
|
||||
t_num_reduce_per_lv?: number;
|
||||
/** L5 触发修正:触发类技能额外触发 1 次的概率(每级百分点;与 bonuses 互斥) */
|
||||
extra_trigger_chance_per_lv?: number;
|
||||
}
|
||||
|
||||
/** 单条已解析的加成(等级已乘算) */
|
||||
@@ -84,208 +98,201 @@ export interface ITalentTarget {
|
||||
base_ap: number;
|
||||
/** 基础血量快照(percent 模式的基数) */
|
||||
base_hp: number;
|
||||
/** L4 写入:触发类技能计数阈值减少量 */
|
||||
talent_t_num_reduce: number;
|
||||
/** L5 写入:触发类技能额外触发 1 次的概率(百分点) */
|
||||
talent_extra_trigger_chance: number;
|
||||
/** 防御基础值(percent 模式的基数,等于 hero.def) */
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 天赋配置表。
|
||||
* uuid 段位:9001-9099 一阶基础(全局);9101-9199 二阶专精(按职业);
|
||||
* 9201-9209 三阶超强·全局;9211-9219 三阶超强·职业。
|
||||
* uuid 段位:9001-9099 第 1 层;9101-9199 第 2 层;9201-9299 第 3 层;
|
||||
* 9301-9399 第 4 层;9401-9499 第 5 层。
|
||||
* 每层建议放置 4-6 个天赋;前置天赋用 prereq_uuid + prereq_lv 声明(软前置,仅限制加点)。
|
||||
* icon 复用 SkillSet/uiconsAtlas 既有帧名,后续可在编辑器侧替换为专属图标。
|
||||
*/
|
||||
export const TalentSet: Record<number, TalentConfig> = {
|
||||
// ==================== 一阶·基础天赋(9001-9099,全局生效) ====================
|
||||
// ==================== 第 1 层(9001-9099,恒解锁,基础属性) ====================
|
||||
9001: {
|
||||
uuid: 9001, tier: TalentTier.Basic, name: "攻击强化", info: "所有英雄攻击 +{value}%", icon: "3-Aggression",
|
||||
uuid: 9001, tier: TalentTier.L1, name: "攻击强化", info: "所有英雄攻击 +{value}%", icon: "3-Aggression",
|
||||
bonuses: [{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 3 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
9002: {
|
||||
uuid: 9002, tier: TalentTier.Basic, name: "生命强化", info: "所有英雄生命 +{value}%", icon: "29-Endure",
|
||||
uuid: 9002, tier: TalentTier.L1, name: "生命强化", info: "所有英雄生命 +{value}%", icon: "29-Endure",
|
||||
bonuses: [{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 5 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
9003: {
|
||||
uuid: 9003, tier: TalentTier.Basic, name: "防御强化", info: "所有英雄防御 +{value} 点", icon: "46-Iron-Clad",
|
||||
uuid: 9003, tier: TalentTier.L1, name: "防御强化", info: "所有英雄防御 +{value} 点", icon: "46-Iron-Clad",
|
||||
bonuses: [{ attr: Attrs.defense, mode: TalentValueMode.Flat, per_lv: 8 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
9004: {
|
||||
uuid: 9004, tier: TalentTier.Basic, name: "暴击强化", info: "所有英雄暴击率 +{value}%", icon: "27-Hawkeye",
|
||||
uuid: 9004, tier: TalentTier.L1, name: "反伤荆棘", info: "所有英雄反伤 +{value} 点", icon: "45-Induration",
|
||||
bonuses: [{ attr: Attrs.thorns_dmg, mode: TalentValueMode.Flat, per_lv: 5 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
|
||||
// ==================== 第 2 层(9101-9199,第 1 层投入 5 点解锁,概率属性) ====================
|
||||
9101: {
|
||||
uuid: 9101, tier: TalentTier.L2, name: "暴击强化", info: "所有英雄暴击率 +{value}%", icon: "27-Hawkeye",
|
||||
bonuses: [{ attr: Attrs.critical, mode: TalentValueMode.Flat, per_lv: 2 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
9005: {
|
||||
uuid: 9005, tier: TalentTier.Basic, name: "击晕强化", info: "所有英雄击晕率 +{value}%", icon: "13-Concussion",
|
||||
bonuses: [{ attr: Attrs.stun_chance, mode: TalentValueMode.Flat, per_lv: 2 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
9006: {
|
||||
uuid: 9006, tier: TalentTier.Basic, name: "冰冻强化", info: "所有英雄冰冻率 +{value}%", icon: "92-Frost-Bite",
|
||||
bonuses: [{ attr: Attrs.freeze_chance, mode: TalentValueMode.Flat, per_lv: 2 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
9007: {
|
||||
uuid: 9007, tier: TalentTier.Basic, name: "击退强化", info: "所有英雄击退距离 +{value}", icon: "34-Force-Push",
|
||||
9102: {
|
||||
uuid: 9102, tier: TalentTier.L2, name: "击退强化", info: "所有英雄击退距离 +{value}", icon: "34-Force-Push",
|
||||
bonuses: [{ attr: Attrs.knockback_distance, mode: TalentValueMode.Flat, per_lv: 10 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
// 风怒机制已停用: 9008 风怒强化天赋已移除
|
||||
/*
|
||||
9008: {
|
||||
uuid: 9008, tier: TalentTier.Basic, name: "风怒强化", info: "所有英雄风怒率 +{value}%", icon: "98-Enchant-Wind",
|
||||
bonuses: [{ attr: Attrs.wfuny, mode: TalentValueMode.Flat, per_lv: 2 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
*/
|
||||
|
||||
// ==================== 二阶·专精天赋(9101-9199,按职业过滤;一阶投入 10 点解锁) ====================
|
||||
9101: {
|
||||
uuid: 9101, tier: TalentTier.Specialized, name: "坦克专精", info: "坦克防御 +{value}%、生命 +{value2}%", icon: "36-Guardian-Stance",
|
||||
bonuses: [
|
||||
{ attr: Attrs.defense, mode: TalentValueMode.Percent, per_lv: 30 },
|
||||
{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 5 },
|
||||
],
|
||||
max_lv: 5, role: HRole.Tank,
|
||||
},
|
||||
9102: {
|
||||
uuid: 9102, tier: TalentTier.Specialized, name: "战士专精", info: "战士生命 +{value}%", icon: "1-Battle-Roar",
|
||||
bonuses: [{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 12 }],
|
||||
max_lv: 5, role: HRole.Warrior,
|
||||
},
|
||||
9103: {
|
||||
uuid: 9103, tier: TalentTier.Specialized, name: "刺客专精", info: "刺客攻击 +{value}%、暴击率 +{value2}%", icon: "127-Hide",
|
||||
bonuses: [
|
||||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 8 },
|
||||
{ attr: Attrs.critical, mode: TalentValueMode.Flat, per_lv: 2 },
|
||||
],
|
||||
max_lv: 5, role: HRole.Assassin,
|
||||
uuid: 9103, tier: TalentTier.L2, name: "冰冻强化", info: "所有英雄冰冻率 +{value}%", icon: "92-Frost-Bite",
|
||||
bonuses: [{ attr: Attrs.freeze_chance, mode: TalentValueMode.Flat, per_lv: 2 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
9104: {
|
||||
uuid: 9104, tier: TalentTier.Specialized, name: "射手专精", info: "射手攻击 +{value}%、穿透率 +{value2}%", icon: "56-Pierce-Shot",
|
||||
bonuses: [
|
||||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 8 },
|
||||
{ attr: Attrs.puncture_chance, mode: TalentValueMode.Flat, per_lv: 2 },
|
||||
],
|
||||
max_lv: 5, role: HRole.Archer,
|
||||
uuid: 9104, tier: TalentTier.L2, name: "击晕强化", info: "所有英雄击晕率 +{value}%", icon: "13-Concussion",
|
||||
bonuses: [{ attr: Attrs.stun_chance, mode: TalentValueMode.Flat, per_lv: 2 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
9105: {
|
||||
uuid: 9105, tier: TalentTier.Specialized, name: "法师专精", info: "法师攻击 +{value}%、冰冻率 +{value2}%", icon: "145-Electromancy",
|
||||
bonuses: [
|
||||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 8 },
|
||||
{ attr: Attrs.freeze_chance, mode: TalentValueMode.Flat, per_lv: 2 },
|
||||
],
|
||||
max_lv: 5, role: HRole.Mage,
|
||||
uuid: 9105, tier: TalentTier.L2, name: "穿透强化", info: "所有英雄穿透率 +{value}%", icon: "56-Pierce-Shot",
|
||||
bonuses: [{ attr: Attrs.puncture_chance, mode: TalentValueMode.Flat, per_lv: 2 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
9106: {
|
||||
uuid: 9106, tier: TalentTier.Specialized, name: "辅助专精", info: "辅助治疗量 +{value}%、施加的增益效果 +{value2}%", icon: "38-Healing-Light",
|
||||
bonuses: [
|
||||
{ attr: Attrs.heal_power, mode: TalentValueMode.Flat, per_lv: 10 },
|
||||
{ attr: Attrs.buff_power, mode: TalentValueMode.Flat, per_lv: 8 },
|
||||
],
|
||||
max_lv: 5, role: HRole.Support,
|
||||
uuid: 9106, tier: TalentTier.L2, name: "暴伤强化", info: "所有英雄暴击伤害 +{value}%", icon: "37-Head-Shot",
|
||||
bonuses: [{ attr: Attrs.critical_damage, mode: TalentValueMode.Flat, per_lv: 5 }],
|
||||
max_lv: 5,
|
||||
},
|
||||
|
||||
// ==================== 三阶·超强天赋(9201-9219,二阶投入 10 点解锁;幅度约为前两阶 2 倍) ====================
|
||||
// ---- 全局超强(9201-9209) ----
|
||||
// ==================== 第 3 层(9201-9299,第 2 层投入 5 点解锁,职业加成) ====================
|
||||
9201: {
|
||||
uuid: 9201, tier: TalentTier.Super, name: "神威降临", info: "所有英雄攻击 +{value}%、生命 +{value2}%", icon: "52-Might-of-Heaven",
|
||||
uuid: 9201, tier: TalentTier.L3, name: "坦克专精", info: "坦克生命 +{value}%、防御 +{value2} 点", icon: "36-Guardian-Stance",
|
||||
bonuses: [
|
||||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 8 },
|
||||
{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 8 },
|
||||
],
|
||||
max_lv: 5,
|
||||
},
|
||||
9202: {
|
||||
uuid: 9202, tier: TalentTier.Super, name: "致命终结", info: "所有英雄暴击率 +{value}%、暴击伤害 +{value2}%", icon: "37-Head-Shot",
|
||||
bonuses: [
|
||||
{ attr: Attrs.critical, mode: TalentValueMode.Flat, per_lv: 3 },
|
||||
{ attr: Attrs.critical_damage, mode: TalentValueMode.Flat, per_lv: 15 },
|
||||
],
|
||||
max_lv: 5,
|
||||
},
|
||||
9203: {
|
||||
uuid: 9203, tier: TalentTier.Super, name: "破甲重创", info: "所有英雄穿透率 +{value}%、穿透伤害 +{value2}%", icon: "76-Shove-Stab",
|
||||
bonuses: [
|
||||
{ attr: Attrs.puncture_chance, mode: TalentValueMode.Flat, per_lv: 3 },
|
||||
{ attr: Attrs.puncture_dmg_bonus, mode: TalentValueMode.Flat, per_lv: 10 },
|
||||
],
|
||||
max_lv: 5,
|
||||
},
|
||||
9204: {
|
||||
uuid: 9204, tier: TalentTier.Super, name: "钢铁之躯", info: "所有英雄防御 +{value}%、生命 +{value2}%", icon: "45-Induration",
|
||||
bonuses: [
|
||||
{ attr: Attrs.defense, mode: TalentValueMode.Percent, per_lv: 20 },
|
||||
{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 6 },
|
||||
],
|
||||
max_lv: 5,
|
||||
},
|
||||
// ---- 职业超强(9211-9219,按 HRole 过滤) ----
|
||||
9211: {
|
||||
uuid: 9211, tier: TalentTier.Super, name: "不朽壁垒", info: "坦克防御 +{value}%、生命 +{value2}%", icon: "36-Guardian-Stance",
|
||||
bonuses: [
|
||||
{ attr: Attrs.defense, mode: TalentValueMode.Percent, per_lv: 40 },
|
||||
{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 8 },
|
||||
{ attr: Attrs.defense, mode: TalentValueMode.Flat, per_lv: 10 },
|
||||
],
|
||||
max_lv: 5, role: HRole.Tank,
|
||||
},
|
||||
9212: {
|
||||
uuid: 9212, tier: TalentTier.Super, name: "狂血战魂", info: "战士攻击 +{value}%、生命 +{value2}%", icon: "113-Rage",
|
||||
9202: {
|
||||
uuid: 9202, tier: TalentTier.L3, name: "战士专精", info: "战士攻击 +{value}%、生命 +{value2}%", icon: "1-Battle-Roar",
|
||||
bonuses: [
|
||||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 10 },
|
||||
{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 8 },
|
||||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 6 },
|
||||
{ attr: Attrs.hp_max, mode: TalentValueMode.Percent, per_lv: 6 },
|
||||
],
|
||||
max_lv: 5, role: HRole.Warrior,
|
||||
},
|
||||
9213: {
|
||||
uuid: 9213, tier: TalentTier.Super, name: "影刃绝杀", info: "刺客攻击 +{value}%、暴击伤害 +{value2}%", icon: "136-Heart-Rip",
|
||||
9203: {
|
||||
uuid: 9203, tier: TalentTier.L3, name: "刺客专精", info: "刺客攻击 +{value}%、攻速 +{value2}%", icon: "127-Hide",
|
||||
bonuses: [
|
||||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 12 },
|
||||
{ attr: Attrs.critical_damage, mode: TalentValueMode.Flat, per_lv: 12 },
|
||||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 8 },
|
||||
{ attr: Attrs.speed, mode: TalentValueMode.Flat, per_lv: 3 },
|
||||
],
|
||||
max_lv: 5, role: HRole.Assassin,
|
||||
},
|
||||
9214: {
|
||||
uuid: 9214, tier: TalentTier.Super, name: "穿云贯日", info: "射手攻击 +{value}%、穿透伤害 +{value2}%", icon: "37-Head-Shot",
|
||||
9204: {
|
||||
uuid: 9204, tier: TalentTier.L3, name: "射手专精", info: "射手攻击 +{value}%、攻速 +{value2}%", icon: "56-Pierce-Shot",
|
||||
bonuses: [
|
||||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 12 },
|
||||
{ attr: Attrs.puncture_dmg_bonus, mode: TalentValueMode.Flat, per_lv: 8 },
|
||||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 8 },
|
||||
{ attr: Attrs.speed, mode: TalentValueMode.Flat, per_lv: 3 },
|
||||
],
|
||||
max_lv: 5, role: HRole.Archer,
|
||||
},
|
||||
9215: {
|
||||
uuid: 9215, tier: TalentTier.Super, name: "元素主宰", info: "法师攻击 +{value}%、冰冻率 +{value2}%", icon: "144-Cryomancy",
|
||||
9205: {
|
||||
uuid: 9205, tier: TalentTier.L3, name: "法师专精", info: "法师攻击 +{value}%、技能增益效果 +{value2}%", icon: "145-Electromancy",
|
||||
bonuses: [
|
||||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 12 },
|
||||
{ attr: Attrs.freeze_chance, mode: TalentValueMode.Flat, per_lv: 3 },
|
||||
{ attr: Attrs.ap, mode: TalentValueMode.Percent, per_lv: 8 },
|
||||
{ attr: Attrs.buff_power, mode: TalentValueMode.Flat, per_lv: 6 },
|
||||
],
|
||||
max_lv: 5, role: HRole.Mage,
|
||||
},
|
||||
9216: {
|
||||
uuid: 9216, tier: TalentTier.Super, name: "圣光普照", info: "辅助治疗量 +{value}%、施加的增益效果 +{value2}%", icon: "40-Holy",
|
||||
9206: {
|
||||
uuid: 9206, tier: TalentTier.L3, name: "辅助专精", info: "辅助治疗量 +{value}%、增益效果 +{value2}%", icon: "38-Healing-Light",
|
||||
bonuses: [
|
||||
{ attr: Attrs.heal_power, mode: TalentValueMode.Flat, per_lv: 15 },
|
||||
{ attr: Attrs.buff_power, mode: TalentValueMode.Flat, per_lv: 12 },
|
||||
{ attr: Attrs.heal_power, mode: TalentValueMode.Flat, per_lv: 10 },
|
||||
{ attr: Attrs.buff_power, mode: TalentValueMode.Flat, per_lv: 6 },
|
||||
],
|
||||
max_lv: 5, role: HRole.Support,
|
||||
},
|
||||
|
||||
// ==================== 第 4 层(9301-9399,第 3 层投入 5 点解锁,触发条件减少,按职业) ====================
|
||||
9301: {
|
||||
uuid: 9301, tier: TalentTier.L4, name: "坦克·蓄势", info: "坦克触发类技能所需次数 -{value}", icon: "36-Guardian-Stance",
|
||||
bonuses: [], t_num_reduce_per_lv: 1,
|
||||
max_lv: 2, role: HRole.Tank,
|
||||
},
|
||||
9302: {
|
||||
uuid: 9302, tier: TalentTier.L4, name: "战士·蓄势", info: "战士触发类技能所需次数 -{value}", icon: "113-Rage",
|
||||
bonuses: [], t_num_reduce_per_lv: 1,
|
||||
max_lv: 2, role: HRole.Warrior,
|
||||
},
|
||||
9303: {
|
||||
uuid: 9303, tier: TalentTier.L4, name: "刺客·蓄势", info: "刺客触发类技能所需次数 -{value}", icon: "136-Heart-Rip",
|
||||
bonuses: [], t_num_reduce_per_lv: 1,
|
||||
max_lv: 2, role: HRole.Assassin,
|
||||
},
|
||||
9304: {
|
||||
uuid: 9304, tier: TalentTier.L4, name: "射手·蓄势", info: "射手触发类技能所需次数 -{value}", icon: "74-Satisfaction",
|
||||
bonuses: [], t_num_reduce_per_lv: 1,
|
||||
max_lv: 2, role: HRole.Archer,
|
||||
},
|
||||
9305: {
|
||||
uuid: 9305, tier: TalentTier.L4, name: "法师·蓄势", info: "法师触发类技能所需次数 -{value}", icon: "144-Cryomancy",
|
||||
bonuses: [], t_num_reduce_per_lv: 1,
|
||||
max_lv: 2, role: HRole.Mage,
|
||||
},
|
||||
9306: {
|
||||
uuid: 9306, tier: TalentTier.L4, name: "辅助·蓄势", info: "辅助触发类技能所需次数 -{value}", icon: "40-Holy",
|
||||
bonuses: [], t_num_reduce_per_lv: 1,
|
||||
max_lv: 2, role: HRole.Support,
|
||||
},
|
||||
|
||||
// ==================== 第 5 层(9401-9499,第 4 层投入 5 点解锁,概率额外触发,按职业) ====================
|
||||
9401: {
|
||||
uuid: 9401, tier: TalentTier.L5, name: "坦克·余震", info: "坦克触发类技能 +{value}% 概率额外触发 1 次", icon: "36-Guardian-Stance",
|
||||
bonuses: [], extra_trigger_chance_per_lv: 10,
|
||||
max_lv: 5, role: HRole.Tank, prereq_uuid: 9301, prereq_lv: 1,
|
||||
},
|
||||
9402: {
|
||||
uuid: 9402, tier: TalentTier.L5, name: "战士·余威", info: "战士触发类技能 +{value}% 概率额外触发 1 次", icon: "113-Rage",
|
||||
bonuses: [], extra_trigger_chance_per_lv: 10,
|
||||
max_lv: 5, role: HRole.Warrior, prereq_uuid: 9302, prereq_lv: 1,
|
||||
},
|
||||
9403: {
|
||||
uuid: 9403, tier: TalentTier.L5, name: "刺客·残影", info: "刺客触发类技能 +{value}% 概率额外触发 1 次", icon: "136-Heart-Rip",
|
||||
bonuses: [], extra_trigger_chance_per_lv: 10,
|
||||
max_lv: 5, role: HRole.Assassin, prereq_uuid: 9303, prereq_lv: 1,
|
||||
},
|
||||
9404: {
|
||||
uuid: 9404, tier: TalentTier.L5, name: "射手·连珠", info: "射手触发类技能 +{value}% 概率额外触发 1 次", icon: "74-Satisfaction",
|
||||
bonuses: [], extra_trigger_chance_per_lv: 10,
|
||||
max_lv: 5, role: HRole.Archer, prereq_uuid: 9304, prereq_lv: 1,
|
||||
},
|
||||
9405: {
|
||||
uuid: 9405, tier: TalentTier.L5, name: "法师·回响", info: "法师触发类技能 +{value}% 概率额外触发 1 次", icon: "144-Cryomancy",
|
||||
bonuses: [], extra_trigger_chance_per_lv: 10,
|
||||
max_lv: 5, role: HRole.Mage, prereq_uuid: 9305, prereq_lv: 1,
|
||||
},
|
||||
9406: {
|
||||
uuid: 9406, tier: TalentTier.L5, name: "辅助·福音", info: "辅助触发类技能 +{value}% 概率额外触发 1 次", icon: "40-Holy",
|
||||
bonuses: [], extra_trigger_chance_per_lv: 10,
|
||||
max_lv: 5, role: HRole.Support, prereq_uuid: 9306, prereq_lv: 1,
|
||||
},
|
||||
};
|
||||
|
||||
/** 天赋升级消耗:按阶位统一消耗,同一阶内每级消耗相同 */
|
||||
export const TALENT_UPGRADE_COST: Record<number, number> = {
|
||||
[TalentTier.Basic]: 1, // 基础天赋:1 点升 1 级
|
||||
[TalentTier.Specialized]: 2, // 专精天赋:2 点升 1 级
|
||||
[TalentTier.Super]: 2, // 传说天赋:2 点升 1 级
|
||||
};
|
||||
/** 天赋升级消耗:全部天赋统一 1 点/级 */
|
||||
export const TALENT_UPGRADE_COST = 1;
|
||||
|
||||
/**
|
||||
* 查询升级所需天赋点数
|
||||
* @param tier 天赋所属阶位
|
||||
* @returns 升 1 级所需点数;非法阶位返回 -1
|
||||
* @param _tier 天赋所属层位(保留参数以兼容旧调用;统一点价后不再按层区分)
|
||||
* @returns 升 1 级所需点数(恒为 1)
|
||||
*/
|
||||
export function getTalentUpgradeCost(tier: TalentTier): number {
|
||||
return TALENT_UPGRADE_COST[tier] ?? -1;
|
||||
export function getTalentUpgradeCost(_tier: TalentTier): number {
|
||||
return TALENT_UPGRADE_COST;
|
||||
}
|
||||
|
||||
/** 天赋等级上限(不含):等级从 0 起步,区间 0~29,共 30 级;每升 1 级产出 1 点天赋点 */
|
||||
@@ -308,42 +315,51 @@ export function getTalentLevelExp(curLv: number): number {
|
||||
return TALENT_LEVEL_EXP[curLv];
|
||||
}
|
||||
|
||||
/** 阶位解锁门槛:前一阶累计投入 ≥ 该点数才能升级下一阶天赋 */
|
||||
export const TALENT_TIER_UNLOCK_THRESHOLD = 10;
|
||||
/** 层位解锁门槛:前一层累计投入 ≥ 该点数才能升级下一层天赋 */
|
||||
export const TALENT_TIER_UNLOCK_THRESHOLD = 5;
|
||||
|
||||
/**
|
||||
* 计算指定阶位已投入的天赋点数(按该阶统一消耗 × 等级累加)。
|
||||
* Why: 阶位解锁按"实际消耗点数"而非"等级总和"口径——与玩家直觉(投入了多少点)
|
||||
* 计算指定层位已投入的天赋点数(统一点价 × 等级累加)。
|
||||
* Why: 层位解锁按"实际消耗点数"而非"等级总和"口径——与玩家直觉(投入了多少点)
|
||||
* 及重置退款口径(resetTalents 同表对账)保持一致。
|
||||
* @param levels 天赋等级表(key 为天赋 uuid,value 为当前等级)
|
||||
* @param tier 目标阶位
|
||||
* @returns 该阶位全部天赋已投入的点数总和
|
||||
* @param tier 目标层位
|
||||
* @returns 该层位全部天赋已投入的点数总和
|
||||
*/
|
||||
export function getTalentTierInvestedPoints(levels: Record<number, number>, tier: TalentTier): number {
|
||||
if (!levels) return 0;
|
||||
const cost = getTalentUpgradeCost(tier);
|
||||
if (cost <= 0) return 0;
|
||||
let invested = 0;
|
||||
for (const key in levels) {
|
||||
const cfg = TalentSet[key];
|
||||
if (!cfg || cfg.tier !== tier) continue;
|
||||
invested += levels[key] * cost;
|
||||
invested += levels[key] * TALENT_UPGRADE_COST;
|
||||
}
|
||||
return invested;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断指定阶位是否已解锁(加点入口校验用;战斗结算无需关心阶位——已投入的等级恒生效)。
|
||||
* 规则:一阶恒解锁;二阶要求一阶累计投入 ≥ TALENT_TIER_UNLOCK_THRESHOLD;三阶要求二阶累计投入达标。
|
||||
* 判断指定层位是否已解锁(加点入口校验用;战斗结算无需关心层位——已投入的等级恒生效)。
|
||||
* 规则:第 1 层恒解锁;第 N 层要求第 N-1 层累计投入 ≥ TALENT_TIER_UNLOCK_THRESHOLD。
|
||||
* @param levels 天赋等级表
|
||||
* @param tier 目标阶位
|
||||
* @param tier 目标层位
|
||||
*/
|
||||
export function isTalentTierUnlocked(levels: Record<number, number>, tier: TalentTier): boolean {
|
||||
if (tier === TalentTier.Basic) return true;
|
||||
if (tier === TalentTier.L1) return true;
|
||||
const prevTier = (tier - 1) as TalentTier;
|
||||
return getTalentTierInvestedPoints(levels, prevTier) >= TALENT_TIER_UNLOCK_THRESHOLD;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断天赋的软前置是否已满足(加点入口校验用;未满足仅限制加点,不影响已有点数的结算)。
|
||||
* @param levels 天赋等级表
|
||||
* @param cfg 天赋配置
|
||||
* @returns 无前置声明或前置天赋等级达标时返回 true
|
||||
*/
|
||||
export function isTalentPrereqMet(levels: Record<number, number>, cfg: TalentConfig): boolean {
|
||||
if (!cfg.prereq_uuid || !cfg.prereq_lv) return true;
|
||||
return (levels?.[cfg.prereq_uuid] ?? 0) >= cfg.prereq_lv;
|
||||
}
|
||||
|
||||
/** 天赋属性的卡面显示名(迷你卡空间有限,用短标签) */
|
||||
const TALENT_ATTR_LABELS: Partial<Record<Attrs, string>> = {
|
||||
[Attrs.ap]: "攻击",
|
||||
@@ -376,6 +392,15 @@ const TALENT_ATTR_SUFFIX: Partial<Record<Attrs, string>> = {
|
||||
*/
|
||||
export function getTalentDisplayText(cfg: TalentConfig, lv: number): string {
|
||||
const mult = lv > 0 ? lv : 1;
|
||||
// L4/L5 效果词条:不走 bonuses,按专属字段生成文案
|
||||
if (cfg.t_num_reduce_per_lv) {
|
||||
const text = `触发次数 -${cfg.t_num_reduce_per_lv * mult}`;
|
||||
return lv > 0 ? text : `${text}/级`;
|
||||
}
|
||||
if (cfg.extra_trigger_chance_per_lv) {
|
||||
const text = `额外触发 +${cfg.extra_trigger_chance_per_lv * mult}%`;
|
||||
return lv > 0 ? text : `${text}/级`;
|
||||
}
|
||||
const parts: string[] = [];
|
||||
for (const b of cfg.bonuses) {
|
||||
const label = TALENT_ATTR_LABELS[b.attr] ?? String(b.attr);
|
||||
@@ -388,8 +413,8 @@ export function getTalentDisplayText(cfg: TalentConfig, lv: number): string {
|
||||
|
||||
/**
|
||||
* 聚合指定职业英雄生效的全部天赋加成。
|
||||
* Why: 基础/超强全局天赋全局生效,专精与超强职业天赋按 role 过滤;
|
||||
* 阶位解锁只约束加点阶段,战斗加载时(Hero.load / applyHeroLevel)按当前等级直接取加成。
|
||||
* Why: 全局天赋全局生效,职业天赋按 role 过滤;
|
||||
* 层位解锁与软前置只约束加点阶段,战斗加载时(Hero.load / applyHeroLevel)按当前等级直接取加成。
|
||||
* @param levels 天赋等级表(key 为天赋 uuid,value 为当前等级)
|
||||
* @param role 英雄职业(职业过滤依据;无 role 时只应用全局天赋)
|
||||
* @returns 已解析的加成列表(等级已乘算进 value)
|
||||
@@ -412,7 +437,47 @@ export function getTalentBonusesForRole(levels: Record<number, number>, role?: H
|
||||
}
|
||||
|
||||
/**
|
||||
* 将天赋加成写入英雄属性模型(在 Hero.load / MissionCardComp.applyHeroLevel 的属性组装段调用)。
|
||||
* 聚合指定职业英雄的 L4 触发阈值修正量。
|
||||
* @param levels 天赋等级表
|
||||
* @param role 英雄职业
|
||||
* @returns 触发计数阈值的总减少量(SkillTriggerHelper 端再 clamp 下限 1)
|
||||
*/
|
||||
export function getTalentTriggerNumReduce(levels: Record<number, number>, role?: HRole): number {
|
||||
let total = 0;
|
||||
if (!levels) return total;
|
||||
for (const key in levels) {
|
||||
const lv = levels[key];
|
||||
if (lv <= 0) continue;
|
||||
const cfg = TalentSet[key];
|
||||
if (!cfg || !cfg.t_num_reduce_per_lv) continue;
|
||||
if (cfg.role !== undefined && cfg.role !== role) continue;
|
||||
total += cfg.t_num_reduce_per_lv * lv;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* 聚合指定职业英雄的 L5 额外触发概率(百分点)。
|
||||
* @param levels 天赋等级表
|
||||
* @param role 英雄职业
|
||||
* @returns 额外触发 1 次的概率(百分点,可超过 100 由消费端自行 clamp)
|
||||
*/
|
||||
export function getTalentExtraTriggerChance(levels: Record<number, number>, role?: HRole): number {
|
||||
let total = 0;
|
||||
if (!levels) return total;
|
||||
for (const key in levels) {
|
||||
const lv = levels[key];
|
||||
if (lv <= 0) continue;
|
||||
const cfg = TalentSet[key];
|
||||
if (!cfg || !cfg.extra_trigger_chance_per_lv) continue;
|
||||
if (cfg.role !== undefined && cfg.role !== role) continue;
|
||||
total += cfg.extra_trigger_chance_per_lv * lv;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将天赋加成写入英雄属性模型(统一由 HeroAttrsComp.applyTalent 调用)。
|
||||
*
|
||||
* 结算规则:
|
||||
* - Percent 模式:以基础快照为基数(ap→base_ap,hp_max→base_hp,defense→def_base),按百分比放大后累加;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { v3 } from "cc"
|
||||
import { v3 } from "cc"
|
||||
import { BoxSet, FacSet, FightSet } from "./GameSet"
|
||||
import { SkillOverrides, TGroup, SkillSet, FieldSkillSet, SkillConfig, SkillKind, FieldSkillConfig, FieldSkillType, mergeSkillParams } from "./SkillSet"
|
||||
import { SkillOverrides, TGroup, SkillSet, FieldSkillSet, SkillConfig, SkillKind, FieldSkillConfig, FieldSkillType, mergeSkillParams, BuffTarget } from "./SkillSet"
|
||||
import { BuffList, BuffConfig, ModOp } from "./BuffSet"
|
||||
import { Attrs } from "./HeroAttrs"
|
||||
|
||||
@@ -58,6 +58,30 @@ export const AtkSpeedSet = {
|
||||
[AtkSpeedLv.VerySlow]: { name: "极慢", cd: 1.50 },
|
||||
};
|
||||
|
||||
/**
|
||||
* 英雄大招(skills[1])CD 分级配置(5 档,与 AtkSpeedLv 五档结构对齐)。
|
||||
* 分档规则:VeryFast=单体爆发/高频压制,Normal=群体伤害/控制,VerySlow=全体增益/治疗/护盾,
|
||||
* Fast/Slow 为中间档,供同类技能内细分释放节奏。
|
||||
* Why: 大招 CD 曾 18/19 英雄统一 8s,场上大招齐发成"脉冲",玩家难以感知单次大招释放;
|
||||
* 按技能效果类型分档交错 CD(6~10s),形成持续鼓点节奏,拉开"高频小爆发 vs 稀有大回报"的感知差。
|
||||
* TODO: CD 档位与数值联动补偿(短 CD 单次数值下调、长 CD 上调)待观察实战强度后统一调整。
|
||||
*/
|
||||
export enum UltCdLv {
|
||||
VeryFast = 1, // 单体爆发/高频压制
|
||||
Fast = 2, // 频繁压制(中间档)
|
||||
Normal = 3, // 群体伤害/控制
|
||||
Slow = 4, // 中度团队增益(中间档)
|
||||
VerySlow = 5, // 全体增益/治疗/护盾
|
||||
}
|
||||
|
||||
export const UltCdSet = {
|
||||
[UltCdLv.VeryFast]: { name: "极频", cd: 6 },
|
||||
[UltCdLv.Fast]: { name: "高频", cd: 7 },
|
||||
[UltCdLv.Normal]: { name: "标准", cd: 8 },
|
||||
[UltCdLv.Slow]: { name: "低频", cd: 9 },
|
||||
[UltCdLv.VerySlow]: { name: "稀有", cd: 10 },
|
||||
};
|
||||
|
||||
export const HeroPos = {
|
||||
0: { pos: v3(-320, BoxSet.GAME_LINE, 0) },
|
||||
1: { pos: v3(0, BoxSet.GAME_LINE, 0) },
|
||||
@@ -400,8 +424,8 @@ export interface heroInfo {
|
||||
[SkillTriggerType.FStart]?: TriggerGrouped; // 战斗开始时释放的技能配置
|
||||
[SkillTriggerType.FEnd]?: TriggerGrouped; // 回合结束时释放的技能配置
|
||||
[SkillTriggerType.Field]?: LvFieldEntry[]; // 驻场光环(按 lv 升序,运行时取 ≤英雄等级 的最大档)
|
||||
[SkillTriggerType.Atking]?: TriggerGrouped; // 普通攻击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的普攻次数
|
||||
[SkillTriggerType.Atked]?: TriggerGrouped; // 受击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的受击次数
|
||||
[SkillTriggerType.Atking]?: TriggerGrouped; // 普通攻击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的普攻次数, t_chance: 触发概率(%),pity_add: 未触发时下次概率增量
|
||||
[SkillTriggerType.Atked]?: TriggerGrouped; // 受击后触发的技能配置,s_uuid: 技能id, t_num: 触发所需的受击次数, t_chance: 触发概率(%),pity_add: 未触发时下次概率增量
|
||||
dis?: number; // 攻击距离(像素)
|
||||
speed?: number; // 移动速度(像素/秒)
|
||||
dodge?: number; // 闪避率(百分点,缺省由初始化处兜底为全局默认值)
|
||||
@@ -480,6 +504,11 @@ export interface LvTriggerEntry {
|
||||
s_lv?: SkillLv; // 此档对应的技能等级(标注用,便于面板显示"技能Lv.x")
|
||||
name?: string; // 该 s_uuid 触发技能组的对外展示名(写在第 1 档,作为组名)
|
||||
t_num: number;
|
||||
/** 触发概率(百分点 0~100,缺省 100 必触发;仅 Atking/Atked 攻受击触发生效) */
|
||||
t_chance?: number;
|
||||
/** 保底叠加:判定未触发时,为该 s_uuid 累积下次概率增量(百分点)。
|
||||
* 缺省/0 = 不叠加;触发成功后清零,最终概率封顶 100 */
|
||||
pity_add?: number;
|
||||
overrides?: SkillOverrides;
|
||||
/** 此档描述模板:缺省回退该组第 1 档 desc;由 HeroSkillText 渲染合并后实时数值。
|
||||
* 显式配置后弹窗提升档(slv2+)直接展示该模板渲染结果,优先于自动 diff */
|
||||
@@ -492,6 +521,20 @@ export interface LvTriggerEntry {
|
||||
*/
|
||||
export type TriggerGrouped = Record<number /*s_uuid*/, LvTriggerEntry[]>;
|
||||
|
||||
/**
|
||||
* 运行时生效的触发条目(resolveTriggerByLv 产出):
|
||||
* 每个 s_uuid 取 ≤lv 最大档的扁平结果,供触发器/评分/文案消费。
|
||||
*/
|
||||
export interface ResolvedTriggerEntry {
|
||||
s_uuid: number;
|
||||
t_num: number;
|
||||
/** 触发概率(百分点,缺省 100 必触发;仅 Atking/Atked 生效) */
|
||||
t_chance?: number;
|
||||
/** 保底叠加:未触发时累积的下次概率增量(百分点,触发成功后清零) */
|
||||
pity_add?: number;
|
||||
overrides?: SkillOverrides;
|
||||
}
|
||||
|
||||
/**
|
||||
* 驻场光环词条:uuid 指向 FieldSkillSet 底座(类型/图标/元数据),
|
||||
* value 为该词条实际生效数值(由配置处按档位指定,不再随 uuid 分档)。
|
||||
@@ -534,26 +577,27 @@ export interface LvBonusAttrsEntry {
|
||||
*=============英雄配置列表================
|
||||
* 几何王国复刻版 — 依据 英雄设计指引.md(A/B 级复刻英雄)配置
|
||||
*
|
||||
* 规则:lv1 激活 skills[0]/skills[1],lv6 解锁 atking/atked/fstart/dead/field 触发技能(触发类统一 lv6 激活,无品质门槛),
|
||||
* 大招(skills[1])lv9/lv16 走 lv_entries 分档成长,lv12 按职业对单项基础属性 +50%(基数取 lv11 有效值),
|
||||
* revive[0] 与 skills[1] 互斥二选一(配置 revive 时按 lv1/lv9/lv16 走 lv_entries 3 级成长),
|
||||
* 品质(rarity)仅影响 lv1 初始基础属性(相邻差 5%,仅 lv1 初始 AP/HP/DEF),不影响 uuid 段位/光环/技能解锁/属性补偿
|
||||
* 编号:本批复刻英雄集中于 5001~5009,rarity 按配置(不遵循段位规则)
|
||||
* 规则:lv1 激活 skills[0]/skills[1],lv4 解锁 atking/atked/fstart/dead/field 触发技能(触发类统一 lv4 激活,无品质门槛),
|
||||
* 大招(skills[1])lv8/lv16 走 lv_entries 分档成长,lv12 按职业对单项基础属性 +50%(基数取"基础×品质+成长"快照),
|
||||
* revive[0] 与 skills[1] 互斥二选一(配置 revive 时按 lv1/lv8/lv16 走 lv_entries 3 级成长),
|
||||
* 品质(rarity)当前全部英雄统一为 1,不再区分品质;getHeroQualityCoef 保留但恒为 1.00,
|
||||
* 若未来重启品质体系,仅影响 lv1 初始基础属性(相邻差 5%),不影响 uuid 段位/光环/技能解锁/属性补偿
|
||||
* 编号:本批复刻英雄集中于 5001~5018,rarity 统一 1
|
||||
*/
|
||||
|
||||
// @hero-setup:region-begin
|
||||
export const HeroInfo: Record<number, heroInfo> = {
|
||||
// @hero-setup:heroes-begin
|
||||
// 5001 叠甲骑士 — CSV导入:自身护盾+全体护盾
|
||||
// 5001 铁憨憨 — CSV导入:自身护盾+全体护盾
|
||||
5001: {
|
||||
uuid: 5001, name: "叠甲骑士", path: "hk1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp + 20, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def + 10,
|
||||
uuid: 5001, name: "铁憨憨", path: "hk1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp + 20, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def + 10,
|
||||
skills: {
|
||||
6004: { uuid: 6004, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: {"ap":100}, desc: "挥剑对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120}, desc: "普通攻击 造成 120% 伤害" },
|
||||
],
|
||||
},
|
||||
6301: { uuid: 6301, name: "魔法盾", lv: 1, cd: 10, ccd: 0, overrides: {"ap":30}, desc: "{target}获得生命最大值{ap}%的护盾",
|
||||
6301: { uuid: 6301, name: "魔法盾", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"ap":30}, desc: "{target}获得生命最大值{ap}%的护盾",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":60}, desc: "{target}获得生命最大值{ap}%的护盾" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":120}, desc: "{target}获得生命最大值{ap}%的护盾" },
|
||||
@@ -561,206 +605,212 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
},
|
||||
},
|
||||
atked: {
|
||||
6301: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "全体圣盾", t_num: 3, overrides: {"TGroup":null,"ap":10,"icon":"Stat_UnitSummonIncrease_01"}, desc: "全队获得本英雄生命最大值{ap}%的护盾" },
|
||||
6412: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"ap":1} },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"def":50}, name: "钢铁壁垒", icon: "46-Iron-Clad", },
|
||||
],
|
||||
info: "自身强护盾+群体小护盾,强生存",
|
||||
info: "自身强护盾+防御强化",
|
||||
},
|
||||
// 5002 易伤剑仙 — CSV导入:击退压场+易伤放大;复刻酒仙
|
||||
// 5002 破防哥 — CSV导入:击退压场+易伤放大;复刻酒仙
|
||||
5002: {
|
||||
uuid: 5002, name: "易伤剑仙", path: "hk3", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: HERO_ROLE_BASE[HRole.Warrior].hp + 5, ap: HERO_ROLE_BASE[HRole.Warrior].ap + 20, def: HERO_ROLE_BASE[HRole.Warrior].def + 5,
|
||||
uuid: 5002, name: "破防哥", path: "hk5", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: HERO_ROLE_BASE[HRole.Warrior].hp + 5, ap: HERO_ROLE_BASE[HRole.Warrior].ap + 20, def: HERO_ROLE_BASE[HRole.Warrior].def + 5,
|
||||
skills: {
|
||||
6004: { uuid: 6004, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: {"ap":100}, desc: "对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120}, desc: "普通攻击造成 120% 攻击伤害" },
|
||||
],
|
||||
},
|
||||
6101: { uuid: 6101, name: "气斩", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7002,"icon":"Stat_AttackSpeed_02"}, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,并使目标易伤(受到伤害加深,持续{dur}秒)",
|
||||
6101: { uuid: 6101, name: "气斩", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7002,"debuff_value":30,"debuff_chance":100,"debuff_duration":5}, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,并使目标易伤(受到伤害加深,持续{dur}秒)",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"buff_value":20} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":180,"bck":60,"buff_value":40}, desc: "斩出气刃,对{target}造成攻击力{ap}%伤害,击退{bck},并使目标易伤(持续{dur}秒)" },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"timed_debuff_id":7002,"debuff_value":70,"debuff_chance":100,"debuff_duration":5} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"timed_debuff_id":7002,"debuff_value":150,"debuff_chance":100,"debuff_duration":7} },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6004: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "风暴打击", t_num: 3, overrides: {"ap":300,"icon":"Stat_AllUnitAttack"}, desc: "立刻打击{target},造成攻击力{ap}%伤害" },
|
||||
6001: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"timed_debuff_id":7002,"debuff_value":10,"debuff_chance":100,"debuff_duration":5} },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
|
||||
],
|
||||
info: "易伤+风怒,近战 dps",
|
||||
info: "易伤,近战 dps",
|
||||
},
|
||||
// 5003 眩晕暴击哥 — CSV导入:高爆发+击晕收割;复刻齐天大圣
|
||||
// 5003 锤哥 — CSV导入:高爆发+击晕收割;复刻齐天大圣
|
||||
5003: {
|
||||
uuid: 5003, name: "眩晕暴击哥", path: "hk5", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: HERO_ROLE_BASE[HRole.Warrior].hp + 5, ap: HERO_ROLE_BASE[HRole.Warrior].ap + 20, def: HERO_ROLE_BASE[HRole.Warrior].def + 5,
|
||||
uuid: 5003, name: "锤哥", path: "hk5", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: HERO_ROLE_BASE[HRole.Warrior].hp + 5, ap: HERO_ROLE_BASE[HRole.Warrior].ap + 20, def: HERO_ROLE_BASE[HRole.Warrior].def + 5,
|
||||
skills: {
|
||||
6004: { uuid: 6004, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: {"ap":100}, desc: "挥斧对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"stun":10}, desc: "普通攻击有{stun}%概率击晕敌人" },
|
||||
],
|
||||
},
|
||||
6104: { uuid: 6104, name: "开山斧", lv: 1, cd: 8, ccd: 0, overrides: {"ap":300,"stun":100}, desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害,必定击晕",
|
||||
6104: { uuid: 6104, name: "开山斧", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":250,"stun":100}, desc: "劈出开山斧,对{target}造成攻击力{ap}%伤害,必定击晕",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":450,"stun":100} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"stun":100} },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":300,"stun":100} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"stun":100} },
|
||||
],
|
||||
},
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7005, value: 0.25, name: "大圣神威" }] },
|
||||
],
|
||||
atking: {
|
||||
6504: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"buff_value":30}, desc: "{t_chance}% 概率提升普通攻击 30%暴击率5秒" },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
|
||||
],
|
||||
info: "必晕爆发+暴击光环,近战收割",
|
||||
},
|
||||
// 5004 刀刀暴击 — CSV导入:暴击/暴伤双光环乘区;复刻剑圣
|
||||
// 5004 刀刀 — CSV导入:暴击/暴伤双光环乘区;复刻剑圣
|
||||
5004: {
|
||||
uuid: 5004, name: "刀刀暴击", path: "hc1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Mid, grow_type: HGrowType.Assassin, role: HRole.Assassin, hp: HERO_ROLE_BASE[HRole.Assassin].hp, ap: HERO_ROLE_BASE[HRole.Assassin].ap + 30, def: HERO_ROLE_BASE[HRole.Assassin].def,
|
||||
uuid: 5004, name: "刀刀", path: "hc1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Mid, grow_type: HGrowType.Assassin, role: HRole.Assassin, hp: HERO_ROLE_BASE[HRole.Assassin].hp, ap: HERO_ROLE_BASE[HRole.Assassin].ap + 30, def: HERO_ROLE_BASE[HRole.Assassin].def,
|
||||
skills: {
|
||||
6002: { uuid: 6002, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, overrides: {"ap":100}, desc: "挥刀对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":10}, desc: "普通攻击有{crt}%概率暴击" },
|
||||
],
|
||||
},
|
||||
6100: { uuid: 6100, name: "光闪", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150}, desc: "斩出光闪,对{target}造成攻击力{ap}%伤害",
|
||||
6150: { uuid: 6150, name: "剑刃风暴", lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":150,"crt":50}, desc: "对{target}造成攻击力{ap}%伤害,有50% 概率暴击",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350} },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"crt":60} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"crt":70} },
|
||||
],
|
||||
},
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7004, value: 0.12, name: "剑刃风暴" }, { uuid: 7005, value: 0.2, name: "斩魂利刃" }] },
|
||||
],
|
||||
atking: {
|
||||
6504: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"timed_buff_id":7012,"buff_value":10,"buff_chance":100,"buff_duration":5}, desc: "{t_chance}% 概率,普通攻击获得 10% 的暴击率" },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "致命本能", icon: "36-Guardian-Stance", },
|
||||
],
|
||||
info: "暴击+暴伤双光环,暴击流刺客",
|
||||
},
|
||||
// 5005 出血贼 — CSV导入:入场先手+受击格挡;复刻剑豪
|
||||
// 5005 流血酱 — CSV导入:入场先手+受击格挡;复刻剑豪
|
||||
5005: {
|
||||
uuid: 5005, name: "出血贼", path: "hc2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Mid, grow_type: HGrowType.Assassin, role: HRole.Assassin, hp: HERO_ROLE_BASE[HRole.Assassin].hp, ap: HERO_ROLE_BASE[HRole.Assassin].ap + 30, def: HERO_ROLE_BASE[HRole.Assassin].def,
|
||||
uuid: 5005, name: "流血酱", path: "hc2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Mid, grow_type: HGrowType.Assassin, role: HRole.Assassin, hp: HERO_ROLE_BASE[HRole.Assassin].hp, ap: HERO_ROLE_BASE[HRole.Assassin].ap + 30, def: HERO_ROLE_BASE[HRole.Assassin].def,
|
||||
skills: {
|
||||
6002: { uuid: 6002, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, overrides: {"ap":100}, desc: "挥刀对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_debuff_id":7007,"debuff_value":30,"debuff_chance":30}, desc: "普通攻击有{debuff_chance}%概率使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_debuff_id":7007,"debuff_value":-30,"debuff_chance":50}, desc: "普通攻击有{debuff_chance}%概率使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
6103: { uuid: 6103, name: "闪电斩", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150}, desc: "高速斩击{target},造成攻击力{ap}%伤害",
|
||||
6150: { uuid: 6150, name: "血刃风暴", lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":200,"timed_debuff_id":7007,"debuff_value":-20,"debuff_chance":100,"debuff_duration":5}, desc: "高速斩击{target},造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_debuff_id":7007,"debuff_value":40}, desc: "高速斩击{target},造成攻击力{ap}%,并使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"timed_debuff_id":7007,"debuff_value":60}, desc: "高速斩击{target},造成攻击力{ap}%,附带 50% 概率麻痹,并使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_debuff_id":7007,"debuff_value":-30,"debuff_chance":100,"debuff_duration":7}, desc: "高速斩击{target},造成攻击力{ap}%,并使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":300,"timed_debuff_id":7007,"debuff_value":-50,"debuff_chance":100,"debuff_duration":9}, desc: "高速斩击{target},造成攻击力{ap}%,附带 50% 概率麻痹,并使目标出血(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7002, value: 10, name: "攻击光环" }] },
|
||||
],
|
||||
atking: {
|
||||
6401: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"buff_value":2} },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "致命本能", icon: "36-Guardian-Stance", },
|
||||
],
|
||||
info: "普攻出血+大招群体出血,持续消耗",
|
||||
},
|
||||
// 5006 冻箭哥 — CSV导入:多重单体箭,带冰冻
|
||||
// 5006 冰棍 — CSV导入:多重单体箭,带冰冻
|
||||
5006: {
|
||||
uuid: 5006, name: "冻箭哥", path: "ha1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp, ap: HERO_ROLE_BASE[HRole.Archer].ap + 30, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||||
uuid: 5006, name: "冰棍", path: "ha1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp, ap: HERO_ROLE_BASE[HRole.Archer].ap + 20, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||||
skills: {
|
||||
6006: { uuid: 6006, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "射出箭矢,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"frz":10}, desc: "普通攻击有{frz}%概率 冰冻敌人" },
|
||||
],
|
||||
},
|
||||
6150: { uuid: 6150, name: "万箭齐发·冰", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150,"frz":30,"icon":"Stat_AttackRangeIncrease_02"}, desc: "万箭齐发,对{target}造成攻击力{ap}%伤害,{frz}%概率冰冻",
|
||||
6150: { uuid: 6150, name: "寒冰箭", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":140,"frz":30,"icon":"Stat_AttackRangeIncrease_02","summon_count":5}, desc: "射出 6 支寒冰箭,对{target}造成攻击力{ap}%伤害,每支箭有{frz}%概率冰冻敌人",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"frz":50} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"frz":70} },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":180,"frz":30} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":220,"frz":30} },
|
||||
],
|
||||
},
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7006, value: 0.15 }] },
|
||||
],
|
||||
atking: {
|
||||
6401: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"buff_value":2,"TGroup": TGroup.Ally}, desc: "{t_chance}%概率,永久提升全队 2% 攻击力" },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", icon: "27-Hawkeye", },
|
||||
],
|
||||
info: "冰冻控场+多重箭,远程控制",
|
||||
},
|
||||
// 5007 击退火女 — CSV导入:群体击退/麻痹压场;复刻深渊女王
|
||||
// 5007 火姐 — CSV导入:群体击退/麻痹压场;复刻深渊女王
|
||||
5007: {
|
||||
uuid: 5007, name: "击退火女", path: "hm1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp - 5, ap: HERO_ROLE_BASE[HRole.Mage].ap + 10, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||||
uuid: 5007, name: "火姐", path: "hm1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp + 5, ap: HERO_ROLE_BASE[HRole.Mage].ap + 10, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||||
skills: {
|
||||
6010: { uuid: 6010, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0, overrides: {"ap":100}, desc: "掷出紫魔球,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"bck_chance":20}, desc: "普通攻击有{bck_chance}%概率击退敌人" },
|
||||
],
|
||||
},
|
||||
6200: { uuid: 6200, name: "火焰喷射", lv: 1, cd: 8, ccd: 0, overrides: {"ap":250,"bck":100}, desc: "喷出烈焰风暴,对{target}造成攻击力{ap}%伤害,击退{bck}",
|
||||
6200: { uuid: 6200, name: "火焰喷射", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":250,"crt":50}, desc: "喷出烈焰风暴,对{target}造成攻击力{ap}%伤害,击退{bck}",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":350,"bck":100} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":450,"bck":100,"summon_count":2} },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":350,"crt":50} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"crt":50,"summon_count":4} },
|
||||
],
|
||||
},
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7002, value: 0.15, name: "深渊威压" }] },
|
||||
{ lv: 4, uuids: [{ uuid: 7002, value: 0.15, name: "攻击光环" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
|
||||
],
|
||||
info: "烈焰击退+易伤光环,法系压场",
|
||||
},
|
||||
// 5008 团疗奶爸 — CSV导入:全体治疗续航+自身护盾
|
||||
// 5008 奶哥 — CSV导入:全体治疗续航+自身护盾
|
||||
5008: {
|
||||
uuid: 5008, name: "团疗奶爸", path: "hh1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Support, role: HRole.Support, hp: HERO_ROLE_BASE[HRole.Support].hp + 10, ap: HERO_ROLE_BASE[HRole.Support].ap + 20, def: HERO_ROLE_BASE[HRole.Support].def,
|
||||
uuid: 5008, name: "奶哥", path: "hh1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Support, role: HRole.Support, hp: HERO_ROLE_BASE[HRole.Support].hp + 10, ap: HERO_ROLE_BASE[HRole.Support].ap + 20, def: HERO_ROLE_BASE[HRole.Support].def,
|
||||
skills: {
|
||||
6011: { uuid: 6011, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "挥杖对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120}, desc: "普通攻击造成 120% 攻击伤害" },
|
||||
],
|
||||
},
|
||||
6302: { uuid: 6302, name: "治疗", lv: 1, cd: 8, ccd: 0, overrides: {"ap":30}, desc: "为{target}回复攻击力{ap}%生命",
|
||||
6302: { uuid: 6302, name: "治疗", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"ap":30,"TGroup": TGroup.Ally}, desc: "为{target}回复攻击力{ap}%生命",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":40} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":50} },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":40,"TGroup": TGroup.Ally} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":50,"TGroup": TGroup.Ally,"timed_buff_id":7024,"buff_value":20,"buff_chance":100,"buff_duration":5} },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6301: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "圣愈之盾", t_num: 3, overrides: {"ap":30}, desc: "{target}获得生命最大值{ap}%的护盾" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7001, value: 20 }], desc: "每回合结束 休整恢复的血量值提升 20%" },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
|
||||
],
|
||||
info: "全体治疗+攻击附盾,团队续航",
|
||||
},
|
||||
// 5009 甲虫领主
|
||||
// 5009 甲壳虫
|
||||
5009: {
|
||||
uuid: 5009, name: "甲虫领主", path: "hk2", fac: FacSet.HERO, rarity: 2, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def,
|
||||
uuid: 5009, name: "甲壳虫", path: "hk3", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def,
|
||||
skills: {
|
||||
6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow].cd, ccd: 0,
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6502,"chance":10,"overrides":{"ap":5,"TGroup": TGroup.Self}}}, desc: "普通攻击有 10% 的概率为自己释放回春(5 秒恢复生命值的{ap}%)" },
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120}, desc: "普通攻击造成的伤害提升 20%" },
|
||||
],
|
||||
},
|
||||
6102: { uuid: 6102, lv: 1, cd: 8, ccd: 0, overrides: {"ap":250,"bck":30},
|
||||
6102: { uuid: 6102, lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":250,"proc_skill":{"s_uuid":6302,"chance":100,"overrides":{"TGroup": TGroup.Self,"buff_value":10}}},
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":300,"bck":50} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"bck":70} },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":300,"proc_skill":{"s_uuid":6302,"chance":100,"overrides":{"TGroup": TGroup.Self,"buff_value":15}}} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"proc_skill":{"s_uuid":6302,"chance":100,"overrides":{"TGroup": TGroup.Self,"buff_value":20}}} },
|
||||
],
|
||||
},
|
||||
},
|
||||
atked: {
|
||||
6302: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, overrides: {"ap":5}, desc: "为自己释放治疗,恢复生命值的{ap}%" },
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 30, pity_add: 20, overrides: {"ap":5}, desc: "{t_chance}%概率,恢复{ap}%生命值" },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
@@ -768,51 +818,51 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
info: "受击自疗+击退,自愈坦克",
|
||||
},
|
||||
// 5010 火箭哥
|
||||
// 5010 火箭筒
|
||||
5010: {
|
||||
uuid: 5010, name: "火箭哥", path: "ha2", fac: FacSet.HERO, rarity: 3, lv: 1, type: HType.Mid, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp, ap: HERO_ROLE_BASE[HRole.Archer].ap, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||||
uuid: 5010, name: "火箭筒", path: "ha2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Mid, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp, ap: HERO_ROLE_BASE[HRole.Archer].ap, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||||
skills: {
|
||||
6006: { uuid: 6006, name: "强化普攻", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0,
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":100,"bck_chance":10} },
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":10} },
|
||||
],
|
||||
},
|
||||
6151: { uuid: 6151, lv: 1, cd: 8, ccd: 0, overrides: {"ap":70,"summon_count":5,"bck_chance":100},
|
||||
6151: { uuid: 6151, lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":70,"summon_count":5,"timed_debuff_id":7006,"debuff_value":-10,"debuff_chance":100,"debuff_duration":5},
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":80,"summon_count":5,"bck_chance":100} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"bck_chance":100,"ap":100,"summon_count":6} },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":80,"timed_debuff_id":7006,"debuff_value":-20,"debuff_chance":100,"debuff_duration":5} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":100,"timed_debuff_id":7006,"debuff_value":-30,"debuff_chance":100,"debuff_duration":5} },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6008: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, overrides: {"ap":120,"bck_chance":50} },
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 50, pity_add: 20, overrides: {"ap":120} },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "鹰眼锁定", icon: "27-Hawkeye", },
|
||||
],
|
||||
info: "万箭齐射+高频击退,远程压制",
|
||||
info: "暴击",
|
||||
},
|
||||
// 5011 控血大师
|
||||
// 5011 血包
|
||||
5011: {
|
||||
uuid: 5011, name: "控血大师", path: "hk3", fac: FacSet.HERO, rarity: 4, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def,
|
||||
uuid: 5011, name: "血包", path: "hk2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def,
|
||||
skills: {
|
||||
6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6502,"chance":10,"overrides":{"ap":5}}}, desc: "普攻有 10% 概率,对自己释放回春(5 秒回复5% 生命)" },
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6502,"chance":10,"overrides":{"ap":5,"TGroup": TGroup.Self}}}, desc: "普攻有 10% 概率,对自己释放回春(5 秒回复5% 生命)" },
|
||||
],
|
||||
},
|
||||
6517: { uuid: 6517, name: "生命爆发", lv: 1, cd: 8, ccd: 0, overrides: {"buff_value":30,"buff_duration":10}, desc: "全体友方最大生命值提升{buff_value}%,持续{dur}秒",
|
||||
6103: { uuid: 6103, name: "闪电战", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"ap":200,"timed_buff_id":7029,"buff_value":30,"buff_chance":100,"buff_duration":5,"buff_target": BuffTarget.Self}, desc: "对前方敌人造成攻击力{ap}%伤害,并提升自己最大生命值{buff_value}%,持续{dur}秒",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"buff_value":40,"buff_duration":10}, desc: "全体友方最大生命值提升{buff_value}%,持续{dur}秒" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"buff_value":50,"buff_duration":15}, desc: "全体友方最大生命值提升{buff_value}%,持续{dur}秒" },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_buff_id":7029,"buff_value":40,"buff_chance":100,"buff_duration":5,"buff_target": BuffTarget.Self} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":300,"timed_buff_id":7029,"buff_value":50,"buff_chance":100,"buff_duration":5,"buff_target": BuffTarget.Self} },
|
||||
],
|
||||
},
|
||||
},
|
||||
atked: {
|
||||
6402: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 5, overrides: {"ap":1,"TGroup": TGroup.Ally,"hit_count":3}, desc: "全队永久增加 1% 生命最大值" },
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 5, t_chance: 30, pity_add: 15, overrides: {"ap":1,"TGroup": TGroup.Ally,"hit_count":3}, desc: "全队永久增加 1% 生命最大值" },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
@@ -820,19 +870,19 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
info: "永久和计时生命最大值,控血大师",
|
||||
},
|
||||
// 5012 疾风法师
|
||||
// 5012 风哥
|
||||
5012: {
|
||||
uuid: 5012, name: "疾风法师", path: "hm2", fac: FacSet.HERO, rarity: 5, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp, ap: HERO_ROLE_BASE[HRole.Mage].ap, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||||
uuid: 5012, name: "风哥", path: "hm2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp, ap: HERO_ROLE_BASE[HRole.Mage].ap, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||||
skills: {
|
||||
6009: { uuid: 6009, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6507,"chance":10,"overrides":{"buff_value":30,"TGroup": TGroup.Self}}} },
|
||||
],
|
||||
},
|
||||
6201: { uuid: 6201, name: "飓风", lv: 1, cd: 8, ccd: 0, overrides: {"ap":100,"summon_count":2,"proc_skill":{"s_uuid":6507,"chance":20,"overrides":{"buff_value":20}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速",
|
||||
6201: { uuid: 6201, name: "飓风", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":100,"summon_count":2,"proc_skill":{"s_uuid":6507,"chance":20,"overrides":{"buff_value":20,"TGroup": TGroup.Ally}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":100,"summon_count":3,"proc_skill":{"s_uuid":6507,"chance":20,"overrides":{"buff_value":20}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":100,"summon_count":4,"proc_skill":{"s_uuid":6507,"chance":20,"overrides":{"buff_value":20}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速" },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":100,"summon_count":3,"proc_skill":{"s_uuid":6507,"chance":25,"overrides":{"buff_value":25,"TGroup": TGroup.Ally}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":100,"summon_count":4,"proc_skill":{"s_uuid":6507,"chance":30,"overrides":{"buff_value":30,"TGroup": TGroup.Ally}}}, desc: "召唤 {summon_count} 道飓风攻击前方敌人,每道飓风造成 {ap}%伤害,每道飓风释放时有<color=#3CE66E>20</color>% 概率增加全体队友<color=#3CE66E>20</color>% 攻速" },
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -844,42 +894,42 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
info: "普攻 大招加速 buff+加速光环,加速大师",
|
||||
},
|
||||
// 5013 反伤哥
|
||||
// 5013 血牛
|
||||
5013: {
|
||||
uuid: 5013, name: "反伤哥", path: "hh2", fac: FacSet.HERO, rarity: 4, lv: 1, type: HType.Long, grow_type: HGrowType.Support, role: HRole.Support, hp: HERO_ROLE_BASE[HRole.Support].hp, ap: HERO_ROLE_BASE[HRole.Support].ap, def: HERO_ROLE_BASE[HRole.Support].def,
|
||||
uuid: 5013, name: "血牛", path: "hh2", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Support, role: HRole.Support, hp: HERO_ROLE_BASE[HRole.Support].hp, ap: HERO_ROLE_BASE[HRole.Support].ap, def: HERO_ROLE_BASE[HRole.Support].def,
|
||||
skills: {
|
||||
6004: { uuid: 6004, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_buff_id":7029,"buff_value":10,"buff_chance":20} },
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"ap":120} },
|
||||
],
|
||||
},
|
||||
6515: { uuid: 6515, name: "荆棘护盾", lv: 1, cd: 8, ccd: 0, overrides: {"buff_value":20,"TGroup": TGroup.Ally,"hit_count":3,"buff_duration":5},
|
||||
6517: { uuid: 6517, name: "生命护盾", lv: 1, cd: UltCdSet[UltCdLv.VerySlow].cd, ccd: 0, overrides: {"buff_value":20,"TGroup": TGroup.Ally,"hit_count":3,"buff_duration":5},
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"buff_value":25,"TGroup": TGroup.Ally,"hit_count":3,"buff_duration":10} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"buff_value":30,"buff_duration":10,"hit_count":3,"TGroup": TGroup.Ally} },
|
||||
],
|
||||
},
|
||||
},
|
||||
fstart: {
|
||||
6301: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 1, overrides: {"ap":20} },
|
||||
atking: {
|
||||
6414: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, t_num: 3, t_chance: 30, pity_add: 15, overrides: {"buff_value":10,"TGroup": TGroup.Ally} },
|
||||
],
|
||||
},
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
|
||||
],
|
||||
info: "大招全体反伤 普攻暴击 暴击反伤辅助",
|
||||
info: "大招全体生命最大值+概率全体+反伤护盾",
|
||||
},
|
||||
// 5014 闪避哥
|
||||
// 5014 闪哥
|
||||
5014: {
|
||||
uuid: 5014, name: "闪避哥", path: "hk4", fac: FacSet.HERO, rarity: 4, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: HERO_ROLE_BASE[HRole.Warrior].hp, ap: HERO_ROLE_BASE[HRole.Warrior].ap, def: HERO_ROLE_BASE[HRole.Warrior].def,
|
||||
uuid: 5014, name: "闪哥", path: "hk4", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: HERO_ROLE_BASE[HRole.Warrior].hp, ap: HERO_ROLE_BASE[HRole.Warrior].ap, def: HERO_ROLE_BASE[HRole.Warrior].def,
|
||||
skills: {
|
||||
6004: { uuid: 6004, name: "普攻强化", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0,
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_buff_id":7030,"buff_value":10,"buff_chance":20} },
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":10} },
|
||||
],
|
||||
},
|
||||
6100: { uuid: 6100, name: "寒冰斩", lv: 1, cd: 8, ccd: 0, overrides: {"ap":200,"timed_buff_id":7030,"buff_value":50},
|
||||
6100: { uuid: 6100, name: "寒冰斩", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":200,"timed_buff_id":7030,"buff_value":50},
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"timed_buff_id":7030,"buff_value":50} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":350,"timed_buff_id":7030,"buff_value":80} },
|
||||
@@ -892,87 +942,74 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "不屈战意", icon: "29-Endure", },
|
||||
],
|
||||
info: "",
|
||||
info: "强闪避",
|
||||
},
|
||||
// 5015 毒箭猎手 — 毒伤持续流:普攻淬毒叠层+毒雨铺DoT+攻击光环喂养毒伤
|
||||
// 5015 毒哥 — 毒伤持续流:普攻淬毒叠层+毒雨铺DoT+攻击光环喂养毒伤
|
||||
5015: {
|
||||
uuid: 5015, name: "毒箭猎手", path: "ha3", fac: FacSet.HERO, rarity: 2, lv: 1, type: HType.Long, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp + 10, ap: HERO_ROLE_BASE[HRole.Archer].ap, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||||
uuid: 5015, name: "毒哥", path: "ha3", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp + 10, ap: HERO_ROLE_BASE[HRole.Archer].ap, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||||
skills: {
|
||||
6007: { uuid: 6007, name: "淬毒箭", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "射出箭矢,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_debuff_id":7005,"debuff_value":30,"debuff_chance":30}, desc: "普通攻击有{debuff_chance}%概率使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"bck_chance":10}, desc: "普通攻击有{bck_chance}%概率击退敌人" },
|
||||
],
|
||||
},
|
||||
6150: { uuid: 6150, name: "万箭齐发·毒", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7005,"debuff_value":30,"debuff_chance":50,"icon":"4-Apply-Poison"}, desc: "毒箭如雨,对{target}造成攻击力{ap}%伤害,{debuff_chance}%概率使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)",
|
||||
6150: { uuid: 6150, name: "万箭齐发·毒", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7005,"debuff_value":-30,"debuff_chance":50,"icon":"4-Apply-Poison"}, desc: "毒箭如雨,对{target}造成攻击力{ap}%伤害,{debuff_chance}%概率使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"buff_value":40,"buff_chance":60} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"buff_value":60,"buff_chance":80,"hit_count":2}, desc: "毒箭如雨,对{target}造成攻击力{ap}%伤害,{buff_chance}%概率使目标中毒(每0.5秒受到{buff_value}点伤害,持续{dur}秒),每支箭可命中{hit_count}个目标" },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"timed_debuff_id":7005,"debuff_value":-60,"debuff_chance":100,"debuff_duration":5} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"timed_debuff_id":7005,"debuff_value":-100,"debuff_chance":100,"debuff_duration":7} },
|
||||
],
|
||||
},
|
||||
},
|
||||
atking: {
|
||||
6007: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "蚀骨毒箭", t_num: 3, overrides: {"ap":80,"timed_debuff_id":7005,"debuff_value":40,"debuff_chance":100}, desc: "追加射出蚀骨毒箭,对{target}造成攻击力{ap}%伤害,必定使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "蚀骨毒箭", t_num: 3, t_chance: 50, pity_add: 20, overrides: {"ap":80,"timed_debuff_id":7005,"debuff_value":40,"debuff_chance":100}, desc: "追加射出蚀骨毒箭,对{target}造成攻击力{ap}%伤害,必定使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7002, value: 0.1, name: "淬毒磨砺" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "剧毒淬炼", icon: "27-Hawkeye", },
|
||||
],
|
||||
info: "淬毒普攻+毒雨叠层,持续消耗型远程毒C",
|
||||
},
|
||||
// 5016 连珠神射 — 暴击连射爆发流:VeryFast极速普攻+概率追射必暴箭+开局团队暴击爆发
|
||||
// 5016 连珠 — 暴击连射爆发流:VeryFast极速普攻+概率追射必暴箭+开局团队暴击爆发
|
||||
5016: {
|
||||
uuid: 5016, name: "连珠神射", path: "ha4", fac: FacSet.HERO, rarity: 4, lv: 1, type: HType.Mid, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp, ap: HERO_ROLE_BASE[HRole.Archer].ap + 10, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||||
uuid: 5016, name: "连珠", path: "ha4", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Mid, grow_type: HGrowType.Archer, role: HRole.Archer, hp: HERO_ROLE_BASE[HRole.Archer].hp, ap: HERO_ROLE_BASE[HRole.Archer].ap + 10, def: HERO_ROLE_BASE[HRole.Archer].def,
|
||||
skills: {
|
||||
6008: { uuid: 6008, name: "连珠箭", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.VeryFast].cd, ccd: 0, overrides: {"ap":100}, desc: "极速连射,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"crt":20,"proc_skill":{"s_uuid":6007,"chance":20,"overrides":{"crt":100}}}, desc: "普通攻击暴击率提升{crt}%,并有概率触发连射追箭(必定暴击)" },
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6007,"chance":15,"overrides":{"TGroup": TGroup.Enemy,"ap":60}}}, desc: "有 20%额外射击,造成 80% 伤害" },
|
||||
],
|
||||
},
|
||||
6151: { uuid: 6151, name: "裂空箭雨", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150,"crt":30,"summon_count":5}, desc: "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击",
|
||||
6151: { uuid: 6151, name: "裂空箭雨", lv: 1, cd: UltCdSet[UltCdLv.VeryFast].cd, ccd: 0, overrides: {"ap":140,"crt":30,"summon_count":4}, desc: "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"crt":50} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"crt":70,"summon_count":6,"hit_count":2}, desc: "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击,每支箭可命中{hit_count}个目标" },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":180,"crt":50} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":220,"crt":70,"summon_count":5}, desc: "箭雨倾泻,对{target}造成攻击力{ap}%伤害,{crt}%概率暴击,每支箭可命中{hit_count}个目标" },
|
||||
],
|
||||
},
|
||||
},
|
||||
fstart: {
|
||||
6504: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "猎杀时刻", t_num: 1, overrides: {"buff_value":30}, desc: "战斗开始时释放暴击爆发,全体友方暴击率提升{buff_value}%,持续{dur}秒" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7004, value: 0.15, name: "猎手集结" }] },
|
||||
{ lv: 4, uuids: [{ uuid: 7004, value: 0.1, name: "猎手集结" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "猎杀直觉", icon: "27-Hawkeye", },
|
||||
],
|
||||
info: "极速连射+暴击追射+开局团队暴击,爆发型射手主C",
|
||||
},
|
||||
// 5017 碎甲术士 — 破甲减防法师:fstart先手/普攻概率/大招必定三通道施加破甲7008+穿透光环,团队物理增伤位
|
||||
// 5017 碎甲 — 破甲减防法师:fstart先手/普攻概率/大招必定三通道施加破甲7008+穿透光环,团队物理增伤位
|
||||
5017: {
|
||||
uuid: 5017, name: "碎甲术士", path: "hm3", fac: FacSet.HERO, rarity: 3, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp, ap: HERO_ROLE_BASE[HRole.Mage].ap + 10, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||||
uuid: 5017, name: "碎甲", path: "hm3", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp, ap: HERO_ROLE_BASE[HRole.Mage].ap + 10, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||||
skills: {
|
||||
6012: { uuid: 6012, name: "蚀甲酸瓶", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "掷出酸瓶,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"timed_debuff_id":7008,"debuff_chance":30}, desc: "普通攻击有{debuff_chance}%概率使目标破甲(防御降低,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
6203: { uuid: 6203, name: "碎甲能量波", lv: 1, cd: 8, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7008}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲(防御降低,持续{dur}秒)",
|
||||
6203: { uuid: 6203, name: "碎甲能量波", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"timed_debuff_id":7008,"debuff_value":-30,"debuff_chance":100,"debuff_duration":5}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲(防御降低,持续{dur}秒)",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"buff_value":-70}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲加深(防御大幅降低,持续{dur}秒)" },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"timed_debuff_id":7008,"debuff_value":-50,"debuff_chance":100,"debuff_duration":5} },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"timed_debuff_id":7008,"debuff_value":-70,"debuff_chance":100,"debuff_duration":7}, desc: "释放碎甲能量波,对{target}造成攻击力{ap}%伤害,并使目标破甲加深(防御大幅降低,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
},
|
||||
fstart: {
|
||||
6012: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "先手蚀甲", t_num: 1, overrides: {"ap":150,"timed_debuff_id":7008}, desc: "战斗开始时掷出蚀甲酸瓶,对{target}造成攻击力{ap}%伤害,并必定使其破甲(防御降低,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7009, value: 0.1, name: "锐矛之赐" }] },
|
||||
],
|
||||
@@ -981,64 +1018,30 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
],
|
||||
info: "先手破甲+概率蚀甲+穿透光环,物理队核心增伤位",
|
||||
},
|
||||
// 5018 雷暴领主 — 雷暴AOE爆发+麻痹控场:先手雷击+高倍率能量波
|
||||
// 5018 雷哥 — 雷暴AOE爆发+麻痹控场:先手雷击+高倍率能量波
|
||||
5018: {
|
||||
uuid: 5018, name: "雷暴领主", path: "hm4", fac: FacSet.HERO, rarity: 5, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp - 10, ap: HERO_ROLE_BASE[HRole.Mage].ap + 20, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||||
uuid: 5018, name: "雷哥", path: "hm4", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp + 10, ap: HERO_ROLE_BASE[HRole.Mage].ap + 20, def: HERO_ROLE_BASE[HRole.Mage].def,
|
||||
skills: {
|
||||
6009: { uuid: 6009, name: "雷霆弹", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, overrides: {"ap":100}, desc: "掷出雷霆弹,对{target}造成攻击力{ap}%伤害",
|
||||
6013: { uuid: 6013, name: "召唤闪电", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast].cd, ccd: 0, overrides: {"ap":100}, desc: "召唤闪电,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"para":15}, desc: "普通攻击有{para}%概率麻痹敌人,减缓其技能冷却恢复" },
|
||||
],
|
||||
},
|
||||
6203: { uuid: 6203, name: "雷霆裂空", lv: 1, cd: 8, ccd: 0, overrides: {"ap":200,"para":40}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人",
|
||||
6204: { uuid: 6204, name: "雷霆裂空", lv: 1, cd: UltCdSet[UltCdLv.Normal].cd, ccd: 0, overrides: {"ap":150,"para":50}, desc: "释放多束闪电,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":250,"para":60}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":300,"para":80,"hit_count":3}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,可多次命中,{para}%概率麻痹敌人" },
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":200,"para":70}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":250,"para":100}, desc: "释放雷霆裂空波,对{target}造成攻击力{ap}%伤害,可多次命中,{para}%概率麻痹敌人" },
|
||||
],
|
||||
},
|
||||
},
|
||||
fstart: {
|
||||
6203: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "雷击先手", t_num: 1, overrides: {"ap":150,"para":30,"icon":"100-Enchant-Magic"}, desc: "战斗开始释放雷击,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7003, value: 10, name: "雷云领域" }] },
|
||||
{ lv: 4, uuids: [{ uuid: 7024, value: 10, name: "雷电精准" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"ap":50}, name: "奥术共鸣", icon: "100-Enchant-Magic", },
|
||||
],
|
||||
info: "雷暴爆发+麻痹控场,法系主C",
|
||||
},
|
||||
// 5019 圣盾贤者 — 护盾反伤生存法:全队圣盾+荆棘反伤+受击荆棘
|
||||
5019: {
|
||||
uuid: 5019, name: "圣盾贤者", path: "hm5", fac: FacSet.HERO, rarity: 2, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: HERO_ROLE_BASE[HRole.Mage].hp + 20, ap: HERO_ROLE_BASE[HRole.Mage].ap - 5, def: HERO_ROLE_BASE[HRole.Mage].def + 5,
|
||||
skills: {
|
||||
6011: { uuid: 6011, name: "圣光飞瓶", lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal].cd, ccd: 0, overrides: {"ap":100}, desc: "掷出圣光飞瓶,对{target}造成攻击力{ap}%伤害",
|
||||
lv_entries: [
|
||||
{ lv: 2, s_lv: SkillLv.Lv2, overrides: {"proc_skill":{"s_uuid":6516,"chance":20,"overrides":{"timed_buff_id":7028,"buff_value":10}}}, desc: "普通攻击概率凝聚荆棘护体(受击时反弹{buff_value}%所受伤害,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
6301: { uuid: 6301, name: "奥术圣壁", lv: 1, cd: 8, ccd: 0, overrides: {"TGroup": TGroup.Ally,"ap":20,"timed_buff_id":7027,"buff_value":10}, desc: "为全体友方施加生命最大值{ap}%的护盾,并附加荆棘(受击时反弹{buff_value}点伤害,持续{dur}秒)",
|
||||
lv_entries: [
|
||||
{ lv: 8, s_lv: SkillLv.Lv2, overrides: {"ap":30,"buff_value":15}, desc: "为全体友方施加生命最大值{ap}%的护盾,并附加荆棘(受击时反弹{buff_value}点伤害,持续{dur}秒)" },
|
||||
{ lv: 16, s_lv: SkillLv.Lv3, overrides: {"ap":40,"buff_value":20}, desc: "为全体友方施加生命最大值{ap}%的护盾,并附加荆棘(受击时反弹{buff_value}点伤害,持续{dur}秒)" },
|
||||
],
|
||||
},
|
||||
},
|
||||
atked: {
|
||||
6516: [
|
||||
{ lv: 4, s_lv: SkillLv.Lv1, name: "荆棘回应", t_num: 3, overrides: {"timed_buff_id":7028,"buff_value":10,"icon":"75-Shield-Stun"}, desc: "凝聚荆棘护体,受击时反弹{buff_value}%所受伤害,持续{dur}秒" },
|
||||
],
|
||||
},
|
||||
field: [
|
||||
{ lv: 4, uuids: [{ uuid: 7022, value: 8, name: "荆棘领域" }] },
|
||||
],
|
||||
bonus: [
|
||||
{ lv: 12, attrs: {"hp":50}, name: "守护之心", icon: "29-Endure", },
|
||||
],
|
||||
info: "全队护盾+荆棘反伤,生存反击法",
|
||||
},
|
||||
// @hero-setup:heroes-end
|
||||
|
||||
/*
|
||||
@@ -1118,9 +1121,9 @@ export const HeroInfo: Record<number, heroInfo> = {
|
||||
};
|
||||
|
||||
export const HeroList: number[] = [
|
||||
// 编辑器导出自动同步(共 19 个)
|
||||
// 编辑器导出自动同步(共 18 个)
|
||||
5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010,
|
||||
5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018, 5019,
|
||||
5011, 5012, 5013, 5014, 5015, 5016, 5017, 5018,
|
||||
];
|
||||
// @hero-setup:region-end
|
||||
|
||||
@@ -1140,48 +1143,48 @@ export interface HeroComboInfo {
|
||||
}
|
||||
|
||||
/**
|
||||
* 推荐阵容表(几何王国复刻版 5001~5009)。
|
||||
* 推荐阵容表(基于现役 5001~5018 英雄实际技能组)。
|
||||
* 设计原则:
|
||||
* 1. 铁三角结构:1 前排(坦克)+ 1 增益(光环/先手)+ 1 主C
|
||||
* 2. 乘区分散:攻击/暴击/暴伤各占独立乘区,组合优先覆盖不同乘区避免稀释
|
||||
* 3. 发动机冗余:前排挨打/死亡触发增益,叠甲骑士(5005)死亡缠绕负责献祭点火
|
||||
* 1. 铁三角结构:heroes[0] 固定为近战前排(坦克/战士),其余按站位从近到远
|
||||
* 2. 乘区分散:攻击/攻速/暴击/穿透各占独立乘区,组合优先覆盖不同乘区避免稀释
|
||||
* 3. 主题唯一:每套阵容围绕一个流派关键词(暴击/控制/续航/破甲/光环/消耗)组队
|
||||
*/
|
||||
export const HeroComboSet: Record<number, HeroComboInfo> = {
|
||||
// 8001 暴击爆发流 — 暴击率与暴伤双乘区互不稀释,成型最强
|
||||
// 8001 暴击爆发流 — 连珠神射暴击光环喂养双物理C,成型最强
|
||||
8001: {
|
||||
uuid: 8001, name: "暴击爆发流",
|
||||
heroes: [5005, 5008, 5002],
|
||||
desc: "叠甲骑士前排抗伤叠甲,刀刀暴击的暴击光环与眩晕暴击哥的暴伤光环组成双乘区,双近战暴击爆发收割。",
|
||||
heroes: [5001, 5016, 5004],
|
||||
desc: "叠甲骑士前排抗伤+受击叠防,连珠神射暴击光环覆盖全队并以极速箭雨压场,刀刀暴击近战收割残局。",
|
||||
},
|
||||
// 8002 冰雷控制流 — 冰冻+击晕双控场,敌人出不了手
|
||||
// 8002 冰雷控制流 — 击晕+冰冻+麻痹三控链,敌人出不了手
|
||||
8002: {
|
||||
uuid: 8002, name: "冰雷控制流",
|
||||
heroes: [5007, 5004, 5001],
|
||||
desc: "微醺战神前排击退压场,冻住不谢冰冻链配合紫电魔女能量波击退击晕,击晕光环叠加,全场控制。",
|
||||
heroes: [5003, 5006, 5018],
|
||||
desc: "眩晕暴击哥前排开山斧必晕压阵,冻箭哥寒冰箭冰冻链,雷暴领主雷霆麻痹迟滞技能,三控交替敌人难以出手。",
|
||||
},
|
||||
// 8003 铁桶续航流 — 双防御前排+双治疗保血,最稳
|
||||
// 8003 铁桶续航流 — 双坦克承伤+治疗保血,最稳
|
||||
8003: {
|
||||
uuid: 8003, name: "铁桶续航流",
|
||||
heroes: [5005, 5009, 5006],
|
||||
desc: "叠甲骑士与铁壳斧弟双前排叠甲叠防,光明奶爸治疗+生命光环抬全队血线,专打持久消耗战。",
|
||||
heroes: [5009, 5011, 5008],
|
||||
desc: "甲虫领主受击自疗顶前排,控血大师受击全队永久生命成长+大招生命爆发,团疗奶爸全体治疗+战后回复光环,专打持久战。",
|
||||
},
|
||||
// 8004 先手爆发流 — 入场剑气先手+能量波跟进,短回合最强
|
||||
// 8004 破甲压制流 — 破甲+减攻双减益,克制高防高攻阵容
|
||||
8004: {
|
||||
uuid: 8004, name: "先手爆发流",
|
||||
heroes: [5003, 5001, 5008],
|
||||
desc: "格挡反杀入场500%剑气先手压血线,紫电魔女能量波击退跟进,眩晕暴击哥开山斧收割残局。",
|
||||
uuid: 8004, name: "破甲压制流",
|
||||
heroes: [5001, 5017, 5010],
|
||||
desc: "碎甲术士普攻/大招双通道破甲+穿透光环放大物理伤害,火箭哥五箭弹幕必挂减攻削弱敌方输出,叠甲骑士前排兜底。",
|
||||
},
|
||||
// 8005 破甲推进流 — 易伤放大全队伤害,克制高血Boss
|
||||
// 8005 光环覆盖流 — 闪避/攻击/攻速三光环全覆盖
|
||||
8005: {
|
||||
uuid: 8005, name: "破甲推进流",
|
||||
heroes: [5007, 5006, 5002],
|
||||
desc: "微醺战神气斩易伤放大全队伤害,光明奶爸治疗保前排,刀刀暴击吃满易伤与自身暴击完成推进。",
|
||||
uuid: 8005, name: "光环覆盖流",
|
||||
heroes: [5014, 5007, 5012],
|
||||
desc: "闪避哥前排+闪避光环提升全队生存,击退火女攻击光环、疾风法师攻速光环持续放大全队输出,三光环增益拉满。",
|
||||
},
|
||||
// 8006 光环覆盖流 — 攻击/暴击/暴伤/生命光环全覆盖
|
||||
// 8006 易伤消耗流 — 易伤放大出血DoT,磨血收割
|
||||
8006: {
|
||||
uuid: 8006, name: "光环覆盖流",
|
||||
heroes: [5002, 5006, 5001],
|
||||
desc: "刀刀暴击暴击+暴伤双光环、紫电魔女攻击光环、光明奶爸生命光环,四光环全覆盖持续放大全队输出。",
|
||||
uuid: 8006, name: "易伤消耗流",
|
||||
heroes: [5002, 5005, 5008],
|
||||
desc: "易伤剑仙气斩+普攻双通道挂易伤放大全队伤害,出血贼普攻+大招叠出血磨血,团疗奶爸治疗保前排打消耗战。",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1256,9 +1259,9 @@ export const HERO_POWER_WEIGHTS = {
|
||||
* 解析触发技能在目标等级下的有效条目列表。
|
||||
* 每个 s_uuid 取 ≤lv 的最大档;返回扁平数组供评分/触发器消费。
|
||||
*/
|
||||
export function resolveTriggerByLv(grouped: TriggerGrouped | undefined, lv: number): { s_uuid: number; t_num: number; overrides?: SkillOverrides }[] {
|
||||
export function resolveTriggerByLv(grouped: TriggerGrouped | undefined, lv: number): ResolvedTriggerEntry[] {
|
||||
if (!grouped) return [];
|
||||
const result: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[] = [];
|
||||
const result: ResolvedTriggerEntry[] = [];
|
||||
for (const key in grouped) {
|
||||
const entries = grouped[key];
|
||||
if (!entries || entries.length === 0) continue;
|
||||
@@ -1266,7 +1269,7 @@ export function resolveTriggerByLv(grouped: TriggerGrouped | undefined, lv: numb
|
||||
for (const e of entries) {
|
||||
if (e.lv <= lv && (!pick || e.lv > pick.lv)) pick = e;
|
||||
}
|
||||
if (pick) result.push({ s_uuid: Number(key), t_num: pick.t_num, overrides: pick.overrides });
|
||||
if (pick) result.push({ s_uuid: Number(key), t_num: pick.t_num, t_chance: pick.t_chance, pity_add: pick.pity_add, overrides: pick.overrides });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1571,7 +1574,7 @@ export interface HeroPowerDetailed {
|
||||
|
||||
/** 计算普通触发类技能(atking/atked/fstart/dead)的详细价值 */
|
||||
function calcTriggerPowerDetailed(
|
||||
triggerConfigs: { s_uuid: number, t_num?: number, overrides?: SkillOverrides }[],
|
||||
triggerConfigs: ResolvedTriggerEntry[],
|
||||
hero: heroInfo,
|
||||
targetLv: number,
|
||||
type: SkillTriggerType,
|
||||
@@ -1612,7 +1615,9 @@ function calcTriggerPowerDetailed(
|
||||
}
|
||||
|
||||
const triggerCount = getTriggerCount(type, tNum, hero, seconds);
|
||||
const value = effectValue * triggerCount * scopeMul * weight;
|
||||
// 期望折算:按基础触发概率缩放(保底叠加提升的是方差体验,不影响长期期望)
|
||||
const chanceMul = (trig.t_chance ?? 100) / 100;
|
||||
const value = effectValue * triggerCount * scopeMul * weight * chanceMul;
|
||||
total += value;
|
||||
items.push({ type, s_uuid: trig.s_uuid, name: skill.name, t_num: tNum, value });
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
* - 升级表 key 为目标等级:need = HERO_UPGRADE_NEED_FRAGMENTS[lv + 1],查不到即满级。
|
||||
*/
|
||||
import { HERO_UPGRADE_NEED_FRAGMENTS } from "./GameSet";
|
||||
import { HeroInfo, HeroList } from "./heroSet";
|
||||
|
||||
/** 英雄升级状态快照 */
|
||||
export interface HeroUpgradeState {
|
||||
@@ -75,3 +76,25 @@ export function getHeroUpgradeState(lv: number, fragments: number): HeroUpgradeS
|
||||
canUpgrade: !isMax && fragments >= (need as number),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 图鉴展示排序:可升级优先 → 现有等级降序 → 品质降序。
|
||||
* Why: 图鉴(HerosListComp)与英雄详情(HeroInfoComp)共用同一排序口径,
|
||||
* 保证图鉴中的卡片顺序与详情面板"前后切换"顺序一致。
|
||||
* @param getGrowth 查询英雄成长数据(lv / fragments)的回调,通常由 smc.getHeroGrowth 注入
|
||||
* @returns 排序后的英雄 uuid 数组(新数组,不修改 HeroList)
|
||||
*/
|
||||
export function getSortedHeroList(getGrowth: (uuid: number) => { lv: number; fragments: number }): number[] {
|
||||
return [...HeroList].sort((a, b) => {
|
||||
const ga = getGrowth(a);
|
||||
const gb = getGrowth(b);
|
||||
// 可升级的一批排在最左
|
||||
const ca = canHeroUpgrade(ga.lv, ga.fragments) ? 0 : 1;
|
||||
const cb = canHeroUpgrade(gb.lv, gb.fragments) ? 0 : 1;
|
||||
if (ca !== cb) return ca - cb;
|
||||
// 同批内:现有等级降序优先
|
||||
if (ga.lv !== gb.lv) return gb.lv - ga.lv;
|
||||
// 等级相同:品质降序(rarity 越大品质越高)
|
||||
return (HeroInfo[b]?.rarity ?? 1) - (HeroInfo[a]?.rarity ?? 1);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
uuid,英雄名称,简化说明,rarity,类型,形态,ap,hp,def,skill[0]_lv1,skill[0]_lv2,skill[1]_lv1,skill[1]_lv8,skill[1]_lv16,atking[0]_lv4,atked[0]_lv4,fstart[0]_lv4,dead[0]_lv4,field[0]_lv4
|
||||
5001,叠甲骑士,CSV导入:自身护盾+全体护盾,1,tank,近战,tank,tank+20,tank+10,6004 强化普攻(ap100;慢速1.20s;触发飞剑6001(100%)),ap120,6301 魔法盾(ap30),ap60,ap120,无,6301 全体圣盾(t_num3;ap10):全队获得本英雄生命最大值{ap}%的护盾,无,无,无
|
||||
5002,易伤剑仙,CSV导入:击退压场+易伤放大;复刻酒仙,1,warrior,近战,warrior+20,warrior+5,warrior+5,6004 强化普攻(ap100;慢速1.20s),ap120,6101 气斩(ap150;附加易伤7002),,ap180;bck60,6004 风暴打击(t_num3;ap300):立刻打击{target},造成攻击力{ap}%伤害,无,无,无,无
|
||||
5003,眩晕暴击哥,CSV导入:高爆发+击晕收割;复刻齐天大圣,1,warrior,近战,warrior+20,warrior+5,warrior+5,6004 强化普攻(ap100;慢速1.20s),stun10,6104 开山斧(ap300;stun100),ap450;stun100,ap450;stun100,无,无,无,无,7005 大圣神威0.25
|
||||
5004,刀刀暴击,CSV导入:暴击/暴伤双光环乘区;复刻剑圣,1,assassin,中程,assassin+30,assassin,assassin,6002 强化普攻(ap100;快速0.90s),crt10,6100 光闪(ap150),ap250,ap350,无,无,无,无,7004 剑刃风暴0.12+7005 斩魂利刃0.2
|
||||
5005,出血贼,CSV导入:入场先手+受击格挡;复刻剑豪,1,assassin,中程,assassin+30,assassin,assassin,6002 强化普攻(ap100;快速0.90s),附加30出血7007buff_chance30,6103 闪电斩(ap150),ap250;附加出血7007,ap350;para50;附加60出血7007,无,无,无,无,7018 连击光环1
|
||||
5006,冻箭哥,CSV导入:多重单体箭,带冰冻,1,archer,远程,archer+30,archer,archer,6006 强化普攻(ap100;中速1.05s),bck10,6150 万箭齐发·冰(ap150;frz30),ap200;frz50,ap250;frz70,无,无,无,无,7006 攻速光环0.15
|
||||
5007,击退火女,CSV导入:群体击退/麻痹压场;复刻深渊女王,1,mage,远程,mage+10,mage-5,mage,6010 强化普攻(ap100;慢速1.20s;bck30),bck40,6200 火焰喷射(ap250;bck100),ap350;bck100,ap450;bck100;summon2,无,无,无,无,7002 深渊威压0.15
|
||||
5008,团疗奶爸,CSV导入:全体治疗续航+自身护盾,1,support,远程,support+20,support+10,support,6011 强化普攻(ap100;中速1.05s),bck10,6302 治疗(ap30),ap40,ap50,6301 圣愈之盾(t_num3;ap30):{target}获得生命最大值{ap}%的护盾,无,无,无,无
|
||||
字段,5001,5002,5003,5004,5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019
|
||||
英雄名称,叠甲骑士,易伤剑仙,眩晕暴击哥,刀刀暴击,出血贼,冻箭哥,击退火女,团疗奶爸,甲虫领主,火箭哥,控血大师,疾风法师,反伤哥,闪避哥,毒箭猎手,连珠神射,碎甲术士,雷暴领主,圣盾贤者
|
||||
简化说明,CSV导入:自身护盾+全体护盾,CSV导入:击退压场+易伤放大;复刻酒仙,CSV导入:高爆发+击晕收割;复刻齐天大圣,CSV导入:暴击/暴伤双光环乘区;复刻剑圣,CSV导入:入场先手+受击格挡;复刻剑豪,CSV导入:多重单体箭,带冰冻,CSV导入:群体击退/麻痹压场;复刻深渊女王,CSV导入:全体治疗续航+自身护盾,,,,,,,毒伤持续流:普攻淬毒叠层+毒雨铺DoT+攻击光环喂养毒伤,暴击连射爆发流:VeryFast极速普攻+概率追射必暴箭+开局团队暴击爆发,破甲减防法师:fstart先手/普攻概率/大招必定三通道施加破甲7008+穿透光环,团队物理增伤位,雷暴AOE爆发+麻痹控场:先手雷击+高倍率能量波,护盾反伤生存法:全队圣盾+荆棘反伤+受击荆棘
|
||||
rarity,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
|
||||
类型,tank,warrior,warrior,assassin,assassin,archer,mage,support,tank,archer,tank,mage,support,warrior,archer,archer,mage,mage,mage
|
||||
形态,近战,近战,近战,中程,中程,远程,远程,远程,近战,中程,近战,远程,远程,近战,远程,中程,远程,远程,远程
|
||||
ap,tank,warrior+20,warrior+20,assassin+30,assassin+30,archer+30,mage+10,support+20,tank,archer,tank,mage,support,warrior,archer,archer+10,mage+10,mage+20,mage-5
|
||||
hp,tank+20,warrior+5,warrior+5,assassin,assassin,archer,mage-5,support+10,tank,archer,tank,mage,support,warrior,archer+10,archer,mage,mage-10,mage+20
|
||||
def,tank+10,warrior+5,warrior+5,assassin,assassin,archer,mage,support,tank,archer,tank,mage,support,warrior,archer,archer,mage,mage,mage+5
|
||||
dodge,,,,,,,,,,,,,,,,,,,
|
||||
accuracy,,,,,,,,,,,,,,,,,,,
|
||||
skill[0]_lv1,6004 强化普攻(ap100;慢速1.20s),6004 强化普攻(ap100;慢速1.20s),6004 强化普攻(ap100;慢速1.20s),6002 强化普攻(ap100;快速0.90s),6002 强化普攻(ap100;快速0.90s),6006 强化普攻(ap100;中速1.05s),6010 强化普攻(ap100;慢速1.20s),6011 强化普攻(ap100;中速1.05s),6004 普攻强化(慢速1.20s),6006 强化普攻(快速0.90s),6004 普攻强化(中速1.05s),6009 普攻强化(中速1.05s),6004 攻击(中速1.05s),6004 普攻强化(中速1.05s),6007 淬毒箭(ap100;中速1.05s),6008 连珠箭(ap100;极速0.75s),6012 蚀甲酸瓶(ap100;中速1.05s),6009 雷霆弹(ap100;快速0.90s),6011 圣光飞瓶(ap100;中速1.05s)
|
||||
skill[0]_lv2,ap120,ap120,stun10,crt10,命中附加30出血7007debuff_chance30,frz10,,ap120,施法触发计时回血6502(10%;ap5),ap100,施法触发计时回血6502(10%;ap5),施法触发攻速爆发6507(10%),附加10生命爆发7029buff_chance20,附加10闪避爆发7030buff_chance20,命中附加30中毒7005debuff_chance30,crt20;施法触发蓝箭6007(20%),命中附加破甲7008debuff_chance30,para15,施法触发次级反伤6516(20%)
|
||||
skill[1]_lv1,6301 魔法盾(ap30),6101 气斩(ap150;命中附加易伤7002),6104 开山斧(ap300;stun100),6100 光闪(ap150),6103 闪电斩(ap150),6150 万箭齐发·冰(ap150;frz30),6200 火焰喷射(ap250;bck100),6302 治疗(ap30),6102 火焰斩(ap250;bck30),6151 万箭齐发.火(ap70;summon5),6517 生命爆发(),6201 飓风(ap100;summon2;施法触发攻速爆发6507(20%)),6515 荆棘护盾(),6100 寒冰斩(ap200;附加50闪避爆发7030),6150 万箭齐发·毒(ap150;命中附加30中毒7005debuff_chance50),6151 裂空箭雨(ap150;crt30;summon5),6203 碎甲能量波(ap150;命中附加破甲7008),6203 雷霆裂空(ap200;para40),6301 奥术圣壁(ap20;附加10荆棘7027)
|
||||
skill[1]_lv8,ap60,,ap450;stun100,ap250,ap250;命中附加40出血7007,ap200;frz50,ap350;bck100,ap40,ap300;bck50,ap80;summon5,,ap100;summon3;施法触发攻速爆发6507(20%),,ap250;附加50闪避爆发7030,ap200,ap200;crt50,ap200,ap250;para60,ap30
|
||||
skill[1]_lv16,ap120,ap180;bck60,ap450;stun100,ap350,ap350;命中附加60出血7007,ap250;frz70,ap450;bck100;summon2,ap50,ap350;bck70,ap100;summon6,,ap100;summon4;施法触发攻速爆发6507(20%),,ap350;附加80闪避爆发7030,ap250,ap250;crt70;summon6,ap250,ap300;para80,ap40
|
||||
atking[0]_lv4,无,6004 风暴打击(t_num3;ap300):立刻打击{target},造成攻击力{ap}%伤害,无,无,无,无,无,6301 圣愈之盾(t_num3;ap30):{target}获得生命最大值{ap}%的护盾,无,6008 红箭(t_num3;ap120):,无,无,无,无,6007 蚀骨毒箭(t_num3;ap80):追加射出蚀骨毒箭,对{target}造成攻击力{ap}%伤害,必定使目标中毒(每0.5秒受到{debuff_value}点伤害,持续{dur}秒),无,无,无,无
|
||||
atked[0]_lv4,6302 治疗(t_num3;概率50%;ap10):有 {t_chance}% 的概率,治疗自己 {ap}%生命最大值,无,无,无,无,无,无,无,6302 治疗(t_num3;ap5):为自己释放治疗,恢复生命值的{ap}%,无,6402 生命强化(t_num5;ap1):全队永久增加 1% 生命最大值,无,无,无,无,无,无,无,6516 荆棘回应(t_num3):凝聚荆棘护体,受击时反弹{buff_value}%所受伤害,持续{dur}秒
|
||||
fstart[0]_lv4,无,无,无,无,无,无,无,无,无,无,无,无,6301 护盾(t_num1;ap20):,无,无,6504 猎杀时刻(t_num1):战斗开始时释放暴击爆发,全体友方暴击率提升{buff_value}%,持续{dur}秒,6012 先手蚀甲(t_num1;ap150):战斗开始时掷出蚀甲酸瓶,对{target}造成攻击力{ap}%伤害,并必定使其破甲(防御降低,持续{dur}秒),6203 雷击先手(t_num1;ap150):战斗开始释放雷击,对{target}造成攻击力{ap}%伤害,{para}%概率麻痹敌人,无
|
||||
fend[0]_lv4,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无
|
||||
dead[0]_lv4,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无,无
|
||||
field[0]_lv4,无,无,7005 大圣神威0.25,7004 剑刃风暴0.12+7005 斩魂利刃0.2,7002 攻击光环10,7006 攻速光环0.15,7002 深渊威压0.15,无,无,无,无,7006 攻速光环10,无,7023 闪避光环10,7002 淬毒磨砺0.1,7004 猎手集结0.15,7009 锐矛之赐0.1,7003 雷云领域10,7022 荆棘领域8
|
||||
bonus,lv12 def+50%,lv12 hp+50%,lv12 hp+50%,lv12 ap+50%,lv12 ap+50%,lv12 ap+50%,lv12 ap+50%,lv12 hp+50%,lv12 def+50%,lv12 ap+50%,lv12 def+50%,lv12 ap+50%,lv12 hp+50%,lv12 hp+50%,lv12 ap+50%,lv12 ap+50%,lv12 ap+50%,lv12 ap+50%,lv12 hp+50%
|
||||
|
||||
|
@@ -13,7 +13,6 @@ import { Attrs } from "../common/config/HeroAttrs";
|
||||
import { MoveComp } from "./MoveComp";
|
||||
import { mLogger } from "../common/Logger";
|
||||
import { FieldSkillType } from "../common/config/SkillSet";
|
||||
import { applyTalentBonuses } from "../common/config/TalentSet";
|
||||
/** 英雄实体:负责英雄节点创建、属性初始化、入场动画与销毁流程 */
|
||||
@ecs.register(`Hero`)
|
||||
|
||||
@@ -173,16 +172,6 @@ export class Hero extends ecs.Entity {
|
||||
model.skills[skill.uuid] = { ...skill, lv: Math.min(FightSet.HERO_SKILL_MAX_LV, Math.max(0, skill.lv + hero_lv - 2)), ccd: 0, overrides: resolveSkillOverrides(skill, hero_lv) };
|
||||
}
|
||||
|
||||
// 按当前英雄等级 resolve 触发技能/光环到运行时缓存,供 SkillTriggerHelper 消费
|
||||
model.runtime_call = resolveTriggerByLv(model.call, hero_lv);
|
||||
model.runtime_dead = resolveTriggerByLv(model.dead, hero_lv);
|
||||
model.runtime_fstart = resolveTriggerByLv(model.fstart, hero_lv);
|
||||
model.runtime_fend = resolveTriggerByLv(model.fend, hero_lv);
|
||||
model.runtime_atking = resolveTriggerByLv(model.atking, hero_lv);
|
||||
model.runtime_atked = resolveTriggerByLv(model.atked, hero_lv);
|
||||
model.runtime_field = resolveFieldByLv(model.field, hero_lv);
|
||||
// 复活已纳入 dead 触发组,无需单独解析 revive
|
||||
|
||||
// 应用额外属性加成(成长类型每级递增 + bonus 档位累加)
|
||||
// 成长增量:仅英雄生效(model.fac 已为 HERO),按 grow_type 递增曲线累计
|
||||
const grow = calcGrowBonus(hero, hero_lv);
|
||||
@@ -211,12 +200,23 @@ export class Hero extends ecs.Entity {
|
||||
|
||||
// lv12 职业专项已移除:单项属性强化统一由 bonus 配置(如 attrs: { ap: 50 })按等级注入
|
||||
|
||||
// 天赋加成层:全局天赋(一阶基础/三阶超强全局)全局生效,职业天赋(二阶专精/三阶超强职业)按 role 过滤(仅英雄生效,怪物跳过)
|
||||
// Why: 放在成长/bonus 之后、光环乘区之后,以基础快照为基数叠加,避免与乘区叠加成乘法膨胀
|
||||
// 天赋加成层:全局天赋(L1/L2)全局生效,职业天赋(L3-L5)按 role 过滤(仅英雄生效,怪物跳过)
|
||||
// Why: 放在成长/bonus 之后、runtime_* resolve 之前——触发修正需先写入模型,L4/L5 才能影响阈值判定;
|
||||
// 属性加成以基础快照为基数叠加,避免与光环乘区叠加成乘法膨胀
|
||||
if (model.fac === FacSet.HERO) {
|
||||
applyTalentBonuses(model, smc.getTalentLevels(), model.role);
|
||||
model.applyTalent();
|
||||
}
|
||||
|
||||
// 按当前英雄等级 resolve 触发技能/光环到运行时缓存,供 SkillTriggerHelper 消费
|
||||
model.runtime_call = resolveTriggerByLv(model.call, hero_lv);
|
||||
model.runtime_dead = resolveTriggerByLv(model.dead, hero_lv);
|
||||
model.runtime_fstart = resolveTriggerByLv(model.fstart, hero_lv);
|
||||
model.runtime_fend = resolveTriggerByLv(model.fend, hero_lv);
|
||||
model.runtime_atking = resolveTriggerByLv(model.atking, hero_lv);
|
||||
model.runtime_atked = resolveTriggerByLv(model.atked, hero_lv);
|
||||
model.runtime_field = resolveFieldByLv(model.field, hero_lv);
|
||||
// 复活已纳入 dead 触发组,无需单独解析 revive
|
||||
|
||||
// 缓存技能射程等派生数据,减少战斗帧内重复计算
|
||||
model.updateSkillDistanceCache();
|
||||
|
||||
|
||||
@@ -80,9 +80,15 @@ export default class HeroAnmComp extends Component {
|
||||
if (this.maxPlaying) return
|
||||
this.anmcon.play(`atk0`)
|
||||
}
|
||||
max() {
|
||||
/**
|
||||
* 播放大招动画。
|
||||
* Why 带 name:技能表 act 直接配置 clip 名(战士技 "max0"、法系技 "max1"),
|
||||
* 固定播 max0 会导致法系大招动画永远播不出。
|
||||
* @param name 大招 clip 名("max0"/"max1"),maxPlaying guard 已同时覆盖两者
|
||||
*/
|
||||
max(name: string = "max0") {
|
||||
if (this.maxPlaying) return
|
||||
this.anmcon.play("max0")
|
||||
this.anmcon.play(name)
|
||||
}
|
||||
play(anm: string = "") {
|
||||
if (anm === "") return
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { HeroDisVal, HeroInfo, HSkillInfo, HType, SkillTriggerType, TriggerGrouped, LvFieldEntry, LvBonusAttrsEntry, FieldEntry, HRole } from "../common/config/heroSet";
|
||||
import { HeroDisVal, HeroInfo, HSkillInfo, HType, SkillTriggerType, TriggerGrouped, LvFieldEntry, LvBonusAttrsEntry, FieldEntry, HRole, ResolvedTriggerEntry } from "../common/config/heroSet";
|
||||
import { mLogger } from "../common/Logger";
|
||||
import { FacSet, FightSet } from "../common/config/GameSet";
|
||||
import { FieldSkillSet, FieldSkillType, SkillOverrides } from "../common/config/SkillSet";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { Attrs } from "../common/config/HeroAttrs";
|
||||
import { applyTalentBonuses, getTalentExtraTriggerChance, getTalentTriggerNumReduce } from "../common/config/TalentSet";
|
||||
import { FieldSkillHelper } from "./FieldSkillHelper";
|
||||
import { BuffComp } from "./BuffComp";
|
||||
import { BuffList, ModOp } from "../common/config/BuffSet";
|
||||
@@ -63,20 +64,26 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
|
||||
// ==================== 运行时解析缓存(按当前等级 resolve 后的有效列表) ====================
|
||||
/** 当前等级下生效的攻击触发条目(供 SkillTriggerHelper 消费) */
|
||||
runtime_atking?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[];
|
||||
runtime_atking?: ResolvedTriggerEntry[];
|
||||
/** 当前等级下生效的受击触发条目 */
|
||||
runtime_atked?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[];
|
||||
runtime_atked?: ResolvedTriggerEntry[];
|
||||
/** 当前等级下生效的召唤触发条目 */
|
||||
runtime_call?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[];
|
||||
runtime_call?: ResolvedTriggerEntry[];
|
||||
/** 当前等级下生效的死亡触发条目 */
|
||||
runtime_dead?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[];
|
||||
runtime_dead?: ResolvedTriggerEntry[];
|
||||
/** 当前等级下生效的战前触发条目 */
|
||||
runtime_fstart?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[];
|
||||
runtime_fstart?: ResolvedTriggerEntry[];
|
||||
/** 当前等级下生效的回合结束触发条目 */
|
||||
runtime_fend?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[];
|
||||
runtime_fend?: ResolvedTriggerEntry[];
|
||||
/** 当前等级下生效的驻场光环词条列表 */
|
||||
runtime_field?: FieldEntry[];
|
||||
|
||||
// ==================== 触发概率保底缓存(key: s_uuid, value: 已累积的概率增量百分点) ====================
|
||||
/** 攻击触发未命中时累积的下次概率增量(pity_add 驱动,触发成功后清零) */
|
||||
pity_atking: Record<number, number> = {};
|
||||
/** 受击触发未命中时累积的下次概率增量(pity_add 驱动,触发成功后清零) */
|
||||
pity_atked: Record<number, number> = {};
|
||||
|
||||
// ==================== 特殊属性 ====================
|
||||
critical: number = 0; // 暴击率
|
||||
critical_res: number = 0; // 暴击抗性
|
||||
@@ -101,6 +108,10 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
thorns_dmg: number = 0; // 反伤伤害(固定值,受到攻击时对攻击者造成等量伤害)
|
||||
thorns_rate: number = 0; // 反伤比例(百分点;反伤值 = 实际受到伤害 * thorns_rate / 100 + thorns_dmg)
|
||||
|
||||
// ==================== 天赋触发修正(L4/L5 写入,SkillTriggerHelper 消费) ====================
|
||||
talent_t_num_reduce: number = 0; // L4:触发类技能计数阈值减少量(下限 1 由消费端 clamp)
|
||||
talent_extra_trigger_chance: number = 0; // L5:触发类技能额外触发 1 次的概率(百分点)
|
||||
|
||||
revived_count: number = 0; // 已复活次数(从 dead 触发配置的 revive_count 限制)
|
||||
death_count: number = 0; // 本回合死亡次数(用于 dead 触发统计)
|
||||
invincible_time: number = 0;// 无敌时间
|
||||
@@ -154,6 +165,20 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
*/
|
||||
initAttrs() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 天赋统一应用入口:写入属性加成(L1-L3)与触发修正(L4/L5)。
|
||||
* Why: 收敛到属性组件单点调用,Hero.load 与局内升级重算(applyHeroLevel)不再各自 import TalentSet;
|
||||
* 触发修正必须在 runtime_* 触发缓存 resolve 之前写入,才能影响 SkillTriggerHelper 的阈值判定。
|
||||
* 调用前请确保触发修正字段已归零(升级重算路径由调用方归零,保证幂等)。
|
||||
*/
|
||||
applyTalent(): void {
|
||||
if (this.fac !== FacSet.HERO) return;
|
||||
const levels = smc.getTalentLevels();
|
||||
this.talent_t_num_reduce = getTalentTriggerNumReduce(levels, this.role);
|
||||
this.talent_extra_trigger_chance = getTalentExtraTriggerChance(levels, this.role);
|
||||
applyTalentBonuses(this, levels, this.role);
|
||||
}
|
||||
/*******************基础属性管理********************/
|
||||
|
||||
add_hp(value: number) {
|
||||
@@ -740,6 +765,9 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
this.runtime_fstart = undefined;
|
||||
this.runtime_fend = undefined;
|
||||
this.runtime_field = undefined;
|
||||
// 清空触发概率保底叠加缓存
|
||||
this.pity_atking = {};
|
||||
this.pity_atked = {};
|
||||
this.critical = 0;
|
||||
this.critical_res = 0;
|
||||
this.dodge = 0;
|
||||
@@ -765,6 +793,8 @@ export class HeroAttrsComp extends ecs.Comp {
|
||||
this.buff_power = 0;
|
||||
this.thorns_dmg = 0;
|
||||
this.thorns_rate = 0;
|
||||
this.talent_t_num_reduce = 0;
|
||||
this.talent_extra_trigger_chance = 0;
|
||||
this.boom = false;
|
||||
|
||||
// 重置技能距离缓存
|
||||
|
||||
@@ -48,14 +48,16 @@ export class HeroSpine extends Component {
|
||||
atk() {
|
||||
this.anm.atk()
|
||||
}
|
||||
max(){
|
||||
this.anm.max()
|
||||
max(name: string = "max0"){
|
||||
this.anm.max(name)
|
||||
}
|
||||
play(name:string){
|
||||
// 技能表 act 配置的是 clip 名(max0/max1),不能用全等匹配 "max"
|
||||
if(name.startsWith("max")){
|
||||
this.max(name)
|
||||
return
|
||||
}
|
||||
switch(name){
|
||||
case "max":
|
||||
this.max()
|
||||
break
|
||||
case "atk":
|
||||
this.atk()
|
||||
break
|
||||
@@ -65,7 +67,7 @@ export class HeroSpine extends Component {
|
||||
case "move":
|
||||
this.move()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
do_atked(){
|
||||
this.anm.atked()
|
||||
|
||||
@@ -487,11 +487,14 @@ export class HeroViewComp extends CCComp {
|
||||
playSkillAnm(act: string = "") {
|
||||
mLogger.log(this.debugMode, 'HeroViewComp', '[heroview] act' + act,)
|
||||
if (act === "") return;
|
||||
// 技能表大招 act 配置为 clip 名("max0"/"max1"),必须前缀匹配,
|
||||
// 全等匹配 "max" 会落空导致大招动画不播、isCastingMax 不置位
|
||||
if (act.startsWith("max")) {
|
||||
this.isCastingMax = true;
|
||||
this.as.max(act)
|
||||
return
|
||||
}
|
||||
switch (act) {
|
||||
case "max":
|
||||
this.isCastingMax = true;
|
||||
this.as.max()
|
||||
break
|
||||
case "atk":
|
||||
this.as.atk()
|
||||
break
|
||||
@@ -544,6 +547,15 @@ export class HeroViewComp extends CCComp {
|
||||
// 清理残留的定时器和缓动
|
||||
this.unscheduleAllCallbacks();
|
||||
Tween.stopAllByTarget(this.node);
|
||||
// 清理挂在节点下未播完的特效子节点(冰冻/击晕/受击等),
|
||||
// 防止对象池复用节点时把上一个单位的特效带到新单位身上。
|
||||
// 判定依据:特效由 spawnTimedFx/spawnAnimEndFx 实例化并挂 timedCom/oneCom,
|
||||
// 预制体自带子节点(anm/top 等)无这两个组件,不受影响。
|
||||
for (const child of [...this.node.children]) {
|
||||
if (child.getComponent(timedCom) || child.getComponent(oneCom)) {
|
||||
child.destroy();
|
||||
}
|
||||
}
|
||||
this.topBar.reset();
|
||||
|
||||
// 清理碰撞器事件监听
|
||||
|
||||
@@ -236,6 +236,21 @@ export class Monster extends ecs.Entity {
|
||||
if (testSkills.fstart !== undefined) model.fstart = testSkills.fstart;
|
||||
if (testSkills.call !== undefined) model.call = testSkills.call;
|
||||
}
|
||||
// Boss 大招注入:在保留普攻的基础上追加(多个大招共存,由 SCastSystem 按 CD 轮转施放,
|
||||
// 含镜头聚焦 + 技能名横幅表现,与英雄大招同一条施法链路)
|
||||
const ults = (this as any)._testSkills?.ults;
|
||||
if (ults && ults.length > 0) {
|
||||
for (const ult of ults) {
|
||||
if (!ult || !ult.s_uuid) continue;
|
||||
model.skills[ult.s_uuid] = {
|
||||
uuid: ult.s_uuid,
|
||||
cd: ult.cd ?? 8,
|
||||
lv: 1,
|
||||
ccd: 0,
|
||||
overrides: ult.overrides
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 按怪物等级 resolve 触发技能到运行时缓存(怪物无 lv 成长,恒用 mon_lv)
|
||||
model.runtime_call = resolveTriggerByLv(model.call, mon_lv);
|
||||
|
||||
@@ -56,7 +56,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
private readonly renderSortInterval = 0.05;
|
||||
private lastRenderSortAt = 0;
|
||||
private heroViewMatcher: ecs.IMatcher | null = null;
|
||||
private readonly renderEntries: { node: Node; bossPriority: number; frontScore: number; spawnOrder: number; eid: number; laneScore: number; isCastingMax: boolean }[] = [];
|
||||
private readonly renderEntries: { node: Node; spawnOrder: number; eid: number; isCastingMax: boolean }[] = [];
|
||||
private renderEntryCount = 0;
|
||||
|
||||
// ======================== 英雄编队排队 ========================
|
||||
@@ -431,8 +431,8 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
const monRoot = layerNode.getChildByName("MON");
|
||||
const bossRoot = layerNode.getChildByName("BOSS");
|
||||
|
||||
/** 分层重排同层节点:各阵营层内按 Y 轴路次 -> 前后位置 -> 出生序 -> eid 排序
|
||||
* (Boss 已有独立 BOSS 层固定在最底,无需 bossPriority 参与排序) */
|
||||
/** 分层重排同层节点:层内层级只由「是否释放大招」决定,出生序/eid 仅保证排序稳定
|
||||
* (Boss 已有独立 BOSS 层固定在最底,天然在最下层) */
|
||||
this.renderEntryCount = 0;
|
||||
ecs.query(this.getHeroViewMatcher()).forEach(e => {
|
||||
const attrs = e.get(HeroAttrsComp);
|
||||
@@ -456,20 +456,13 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
const move = e.get(MoveComp);
|
||||
const spawnOrder = move?.spawnOrder ?? 0;
|
||||
|
||||
// 按 Y 轴计算渲染层级权重(Y 越小,说明越靠近屏幕下方,应该渲染在越前面)
|
||||
const laneScore = -actorView.node.position.y;
|
||||
// X 轴权重:站在前排的(交战处)优先渲染
|
||||
const frontScore = attrs.fac === FacSet.HERO ? actorView.node.position.x : -actorView.node.position.x;
|
||||
|
||||
const entryIndex = this.renderEntryCount;
|
||||
let entry = this.renderEntries[entryIndex];
|
||||
if (!entry) {
|
||||
entry = { node: actorView.node, bossPriority: 0, frontScore: 0, spawnOrder: 0, eid: 0, laneScore: 0, isCastingMax: false };
|
||||
entry = { node: actorView.node, spawnOrder: 0, eid: 0, isCastingMax: false };
|
||||
this.renderEntries.push(entry);
|
||||
}
|
||||
entry.node = actorView.node;
|
||||
entry.laneScore = laneScore;
|
||||
entry.frontScore = frontScore;
|
||||
entry.spawnOrder = spawnOrder;
|
||||
entry.eid = e.eid;
|
||||
entry.isCastingMax = actorView.isCastingMax;
|
||||
@@ -478,11 +471,9 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
this.renderEntries.length = this.renderEntryCount;
|
||||
|
||||
this.renderEntries.sort((a, b) => {
|
||||
// 正在播放大招的英雄排在最后,siblingIndex 越大渲染层级越靠上
|
||||
// 层级只受大招影响:正在播放大招的单位排在最后,siblingIndex 越大渲染层级越靠上
|
||||
if (a.isCastingMax !== b.isCastingMax) return a.isCastingMax ? 1 : -1;
|
||||
// Y轴靠下的(laneScore 较大)应该在后面,从而渲染在上面
|
||||
if (Math.abs(a.laneScore - b.laneScore) > 10) return a.laneScore - b.laneScore;
|
||||
if (a.frontScore !== b.frontScore) return a.frontScore - b.frontScore;
|
||||
// 与位置无关的稳定排序:出生序 -> eid
|
||||
if (a.spawnOrder !== b.spawnOrder) return a.spawnOrder - b.spawnOrder;
|
||||
return a.eid - b.eid;
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { Vec3, Prefab, instantiate, tween, Node } from "cc";
|
||||
import { Vec3, Prefab, instantiate, tween, Node, UITransform } from "cc";
|
||||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||||
import { HeroViewComp } from "./HeroViewComp";
|
||||
import { DTType, RType, SkillConfig, SkillKind, SkillSet, TGroup, SkillOverrides, mergeSkillParams } from "../common/config/SkillSet";
|
||||
import { DTType, RType, SkillConfig, SkillKind, SkillSet, SummonTMode, TGroup, SkillOverrides, mergeSkillParams } from "../common/config/SkillSet";
|
||||
import { Skill } from "../skill/Skill";
|
||||
import { SkillView } from "../skill/SkillView";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
@@ -20,6 +20,16 @@ import { BuffList } from "../common/config/BuffSet";
|
||||
import { CameraFX } from "../common/CameraFX";
|
||||
import { ScreenShake } from "../common/ScreenShake";
|
||||
|
||||
/** 召唤参数:数量 / XY 步进偏移 / 生成间隔 / 目标选择模式,均由技能 prefab 上的 SkillView 配置 */
|
||||
export interface SummonParams {
|
||||
count: number;
|
||||
x_offset: number;
|
||||
y_offset: number;
|
||||
interval: number;
|
||||
/** 多次施放的目标选择模式(同一敌人/随机敌人/避免相同敌人) */
|
||||
target_mode: SummonTMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* ==================== 自动施法系统 ====================
|
||||
*
|
||||
@@ -93,9 +103,10 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
targetEids = this.collectFriendlyTargetEids(FacSet.HERO, undefined, true); // 获取所有英雄阵营的目标
|
||||
}
|
||||
|
||||
const summonCount = this.resolveSummonCount(config);
|
||||
const cNum = summonCount > 1 ? 0 : Math.min(2, Math.max(0, Math.floor(overrides?.num ?? 0)));
|
||||
const castTimes = Math.max(summonCount, 1 + cNum);
|
||||
const summon = this.resolveSummonParams(config);
|
||||
const cNum = summon.count > 1 ? 0 : Math.min(2, Math.max(0, Math.floor(overrides?.num ?? 0)));
|
||||
const castTimes = Math.max(summon.count, 1 + cNum);
|
||||
const castInterval = this.resolveCastInterval(summon);
|
||||
|
||||
// 构造一个模拟的 HeroAttrsComp 用于数值计算,只包含基础卡牌伤害计算所需的属性
|
||||
const mockAttrs = new HeroAttrsComp();
|
||||
@@ -128,12 +139,12 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
mockAttrs.type = HType.Long; // 假定为远程,拥有较长索敌范围
|
||||
mockAttrs.dis = 2000; // 给予全屏以上的索敌范围
|
||||
|
||||
// 伪造一个 view 供找敌逻辑使用,位置为 spawnPos(random/unique 模式实时索敌也复用)
|
||||
const mockView = {
|
||||
node: { position: spawnPos }
|
||||
} as any;
|
||||
let targetPos: Vec3 | null = null;
|
||||
if (!isFriendly) {
|
||||
// 伪造一个 view 供找敌逻辑使用,位置为 spawnPos
|
||||
const mockView = {
|
||||
node: { position: spawnPos }
|
||||
} as any;
|
||||
// 获取全屏索敌范围
|
||||
const maxRange = this.resolveMaxCastRange(mockAttrs, mockAttrs.type as HType);
|
||||
const target = this.findNearestEnemyInRange(mockAttrs, mockView, maxRange);
|
||||
@@ -148,8 +159,10 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
}
|
||||
|
||||
mLogger.log(this.debugMode, "SCastSystem", `[卡牌施法] 释放技能「${config.name}」(s_uuid:${s_uuid}) rarity:${rarity} castTimes:${castTimes} targetPos:${targetPos ? `(${targetPos.x.toFixed(0)},${targetPos.y.toFixed(0)})` : "none"} isFriendly:${isFriendly}`);
|
||||
// unique 模式去重记录:本次施法序列内已锁定过的敌人 eid
|
||||
const usedTargetEids = new Set<number>();
|
||||
for (let i = 0; i < castTimes; i++) {
|
||||
// 多发/召唤按间隔错峰执行:i=0 立即,其余延迟 i*SUMMON_INTERVAL(卡牌无施法主体,用 setTimeout 并在回调内做效期校验)
|
||||
// 多发/召唤按间隔错峰执行:i=0 立即,其余延迟 i*castInterval(召唤间隔由 prefab 配置)
|
||||
const exec = () => {
|
||||
if (!smc.mission.play || smc.mission.pause) return;
|
||||
if (isFriendly) {
|
||||
@@ -158,14 +171,14 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
if (friendlyTargets.length === 0) return;
|
||||
this.applyFriendlySkillEffects(s_uuid, rarity, config, null as any, mockAttrs, friendlyTargets, spawnPos);
|
||||
} else {
|
||||
const enemyTargetPos = this.resolveRepeatCastTargetPos(targetPos, i);
|
||||
this.createSkillEntityForCard(s_uuid, rarity, mockAttrs, spawnPos, enemyTargetPos, i, overrides);
|
||||
const enemyTargetPos = this.resolveSummonCastTargetPos(config, mockAttrs, mockView, targetPos, i, summon, usedTargetEids);
|
||||
this.createSkillEntityForCard(s_uuid, rarity, mockAttrs, spawnPos, enemyTargetPos, i, overrides, summon);
|
||||
}
|
||||
};
|
||||
if (i === 0) {
|
||||
exec();
|
||||
} else {
|
||||
setTimeout(exec, i * FightSet.SUMMON_INTERVAL * 1000);
|
||||
setTimeout(exec, i * castInterval * 1000);
|
||||
}
|
||||
}
|
||||
// 施法后概率触发额外技能(proc_skill,原命中触发改为出手即判定;卡牌技能无视 CD、无施法主体)
|
||||
@@ -173,7 +186,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
}
|
||||
|
||||
/** 专用于卡牌施放的技能实体生成 */
|
||||
private createSkillEntityForCard(s_uuid: number, skillLv: number, mockAttrs: HeroAttrsComp, startPos: Vec3, targetPos: Vec3 | null, castIndex: number = 0, overrides?: SkillOverrides) {
|
||||
private createSkillEntityForCard(s_uuid: number, skillLv: number, mockAttrs: HeroAttrsComp, startPos: Vec3, targetPos: Vec3 | null, castIndex: number = 0, overrides?: SkillOverrides, summon?: SummonParams) {
|
||||
const scene = smc.map.MapView.scene;
|
||||
const parent = scene.entityLayer?.node?.getChildByName("SKILL");
|
||||
if (!parent || !targetPos) {
|
||||
@@ -182,7 +195,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
}
|
||||
|
||||
const skill = ecs.getEntity<Skill>(Skill);
|
||||
const actualStartPos = this.resolveRepeatCastStartPos(startPos, castIndex);
|
||||
const actualStartPos = this.resolveRepeatCastStartPos(startPos, castIndex, summon);
|
||||
|
||||
// 伪造一个简单的 heroView 供 Skill 初始化使用,只包含方向信息
|
||||
const mockView = {
|
||||
@@ -199,31 +212,51 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
/** 查询缓存:避免每帧重复创建 matcher */
|
||||
private heroMatcher: ecs.IMatcher | null = null;
|
||||
|
||||
/** 技能 prefab 召唤数量缓存:sp_name -> summon_count */
|
||||
private summonCountCache: Map<string, number> = new Map();
|
||||
/** 技能 prefab 召唤参数缓存:sp_name -> 召唤参数(数量/XY偏移/间隔) */
|
||||
private summonParamsCache: Map<string, SummonParams> = new Map();
|
||||
|
||||
/**
|
||||
* 解析单次施法的召唤数量。
|
||||
* 优先级:合并后配置上的 summon_count(heroSet overrides 可覆写) > prefab 上 SkillView.summon_count。
|
||||
* prefab 回退路径仅使用已缓存的资源(oops.res.get 同步命中),未加载时回退 1(单体),不引入异步等待。
|
||||
* 解析单次施法的召唤参数。
|
||||
* 数量优先级:合并后配置上的 summon_count(heroSet overrides 可覆写) > prefab 上 SkillView.summon_count;
|
||||
* XY 偏移、间隔与目标选择模式仅由 prefab 配置。
|
||||
*/
|
||||
private resolveSummonCount(config: SkillConfig): number {
|
||||
if (typeof config.summon_count === "number") {
|
||||
return Math.max(1, Math.floor(config.summon_count));
|
||||
}
|
||||
const cached = this.summonCountCache.get(config.sp_name);
|
||||
if (cached !== undefined) return cached;
|
||||
const path = `game/skill/atk/${config.sp_name}`;
|
||||
let count = 1;
|
||||
private resolveSummonParams(config: SkillConfig): SummonParams {
|
||||
const fromPrefab = this.readSummonParamsFromPrefab(config.sp_name);
|
||||
const count = typeof config.summon_count === "number"
|
||||
? Math.max(1, Math.floor(config.summon_count))
|
||||
: fromPrefab.count;
|
||||
return { count, x_offset: fromPrefab.x_offset, y_offset: fromPrefab.y_offset, interval: fromPrefab.interval, target_mode: fromPrefab.target_mode };
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取 prefab 上 SkillView 的召唤参数(带缓存)。
|
||||
* prefab 回退路径仅使用已缓存的资源(oops.res.get 同步命中),未加载时回退默认值(单体、无偏移),不引入异步等待。
|
||||
*/
|
||||
private readSummonParamsFromPrefab(sp_name: string): SummonParams {
|
||||
const cached = this.summonParamsCache.get(sp_name);
|
||||
if (cached) return cached;
|
||||
const path = `game/skill/atk/${sp_name}`;
|
||||
let params: SummonParams = { count: 1, x_offset: 0, y_offset: 0, interval: 0, target_mode: SummonTMode.same };
|
||||
const prefab = oops.res.get(path, Prefab) as Prefab | null;
|
||||
if (prefab) {
|
||||
const view = prefab.data?.getComponent(SkillView);
|
||||
if (view) {
|
||||
count = Math.max(1, Math.floor(view.summon_count));
|
||||
params = {
|
||||
count: Math.max(1, Math.floor(view.summon_count)),
|
||||
x_offset: view.summon_x_offset,
|
||||
y_offset: view.summon_y_offset,
|
||||
interval: view.summon_interval,
|
||||
target_mode: view.summon_target_mode ?? SummonTMode.same,
|
||||
};
|
||||
}
|
||||
this.summonCountCache.set(config.sp_name, count);
|
||||
this.summonParamsCache.set(sp_name, params);
|
||||
}
|
||||
return count;
|
||||
return params;
|
||||
}
|
||||
|
||||
/** 解析错峰施法间隔:召唤技能优先 prefab 配置(>0),其余场景回退全局 SUMMON_INTERVAL */
|
||||
private resolveCastInterval(summon: SummonParams): number {
|
||||
return summon.count > 1 && summon.interval > 0 ? summon.interval : FightSet.SUMMON_INTERVAL;
|
||||
}
|
||||
|
||||
/** 获取英雄查询条件(包含属性与视图组件) */
|
||||
@@ -317,18 +350,21 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
}
|
||||
}
|
||||
|
||||
const summonCount = this.resolveSummonCount(config);
|
||||
const cNum = summonCount > 1 ? 0 : Math.min(2, Math.max(0, Math.floor(overrides?.num ?? 0)));
|
||||
const castTimes = Math.max(summonCount, 1 + cNum);
|
||||
const summon = this.resolveSummonParams(config);
|
||||
const cNum = summon.count > 1 ? 0 : Math.min(2, Math.max(0, Math.floor(overrides?.num ?? 0)));
|
||||
const castTimes = Math.max(summon.count, 1 + cNum);
|
||||
const castInterval = this.resolveCastInterval(summon);
|
||||
let val = ""
|
||||
if (castTimes > 1) {
|
||||
val = "*" + castTimes.toString()
|
||||
}
|
||||
heroView.skill_name(val, s_uuid)
|
||||
mLogger.log(this.debugMode, "SCastSystem", `[触发施法] ${heroAttrs.hero_name}(uuid:${heroAttrs.hero_uuid}) 触发类型:${triggerType ?? "none"} 释放技能「${config.name}」(s_uuid:${s_uuid}) lv:${skillLv} ${isFriendly ? "友方" : "对敌"} castTimes:${castTimes}`);
|
||||
// unique 模式去重记录:本次施法序列内已锁定过的敌人 eid
|
||||
const usedTargetEids = new Set<number>();
|
||||
for (let i = 0; i < castTimes; i++) {
|
||||
if (!heroView.node || !heroView.node.isValid) return;
|
||||
// 多发/召唤按间隔错峰执行:i=0 立即,其余延迟 i*SUMMON_INTERVAL
|
||||
// 多发/召唤按间隔错峰执行:i=0 立即,其余延迟 i*castInterval(召唤间隔由 prefab 配置)
|
||||
heroView.scheduleOnce(() => {
|
||||
if (!smc.mission.play || smc.mission.pause) return;
|
||||
if (!heroView.node || !heroView.node.isValid || heroAttrs.is_dead) return;
|
||||
@@ -338,9 +374,9 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
this.applyFriendlySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, friendlyTargets, null);
|
||||
return;
|
||||
}
|
||||
const enemyTargetPos = this.resolveRepeatCastTargetPos(targetPos, i);
|
||||
this.applyEnemySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, enemyTargetPos, i, overrides);
|
||||
}, i * FightSet.SUMMON_INTERVAL);
|
||||
const enemyTargetPos = this.resolveSummonCastTargetPos(config, heroAttrs, heroView, targetPos, i, summon, usedTargetEids);
|
||||
this.applyEnemySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, enemyTargetPos, i, overrides, summon);
|
||||
}, i * castInterval);
|
||||
}
|
||||
// 施法后概率触发额外技能(proc_skill,原命中触发改为出手即判定,无视 CD)
|
||||
this.tryProcSkill(config, heroAttrs, heroView, triggerType);
|
||||
@@ -399,10 +435,11 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
|
||||
config = mergeSkillParams(config, overrides);
|
||||
|
||||
const summonCount = this.resolveSummonCount(config);
|
||||
const isSummonSkill = summonCount > 1;
|
||||
const summon = this.resolveSummonParams(config);
|
||||
const isSummonSkill = summon.count > 1;
|
||||
const cNum = isSummonSkill ? 0 : Math.min(2, Math.max(0, Math.floor(overrides?.num ?? 0)));
|
||||
const castTimes = Math.max(summonCount, 1 + cNum);
|
||||
const castTimes = Math.max(summon.count, 1 + cNum);
|
||||
const castInterval = this.resolveCastInterval(summon);
|
||||
|
||||
mLogger.log(this.debugMode, "SCastSystem", `[施法] ${heroAttrs.hero_name}(uuid:${heroAttrs.hero_uuid}) 释放技能「${config.name}」(s_uuid:${s_uuid}) lv:${skillLv} ${castPlan.isFriendly ? "友方" : "对敌"} castTimes:${castTimes}`);
|
||||
|
||||
@@ -439,12 +476,14 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
// 注意:这里仍然是基于时间的延迟,受帧率波动影响。
|
||||
// 若需精确同步,建议在动画中添加帧事件并在 HeroViewComp 中监听。
|
||||
const delay = config.ready > 0 ? config.ready : FightSet.SKILL_CAST_DELAY;
|
||||
// unique 模式去重记录:本次施法序列内已锁定过的敌人 eid
|
||||
const usedTargetEids = new Set<number>();
|
||||
|
||||
heroView.scheduleOnce(() => {
|
||||
if (!smc.mission.play || smc.mission.pause || !smc.mission.in_fight) return;
|
||||
if (!heroView.node || !heroView.node.isValid || heroAttrs.is_dead) return;
|
||||
for (let i = 0; i < castTimes; i++) {
|
||||
// 多发/召唤按间隔错峰执行:i=0 立即,其余延迟 i*SUMMON_INTERVAL
|
||||
// 多发/召唤按间隔错峰执行:i=0 立即,其余延迟 i*castInterval(召唤间隔由 prefab 配置)
|
||||
heroView.scheduleOnce(() => {
|
||||
if (!smc.mission.play || smc.mission.pause || !smc.mission.in_fight) return;
|
||||
if (!heroView.node || !heroView.node.isValid || heroAttrs.is_dead) return;
|
||||
@@ -454,9 +493,9 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
this.applyFriendlySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, friendlyTargets, null);
|
||||
return;
|
||||
}
|
||||
const enemyTargetPos = this.resolveRepeatCastTargetPos(castPlan.targetPos, i);
|
||||
this.applyEnemySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, enemyTargetPos, i, overrides);
|
||||
}, i * FightSet.SUMMON_INTERVAL);
|
||||
const enemyTargetPos = this.resolveSummonCastTargetPos(config, heroAttrs, heroView, castPlan.targetPos, i, summon, usedTargetEids);
|
||||
this.applyEnemySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, enemyTargetPos, i, overrides, summon);
|
||||
}, i * castInterval);
|
||||
}
|
||||
}, delay);
|
||||
|
||||
@@ -497,14 +536,91 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
}
|
||||
}
|
||||
|
||||
/** 多发/召唤的纵向扇形偏移档位(像素),索引按 中/上/下/上上/下下... 循环 */
|
||||
/** 多发的纵向扇形偏移档位(像素),索引按 中/上/下/上上/下下... 循环;召唤技能偏移由 prefab 配置 */
|
||||
private static readonly REPEAT_Y_OFFSETS: number[] = [0, 15, -15, 30, -30, 45, -45, 60, -60];
|
||||
|
||||
private resolveRepeatCastTargetPos(targetPos: Vec3 | null, castIndex: number): Vec3 | null {
|
||||
private resolveRepeatCastTargetPos(targetPos: Vec3 | null, castIndex: number, summon?: SummonParams): Vec3 | null {
|
||||
if (!targetPos) return null;
|
||||
const offset = SCastSystem.REPEAT_Y_OFFSETS[castIndex % SCastSystem.REPEAT_Y_OFFSETS.length];
|
||||
if (offset === 0) return targetPos;
|
||||
return new Vec3(targetPos.x, targetPos.y + offset, targetPos.z);
|
||||
const offset = this.resolveCastOffset(castIndex, summon);
|
||||
if (offset.x === 0 && offset.y === 0) return targetPos;
|
||||
return new Vec3(targetPos.x + offset.x, targetPos.y + offset.y, targetPos.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析第 castIndex 次施放的对敌目标点(召唤目标选择模式入口)。
|
||||
* - same(默认):沿用施法时锁定的目标点并按召唤偏移对称铺开(原行为);
|
||||
* - random:每次出手时从射程内敌人中随机锁定一个(错峰施放时实时索敌,目标状态最新鲜);
|
||||
* - unique:优先锁定本轮未选过的敌人,敌人不足一轮时重置去重记录再来一轮;
|
||||
* 实时索敌失败(敌人死亡/移动出射程)时回退施法时锁定的目标点,保证技能不落空。
|
||||
*/
|
||||
private resolveSummonCastTargetPos(config: SkillConfig, heroAttrs: HeroAttrsComp, heroView: HeroViewComp | null, baseTargetPos: Vec3 | null, castIndex: number, summon: SummonParams | undefined, usedEids: Set<number>): Vec3 | null {
|
||||
if (!summon || summon.count <= 1 || summon.target_mode === SummonTMode.same) {
|
||||
return this.resolveRepeatCastTargetPos(baseTargetPos, castIndex, summon);
|
||||
}
|
||||
const maxRange = this.resolveMaxCastRange(heroAttrs, heroAttrs.type as HType);
|
||||
const enemies = this.collectEnemiesInRange(heroAttrs, heroView, maxRange);
|
||||
const picked = enemies.length > 0 ? this.pickEnemyByTargetMode(enemies, summon.target_mode, usedEids) : null;
|
||||
if (picked?.node) {
|
||||
mLogger.log(this.debugMode, "SCastSystem", `[召唤索敌] 「${config.name}」第${castIndex + 1}个实体锁定目标 eid:${picked.ent?.eid} 模式:${SummonTMode[summon.target_mode]}`);
|
||||
// 与 resolveEnemyCastTargetPos 保持一致:贝塞尔取脚底原始坐标,其余补半身高命中身体中心
|
||||
const pos = config.RType === RType.bezier ? picked.node.position.clone() : this.buildEnemyCastTargetPos(picked);
|
||||
// 召唤偏移铺开仍生效:random 模式重复锁定同一敌人时,避免实体完全重叠
|
||||
const offset = this.resolveCastOffset(castIndex, summon);
|
||||
pos.x += offset.x;
|
||||
pos.y += offset.y;
|
||||
return pos;
|
||||
}
|
||||
// 实时索敌失败:回退施法时锁定的目标点
|
||||
return this.resolveRepeatCastTargetPos(baseTargetPos, castIndex, summon);
|
||||
}
|
||||
|
||||
/** 按目标模式从射程内候选敌人中挑选本次施放的锁定目标,并写入去重记录 */
|
||||
private pickEnemyByTargetMode(enemies: HeroViewComp[], mode: SummonTMode, usedEids: Set<number>): HeroViewComp | null {
|
||||
let pool = enemies;
|
||||
if (mode === SummonTMode.unique) {
|
||||
const unused = enemies.filter(view => !view.ent || !usedEids.has(view.ent.eid));
|
||||
if (unused.length > 0) {
|
||||
pool = unused;
|
||||
} else {
|
||||
// 敌人不足一轮:重置已选记录,重新开始去重,保证尽量分散
|
||||
usedEids.clear();
|
||||
}
|
||||
}
|
||||
const picked = pool[Math.floor(Math.random() * pool.length)];
|
||||
if (picked?.ent) usedEids.add(picked.ent.eid);
|
||||
return picked ?? null;
|
||||
}
|
||||
|
||||
/** 收集施法者射程内的全部敌方目标(随机/去重目标模式实时索敌用),网格遍历与 findNearestEnemyByGrid 同源 */
|
||||
private collectEnemiesInRange(heroAttrs: HeroAttrsComp, heroView: HeroViewComp | null, maxRange: number): HeroViewComp[] {
|
||||
const result: HeroViewComp[] = [];
|
||||
if (!heroView?.node) return result;
|
||||
const grid = heroAttrs.fac === FacSet.HERO ? smc.mission.monGrid : smc.mission.heroGrid;
|
||||
const currentX = heroView.node.position.x;
|
||||
for (const eid of grid) {
|
||||
if (eid < 0) continue;
|
||||
const entity = ecs.getEntityByEid(eid);
|
||||
if (!entity) continue;
|
||||
const model = entity.get(HeroAttrsComp);
|
||||
const view = entity.get(HeroViewComp);
|
||||
if (!model || model.is_dead || model.is_reviving || !view?.node) continue;
|
||||
if (Math.abs(currentX - view.node.position.x) <= maxRange) {
|
||||
result.push(view);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 解析第 castIndex 个实体的偏移:召唤技能按 prefab 配置对称交替铺开(0, +1, -1, +2, -2... 档 × 步进值);多发回落纵向扇形档位 */
|
||||
private resolveCastOffset(castIndex: number, summon?: SummonParams): { x: number; y: number } {
|
||||
if (summon && summon.count > 1) {
|
||||
// 对称交替:偶数索引(>=2)取负档,奇数索引取正档,使召唤物以原点为中心向两侧展开
|
||||
const level = Math.ceil(castIndex / 2);
|
||||
const sign = castIndex % 2 === 0 ? -1 : 1;
|
||||
const factor = castIndex === 0 ? 0 : sign * level;
|
||||
return { x: factor * summon.x_offset, y: factor * summon.y_offset };
|
||||
}
|
||||
return { x: 0, y: SCastSystem.REPEAT_Y_OFFSETS[castIndex % SCastSystem.REPEAT_Y_OFFSETS.length] };
|
||||
}
|
||||
|
||||
/** 构建技能尝试顺序:优先主动技能,其次普攻 */
|
||||
@@ -518,12 +634,12 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
* 创建技能实体(投射物/范围体等)。
|
||||
* 仅用于对敌伤害技能的实体化表现与碰撞伤害分发。
|
||||
*/
|
||||
private createSkillEntity(s_uuid: number, skillLv: number, caster: HeroViewComp, cAttrsComp: HeroAttrsComp, targetPos: Vec3, castIndex: number = 0, overrides?: SkillOverrides) {
|
||||
private createSkillEntity(s_uuid: number, skillLv: number, caster: HeroViewComp, cAttrsComp: HeroAttrsComp, targetPos: Vec3, castIndex: number = 0, overrides?: SkillOverrides, summon?: SummonParams) {
|
||||
if (!caster.node || !caster.node.isValid) return;
|
||||
const parent = caster.node.parent;
|
||||
if (!parent) return;
|
||||
const skill = ecs.getEntity<Skill>(Skill);
|
||||
const startPos = this.resolveRepeatCastStartPos(caster.node.position, castIndex);
|
||||
const startPos = this.resolveRepeatCastStartPos(caster.node.position, castIndex, summon);
|
||||
skill.load(startPos, parent, s_uuid, targetPos.clone(), caster, cAttrsComp, skillLv, 0, overrides);
|
||||
}
|
||||
|
||||
@@ -531,17 +647,17 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
* 对敌技能效果处理。
|
||||
* 当前职责:仅处理伤害技能并创建技能实体。
|
||||
*/
|
||||
private applyEnemySkillEffects(s_uuid: number, skillLv: number, config: SkillConfig, heroView: HeroViewComp, cAttrsComp: HeroAttrsComp, targetPos: Vec3 | null, castIndex: number = 0, overrides?: SkillOverrides) {
|
||||
private applyEnemySkillEffects(s_uuid: number, skillLv: number, config: SkillConfig, heroView: HeroViewComp, cAttrsComp: HeroAttrsComp, targetPos: Vec3 | null, castIndex: number = 0, overrides?: SkillOverrides, summon?: SummonParams) {
|
||||
const kind = config.kind ?? SkillKind.Damage;
|
||||
if (kind !== SkillKind.Damage) return;
|
||||
if (config.ap <= 0 || !targetPos) return;
|
||||
this.createSkillEntity(s_uuid, skillLv, heroView, cAttrsComp, targetPos, castIndex, overrides);
|
||||
this.createSkillEntity(s_uuid, skillLv, heroView, cAttrsComp, targetPos, castIndex, overrides, summon);
|
||||
}
|
||||
|
||||
private resolveRepeatCastStartPos(startPos: Readonly<Vec3>, castIndex: number): Vec3 {
|
||||
const offset = SCastSystem.REPEAT_Y_OFFSETS[castIndex % SCastSystem.REPEAT_Y_OFFSETS.length];
|
||||
if (offset === 0) return startPos.clone();
|
||||
return new Vec3(startPos.x, startPos.y + offset, startPos.z);
|
||||
private resolveRepeatCastStartPos(startPos: Readonly<Vec3>, castIndex: number, summon?: SummonParams): Vec3 {
|
||||
const offset = this.resolveCastOffset(castIndex, summon);
|
||||
if (offset.x === 0 && offset.y === 0) return startPos.clone();
|
||||
return new Vec3(startPos.x + offset.x, startPos.y + offset.y, startPos.z);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -841,7 +957,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
return nearestEnemy.node?.position.clone() ?? null;
|
||||
}
|
||||
if (config.DTType !== DTType.range) {
|
||||
return this.buildEnemyCastTargetPos(heroView, nearestEnemy, maxRange);
|
||||
return this.buildEnemyCastTargetPos(nearestEnemy);
|
||||
}
|
||||
const frontEnemy = this.findFrontEnemyInRange(heroAttrs, heroView, maxRange, nearestEnemy);
|
||||
if (!frontEnemy?.node) return null;
|
||||
@@ -855,19 +971,10 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
return heroAttrs.dis;
|
||||
}
|
||||
|
||||
/** 生成沿目标方向的施法目标坐标 */
|
||||
private buildEnemyCastTargetPos(caster: HeroViewComp, target: HeroViewComp, castRange: number): Vec3 {
|
||||
// 直接返回目标的真实坐标,保留其 Y 轴信息,确保能向目标真实所在位置发射
|
||||
// 考虑到目前角色的 y 坐标都是脚底(碰撞体底部),为了命中身体中心,给目标 y 加上高度的一半
|
||||
let halfHeight = 0;
|
||||
if (target.node) {
|
||||
const transform = target.node.getComponent('cc.UITransform') as any;
|
||||
if (transform) {
|
||||
halfHeight = transform.height / 2;
|
||||
} else {
|
||||
halfHeight = 40; // 如果没有 UITransform,给一个默认高度偏移
|
||||
}
|
||||
}
|
||||
/** 生成对敌施法目标坐标:直接返回目标的真实坐标;y 为脚底(碰撞体底部),补半身高以命中身体中心 */
|
||||
private buildEnemyCastTargetPos(target: HeroViewComp): Vec3 {
|
||||
const transform = target.node?.getComponent(UITransform);
|
||||
const halfHeight = transform ? transform.height / 2 : 40; // 无 UITransform 时给默认高度偏移
|
||||
|
||||
const pos = target.node.position.clone();
|
||||
pos.y += halfHeight;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { SkillTriggerType } from "../common/config/heroSet";
|
||||
import { ResolvedTriggerEntry, SkillTriggerType } from "../common/config/heroSet";
|
||||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||||
import { HeroViewComp } from "./HeroViewComp";
|
||||
import { FacSet } from "../common/config/GameSet";
|
||||
@@ -98,6 +98,7 @@ export class SkillTriggerHelper {
|
||||
/**
|
||||
* 处理攻击附加技能
|
||||
* 判定逻辑:依据配置中的 t_num(触发所需普攻次数),对比当前的普攻累计次数取模判定。
|
||||
* 天赋修正:L4 减少 t_num 阈值(下限 1);L5 按概率额外触发 1 次。
|
||||
*/
|
||||
private static handleAtking(model: HeroAttrsComp, view: HeroViewComp) {
|
||||
if (!model.runtime_atking || model.runtime_atking.length === 0) return;
|
||||
@@ -107,10 +108,18 @@ export class SkillTriggerHelper {
|
||||
triggerCount += FieldSkillHelper.getFieldSkillTotalValue(FieldSkillType.AtkCount);
|
||||
}
|
||||
triggerCount = Math.max(1, Math.floor(triggerCount));
|
||||
// L5 天赋:概率额外触发 1 次(与羁绊次数加成独立乘算)
|
||||
if (model.talent_extra_trigger_chance > 0 && Math.random() * 100 < model.talent_extra_trigger_chance) {
|
||||
triggerCount += 1;
|
||||
}
|
||||
// L4 天赋:减少触发所需次数(下限 1)
|
||||
const tNumReduce = model.talent_t_num_reduce;
|
||||
|
||||
model.runtime_atking.forEach(atkConfig => {
|
||||
// atk_count 代表已进行的普攻次数。当其余数刚好整除配置阈值时触发。
|
||||
if (model.atk_count > 0 && model.atk_count % atkConfig.t_num === 0) {
|
||||
const tNum = Math.max(1, atkConfig.t_num - tNumReduce);
|
||||
if (model.atk_count > 0 && model.atk_count % tNum === 0
|
||||
&& this.rollTriggerChance(model, SkillTriggerType.Atking, atkConfig)) {
|
||||
for (let i = 0; i < triggerCount; i++) {
|
||||
this.dispatchSingle(atkConfig.s_uuid, model, view, SkillTriggerType.Atking, atkConfig.overrides);
|
||||
}
|
||||
@@ -121,6 +130,7 @@ export class SkillTriggerHelper {
|
||||
/**
|
||||
* 处理受击附加技能
|
||||
* 判定逻辑:依据配置中的 t_num(触发所需受击次数),对比当前的受击累计次数取模判定。
|
||||
* 天赋修正:L4 减少 t_num 阈值(下限 1);L5 按概率额外触发 1 次。
|
||||
*/
|
||||
private static handleAtked(model: HeroAttrsComp, view: HeroViewComp) {
|
||||
if (!model.runtime_atked || model.runtime_atked.length === 0) return;
|
||||
@@ -130,10 +140,18 @@ export class SkillTriggerHelper {
|
||||
triggerCount += FieldSkillHelper.getFieldSkillTotalValue(FieldSkillType.BeAtkCount);
|
||||
}
|
||||
triggerCount = Math.max(1, Math.floor(triggerCount));
|
||||
// L5 天赋:概率额外触发 1 次(与羁绊次数加成独立乘算)
|
||||
if (model.talent_extra_trigger_chance > 0 && Math.random() * 100 < model.talent_extra_trigger_chance) {
|
||||
triggerCount += 1;
|
||||
}
|
||||
// L4 天赋:减少触发所需次数(下限 1)
|
||||
const tNumReduce = model.talent_t_num_reduce;
|
||||
|
||||
model.runtime_atked.forEach(atkConfig => {
|
||||
// atked_count 代表已承受的受击次数。当其余数刚好整除配置阈值时触发。
|
||||
if (model.atked_count > 0 && model.atked_count % atkConfig.t_num === 0) {
|
||||
const tNum = Math.max(1, atkConfig.t_num - tNumReduce);
|
||||
if (model.atked_count > 0 && model.atked_count % tNum === 0
|
||||
&& this.rollTriggerChance(model, SkillTriggerType.Atked, atkConfig)) {
|
||||
for (let i = 0; i < triggerCount; i++) {
|
||||
this.dispatchSingle(atkConfig.s_uuid, model, view, SkillTriggerType.Atked, atkConfig.overrides);
|
||||
}
|
||||
@@ -141,6 +159,31 @@ export class SkillTriggerHelper {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发概率判定 + 保底叠加(仅 Atking/Atked 消费)
|
||||
* 次数条件达成后按 t_chance(缺省 100 必触发,兼容存量配置)掷骰;
|
||||
* 未命中且配置 pity_add > 0 时,为该 s_uuid 累积下次概率增量,形成"越不触发越容易触发"的保底体验;
|
||||
* 触发成功后清空叠加,最终概率封顶 100。
|
||||
*
|
||||
* @param model 施法者属性组件(保底缓存挂载于此)
|
||||
* @param type 触发类型(决定读/写哪份保底缓存)
|
||||
* @param config 当前生效的触发条目
|
||||
* @returns 是否通过概率判定
|
||||
*/
|
||||
private static rollTriggerChance(model: HeroAttrsComp, type: SkillTriggerType, config: ResolvedTriggerEntry): boolean {
|
||||
const pityMap = type === SkillTriggerType.Atking ? model.pity_atking : model.pity_atked;
|
||||
const chance = Math.min(100, (config.t_chance ?? 100) + (pityMap[config.s_uuid] ?? 0));
|
||||
if (chance >= 100 || Math.random() * 100 < chance) {
|
||||
pityMap[config.s_uuid] = 0; // 触发成功:清空保底叠加
|
||||
return true;
|
||||
}
|
||||
const pityAdd = config.pity_add ?? 0;
|
||||
if (pityAdd > 0) {
|
||||
pityMap[config.s_uuid] = (pityMap[config.s_uuid] ?? 0) + pityAdd;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的数组型触发器处理(适用于 FStart 等无需额外判定的简单列表触发)
|
||||
*/
|
||||
|
||||
686
assets/script/game/map/HeroInfoComp.ts
Normal file
@@ -0,0 +1,686 @@
|
||||
/**
|
||||
* @file HeroInfoComp.ts
|
||||
* @description 英雄详情弹窗(UI 视图层,oops.gui 弹窗)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 展示单个英雄的详情:idle 动画、名称、AP / DEF / HP / CD、技能描述、
|
||||
* 稀有度底框、局外等级、职业、碎片数量、升级按钮、技能图标列表。
|
||||
* 2. 提供升级操作(消耗碎片提升局外等级,成功后播放升级特效)。
|
||||
* 3. 提供前后英雄切换按钮,按图鉴排序顺序循环切换(品质降序 → uuid 升序)。
|
||||
* 4. 提供关闭按钮 / 遮罩点击关闭弹窗。
|
||||
*
|
||||
* 使用(oops.gui 模块):
|
||||
* oops.gui.open(UIID.HeroInfo, { uuid: 5001 });
|
||||
*
|
||||
* 关键设计:
|
||||
* - 详情渲染逻辑与原 HerosListComp 详情面板同源(已迁移至此),
|
||||
* HerosListComp 仅保留卡片列表,点击卡片改为打开本弹窗。
|
||||
* - 前后切换按品质降序 → uuid 升序循环(与图鉴页面卡片顺序一致)。
|
||||
* - hero_icon 使用 Animation + iconVisualToken 机制防止异步加载竞态。
|
||||
*
|
||||
* 依赖:
|
||||
* - HeroInfo / HeroList(heroSet)—— 英雄静态配置与全量 UUID 列表
|
||||
* - smc.getHeroGrowth / smc.getHeroOuterLv / smc.upgradeHero —— 成长数据
|
||||
* - buildHeroSkillDesc(HeroSkillText)—— 技能描述生成器
|
||||
* - SSkillBoxComp / ChipComp / SmallTipComp —— 子组件
|
||||
*/
|
||||
import { _decorator, Animation, AnimationClip, Button, EventTouch, Label, Node, NodeEventType, Prefab, RichText, Sprite, Tween, Vec3, instantiate, resources, tween } from "cc";
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { mLogger } from "../common/Logger";
|
||||
import { HeroInfo, HeroList, SkillTriggerType, LvFieldEntry, LvTriggerEntry, TriggerGrouped, HSkillInfo, getHeroDisplayStats, LvBonusAttrsEntry } from "../common/config/heroSet";
|
||||
import { buildHeroSkillDesc } from "../common/HeroSkillText";
|
||||
import { outlineRich } from "../common/RichOutline";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { HERO_UPGRADE_NEED_FRAGMENTS, RARITY_BG_COLORS } from "../common/config/GameSet";
|
||||
import { ChipComp } from "./ChipComp";
|
||||
import { SmallTipComp } from "./SmallTipComp";
|
||||
import { SSkillBoxComp } from "./SSkillBoxComp";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
|
||||
const { property, ccclass } = _decorator;
|
||||
|
||||
/** HeroInfo 弹窗初始化参数 */
|
||||
export interface HeroInfoParams {
|
||||
/** 英雄模板 uuid */
|
||||
uuid: number;
|
||||
}
|
||||
|
||||
@ccclass('HeroInfoComp')
|
||||
@ecs.register('HeroInfoComp', false)
|
||||
export class HeroInfoComp extends CCComp {
|
||||
// ======================== 编辑器绑定节点 ========================
|
||||
|
||||
@property(Node)
|
||||
hero_icon = null!
|
||||
|
||||
@property(Node)
|
||||
ap_node = null!
|
||||
|
||||
@property(Node)
|
||||
def_node = null!
|
||||
|
||||
@property(Node)
|
||||
hp_node = null!
|
||||
|
||||
@property(Node)
|
||||
cd_node = null!
|
||||
|
||||
/** 卡牌背景底框节点(按卡池等级切换子节点显示) */
|
||||
@property(Node)
|
||||
BG_node = null!
|
||||
|
||||
@property(Node)
|
||||
info_node = null!
|
||||
|
||||
@property(Node)
|
||||
name_node = null!
|
||||
|
||||
/** 卡池等级 Label,直接显示 X */
|
||||
@property(Label)
|
||||
lv_label = null!
|
||||
|
||||
/** 职业展示节点(子节点按 HRole 枚举值命名 0~5) */
|
||||
@property(Node)
|
||||
role_node = null!
|
||||
|
||||
/** 升级按钮节点(smalltip 气泡已作为其子节点挂在下面) */
|
||||
@property(Node)
|
||||
upgrade_btn = null!
|
||||
|
||||
/** 碎片图标节点(挂载 ChipComp 用于渲染碎片图标) */
|
||||
@property(Node)
|
||||
chip_node = null!
|
||||
|
||||
/** 技能描述节点 */
|
||||
@property(Node)
|
||||
infos_node = null!
|
||||
|
||||
/** 技能图标容器节点 */
|
||||
@property(Node)
|
||||
skills_node = null!
|
||||
|
||||
/** 技能小图标预制体(根节点挂 SSkillBoxComp) */
|
||||
@property(Prefab)
|
||||
skill_icon_prefab = null!
|
||||
|
||||
/** 升级特效动画节点(内含升级效果 Animation,点击升级时从头播放) */
|
||||
@property(Node)
|
||||
upgrade_anim_node = null!
|
||||
|
||||
/** 碎片需求/总量 Label(显示 当前碎片 / 下级需求) */
|
||||
@property(Label)
|
||||
fragment_label = null!
|
||||
|
||||
/** 升级提升加成说明 RichText(展示升级后的属性提升,数值绿色高亮) */
|
||||
@property(RichText)
|
||||
upgrade_info_label = null!
|
||||
|
||||
/** 关闭按钮节点 */
|
||||
@property({ type: Node, displayName: "关闭按钮" })
|
||||
close_btn: Node = null!
|
||||
|
||||
/** 上一个英雄切换按钮节点 */
|
||||
@property({ type: Node, displayName: "上一个英雄按钮" })
|
||||
prev_btn: Node = null!
|
||||
|
||||
/** 下一个英雄切换按钮节点 */
|
||||
@property({ type: Node, displayName: "下一个英雄按钮" })
|
||||
next_btn: Node = null!
|
||||
|
||||
/** 全屏遮罩节点(点击弹窗主体以外区域关闭,可选) */
|
||||
@property({ type: Node, displayName: "遮罩节点" })
|
||||
mask_node: Node = null!
|
||||
|
||||
// ======================== 运行时状态 ========================
|
||||
|
||||
/** 当前展示的英雄模板 uuid */
|
||||
huuid: number = 0
|
||||
private iconVisualToken: number = 0
|
||||
debugMode: boolean = false
|
||||
|
||||
// ======================== 生命周期 ========================
|
||||
|
||||
protected onLoad(): void {
|
||||
// 关闭按钮点击
|
||||
if (this.close_btn && this.close_btn.isValid) {
|
||||
this.close_btn.on(NodeEventType.TOUCH_END, this.onCloseClick, this);
|
||||
}
|
||||
// 前后切换按钮
|
||||
if (this.prev_btn && this.prev_btn.isValid) {
|
||||
this.prev_btn.on(NodeEventType.TOUCH_END, this.onPrevClick, this);
|
||||
}
|
||||
if (this.next_btn && this.next_btn.isValid) {
|
||||
this.next_btn.on(NodeEventType.TOUCH_END, this.onNextClick, this);
|
||||
}
|
||||
// 遮罩点击关闭
|
||||
if (this.mask_node && this.mask_node.isValid) {
|
||||
this.mask_node.on(NodeEventType.TOUCH_END, this.onMaskClick, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* oops.gui 添加到舞台回调(框架约定入口)
|
||||
* @param params 见 HeroInfoParams
|
||||
*/
|
||||
onAdded(params: HeroInfoParams) {
|
||||
this.huuid = params?.uuid ?? 0;
|
||||
this.bindUpgradeBtn();
|
||||
if (this.upgrade_anim_node) this.upgrade_anim_node.active = false;
|
||||
if (this.huuid) {
|
||||
this.updateHeroDetail(this.huuid);
|
||||
}
|
||||
}
|
||||
|
||||
protected onEnable(): void {
|
||||
oops.message.on(GameEvent.HERO_GROWTH_UPDATE, this.onGrowthUpdate, this);
|
||||
}
|
||||
|
||||
protected onDisable(): void {
|
||||
oops.message.off(GameEvent.HERO_GROWTH_UPDATE, this.onGrowthUpdate, this);
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
super.onDestroy();
|
||||
if (this.close_btn && this.close_btn.isValid) {
|
||||
this.close_btn.off(NodeEventType.TOUCH_END, this.onCloseClick, this);
|
||||
}
|
||||
if (this.prev_btn && this.prev_btn.isValid) {
|
||||
this.prev_btn.off(NodeEventType.TOUCH_END, this.onPrevClick, this);
|
||||
}
|
||||
if (this.next_btn && this.next_btn.isValid) {
|
||||
this.next_btn.off(NodeEventType.TOUCH_END, this.onNextClick, this);
|
||||
}
|
||||
if (this.mask_node && this.mask_node.isValid) {
|
||||
this.mask_node.off(NodeEventType.TOUCH_END, this.onMaskClick, this);
|
||||
}
|
||||
if (this.upgrade_btn && this.upgrade_btn.isValid) {
|
||||
this.upgrade_btn.off(Button.EventType.CLICK, this.onUpgradeClick, this);
|
||||
}
|
||||
}
|
||||
|
||||
private onGrowthUpdate() {
|
||||
if (this.huuid) {
|
||||
this.updateHeroDetail(this.huuid);
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 按钮回调 ========================
|
||||
|
||||
/** 关闭按钮点击 */
|
||||
private onCloseClick(event: EventTouch) {
|
||||
event.propagationStopped = true;
|
||||
oops.audio.playEffect("music/button");
|
||||
this.close();
|
||||
}
|
||||
|
||||
/** 遮罩点击关闭 */
|
||||
private onMaskClick(event: EventTouch) {
|
||||
event.propagationStopped = true;
|
||||
oops.audio.playEffect("music/button");
|
||||
this.close();
|
||||
}
|
||||
|
||||
/** 关闭弹窗 */
|
||||
private close() {
|
||||
if (!this.node || !this.node.isValid || !this.node.parent) return;
|
||||
oops.gui.removeByNode(this.node);
|
||||
}
|
||||
|
||||
/** 切换到上一个英雄(按图鉴排序循环) */
|
||||
private onPrevClick(event: EventTouch) {
|
||||
event.propagationStopped = true;
|
||||
oops.audio.playEffect("music/button");
|
||||
this.switchHero(-1);
|
||||
}
|
||||
|
||||
/** 切换到下一个英雄(按图鉴排序循环) */
|
||||
private onNextClick(event: EventTouch) {
|
||||
event.propagationStopped = true;
|
||||
oops.audio.playEffect("music/button");
|
||||
this.switchHero(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按图鉴排序顺序循环切换英雄
|
||||
* @param delta 1 下一个,-1 上一个
|
||||
*/
|
||||
private switchHero(delta: 1 | -1) {
|
||||
// 与图鉴页面排序同源:按职业(HRole)升序 → uuid 升序
|
||||
const sorted = [...HeroList].sort((a, b) => {
|
||||
const heroA = HeroInfo[a];
|
||||
const heroB = HeroInfo[b];
|
||||
const roleA = heroA?.role ?? 0;
|
||||
const roleB = heroB?.role ?? 0;
|
||||
if (roleA !== roleB) return roleA - roleB;
|
||||
return a - b;
|
||||
});
|
||||
if (sorted.length === 0) return;
|
||||
const idx = sorted.indexOf(this.huuid);
|
||||
// 当前 uuid 不在列表中(异常)时回退到第一个
|
||||
const cur = idx >= 0 ? idx : 0;
|
||||
const next = (cur + delta + sorted.length) % sorted.length;
|
||||
this.huuid = sorted[next];
|
||||
this.updateHeroDetail(this.huuid);
|
||||
}
|
||||
|
||||
// ======================== 升级 ========================
|
||||
|
||||
/**
|
||||
* 绑定升级按钮点击事件
|
||||
* 在 onAdded 中调用,确保 @property 属性已正确赋值
|
||||
*/
|
||||
private bindUpgradeBtn() {
|
||||
if (!this.upgrade_btn) {
|
||||
mLogger.error(this.debugMode, "HeroInfoComp", "upgrade_btn 未绑定,请检查编辑器属性面板");
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保 smalltip 气泡初始隐藏,避免遮挡按钮触摸(组件缺失时兜底补挂)
|
||||
const tipNode = this.upgrade_btn.getChildByName("smalltip");
|
||||
if (tipNode) {
|
||||
tipNode.getComponent(SmallTipComp) ?? tipNode.addComponent(SmallTipComp);
|
||||
tipNode.active = false;
|
||||
}
|
||||
|
||||
let btn = this.upgrade_btn.getComponent(Button);
|
||||
if (!btn) btn = this.upgrade_btn.addComponent(Button);
|
||||
btn.interactable = true;
|
||||
this.upgrade_btn.off(Button.EventType.CLICK, this.onUpgradeClick, this);
|
||||
this.upgrade_btn.on(Button.EventType.CLICK, this.onUpgradeClick, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 升级按钮点击回调
|
||||
* 消耗碎片提升英雄局外等级,成功后刷新详情面板
|
||||
*/
|
||||
onUpgradeClick() {
|
||||
const uuid = this.huuid;
|
||||
if (!uuid) return;
|
||||
|
||||
this.playUpgradeBtnAnim();
|
||||
|
||||
const success = smc.upgradeHero(uuid);
|
||||
if (success) {
|
||||
mLogger.log(this.debugMode, "HeroInfoComp", `英雄 ${uuid} 升级成功`);
|
||||
this.playUpgradeAnim();
|
||||
this.updateHeroDetail(uuid);
|
||||
} else {
|
||||
const growth = smc.getHeroGrowth(uuid);
|
||||
const need = HERO_UPGRADE_NEED_FRAGMENTS[growth.lv + 1];
|
||||
// 碎片不足 / 已满级:气泡提示
|
||||
const tipText = need === undefined ? "已满级" : "碎片不足";
|
||||
this.showSmallTip(tipText);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放升级按钮按压回弹动画
|
||||
*/
|
||||
private playUpgradeBtnAnim() {
|
||||
if (!this.upgrade_btn) return;
|
||||
Tween.stopAllByTarget(this.upgrade_btn);
|
||||
this.upgrade_btn.setScale(1, 1, 1);
|
||||
tween(this.upgrade_btn)
|
||||
.to(0.08, { scale: new Vec3(0.9, 0.9, 1) }, { easing: 'quadOut' })
|
||||
.to(0.12, { scale: new Vec3(1.1, 1.1, 1) }, { easing: 'quadOut' })
|
||||
.to(0.08, { scale: new Vec3(1, 1, 1) }, { easing: 'quadIn' })
|
||||
.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放升级特效动画
|
||||
* 每次升级成功均从头播放;动画未播完时再次升级,立即重新开始
|
||||
*/
|
||||
private playUpgradeAnim() {
|
||||
if (!this.upgrade_anim_node) return;
|
||||
const anim = this.upgrade_anim_node.getComponent(Animation);
|
||||
const clip = anim?.clips?.[0];
|
||||
if (!anim || !clip) {
|
||||
mLogger.log(this.debugMode, "HeroInfoComp", "playUpgradeAnim: 缺少 Animation 组件或动画剪辑");
|
||||
return;
|
||||
}
|
||||
|
||||
this.upgrade_anim_node.active = true;
|
||||
anim.stop();
|
||||
|
||||
const animState = anim.getState(clip.name);
|
||||
if (animState) {
|
||||
animState.off('finished', this.onUpgradeAnimFinished, this);
|
||||
animState.once('finished', this.onUpgradeAnimFinished, this);
|
||||
}
|
||||
anim.play(clip.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 升级特效动画播放结束回调:隐藏特效节点
|
||||
*/
|
||||
private onUpgradeAnimFinished() {
|
||||
if (this.upgrade_anim_node && this.upgrade_anim_node.isValid) {
|
||||
this.upgrade_anim_node.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在升级按钮附近弹出 smalltip 气泡提示
|
||||
* @param text 提示文案
|
||||
*/
|
||||
private showSmallTip(text: string) {
|
||||
const tipNode = this.upgrade_btn?.getChildByName("smalltip");
|
||||
if (!tipNode || !tipNode.isValid) {
|
||||
mLogger.log(this.debugMode, "HeroInfoComp", `未在 upgrade_btn 下找到 smalltip 节点,无法提示:${text}`);
|
||||
return;
|
||||
}
|
||||
const tip = tipNode.getComponent(SmallTipComp) ?? tipNode.addComponent(SmallTipComp);
|
||||
tip.show(text);
|
||||
}
|
||||
|
||||
// ======================== 详情面板 ========================
|
||||
|
||||
private updateHeroDetail(uuid: number) {
|
||||
const hero = HeroInfo[uuid];
|
||||
if (!hero) return;
|
||||
|
||||
// 属性按当前局外等级计算
|
||||
const heroLv = Math.max(1, smc.getHeroOuterLv(uuid));
|
||||
this.setLabelText(this.name_node, hero.name || "");
|
||||
const stats = getHeroDisplayStats(hero, heroLv);
|
||||
this.setLabelText(this.ap_node, `${stats.ap}`);
|
||||
this.setLabelText(this.def_node, `${stats.def}`);
|
||||
this.setLabelText(this.hp_node, `${stats.hp}`);
|
||||
|
||||
this.updateCdDisplay(hero);
|
||||
|
||||
if (this.info_node) {
|
||||
// Label 承载:HeroSkillText 输出富文本,剥离 BBCode 标签转纯文本
|
||||
const desc = buildHeroSkillDesc(hero.uuid, true, true).replace(/<[^>]+>/g, "");
|
||||
const infoLabel = this.info_node.getChildByName("info")?.getComponent(Label)
|
||||
|| this.info_node.getComponent(Label)
|
||||
|| this.info_node.getComponentInChildren(Label);
|
||||
if (infoLabel) infoLabel.string = desc || hero.info || "";
|
||||
}
|
||||
|
||||
this.updatePoolLvBg(hero.rarity ?? 1);
|
||||
this.updateLvDisplay(uuid);
|
||||
this.updateRoleDisplay(hero);
|
||||
this.updateHeroAnimation(uuid);
|
||||
this.updateGrowthPanel(uuid);
|
||||
this.updateSkillIcons(hero);
|
||||
}
|
||||
|
||||
private updatePoolLvBg(rarity: number) {
|
||||
if (!this.BG_node) return;
|
||||
// BG_node 下直接放置颜色节点(green/blue/purple/yellow/red),按卡池等级激活对应颜色
|
||||
const color = RARITY_BG_COLORS[Math.min(rarity, 5) - 1];
|
||||
this.BG_node.children.forEach(child => {
|
||||
child.active = (child.name === color);
|
||||
});
|
||||
}
|
||||
|
||||
private updateCdDisplay(hero: typeof HeroInfo[number]) {
|
||||
if (!this.cd_node) return;
|
||||
const skillKeys = Object.keys(hero.skills);
|
||||
if (skillKeys.length === 0) return;
|
||||
const firstSkill = hero.skills[Number(skillKeys[0])];
|
||||
if (firstSkill) {
|
||||
this.setLabelText(this.cd_node, `${firstSkill.cd}s`);
|
||||
}
|
||||
}
|
||||
|
||||
private updateLvDisplay(uuid: number) {
|
||||
if (!this.lv_label) return;
|
||||
const outerLv = smc.getHeroOuterLv(uuid);
|
||||
this.lv_label.string = `${outerLv}`;
|
||||
}
|
||||
|
||||
private updateRoleDisplay(hero: typeof HeroInfo[number]) {
|
||||
if (!this.role_node) return;
|
||||
this.role_node.active = true;
|
||||
const roleStr = `${hero.role ?? 0}`;
|
||||
this.role_node.children.forEach(child => {
|
||||
child.active = (child.name === roleStr);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新局外成长面板:碎片数量与升级按钮状态
|
||||
* @param uuid 英雄模板 uuid
|
||||
*/
|
||||
private updateGrowthPanel(uuid: number) {
|
||||
const growth = smc.getHeroGrowth(uuid);
|
||||
const needFragments = HERO_UPGRADE_NEED_FRAGMENTS[growth.lv + 1];
|
||||
const isMaxLv = needFragments === undefined;
|
||||
|
||||
// 碎片数量显示:当前拥有 / 下一级所需(满级时显示 MAX)
|
||||
const fragmentText = isMaxLv
|
||||
? `${growth.fragments} / MAX`
|
||||
: `${growth.fragments} / ${needFragments}`;
|
||||
if (this.fragment_label) {
|
||||
this.fragment_label.string = fragmentText;
|
||||
}
|
||||
|
||||
// 升级提升加成说明
|
||||
this.updateUpgradeInfoLabel(uuid, growth.lv, isMaxLv);
|
||||
|
||||
// 碎片图标:使用 ChipComp 渲染英雄图标
|
||||
if (this.chip_node) {
|
||||
const chipComp = this.chip_node.getComponent(ChipComp) || this.chip_node.addComponent(ChipComp);
|
||||
chipComp.setHeroByUuid(uuid);
|
||||
}
|
||||
|
||||
// 升级按钮状态:始终可点击,碎片不足时通过气泡提示
|
||||
if (this.upgrade_btn) {
|
||||
this.upgrade_btn.active = true;
|
||||
const btnComp = this.upgrade_btn.getComponent(Button);
|
||||
if (btnComp) btnComp.interactable = true;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 技能图标列表 ========================
|
||||
|
||||
/**
|
||||
* 刷新升级提升加成说明 RichText
|
||||
* 展示口径:对比当前等级与下一等级,仅列出 AP/HP/DEF 属性差值,单行展示
|
||||
*/
|
||||
private updateUpgradeInfoLabel(uuid: number, curLv: number, isMaxLv: boolean) {
|
||||
if (!this.upgrade_info_label) return;
|
||||
const hero = HeroInfo[uuid];
|
||||
if (!hero) { this.upgrade_info_label.string = ""; return; }
|
||||
|
||||
if (isMaxLv) {
|
||||
this.upgrade_info_label.string = outlineRich("已满级");
|
||||
return;
|
||||
}
|
||||
|
||||
const nextLv = curLv + 1;
|
||||
const cur = getHeroDisplayStats(hero, curLv);
|
||||
const nxt = getHeroDisplayStats(hero, nextLv);
|
||||
|
||||
// 属性提升差值:单行展示 AP/HP/DEF,数值绿色高亮
|
||||
const parts: string[] = [];
|
||||
if (nxt.hp > cur.hp) parts.push(`生命<color=#00FF00>+${nxt.hp - cur.hp}</color>`);
|
||||
if (nxt.ap > cur.ap) parts.push(`攻击<color=#00FF00>+${nxt.ap - cur.ap}</color>`);
|
||||
if (nxt.def > cur.def) parts.push(`防御<color=#00FF00>+${nxt.def - cur.def}</color>`);
|
||||
|
||||
this.upgrade_info_label.string = parts.length > 0
|
||||
? outlineRich(`升级属性提升:${parts.join(" ")}`)
|
||||
: outlineRich(`升级至 Lv.${nextLv}`);
|
||||
}
|
||||
|
||||
/** 详情面板展示的触发技能槽位(按触发时机排序) */
|
||||
private static readonly PANEL_TRIGGER_TYPES: SkillTriggerType[] = [
|
||||
SkillTriggerType.Call,
|
||||
SkillTriggerType.FStart,
|
||||
SkillTriggerType.Atking,
|
||||
SkillTriggerType.Atked,
|
||||
SkillTriggerType.Dead,
|
||||
SkillTriggerType.FEnd,
|
||||
SkillTriggerType.Field,
|
||||
];
|
||||
|
||||
/**
|
||||
* 刷新当前英雄的技能图标列表:
|
||||
* 1. 大招:skills[1] 及以后(首个为普攻,跳过)。
|
||||
* 2. 触发技能:每个触发槽位整组视为一个技能。
|
||||
* 以局外等级为当前等级,未达解锁档的显示 locked。
|
||||
*/
|
||||
private updateSkillIcons(hero: typeof HeroInfo[number]) {
|
||||
if (!this.skills_node || !this.skill_icon_prefab) return;
|
||||
|
||||
// 清空旧图标(显式销毁,避免节点泄漏)
|
||||
for (let i = this.skills_node.children.length - 1; i >= 0; i--) {
|
||||
this.skills_node.children[i].destroy();
|
||||
}
|
||||
|
||||
const lv = Math.max(1, smc.getHeroOuterLv(hero.uuid));
|
||||
|
||||
// ---- 大招:skills[1] 及以后 ----
|
||||
Object.values(hero.skills).slice(1).forEach(hSkill => {
|
||||
const sLv = hSkill.lv_entries?.length
|
||||
? (hSkill.lv_entries.filter(e => e.lv <= lv).pop()?.s_lv ?? hSkill.lv)
|
||||
: hSkill.lv;
|
||||
this.addSkillIcon(hSkill.uuid, sLv, false, false);
|
||||
});
|
||||
|
||||
// ---- 普攻 lv2 强化档 ----
|
||||
this.addNormalLv2Icon(Object.values(hero.skills)[0], lv);
|
||||
|
||||
// ---- 触发技能 ----
|
||||
for (const type of HeroInfoComp.PANEL_TRIGGER_TYPES) {
|
||||
if (type === SkillTriggerType.Field) {
|
||||
this.addFieldGroupIcon(hero[SkillTriggerType.Field], lv);
|
||||
} else {
|
||||
this.addTriggerGroupIcon(hero[type] as TriggerGrouped | undefined, lv, type);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- bonus 档位 ----
|
||||
this.addBonusIcons(hero.bonus, lv);
|
||||
}
|
||||
|
||||
/**
|
||||
* bonus 档位图标:配置了 icon 的档位各出一个图标(追加在技能列表最末)。
|
||||
*/
|
||||
private addBonusIcons(bonus: LvBonusAttrsEntry[] | undefined, lv: number) {
|
||||
if (!bonus?.length) return;
|
||||
for (const entry of bonus) {
|
||||
if (!entry.icon) continue;
|
||||
const node = instantiate(this.skill_icon_prefab);
|
||||
node.name = `bonus_lv${entry.lv}`;
|
||||
const comp = node.getComponent(SSkillBoxComp) || node.addComponent(SSkillBoxComp);
|
||||
comp.initBonus(this.huuid, entry, lv < entry.lv);
|
||||
this.skills_node.addChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化技能小图标并初始化
|
||||
*/
|
||||
private addSkillIcon(s_uuid: number, s_lv: number, locked: boolean, isField: boolean, slot?: SkillTriggerType, isGroup: boolean = false, normalLv2: boolean = false, unlockLv?: number) {
|
||||
const node = instantiate(this.skill_icon_prefab);
|
||||
node.name = `skill_${s_uuid}`;
|
||||
const comp = node.getComponent(SSkillBoxComp) || node.addComponent(SSkillBoxComp);
|
||||
comp.initHeroSkill(s_uuid, s_lv, locked, isField, this.huuid, slot, isGroup, normalLv2, unlockLv);
|
||||
this.skills_node.addChild(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发技能槽位(call/fstart/atking/atked/dead)整组一个图标
|
||||
*/
|
||||
private addTriggerGroupIcon(grouped: TriggerGrouped | undefined, lv: number, type: SkillTriggerType) {
|
||||
if (!grouped) return;
|
||||
const keys = Object.keys(grouped).map(Number).filter(k => grouped[k]?.length);
|
||||
if (keys.length === 0) return;
|
||||
const sorted = [...grouped[keys[0]]].sort((a, b) => a.lv - b.lv);
|
||||
let active: LvTriggerEntry | undefined;
|
||||
for (const e of sorted) { if (e.lv <= lv) active = e; }
|
||||
let anyActive = !!active;
|
||||
for (const key of keys) {
|
||||
if (anyActive) break;
|
||||
for (const e of grouped[key] ?? []) {
|
||||
if (e.lv <= lv) { anyActive = true; break; }
|
||||
}
|
||||
}
|
||||
const pick = active ?? sorted[0];
|
||||
this.addSkillIcon(keys[0], pick.s_lv ?? 1, !anyActive, false, type, true, false, anyActive ? undefined : pick.lv);
|
||||
}
|
||||
|
||||
/**
|
||||
* 驻场光环槽位整组一个图标
|
||||
*/
|
||||
private addFieldGroupIcon(field: LvFieldEntry[] | undefined, lv: number) {
|
||||
if (!field?.length) return;
|
||||
const sorted = [...field].sort((a, b) => a.lv - b.lv);
|
||||
let active: LvFieldEntry | undefined;
|
||||
for (const e of sorted) { if (e.lv <= lv) active = e; }
|
||||
const pick = active ?? sorted[0];
|
||||
const firstUuid = pick.uuids[0]?.uuid;
|
||||
if (!firstUuid) return;
|
||||
this.addSkillIcon(firstUuid, 1, !active, true, SkillTriggerType.Field, true, false, active ? undefined : pick.lv);
|
||||
}
|
||||
|
||||
/**
|
||||
* 普攻 lv2+ 强化档作为独立技能图标
|
||||
*/
|
||||
private addNormalLv2Icon(normal: HSkillInfo | undefined, lv: number) {
|
||||
const entry = normal?.lv_entries?.[0];
|
||||
if (!normal || !entry) return;
|
||||
this.addSkillIcon(normal.uuid, entry.s_lv ?? 2, lv < entry.lv, false, undefined, false, true, entry.lv);
|
||||
const icon = this.skills_node.children[this.skills_node.children.length - 1];
|
||||
if (icon) icon.name = `skill_${normal.uuid}_lv2`;
|
||||
}
|
||||
|
||||
// ======================== 英雄动画 ========================
|
||||
|
||||
private updateHeroAnimation(uuid: number) {
|
||||
if (!this.hero_icon) return;
|
||||
const hero = HeroInfo[uuid];
|
||||
if (!hero) return;
|
||||
|
||||
const sprite = this.hero_icon.getComponent(Sprite) || this.hero_icon.getComponentInChildren(Sprite);
|
||||
if (sprite) sprite.spriteFrame = null;
|
||||
|
||||
const anim = this.hero_icon.getComponent(Animation) || this.hero_icon.addComponent(Animation);
|
||||
this.clearAnimationClips(anim);
|
||||
|
||||
this.iconVisualToken += 1;
|
||||
const token = this.iconVisualToken;
|
||||
const path = `game/heros/hero/${hero.path}/idle`;
|
||||
|
||||
resources.load(path, AnimationClip, (err, clip) => {
|
||||
if (err || !clip) {
|
||||
mLogger.log(this.debugMode, "HeroInfoComp", `load hero animation failed ${uuid}`, err);
|
||||
return;
|
||||
}
|
||||
if (token !== this.iconVisualToken) return;
|
||||
this.clearAnimationClips(anim);
|
||||
anim.addClip(clip);
|
||||
anim.play("idle");
|
||||
});
|
||||
}
|
||||
|
||||
private clearAnimationClips(anim: Animation) {
|
||||
const clips = anim.clips;
|
||||
if (clips && clips.length > 0) {
|
||||
for (let i = clips.length - 1; i >= 0; i--) {
|
||||
const clip = clips[i];
|
||||
if (clip) anim.removeClip(clip, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== UI 工具 ========================
|
||||
|
||||
private setLabelText(node: Node, text: string) {
|
||||
if (!node) return;
|
||||
const label = node.getComponent(Label) || node.getComponentInChildren(Label);
|
||||
if (label) {
|
||||
label.string = text;
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.node.destroy();
|
||||
}
|
||||
}
|
||||
9
assets/script/game/map/HeroInfoComp.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "16f4e273-a558-4bbe-8d0d-2c0210d9e9fe",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -1,38 +1,32 @@
|
||||
/**
|
||||
* @file HerosListComp.ts
|
||||
* @description 英雄图鉴弹出页面(UI 视图层)
|
||||
* @description 英雄图鉴页面(UI 视图层)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 以卡片列表形式展示所有可用英雄(使用 CardLiteComp 预制体)。
|
||||
* 2. 点击卡片选中英雄,右侧详情面板显示 idle 动画、名称、AP、HP、CD、技能描述。
|
||||
* 3. 支持卡池等级筛选(全部 / Lv1 / Lv2 / Lv3)。
|
||||
* 2. 点击卡片打开英雄详情弹窗(UIID.HeroInfo),详情/升级在 HeroInfoComp 中处理。
|
||||
* 3. 卡片排序:仅按品质降序 → uuid 升序(与养成进度解耦,保持展示稳定)。
|
||||
*
|
||||
* 关键设计:
|
||||
* - cards_node 为卡片容器,通过 instantiate(card_lite_prefab) 动态生成卡片。
|
||||
* - 选中状态通过 selectNode 高亮管理,同一时间只有一张卡片高亮。
|
||||
* - hero_icon 使用 Animation + iconVisualToken 机制防止异步加载竞态。
|
||||
* - 升级/碎片变动后通过 HERO_GROWTH_UPDATE 事件统一刷新所有卡片的可升级标识。
|
||||
* - 详情面板已从本组件剥离,由 HeroInfoComp 承载。
|
||||
* - 排序不依赖 smc,仅读取静态配置(HeroInfo.rarity)。
|
||||
*
|
||||
* 依赖:
|
||||
* - HeroInfo / HeroList(heroSet)—— 英雄静态配置与全量 UUID 列表
|
||||
* - CardLiteComp —— 轻量卡片组件
|
||||
* - buildHeroSkillDesc(HeroSkillText)—— 技能描述生成器(局外等级口径)
|
||||
* - UIID.HeroInfo(oops.gui)—— 英雄详情弹窗
|
||||
*/
|
||||
import { _decorator, Animation, AnimationClip, Button, Label, Node, Prefab, RichText, Sprite, UITransform, Vec3, Widget, instantiate, resources, tween, Tween } from "cc";
|
||||
import { _decorator, Node, Prefab, UITransform, instantiate } from "cc";
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { mLogger } from "../common/Logger";
|
||||
import { HeroInfo, HeroList, SkillTriggerType, LvFieldEntry, LvTriggerEntry, TriggerGrouped, HSkillInfo, getHeroDisplayStats, LvBonusAttrsEntry } from "../common/config/heroSet";
|
||||
import { buildHeroSkillDesc } from "../common/HeroSkillText";
|
||||
import { outlineRich } from "../common/RichOutline";
|
||||
import { HeroInfo, HeroList } from "../common/config/heroSet";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { HERO_UPGRADE_NEED_FRAGMENTS, RARITY_BG_COLORS } from "../common/config/GameSet";
|
||||
import { canHeroUpgrade } from "../common/config/heroUpSet";
|
||||
import { UIID } from "../common/config/GameUIConfig";
|
||||
import { CardLiteComp } from "./CardLiteComp";
|
||||
import { ChipComp } from "./ChipComp";
|
||||
import { SmallTipComp } from "./SmallTipComp";
|
||||
import { SSkillBoxComp } from "./SSkillBoxComp";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
|
||||
const { property, ccclass } = _decorator;
|
||||
|
||||
@@ -41,149 +35,53 @@ const { property, ccclass } = _decorator;
|
||||
export class HerosListComp extends CCComp {
|
||||
// ======================== 编辑器绑定节点 ========================
|
||||
|
||||
@property(Node)
|
||||
hero_icon = null!
|
||||
|
||||
@property(Node)
|
||||
ap_node = null!
|
||||
|
||||
@property(Node)
|
||||
def_node = null!
|
||||
|
||||
@property(Node)
|
||||
hp_node = null!
|
||||
|
||||
@property(Node)
|
||||
cd_node = null!
|
||||
|
||||
/** 卡牌背景底框节点(按卡池等级切换子节点显示) */
|
||||
@property(Node)
|
||||
BG_node = null!
|
||||
|
||||
@property(Node)
|
||||
info_node = null!
|
||||
|
||||
@property(Node)
|
||||
name_node = null!
|
||||
|
||||
@property(Node)
|
||||
cards_node = null!
|
||||
|
||||
@property(Prefab)
|
||||
card_lite_prefab = null!
|
||||
|
||||
/** 卡池等级 Label,直接显示 X */
|
||||
@property(Label)
|
||||
lv_label = null!
|
||||
|
||||
/** 职业展示节点(子节点按 HRole 枚举值命名 0~5:0=坦克 1=战士 2=刺客 3=射手 4=法师 5=辅助) */
|
||||
@property(Node)
|
||||
role_node = null!
|
||||
|
||||
/** 升级按钮节点(smalltip 气泡已作为其子节点挂在下面) */
|
||||
@property(Node)
|
||||
upgrade_btn = null!
|
||||
|
||||
/** 碎片数量显示节点(Label) */
|
||||
@property(Node)
|
||||
fragment_node = null!
|
||||
|
||||
/** 碎片图标节点(挂载 ChipComp 用于渲染碎片图标) */
|
||||
@property(Node)
|
||||
chip_node = null!
|
||||
|
||||
/** 技能描述节点() */
|
||||
@property(Node)
|
||||
infos_node = null!
|
||||
|
||||
/** 技能图标容器节点(动态挂载 SSkillBoxComp 实例,展示当前英雄技能) */
|
||||
@property(Node)
|
||||
skills_node = null!
|
||||
|
||||
/** 技能小图标预制体(根节点挂 SSkillBoxComp) */
|
||||
@property(Prefab)
|
||||
skill_icon_prefab = null!
|
||||
/** 升级特效动画节点(内含升级效果 Animation,点击升级时从头播放) */
|
||||
@property(Node)
|
||||
upgrade_anim_node = null!
|
||||
|
||||
/** 碎片需求/总量 Label(显示 当前碎片 / 下级需求) */
|
||||
@property(Label)
|
||||
fragment_label = null!
|
||||
|
||||
/** 升级提升加成说明 RichText(展示升级后的属性提升,数值绿色高亮) */
|
||||
@property(RichText)
|
||||
upgrade_info_label = null!
|
||||
|
||||
/** 卡片宽度 */
|
||||
@property
|
||||
card_w = 120
|
||||
|
||||
/** 卡片高度 */
|
||||
@property
|
||||
card_h = 200
|
||||
|
||||
/** 卡片横向间隔 */
|
||||
@property
|
||||
spacing_x = 10
|
||||
|
||||
/** 卡片纵向间隔 */
|
||||
@property
|
||||
spacing_y = 10
|
||||
|
||||
/** 每行卡片数(竖向滚动时按列排列) */
|
||||
@property
|
||||
cols = 4
|
||||
|
||||
/** 卡片左右边距 */
|
||||
@property
|
||||
margin_x = 15
|
||||
|
||||
/** 卡片上下边距 */
|
||||
@property
|
||||
margin_y = 50
|
||||
|
||||
// ======================== 运行时状态 ========================
|
||||
|
||||
huuid: number = 0
|
||||
private iconVisualToken: number = 0
|
||||
private selectNode: Node | null = null
|
||||
debugMode: boolean = false
|
||||
|
||||
start() {
|
||||
this.bindUpgradeBtn()
|
||||
this.initCardList()
|
||||
// 升级特效动画初始隐藏,点击升级时才显示播放
|
||||
if (this.upgrade_anim_node) this.upgrade_anim_node.active = false
|
||||
if (HeroList.length > 0) {
|
||||
this.onCardSelect(HeroList[0])
|
||||
}
|
||||
}
|
||||
|
||||
protected onLoad(): void {
|
||||
// onLoad 阶段属性可能尚未绑定,延迟到 start 再处理
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定升级按钮点击事件
|
||||
* 在 start 中调用,确保 @property 属性已正确赋值
|
||||
*/
|
||||
private bindUpgradeBtn() {
|
||||
mLogger.log(this.debugMode, "HerosListComp", "bindUpgradeBtn", {
|
||||
hasUpgradeBtn: !!this.upgrade_btn,
|
||||
upgradeBtnName: this.upgrade_btn?.name,
|
||||
upgradeBtnActive: this.upgrade_btn?.active,
|
||||
upgradeBtnValid: this.upgrade_btn?.isValid,
|
||||
})
|
||||
|
||||
if (!this.upgrade_btn) {
|
||||
mLogger.error(this.debugMode, "HerosListComp", "upgrade_btn 未绑定,请检查编辑器属性面板")
|
||||
return
|
||||
}
|
||||
|
||||
// 确保 smalltip 气泡初始隐藏,避免遮挡按钮触摸(组件缺失时兜底补挂)
|
||||
const tipNode = this.upgrade_btn.getChildByName("smalltip")
|
||||
if (tipNode) {
|
||||
tipNode.getComponent(SmallTipComp) ?? tipNode.addComponent(SmallTipComp)
|
||||
tipNode.active = false
|
||||
}
|
||||
|
||||
let btn = this.upgrade_btn.getComponent(Button)
|
||||
if (!btn) btn = this.upgrade_btn.addComponent(Button)
|
||||
btn.interactable = true
|
||||
this.upgrade_btn.on(Button.EventType.CLICK, this.onUpgradeClick, this)
|
||||
mLogger.log(this.debugMode, "HerosListComp", "升级按钮点击事件已绑定")
|
||||
}
|
||||
|
||||
protected onEnable(): void {
|
||||
oops.message.on(GameEvent.HERO_GROWTH_UPDATE, this.onGrowthUpdate, this)
|
||||
if (this.cards_node && this.cards_node.children.length > 0) {
|
||||
this.onCardSelect(this.huuid || HeroList[0])
|
||||
}
|
||||
// 页面隐藏期间会错过事件(战斗结算发碎片时本节点 active=false 已注销监听),
|
||||
// 重新显示时必须补刷;首次 onEnable 早于 start,卡片未创建时 forEach 空数组安全
|
||||
this.refreshAllCardsCanUp()
|
||||
}
|
||||
|
||||
protected onDisable(): void {
|
||||
@@ -191,13 +89,10 @@ export class HerosListComp extends CCComp {
|
||||
}
|
||||
|
||||
private onGrowthUpdate() {
|
||||
if (this.huuid) {
|
||||
this.updateHeroDetail(this.huuid)
|
||||
}
|
||||
this.refreshAllCardsCanUp()
|
||||
}
|
||||
|
||||
/** 升级/碎片变动后统一刷新所有卡片的可升级标识与等级数字(升级入口仅在本面板,无需卡片各自监听事件) */
|
||||
/** 升级/碎片变动后统一刷新所有卡片的可升级标识与等级数字 */
|
||||
private refreshAllCardsCanUp() {
|
||||
if (!this.cards_node) return
|
||||
this.cards_node.children.forEach(cardNode => {
|
||||
@@ -211,143 +106,22 @@ export class HerosListComp extends CCComp {
|
||||
this.node.active = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 升级按钮点击回调
|
||||
* 消耗碎片提升英雄局外等级,成功后刷新详情面板
|
||||
*/
|
||||
onUpgradeClick() {
|
||||
mLogger.log(this.debugMode, "HerosListComp", "onUpgradeClick 被触发", { huuid: this.huuid })
|
||||
|
||||
const uuid = this.huuid
|
||||
if (!uuid) return
|
||||
|
||||
// 点击动画:按压回弹
|
||||
this.playUpgradeBtnAnim()
|
||||
|
||||
const success = smc.upgradeHero(uuid)
|
||||
if (success) {
|
||||
mLogger.log(this.debugMode, "HerosListComp", `英雄 ${uuid} 升级成功`)
|
||||
this.playUpgradeAnim()
|
||||
this.updateHeroDetail(uuid)
|
||||
} else {
|
||||
const growth = smc.getHeroGrowth(uuid)
|
||||
const need = HERO_UPGRADE_NEED_FRAGMENTS[growth.lv + 1]
|
||||
mLogger.log(this.debugMode, "HerosListComp", `英雄 ${uuid} 升级失败`, {
|
||||
currentLv: growth.lv,
|
||||
fragments: growth.fragments,
|
||||
needFragments: need ?? "MAX",
|
||||
})
|
||||
// 碎片不足 / 已满级:气泡提示
|
||||
const tipText = need === undefined ? "已满级" : "碎片不足"
|
||||
this.showSmallTip(tipText)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放升级按钮按压回弹动画
|
||||
*/
|
||||
private playUpgradeBtnAnim() {
|
||||
if (!this.upgrade_btn) {
|
||||
mLogger.log(this.debugMode, "HerosListComp", "playUpgradeBtnAnim: upgrade_btn 为空")
|
||||
return
|
||||
}
|
||||
mLogger.log(this.debugMode, "HerosListComp", "播放按钮动画")
|
||||
Tween.stopAllByTarget(this.upgrade_btn)
|
||||
this.upgrade_btn.setScale(1, 1, 1)
|
||||
tween(this.upgrade_btn)
|
||||
.to(0.08, { scale: new Vec3(0.9, 0.9, 1) }, { easing: 'quadOut' })
|
||||
.to(0.12, { scale: new Vec3(1.1, 1.1, 1) }, { easing: 'quadOut' })
|
||||
.to(0.08, { scale: new Vec3(1, 1, 1) }, { easing: 'quadIn' })
|
||||
.start()
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放升级特效动画
|
||||
* 每次升级成功均从头播放;动画未播完时再次升级,立即重新开始
|
||||
*/
|
||||
private playUpgradeAnim() {
|
||||
if (!this.upgrade_anim_node) {
|
||||
mLogger.log(this.debugMode, "HerosListComp", "playUpgradeAnim: upgrade_anim_node 未绑定")
|
||||
return
|
||||
}
|
||||
const anim = this.upgrade_anim_node.getComponent(Animation)
|
||||
const clip = anim?.clips?.[0]
|
||||
if (!anim || !clip) {
|
||||
mLogger.log(this.debugMode, "HerosListComp", "playUpgradeAnim: 缺少 Animation 组件或动画剪辑")
|
||||
return
|
||||
}
|
||||
|
||||
this.upgrade_anim_node.active = true
|
||||
// 停止当前播放(如有),保证从头开始
|
||||
anim.stop()
|
||||
|
||||
const animState = anim.getState(clip.name)
|
||||
if (animState) {
|
||||
// 防止重复注册,播放结束后自动隐藏特效节点
|
||||
animState.off('finished', this.onUpgradeAnimFinished, this)
|
||||
animState.once('finished', this.onUpgradeAnimFinished, this)
|
||||
}
|
||||
anim.play(clip.name)
|
||||
}
|
||||
|
||||
/**
|
||||
* 升级特效动画播放结束回调:隐藏特效节点
|
||||
*/
|
||||
private onUpgradeAnimFinished() {
|
||||
if (this.upgrade_anim_node && this.upgrade_anim_node.isValid) {
|
||||
this.upgrade_anim_node.active = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在升级按钮附近弹出 smalltip 气泡提示
|
||||
* @param text 提示文案
|
||||
*/
|
||||
private showSmallTip(text: string) {
|
||||
// smalltip 作为 upgrade_btn 的子节点挂在下面,统一走 SmallTipComp 播动画
|
||||
const tipNode = this.upgrade_btn?.getChildByName("smalltip")
|
||||
if (!tipNode || !tipNode.isValid) {
|
||||
mLogger.log(this.debugMode, "HerosListComp", `未在 upgrade_btn 下找到 smalltip 节点,无法提示:${text}`)
|
||||
return
|
||||
}
|
||||
const tip = tipNode.getComponent(SmallTipComp) ?? tipNode.addComponent(SmallTipComp)
|
||||
tip.show(text)
|
||||
}
|
||||
|
||||
// ======================== 卡片列表 ========================
|
||||
|
||||
private initCardList() {
|
||||
mLogger.log(this.debugMode, "HerosListComp", "initCardList start", {
|
||||
hasCardsNode: !!this.cards_node,
|
||||
hasPrefab: !!this.card_lite_prefab,
|
||||
heroListLen: HeroList.length,
|
||||
})
|
||||
|
||||
if (!this.cards_node || !this.card_lite_prefab) return
|
||||
|
||||
mLogger.log(this.debugMode, "HerosListComp", "cards_node info", {
|
||||
name: this.cards_node.name,
|
||||
active: this.cards_node.active,
|
||||
childrenCount: this.cards_node.children.length,
|
||||
pos: this.cards_node.position.toString(),
|
||||
scale: this.cards_node.scale.toString(),
|
||||
parentName: this.cards_node.parent?.name || "none",
|
||||
})
|
||||
|
||||
this.cards_node.removeAllChildren()
|
||||
|
||||
// 图鉴排序:按职业(HRole)升序 → uuid 升序(与养成进度解耦,保持展示稳定)
|
||||
const sorted = [...HeroList].sort((a, b) => {
|
||||
const ga = smc.getHeroGrowth(a)
|
||||
const gb = smc.getHeroGrowth(b)
|
||||
// 可升级的一批排在最左
|
||||
const ca = canHeroUpgrade(ga.lv, ga.fragments) ? 0 : 1
|
||||
const cb = canHeroUpgrade(gb.lv, gb.fragments) ? 0 : 1
|
||||
if (ca !== cb) return ca - cb
|
||||
// 同批内:现有等级降序优先
|
||||
if (ga.lv !== gb.lv) return gb.lv - ga.lv
|
||||
// 等级相同:品质降序(rarity 越大品质越高)
|
||||
return (HeroInfo[b]?.rarity ?? 1) - (HeroInfo[a]?.rarity ?? 1)
|
||||
});
|
||||
const heroA = HeroInfo[a];
|
||||
const heroB = HeroInfo[b];
|
||||
const roleA = heroA?.role ?? 0;
|
||||
const roleB = heroB?.role ?? 0;
|
||||
if (roleA !== roleB) return roleA - roleB;
|
||||
return a - b;
|
||||
})
|
||||
|
||||
for (const uuid of sorted) {
|
||||
const hero = HeroInfo[uuid]
|
||||
@@ -356,20 +130,12 @@ export class HerosListComp extends CCComp {
|
||||
const cardNode = instantiate(this.card_lite_prefab)
|
||||
cardNode.name = `card_${uuid}`
|
||||
|
||||
mLogger.log(this.debugMode, "HerosListComp", `card instantiated ${uuid}`, {
|
||||
cardActive: cardNode.active,
|
||||
cardPos: cardNode.position.toString(),
|
||||
cardScale: cardNode.scale.toString(),
|
||||
cardChildren: cardNode.children.map(c => c.name),
|
||||
cardWidth: cardNode.getComponent("cc.UITransform")?.width,
|
||||
cardHeight: cardNode.getComponent("cc.UITransform")?.height,
|
||||
})
|
||||
|
||||
const comp = cardNode.getComponent(CardLiteComp) || cardNode.addComponent(CardLiteComp)
|
||||
comp.setHeroByUuid(uuid)
|
||||
comp.onClickCallback = (cardComp: CardLiteComp) => {
|
||||
this.onCardSelect(uuid)
|
||||
this.highlightCard(cardNode)
|
||||
comp.onClickCallback = () => {
|
||||
// 点击卡片:打开英雄详情弹窗(详情/升级/前后切换由 HeroInfoComp 承载)
|
||||
oops.audio.playEffect("music/button");
|
||||
oops.gui.open(UIID.HeroInfo, { uuid })
|
||||
}
|
||||
|
||||
this.cards_node.addChild(cardNode)
|
||||
@@ -386,389 +152,23 @@ export class HerosListComp extends CCComp {
|
||||
const total = this.cards_node.children.length
|
||||
if (total === 0) return
|
||||
|
||||
// 宽度 = 卡片总宽 + 卡片间隔 + 左右边距
|
||||
const contentW = total * this.card_w
|
||||
+ (total - 1) * this.spacing_x
|
||||
// 竖向滚动:宽度固定(每行 cols 列),高度按行数累计
|
||||
const rows = Math.ceil(total / this.cols)
|
||||
|
||||
// 宽度 = 每行卡片总宽 + 横向间隔 + 左右边距
|
||||
const contentW = this.cols * this.card_w
|
||||
+ (this.cols - 1) * this.spacing_x
|
||||
+ this.margin_x * 2
|
||||
|
||||
const cols = 4
|
||||
const rows = Math.ceil(total / cols)
|
||||
const cardH = 200
|
||||
const spacingY = 10
|
||||
const contentH = Math.max(1000, rows * (cardH + spacingY) + 50)
|
||||
// 高度 = 行数 × 卡片高 + 纵向间隔 + 上下边距
|
||||
const contentH = rows * this.card_h
|
||||
+ (rows - 1) * this.spacing_y
|
||||
+ this.margin_y * 2
|
||||
|
||||
const uiTrans = this.cards_node.getComponent(UITransform)
|
||||
if (uiTrans) {
|
||||
uiTrans.setContentSize(contentW, contentH)
|
||||
}
|
||||
|
||||
mLogger.log(this.debugMode, "HerosListComp", "updateContentSize", {
|
||||
total, cols, rows, contentW, contentH,
|
||||
})
|
||||
}
|
||||
|
||||
private highlightCard(cardNode: Node) {
|
||||
// 取消旧选中:关闭其 active 标识节点
|
||||
if (this.selectNode) {
|
||||
this.selectNode.getComponent(CardLiteComp)?.setSelected(false)
|
||||
}
|
||||
this.selectNode = cardNode
|
||||
// 新选中:激活根节点下的 active 标识节点(替代原缩放高亮)
|
||||
cardNode.getComponent(CardLiteComp)?.setSelected(true)
|
||||
}
|
||||
|
||||
private onCardSelect(uuid: number) {
|
||||
this.huuid = uuid
|
||||
this.updateHeroDetail(uuid)
|
||||
}
|
||||
|
||||
// ======================== 详情面板 ========================
|
||||
|
||||
private updateHeroDetail(uuid: number) {
|
||||
const hero = HeroInfo[uuid]
|
||||
if (!hero) return
|
||||
|
||||
// 属性按当前局外等级计算(与技能面板 updateSkillIcons 同源,均为 getHeroOuterLv)
|
||||
const heroLv = Math.max(1, smc.getHeroOuterLv(uuid))
|
||||
this.setLabelText(this.name_node, hero.name || "")
|
||||
// 属性面板与运行时口径一致:基础值 × 品质系数 + 职业成长 + bonus + lv12 专项
|
||||
const stats = getHeroDisplayStats(hero, heroLv)
|
||||
this.setLabelText(this.ap_node, `${stats.ap}`)
|
||||
this.setLabelText(this.def_node, `${stats.def}`)
|
||||
this.setLabelText(this.hp_node, `${stats.hp}`)
|
||||
|
||||
this.updateCdDisplay(hero)
|
||||
|
||||
if (this.info_node) {
|
||||
// Label 承载:HeroSkillText 输出富文本,剥离 BBCode 标签转纯文本
|
||||
const desc = buildHeroSkillDesc(hero.uuid, true, true).replace(/<[^>]+>/g, "")
|
||||
const infoLabel = this.info_node.getChildByName("info")?.getComponent(Label)
|
||||
|| this.info_node.getComponent(Label)
|
||||
|| this.info_node.getComponentInChildren(Label)
|
||||
if (infoLabel) infoLabel.string = desc || hero.info || ""
|
||||
}
|
||||
|
||||
this.updatePoolLvBg(hero.rarity ?? 1)
|
||||
this.updateLvDisplay(uuid)
|
||||
this.updateRoleDisplay(hero)
|
||||
this.updateHeroAnimation(uuid)
|
||||
this.updateGrowthPanel(uuid)
|
||||
this.updateSkillIcons(hero)
|
||||
}
|
||||
|
||||
private updatePoolLvBg(rarity: number) {
|
||||
if (!this.BG_node) return
|
||||
// BG_node 下直接放置颜色节点(green/blue/purple/yellow/red),按卡池等级激活对应颜色
|
||||
const color = RARITY_BG_COLORS[Math.min(rarity, 5) - 1]
|
||||
this.BG_node.children.forEach(child => {
|
||||
child.active = (child.name === color)
|
||||
})
|
||||
}
|
||||
|
||||
private updateCdDisplay(hero: typeof HeroInfo[number]) {
|
||||
if (!this.cd_node) return
|
||||
const skillKeys = Object.keys(hero.skills)
|
||||
if (skillKeys.length === 0) return
|
||||
const firstSkill = hero.skills[Number(skillKeys[0])]
|
||||
if (firstSkill) {
|
||||
this.setLabelText(this.cd_node, `${firstSkill.cd}s`)
|
||||
}
|
||||
}
|
||||
|
||||
private updateLvDisplay(uuid: number) {
|
||||
if (!this.lv_label) return
|
||||
const outerLv = smc.getHeroOuterLv(uuid)
|
||||
this.lv_label.string = `${outerLv}`
|
||||
}
|
||||
|
||||
private updateRoleDisplay(hero: typeof HeroInfo[number]) {
|
||||
if (!this.role_node) return
|
||||
this.role_node.active = true
|
||||
const roleStr = `${hero.role ?? 0}`
|
||||
this.role_node.children.forEach(child => {
|
||||
child.active = (child.name === roleStr)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新局外成长面板:碎片数量与升级按钮状态
|
||||
* @param uuid 英雄模板 uuid
|
||||
*/
|
||||
private updateGrowthPanel(uuid: number) {
|
||||
const growth = smc.getHeroGrowth(uuid)
|
||||
const needFragments = HERO_UPGRADE_NEED_FRAGMENTS[growth.lv + 1]
|
||||
const isMaxLv = needFragments === undefined
|
||||
|
||||
// 碎片数量显示:当前拥有 / 下一级所需(满级时显示 MAX)
|
||||
if (this.fragment_node) {
|
||||
const fragmentText = isMaxLv
|
||||
? `${growth.fragments} / MAX`
|
||||
: `${growth.fragments} / ${needFragments}`
|
||||
this.setLabelText(this.fragment_node, fragmentText)
|
||||
}
|
||||
// 独立碎片 Label(编辑器可直接绑定 Label 组件,与 fragment_node 二选一或并存)
|
||||
if (this.fragment_label) {
|
||||
const fragmentText = isMaxLv
|
||||
? `${growth.fragments} / MAX`
|
||||
: `${growth.fragments} / ${needFragments}`
|
||||
this.fragment_label.string = fragmentText
|
||||
}
|
||||
|
||||
// 升级提升加成说明
|
||||
this.updateUpgradeInfoLabel(uuid, growth.lv, isMaxLv)
|
||||
|
||||
// 碎片图标:使用 ChipComp 渲染英雄图标(自动读取 HeroInfo 配置)
|
||||
if (this.chip_node) {
|
||||
const chipComp = this.chip_node.getComponent(ChipComp) || this.chip_node.addComponent(ChipComp)
|
||||
chipComp.setHeroByUuid(uuid)
|
||||
}
|
||||
|
||||
// 升级按钮状态:始终可点击,点击后由 onUpgradeClick 判断碎片是否足够
|
||||
// 碎片不足时按钮保持可点,通过气泡提示用户(而非禁用按钮)
|
||||
if (this.upgrade_btn) {
|
||||
this.upgrade_btn.active = true
|
||||
const btnComp = this.upgrade_btn.getComponent("cc.Button") as import("cc").Button | null
|
||||
if (btnComp) btnComp.interactable = true
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 技能图标列表 ========================
|
||||
|
||||
/**
|
||||
* 刷新升级提升加成说明 RichText
|
||||
* 展示口径:对比当前等级与下一等级,仅列出 AP/HP/DEF 属性差值,单行展示
|
||||
* 数值用绿色高亮,整体通过 outlineRich 包裹描边标签
|
||||
* @param uuid 英雄模板 uuid
|
||||
* @param curLv 当前局外等级(≥1)
|
||||
* @param isMaxLv 是否已满级
|
||||
*/
|
||||
private updateUpgradeInfoLabel(uuid: number, curLv: number, isMaxLv: boolean) {
|
||||
if (!this.upgrade_info_label) return
|
||||
const hero = HeroInfo[uuid]
|
||||
if (!hero) { this.upgrade_info_label.string = ""; return }
|
||||
|
||||
if (isMaxLv) {
|
||||
this.upgrade_info_label.string = outlineRich("已满级")
|
||||
return
|
||||
}
|
||||
|
||||
const nextLv = curLv + 1
|
||||
const cur = getHeroDisplayStats(hero, curLv)
|
||||
const nxt = getHeroDisplayStats(hero, nextLv)
|
||||
|
||||
// 属性提升差值:单行展示 AP/HP/DEF,数值绿色高亮
|
||||
const parts: string[] = []
|
||||
if (nxt.hp > cur.hp) parts.push(`生命<color=#00FF00>+${nxt.hp - cur.hp}</color>`)
|
||||
if (nxt.ap > cur.ap) parts.push(`攻击<color=#00FF00>+${nxt.ap - cur.ap}</color>`)
|
||||
if (nxt.def > cur.def) parts.push(`防御<color=#00FF00>+${nxt.def - cur.def}</color>`)
|
||||
|
||||
this.upgrade_info_label.string = parts.length > 0
|
||||
? outlineRich(`升级属性提升:${parts.join(" ")}`)
|
||||
: outlineRich(`升级至 Lv.${nextLv}`)
|
||||
}
|
||||
|
||||
/** 图鉴面板展示的触发技能槽位(按触发时机排序:召唤→回合开始→攻击后→受击后→死亡→回合结束→常驻光环) */
|
||||
private static readonly PANEL_TRIGGER_TYPES: SkillTriggerType[] = [
|
||||
SkillTriggerType.Call,
|
||||
SkillTriggerType.FStart,
|
||||
SkillTriggerType.Atking,
|
||||
SkillTriggerType.Atked,
|
||||
SkillTriggerType.Dead,
|
||||
SkillTriggerType.FEnd,
|
||||
SkillTriggerType.Field,
|
||||
]
|
||||
|
||||
/**
|
||||
* 刷新当前英雄的技能图标列表:
|
||||
* 1. 大招:skills[1] 及以后(首个为普攻,跳过)。
|
||||
* 2. 触发技能:每个触发槽位(Call/FStart/Atking/Atked/Dead/FEnd/Field)整组视为一个技能,
|
||||
* 只出一个图标,组内多技能/词条合并展示(复活已纳入 dead)。
|
||||
* 以局外等级(getHeroOuterLv)为当前等级,未达解锁档的显示 locked,
|
||||
* 已激活的显示当前等级对应的技能等级。
|
||||
*/
|
||||
private updateSkillIcons(hero: typeof HeroInfo[number]) {
|
||||
if (!this.skills_node || !this.skill_icon_prefab) return
|
||||
|
||||
// 清空旧图标(显式销毁,避免节点泄漏)
|
||||
for (let i = this.skills_node.children.length - 1; i >= 0; i--) {
|
||||
this.skills_node.children[i].destroy()
|
||||
}
|
||||
|
||||
// huuid 已在 onCardSelect 赋值,addSkillIcon 用它携带英雄语境
|
||||
const lv = Math.max(1, smc.getHeroOuterLv(hero.uuid))
|
||||
|
||||
// ---- 大招:skills[1] 及以后(英雄出场即激活,与能量条同语义,恒不锁定) ----
|
||||
Object.values(hero.skills).slice(1).forEach(hSkill => {
|
||||
// 技能等级展示与 HeroSkillText 取档同规则:lv_entries 取 ≤lv 最大档的 s_lv,无生效档回退配置 lv
|
||||
const sLv = hSkill.lv_entries?.length
|
||||
? (hSkill.lv_entries.filter(e => e.lv <= lv).pop()?.s_lv ?? hSkill.lv)
|
||||
: hSkill.lv
|
||||
this.addSkillIcon(hSkill.uuid, sLv, false, false)
|
||||
})
|
||||
|
||||
// ---- 普攻 lv2 强化档:作为独立技能图标(名称/图标取 lv1,弹窗只展示 lv2 说明) ----
|
||||
this.addNormalLv2Icon(Object.values(hero.skills)[0], lv)
|
||||
|
||||
// ---- 触发技能:每个触发槽位整组一个图标,按 PANEL_TRIGGER_TYPES 顺序追加 ----
|
||||
for (const type of HerosListComp.PANEL_TRIGGER_TYPES) {
|
||||
if (type === SkillTriggerType.Field) {
|
||||
this.addFieldGroupIcon(hero[SkillTriggerType.Field], lv)
|
||||
} else {
|
||||
this.addTriggerGroupIcon(hero[type] as TriggerGrouped | undefined, lv, type)
|
||||
}
|
||||
}
|
||||
|
||||
// ---- bonus 档位:配置了 icon 的档位在技能列表最末各出一个图标 ----
|
||||
this.addBonusIcons(hero.bonus, lv)
|
||||
}
|
||||
|
||||
/**
|
||||
* bonus 档位图标:配置了 icon 的档位各出一个图标(追加在技能列表最末)。
|
||||
* 激活判定:英雄局外等级 ≥ 档位 lv;未激活显示锁定遮罩。
|
||||
* 点击弹窗走 SinfoComp bonus 专属渲染(名称/图标取档位配置,主说明为 attrs 效果)。
|
||||
*/
|
||||
private addBonusIcons(bonus: LvBonusAttrsEntry[] | undefined, lv: number) {
|
||||
if (!bonus?.length) return
|
||||
for (const entry of bonus) {
|
||||
if (!entry.icon) continue
|
||||
const node = instantiate(this.skill_icon_prefab)
|
||||
node.name = `bonus_lv${entry.lv}`
|
||||
const comp = node.getComponent(SSkillBoxComp) || node.addComponent(SSkillBoxComp)
|
||||
comp.initBonus(this.huuid, entry, lv < entry.lv)
|
||||
this.skills_node.addChild(node)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化技能小图标并初始化
|
||||
* @param s_uuid 技能 UUID(SkillSet 或 FieldSkillSet;整组模式下取组内首个,仅用于图标)
|
||||
* @param s_lv 当前等级对应的技能等级(locked 时为解锁预览档)
|
||||
* @param locked 当前等级未激活 → 显示锁定遮罩
|
||||
* @param isField true 表示驻场光环词条(图标取 FieldSkillSet)
|
||||
* @param slot 技能所属槽位(普攻/大招传 undefined;触发/光环传对应类型,
|
||||
* 同一底座不同槽位视为不同技能,弹窗按槽位取档;复活已纳入 dead)
|
||||
* @param isGroup 整组模式:该图标代表整个触发槽位,组名取组内首个自定义名,
|
||||
* 弹窗按整组合并渲染(组内多技能/词条统一说明)
|
||||
* @param normalLv2 普攻 lv2 专属模式:该图标代表普攻 lv2 强化档,名称/图标取 lv1,
|
||||
* 弹窗只展示 lv2 档位说明
|
||||
* @param unlockLv 未激活时的解锁所需英雄等级(用于"x级解锁"展示,与技能等级 s_lv 解耦)
|
||||
*/
|
||||
private addSkillIcon(s_uuid: number, s_lv: number, locked: boolean, isField: boolean, slot?: SkillTriggerType, isGroup: boolean = false, normalLv2: boolean = false, unlockLv?: number) {
|
||||
const node = instantiate(this.skill_icon_prefab)
|
||||
node.name = `skill_${s_uuid}`
|
||||
const comp = node.getComponent(SSkillBoxComp) || node.addComponent(SSkillBoxComp)
|
||||
// 携带所属英雄与槽位,点击弹窗按英雄技能分档描述渲染
|
||||
comp.initHeroSkill(s_uuid, s_lv, locked, isField, this.huuid, slot, isGroup, normalLv2, unlockLv)
|
||||
this.skills_node.addChild(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发技能槽位(call/fstart/atking/atked/dead)整组一个图标:
|
||||
* 组内多 s_uuid 合并展示,图标/等级取组内首个 s_uuid 的生效档(未激活预览最低档);
|
||||
* 整组激活判定:组内任一 s_uuid 存在 ≤lv 生效档即视为已激活(与 resolveTriggerByLv 同语义)
|
||||
* @param type 触发槽位(随图标透传,弹窗按整组取档)
|
||||
*/
|
||||
private addTriggerGroupIcon(grouped: TriggerGrouped | undefined, lv: number, type: SkillTriggerType) {
|
||||
if (!grouped) return
|
||||
const keys = Object.keys(grouped).map(Number).filter(k => grouped[k]?.length)
|
||||
if (keys.length === 0) return
|
||||
// 图标/等级取组内首个 s_uuid 的生效档
|
||||
const sorted = [...grouped[keys[0]]].sort((a, b) => a.lv - b.lv)
|
||||
let active: LvTriggerEntry | undefined
|
||||
for (const e of sorted) { if (e.lv <= lv) active = e }
|
||||
// 整组激活判定:组内任一 s_uuid 存在生效档即激活
|
||||
let anyActive = !!active
|
||||
for (const key of keys) {
|
||||
if (anyActive) break
|
||||
for (const e of grouped[key] ?? []) {
|
||||
if (e.lv <= lv) { anyActive = true; break }
|
||||
}
|
||||
}
|
||||
const pick = active ?? sorted[0]
|
||||
this.addSkillIcon(keys[0], pick.s_lv ?? 1, !anyActive, false, type, true, false, anyActive ? undefined : pick.lv)
|
||||
}
|
||||
|
||||
/**
|
||||
* 驻场光环槽位整组一个图标:组内多词条合并展示,
|
||||
* 图标取生效档(未激活预览最低档)的首个词条
|
||||
*/
|
||||
private addFieldGroupIcon(field: LvFieldEntry[] | undefined, lv: number) {
|
||||
if (!field?.length) return
|
||||
const sorted = [...field].sort((a, b) => a.lv - b.lv)
|
||||
let active: LvFieldEntry | undefined
|
||||
for (const e of sorted) { if (e.lv <= lv) active = e }
|
||||
const pick = active ?? sorted[0]
|
||||
const firstUuid = pick.uuids[0]?.uuid
|
||||
if (!firstUuid) return
|
||||
// 词条档位无 s_lv 概念,技能等级恒为 1(等级标签展示技能等级而非解锁的英雄等级)
|
||||
this.addSkillIcon(firstUuid, 1, !active, true, SkillTriggerType.Field, true, false, active ? undefined : pick.lv)
|
||||
}
|
||||
|
||||
/** 复活技能已纳入 dead 触发组,通过 dead 配置展示(revive_hp / revive_count),无需单独处理 */
|
||||
|
||||
/**
|
||||
* 普攻 lv2+ 强化档作为独立技能图标:
|
||||
* 普攻(skills[0])lv_entries 存在档时单独出图标,名称/图标取 lv1(s_uuid 相同),
|
||||
* 等级显示偏移一档(配置 Lv2 → Lv1,SSkillBoxComp 统一处理),弹窗按 hero_normal_lv2
|
||||
* 模式只展示 lv2+ 档位说明;激活判定按档位的英雄等级(lv 阈值)。
|
||||
* Why: 普攻 lv2 档是独立成长机制(如附加暴击/冰冻),需让玩家明确感知其存在与解锁条件。
|
||||
*/
|
||||
private addNormalLv2Icon(normal: HSkillInfo | undefined, lv: number) {
|
||||
const entry = normal?.lv_entries?.[0]
|
||||
if (!normal || !entry) return
|
||||
// 节点命名区分 lv2 档(普攻与触发槽位可能同底座,uuid 重名会互相干扰)
|
||||
this.addSkillIcon(normal.uuid, entry.s_lv ?? 2, lv < entry.lv, false, undefined, false, true, entry.lv)
|
||||
const icon = this.skills_node.children[this.skills_node.children.length - 1]
|
||||
if (icon) icon.name = `skill_${normal.uuid}_lv2`
|
||||
}
|
||||
|
||||
// ======================== 英雄动画 ========================
|
||||
|
||||
private updateHeroAnimation(uuid: number) {
|
||||
if (!this.hero_icon) return
|
||||
const hero = HeroInfo[uuid]
|
||||
if (!hero) return
|
||||
|
||||
const sprite = this.hero_icon.getComponent(Sprite) || this.hero_icon.getComponentInChildren(Sprite)
|
||||
if (sprite) sprite.spriteFrame = null
|
||||
|
||||
const anim = this.hero_icon.getComponent(Animation) || this.hero_icon.addComponent(Animation)
|
||||
this.clearAnimationClips(anim)
|
||||
|
||||
this.iconVisualToken += 1
|
||||
const token = this.iconVisualToken
|
||||
const path = `game/heros/hero/${hero.path}/idle`
|
||||
|
||||
resources.load(path, AnimationClip, (err, clip) => {
|
||||
if (err || !clip) {
|
||||
mLogger.log(this.debugMode, "HerosListComp", `load hero animation failed ${uuid}`, err)
|
||||
return
|
||||
}
|
||||
if (token !== this.iconVisualToken) return
|
||||
this.clearAnimationClips(anim)
|
||||
anim.addClip(clip)
|
||||
anim.play("idle")
|
||||
})
|
||||
}
|
||||
|
||||
private clearAnimationClips(anim: Animation) {
|
||||
const clips = anim.clips
|
||||
if (clips && clips.length > 0) {
|
||||
for (let i = clips.length - 1; i >= 0; i--) {
|
||||
const clip = clips[i]
|
||||
if (clip) anim.removeClip(clip, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== UI 工具 ========================
|
||||
|
||||
private setLabelText(node: Node, text: string) {
|
||||
if (!node) return
|
||||
const label = node.getComponent(Label) || node.getComponentInChildren(Label)
|
||||
if (label) {
|
||||
label.string = text
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
|
||||
@@ -54,7 +54,6 @@ import { oops } from "db://oops-framework/core/Oops";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { HeroInfo, HType, resolveTriggerByLv, resolveFieldByLv, resolveSkillOverrides, calcGrowBonus, getHeroQualityCoef } from "../common/config/heroSet";
|
||||
import { applyTalentBonuses } from "../common/config/TalentSet";
|
||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||
import { FacSet, FightSet } from "../common/config/GameSet";
|
||||
import { MissionEconomy } from "./MissionEconomy";
|
||||
@@ -2094,13 +2093,16 @@ export class MissionCardComp extends CCComp {
|
||||
model.knockback_distance = 0;
|
||||
model.heal_power = 0;
|
||||
model.buff_power = 0;
|
||||
applyTalentBonuses(model, smc.getTalentLevels(), model.role);
|
||||
// 天赋触发修正归零(applyTalent 内部重算,保证升级重算幂等)
|
||||
model.talent_t_num_reduce = 0;
|
||||
model.talent_extra_trigger_chance = 0;
|
||||
model.applyTalent();
|
||||
}
|
||||
|
||||
// 血量按当前血线比例映射到新上限,保留升级前战斗状态
|
||||
model.hp = Math.max(1, Math.floor(model.hp_max * Math.max(0, Math.min(1, hpRate))));
|
||||
|
||||
// 重新解析触发技能/驻场光环/复活到运行时缓存(与 Hero.load 对齐)
|
||||
// 重新解析触发技能/驻场光环/复活到运行时缓存(在 applyTalent 之后,确保 L4/L5 触发修正已写入模型)
|
||||
model.runtime_call = resolveTriggerByLv(model.call, nextLv);
|
||||
model.runtime_dead = resolveTriggerByLv(model.dead, nextLv);
|
||||
model.runtime_fstart = resolveTriggerByLv(model.fstart, nextLv);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* - 第 5 节胜利 → open_Victory(final) 弹结算,确认退出并存档进下一关。
|
||||
* - cleanComponents() / clearBattlePools() 仅在整关开始/结束时执行,节间不调用。
|
||||
*/
|
||||
import { _decorator, Vec3, Animation, instantiate, Prefab, Node, NodeEventType, ProgressBar, Label, CCInteger, tween, v3, Tween, Widget, UIOpacity } from "cc";
|
||||
import { _decorator, Node, NodeEventType, Label, tween, v3, Tween, Widget, Color, Sprite, ProgressBar } from "cc";
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
@@ -31,7 +31,6 @@ import { SkillTriggerHelper } from "../hero/SkillTriggerHelper";
|
||||
import { UIID } from "../common/config/GameUIConfig";
|
||||
import { SkillView } from "../skill/SkillView";
|
||||
import { FacSet, FightSet } from "../common/config/GameSet";
|
||||
import { HeroInfo } from "../common/config/heroSet";
|
||||
import { mLogger } from "../common/Logger";
|
||||
import { Monster } from "../hero/Mon";
|
||||
import { Skill } from "../skill/Skill";
|
||||
@@ -80,8 +79,6 @@ type SettleType = "defeat" | "final";
|
||||
export class MissionComp extends CCComp {
|
||||
@property({ tooltip: "是否启用调试日志" })
|
||||
private debugMode: boolean = true;
|
||||
@property({ tooltip: "是否显示战斗内存观测面板" })
|
||||
private showMemoryPanel: boolean = false;
|
||||
|
||||
|
||||
// ======================== 配置参数 ========================
|
||||
@@ -97,6 +94,21 @@ export class MissionComp extends CCComp {
|
||||
@property(Node)
|
||||
tooltip: Node = null!
|
||||
|
||||
/** 回合指示节点(5 个,索引 0~4 对应回合 1~5),按回合进度染色 */
|
||||
@property({ type: [Node], tooltip: "回合指示节点(按回合 1~5 顺序绑定)" })
|
||||
round_nodes: Node[] = [];
|
||||
|
||||
/** 回合进度条:第 1 回合 0%,每推进一回合 +25%(第 5 回合满格) */
|
||||
@property({ type: ProgressBar, tooltip: "回合进度条(第 1 回合 0%,每回合 +25%)" })
|
||||
round_progress: ProgressBar = null!;
|
||||
|
||||
/** 回合指示:未激活(白色) */
|
||||
private static readonly ROUND_INACTIVE = new Color(255, 255, 255, 255);
|
||||
/** 回合指示:已激活(橙黄 #FFA300) */
|
||||
private static readonly ROUND_ACTIVE = new Color(255, 163, 0, 255);
|
||||
/** 回合指示:Boss 当前回合(红色) */
|
||||
private static readonly ROUND_BOSS = new Color(230, 60, 60, 255);
|
||||
|
||||
/** 阶段名称映射表(用于 UI 显示) */
|
||||
private static readonly PhaseNameMap: Record<MissionPhase, string> = {
|
||||
[MissionPhase.None]: "未开始",
|
||||
@@ -133,26 +145,6 @@ export class MissionComp extends CCComp {
|
||||
private lastTimeStr: string = "";
|
||||
/** 上一次显示的秒数(避免重复计算) */
|
||||
private lastTimeSecond: number = -1;
|
||||
/** 性能监控面板 Label 引用 */
|
||||
private memoryLabel: Label | null = null;
|
||||
/** 性能监控刷新计时器 */
|
||||
private memoryRefreshTimer: number = 0;
|
||||
/** 上一次性能文本(避免重复渲染) */
|
||||
private lastMemoryText: string = "";
|
||||
/** 帧间隔累加(用于计算平均 FPS) */
|
||||
private perfDtAcc: number = 0;
|
||||
/** 帧数计数 */
|
||||
private perfFrameCount: number = 0;
|
||||
/** 初始堆内存基准值(MB) */
|
||||
private heapBaseMB: number = -1;
|
||||
/** 堆内存峰值(MB) */
|
||||
private heapPeakMB: number = 0;
|
||||
/** 堆内存增长趋势(MB/分钟) */
|
||||
private heapTrendPerMinMB: number = 0;
|
||||
/** 趋势计算计时器 */
|
||||
private heapTrendTimer: number = 0;
|
||||
/** 趋势计算基准(MB) */
|
||||
private heapTrendBaseMB: number = -1;
|
||||
/** 怪物数量同步计时器(降低同步频率) */
|
||||
private monsterCountSyncTimer: number = 0;
|
||||
/** 当前回合数(= 当前小节号,驱动 HUD 回合/进度显示) */
|
||||
@@ -161,8 +153,6 @@ export class MissionComp extends CCComp {
|
||||
private isBossWave: boolean = false;
|
||||
/** 超时回合已在 onBattleTimeout 预扣留存分,BattleEnd 需跳过重复累加 */
|
||||
private skipRemainScoreOnBattleEnd: boolean = false;
|
||||
/** 上节清场时间快照(含清场加速还原,供评分统计) */
|
||||
private lastWaveClearTime: number = 0;
|
||||
/** 当前任务阶段 */
|
||||
public currentPhase: MissionPhase = MissionPhase.None;
|
||||
/** 是否处于回合间倒计时状态 */
|
||||
@@ -180,11 +170,9 @@ export class MissionComp extends CCComp {
|
||||
|
||||
// ======================== 关卡进度状态 ========================
|
||||
|
||||
/** 当前章节号 */
|
||||
public currentChapter: number = 1;
|
||||
/** 当前关卡号(1~10) */
|
||||
/** 当前关卡号(无限关,1~∞) */
|
||||
public currentStage: number = 1;
|
||||
/** 当前小节号(1~SECTIONS_PER_STAGE) */
|
||||
/** 当前回合号(1~SECTIONS_PER_STAGE) */
|
||||
public currentSection: number = 1;
|
||||
|
||||
// ======================== ECS 查询匹配器(预缓存) ========================
|
||||
@@ -202,7 +190,6 @@ export class MissionComp extends CCComp {
|
||||
this.heroViewMatcher = ecs.allOf(HeroViewComp);
|
||||
this.skillViewMatcher = ecs.allOf(SkillView);
|
||||
this.heroAttrsMatcher = ecs.allOf(HeroAttrsComp);
|
||||
this.showMemoryPanel = false
|
||||
// 注册生命周期事件
|
||||
this.on(GameEvent.MissionEnd, this.mission_end, this)
|
||||
this.on(GameEvent.NewWave, this.onNewWave, this)
|
||||
@@ -212,10 +199,9 @@ export class MissionComp extends CCComp {
|
||||
this.start_btn?.on(NodeEventType.TOUCH_END, this.onStartFightBtnClick, this)
|
||||
// 开局免费三选一选完后自动进入战斗
|
||||
oops.message.on("OpeningPicksDone", this.onOpeningPicksDone, this);
|
||||
this.removeMemoryPanel()
|
||||
}
|
||||
|
||||
onAdded(args: any) {
|
||||
onAdded() {
|
||||
// 使用 scheduleOnce 将事件推迟到下一帧执行,
|
||||
// 确保所有关联组件(如 MissionCardComp 等)都已经完成其 onLoad 生命周期。
|
||||
this.scheduleOnce(() => {
|
||||
@@ -370,7 +356,6 @@ export class MissionComp extends CCComp {
|
||||
this.changePhase(MissionPhase.Prepare);
|
||||
// 派发首个 SectionStart,MissionMonComp 据此生成开局怪物
|
||||
oops.message.dispatchEvent(GameEvent.SectionStart, {
|
||||
chapter: this.currentChapter,
|
||||
stage: this.currentStage,
|
||||
section: this.currentSection,
|
||||
});
|
||||
@@ -426,22 +411,20 @@ export class MissionComp extends CCComp {
|
||||
|
||||
Tween.stopAllByTarget(this.tooltip);
|
||||
|
||||
// 动感动画设计:右侧进入 -> 屏幕中央(带有轻微的弹跳和滑动) -> 左侧飞出
|
||||
// 假设屏幕宽度适配下,1200是一个足够的屏幕外距离,适配横竖屏
|
||||
const startPos = v3(1200, this.tooltip.position.y, this.tooltip.position.z);
|
||||
const centerPos = v3(0, this.tooltip.position.y, this.tooltip.position.z);
|
||||
const driftPos = v3(-50, this.tooltip.position.y, this.tooltip.position.z); // 在中央时的缓慢漂移
|
||||
const endPos = v3(-1200, this.tooltip.position.y, this.tooltip.position.z);
|
||||
|
||||
this.tooltip.setPosition(startPos);
|
||||
// 动感动画设计:原地缩放弹入(0 -> 1,带轻微回弹)-> 短暂停留 -> 收缩消失
|
||||
// 相比位移飞入飞出,缩放动画更轻快,避免横幅长时间占用屏幕
|
||||
this.tooltip.setPosition(0, this.tooltip.position.y, this.tooltip.position.z);
|
||||
this.tooltip.setScale(0, 0, 1);
|
||||
|
||||
tween(this.tooltip)
|
||||
// 1. 从右侧快速飞入并带回弹效果 (0.5秒)
|
||||
.to(0.5, { position: centerPos }, { easing: "backOut" })
|
||||
// 2. 在屏幕中央缓慢向左漂移,增强动感停留 (1.0秒)
|
||||
.to(1.0, { position: driftPos }, { easing: "sineInOut" })
|
||||
// 3. 快速向左飞出并消失 (0.4秒)
|
||||
.to(0.4, { position: endPos }, { easing: "backIn" })
|
||||
// 1. 缩放从 0 快速弹到 1.1,制造轻微"冲出来"的动感 (0.18秒)
|
||||
.to(0.18, { scale: v3(1.1, 1.1, 1) }, { easing: "sineOut" })
|
||||
// 2. 回弹收缩到标准大小 1.0 (0.1秒)
|
||||
.to(0.1, { scale: v3(1, 1, 1) }, { easing: "sineIn" })
|
||||
// 3. 停留展示 (0.5秒)
|
||||
.delay(0.5)
|
||||
// 4. 向上轻弹并收缩消失,带背入加速感 (0.2秒)
|
||||
.to(0.2, { scale: v3(0, 0, 1) }, { easing: "backIn" })
|
||||
.call(() => {
|
||||
this.tooltip.active = false;
|
||||
})
|
||||
@@ -455,7 +438,6 @@ export class MissionComp extends CCComp {
|
||||
*/
|
||||
private changePhase(targetPhase: MissionPhase) {
|
||||
if (this.currentPhase === targetPhase) return;
|
||||
const oldPhase = this.currentPhase;
|
||||
this.currentPhase = targetPhase;
|
||||
|
||||
const phaseName = MissionComp.PhaseNameMap[targetPhase] || "未知";
|
||||
@@ -556,8 +538,6 @@ export class MissionComp extends CCComp {
|
||||
// 英雄为真实死亡(实体已销毁),本节死亡数取死亡记录长度
|
||||
const heroDeathCount = smc.mission.dead_heroes.length;
|
||||
|
||||
// 快照清场时间供评分统计(onNewWave 会清零 clearTime,必须提前快照)
|
||||
this.lastWaveClearTime = this.clearTime;
|
||||
// 【评分系统 - 战绩分】记录全员存活的胜利节数(额外加分)
|
||||
if (hasHero && heroDeathCount === 0) {
|
||||
smc.vmdata.scores.wave_all_alive_count++;
|
||||
@@ -751,11 +731,11 @@ export class MissionComp extends CCComp {
|
||||
* - 胜利即 final(通关),存档推进到下一关;失败即 defeat(进度不变,可复活/再来一次)
|
||||
* - 切入 BattleEnd,2s 后由 autoNextPhase 自动弹出 VictoryComp
|
||||
*
|
||||
* @param e 事件对象(未使用)
|
||||
* @param is_hero_dead 是否因英雄全灭触发
|
||||
* @param _e 事件对象(未使用)
|
||||
* @param _is_hero_dead 是否因英雄全灭触发(当前未使用,保留签名以统一事件调用口径)
|
||||
* @param victory 是否胜利(默认 false)
|
||||
*/
|
||||
open_Victory(e: any, is_hero_dead: boolean = false, victory: boolean = false) {
|
||||
open_Victory(_e: any, _is_hero_dead: boolean = false, victory: boolean = false) {
|
||||
// 战斗结束(通关/失败),标记暂停状态以切断节间流转逻辑
|
||||
smc.mission.pause = true;
|
||||
this._victory = victory;
|
||||
@@ -765,23 +745,18 @@ export class MissionComp extends CCComp {
|
||||
// 失败:进度不变,结算窗走复活/再来一次/退出流程
|
||||
this._settleType = "defeat";
|
||||
} else {
|
||||
// 通关(Boss 节胜利):结算窗显示通关标题,确认退出并存档进下一关
|
||||
// 通关(Boss 回合胜利):无限关卡模式,存档永远推进到下一关第 1 节
|
||||
// (仅写存档,内存进度保留用于本局结算显示)
|
||||
this._settleType = "final";
|
||||
this._settleTitle = this.currentStage >= 10 ? "本章通关" : "本关通关";
|
||||
// 存档推进到下一关第 1 节(仅写存档,内存进度保留用于本局结算显示);
|
||||
// 第 10 关通关即本章全通,存档停留等待后续章节扩展
|
||||
if (this.currentStage < 10) {
|
||||
smc.updateStageProgress({
|
||||
chapter: this.currentChapter,
|
||||
stage: this.currentStage + 1,
|
||||
section: 1,
|
||||
});
|
||||
if ((smc as any).updateCloudData) {
|
||||
(smc as any).updateCloudData();
|
||||
}
|
||||
mLogger.log(this.debugMode, 'MissionComp',
|
||||
`[StageProgress] 本关通关,存档推进: ${this.currentChapter}-${this.currentStage + 1}-1`);
|
||||
this._settleTitle = "本关通关";
|
||||
smc.updateStageProgress({
|
||||
stage: this.currentStage + 1,
|
||||
});
|
||||
if ((smc as any).updateCloudData) {
|
||||
(smc as any).updateCloudData();
|
||||
}
|
||||
mLogger.log(this.debugMode, 'MissionComp',
|
||||
`[StageProgress] 本关通关,存档推进: ${this.currentStage + 1}-1`);
|
||||
}
|
||||
// 直接切入 BattleEnd,2s 后由 autoNextPhase 自动流转弹窗结算
|
||||
this.changePhase(MissionPhase.BattleEnd);
|
||||
@@ -836,20 +811,11 @@ export class MissionComp extends CCComp {
|
||||
this.currentWave = 1;
|
||||
this.isBossWave = false;
|
||||
this.skipRemainScoreOnBattleEnd = false;
|
||||
this.lastWaveClearTime = 0;
|
||||
this.updateRoundNodes();
|
||||
this.rewards = []
|
||||
this.revive_times = 1;
|
||||
this.lastTimeStr = "";
|
||||
this.lastTimeSecond = -1;
|
||||
this.memoryRefreshTimer = 0;
|
||||
this.lastMemoryText = "";
|
||||
this.perfDtAcc = 0;
|
||||
this.perfFrameCount = 0;
|
||||
this.heapBaseMB = -1;
|
||||
this.heapPeakMB = 0;
|
||||
this.heapTrendPerMinMB = 0;
|
||||
this.heapTrendTimer = 0;
|
||||
this.heapTrendBaseMB = -1;
|
||||
this.monsterCountSyncTimer = 0;
|
||||
|
||||
spawningEngine.reset();
|
||||
@@ -868,57 +834,48 @@ export class MissionComp extends CCComp {
|
||||
// ======================== 关卡进度管理 ========================
|
||||
|
||||
/**
|
||||
* 加载关卡进度存档(一关一局:只恢复大关,节恒从 1 开始)
|
||||
* 从 smc.data.stage_progress 恢复章节/大关,缺省从 1-1-1 开始
|
||||
* 加载关卡进度存档(一关一局:只恢复大关,回合恒从 1 开始)
|
||||
* 从 smc.data.stage_progress 恢复关卡号,缺省从第 1 关开始
|
||||
*/
|
||||
private loadStageProgress() {
|
||||
const progress = smc.data.stage_progress;
|
||||
if (progress && progress.chapter >= 1 && progress.stage >= 1) {
|
||||
this.currentChapter = progress.chapter;
|
||||
this.currentStage = progress.stage;
|
||||
} else {
|
||||
this.currentChapter = 1;
|
||||
this.currentStage = 1;
|
||||
}
|
||||
// 一关一局:进入关卡始终从第 1 节开打
|
||||
this.currentStage = Math.max(1, Math.floor(progress?.stage ?? 1));
|
||||
// 一关一局:进入关卡始终从第 1 回合开打
|
||||
this.currentSection = 1;
|
||||
// 加载完成后将权威进度镜像到 vmdata,驱动 HUD 实时显示
|
||||
smc.syncStageProgressToView();
|
||||
mLogger.log(this.debugMode, 'MissionComp',
|
||||
`[StageProgress] 加载进度: ${getProgressText(this.currentChapter, this.currentStage, this.currentSection)}`);
|
||||
`[StageProgress] 加载进度: ${getProgressText(this.currentStage, this.currentSection)}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 推进到下一小节(节间自动推进):
|
||||
* 1. 节号 +1,派发 SectionStart 触发 MissionMonComp 生成下一节怪物(从右侧跑入)。
|
||||
* 推进到下一回合(回合间自动推进):
|
||||
* 1. 回合号 +1,派发 SectionStart 触发 MissionMonComp 生成下一回合怪物(从右侧跑入)。
|
||||
* 2. 不清理英雄/技能实体、不重置局内数据、不重新三选一——英雄保留并自动归位(编队排队)。
|
||||
* 3. 进度实时镜像到 HUD,但不写持久存档(存档只在整关通关时推进到下一关)。
|
||||
*
|
||||
* 调用时机:PrepareStart 过场倒计时结束(autoNextPhase)。
|
||||
* 保证:仅 1~4 节清场后触发,末节(BOSS_SECTION)已走 open_Victory 结算,不会推进。
|
||||
* 保证:仅 1~4 回合清场后触发,末回合(BOSS_SECTION)已走 open_Victory 结算,不会推进。
|
||||
*/
|
||||
private advanceToNextSection() {
|
||||
this.currentSection++;
|
||||
// 节号实时同步到 HUD(内存进度,不持久化;整关通关时才统一写大关存档)。
|
||||
// 回合号实时同步到 HUD(内存进度,不持久化;整关通关时才统一写大关存档)。
|
||||
// 直接写 vmdata 视图层而非走 syncStageProgressToView(后者从 data 读,而 data 仍停留在大关起点)
|
||||
const view = smc.vmdata.stage_progress;
|
||||
view.chapter = this.currentChapter;
|
||||
view.stage = this.currentStage;
|
||||
view.section = this.currentSection;
|
||||
oops.message.dispatchEvent(GameEvent.STAGE_PROGRESS_UPDATE);
|
||||
// 触发 SectionStart 事件,MissionMonComp 据此生成下一节怪物(从右侧跑入)
|
||||
// 触发 SectionStart 事件,MissionMonComp 据此生成下一回合怪物(从右侧跑入)
|
||||
oops.message.dispatchEvent(GameEvent.SectionStart, {
|
||||
chapter: this.currentChapter,
|
||||
stage: this.currentStage,
|
||||
section: this.currentSection,
|
||||
});
|
||||
mLogger.log(this.debugMode, 'MissionComp',
|
||||
`[StageProgress] 进入小节: ${getProgressText(this.currentChapter, this.currentStage, this.currentSection)}`);
|
||||
`[StageProgress] 进入回合: ${getProgressText(this.currentStage, this.currentSection)}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重开本关:清理战场并重置数据,从本关第 1 节重新开始
|
||||
* Why: 一关一局,失败"再来一次"即整关重打(节恒从 1 开始)
|
||||
* 重开本关:清理战场并重置数据,从本关第 1 回合重新开始
|
||||
* Why: 一关一局,失败"再来一次"即整关重打(回合恒从 1 开始)
|
||||
*/
|
||||
private restartCurrentMission() {
|
||||
// 清理战场与局内数据
|
||||
@@ -929,21 +886,20 @@ export class MissionComp extends CCComp {
|
||||
this._victory = false;
|
||||
this._settleType = "defeat";
|
||||
this._settleTitle = "";
|
||||
// 一关一局:重开从第 1 节开始
|
||||
// 一关一局:重开从第 1 回合开始
|
||||
this.currentSection = 1;
|
||||
// 进入准备阶段
|
||||
this.changePhase(MissionPhase.Prepare);
|
||||
// 触发 MissionStart 重置开局免费抽卡
|
||||
oops.message.dispatchEvent(GameEvent.MissionStart, {});
|
||||
oops.message.dispatchEvent(GameEvent.FightReady);
|
||||
// 触发 SectionStart 重新生成本关第 1 节怪物
|
||||
// 触发 SectionStart 重新生成本关第 1 回合怪物
|
||||
oops.message.dispatchEvent(GameEvent.SectionStart, {
|
||||
chapter: this.currentChapter,
|
||||
stage: this.currentStage,
|
||||
section: this.currentSection,
|
||||
});
|
||||
mLogger.log(this.debugMode, 'MissionComp',
|
||||
`[StageProgress] 重开本关: ${getProgressText(this.currentChapter, this.currentStage, this.currentSection)}`);
|
||||
`[StageProgress] 重开本关: ${getProgressText(this.currentStage, this.currentSection)}`);
|
||||
}
|
||||
|
||||
// ======================== 回合管理 ========================
|
||||
@@ -959,7 +915,7 @@ export class MissionComp extends CCComp {
|
||||
* @param event 事件名
|
||||
* @param data { wave: number, bossWave?: boolean }
|
||||
*/
|
||||
private onNewWave(event: string, data: any) {
|
||||
private onNewWave(_event: string, data: any) {
|
||||
const wave = Number(data?.wave ?? 0);
|
||||
if (wave <= 0) return;
|
||||
|
||||
@@ -968,12 +924,46 @@ export class MissionComp extends CCComp {
|
||||
|
||||
this.currentWave = wave;
|
||||
smc.vmdata.mission_data.level = wave;
|
||||
this.updateRoundNodes();
|
||||
// 金币改为怪物死亡掉落(见 HeroAtkSystem),不再每回合固定发放
|
||||
this.lastTimeSecond = -1;
|
||||
this.clearTime = 0;
|
||||
this.update_time();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新回合指示节点颜色:
|
||||
* - 已激活(已完成 + 当前回合)→ 黄色;当前回合且为 Boss 节 → 红色;未激活 → 白色。
|
||||
* Why: 回合推进时(onNewWave)与开局重置(data_init)调用,驱动 HUD 回合指示实时反馈。
|
||||
*/
|
||||
private updateRoundNodes() {
|
||||
const len = Math.min(this.round_nodes.length, SECTIONS_PER_STAGE);
|
||||
for (let i = 0; i < len; i++) {
|
||||
const node = this.round_nodes[i];
|
||||
if (!node || !node.isValid) continue;
|
||||
const round = i + 1;
|
||||
const color = round > this.currentWave
|
||||
? MissionComp.ROUND_INACTIVE
|
||||
: (round === this.currentWave && this.isBossWave)
|
||||
? MissionComp.ROUND_BOSS
|
||||
: MissionComp.ROUND_ACTIVE;
|
||||
// 优先染色 Sprite(图标配色),无 Sprite 时退化到 Label,均无则跳过
|
||||
const sprite = node.getComponent(Sprite);
|
||||
if (sprite) {
|
||||
sprite.color = color;
|
||||
} else {
|
||||
const label = node.getComponent(Label);
|
||||
if (label) label.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
// 进度条:第 1 回合 0%,每推进一回合 +25%(第 5 回合满格)
|
||||
if (this.round_progress && this.round_progress.isValid) {
|
||||
this.round_progress.progress =
|
||||
Math.max(0, Math.min(SECTIONS_PER_STAGE, this.currentWave) - 1) / (SECTIONS_PER_STAGE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 怪物数量管理 ========================
|
||||
|
||||
/**
|
||||
@@ -1182,115 +1172,6 @@ export class MissionComp extends CCComp {
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取战斗层的英雄和技能节点数量(用于性能监控) */
|
||||
private getBattleLayerNodeCount() {
|
||||
const scene = smc.map?.MapView?.scene;
|
||||
const layer = scene?.entityLayer?.node;
|
||||
if (!layer) return { heroNodes: 0, skillNodes: 0 };
|
||||
const heroRoot = layer.getChildByName("HERO");
|
||||
const skillRoot = layer.getChildByName("SKILL");
|
||||
return {
|
||||
heroNodes: heroRoot?.children.length || 0,
|
||||
skillNodes: skillRoot?.children.length || 0
|
||||
};
|
||||
}
|
||||
|
||||
// ======================== 性能监控面板 ========================
|
||||
|
||||
/** 性能监控相关代码 */
|
||||
|
||||
/** 初始化性能监控面板:在本组件节点下创建 Label */
|
||||
private initMemoryPanel() {
|
||||
if (!this.showMemoryPanel) return;
|
||||
let panel = this.node.getChildByName("mem_panel");
|
||||
if (!panel) {
|
||||
panel = new Node("mem_panel");
|
||||
panel.parent = this.node;
|
||||
panel.setPosition(0, -32, 0);
|
||||
}
|
||||
let label = panel.getComponent(Label);
|
||||
if (!label) {
|
||||
label = panel.addComponent(Label);
|
||||
}
|
||||
label.fontSize = 16;
|
||||
label.lineHeight = 20;
|
||||
this.memoryLabel = label;
|
||||
}
|
||||
|
||||
/** 移除性能监控面板 */
|
||||
private removeMemoryPanel() {
|
||||
const panel = this.node?.getChildByName("mem_panel");
|
||||
if (panel) {
|
||||
panel.destroy();
|
||||
}
|
||||
this.memoryLabel = null;
|
||||
this.lastMemoryText = "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新性能监控面板内容(每 0.5 秒一次):
|
||||
* 显示 堆内存 / 增长趋势 / 帧率 / 实体数量 / 对象池状态 等信息。
|
||||
*/
|
||||
private updateMemoryPanel(dt: number) {
|
||||
if (!this.showMemoryPanel || !this.memoryLabel) return;
|
||||
this.perfDtAcc += dt;
|
||||
this.perfFrameCount += 1;
|
||||
this.memoryRefreshTimer += dt;
|
||||
if (this.memoryRefreshTimer < 0.5) return;
|
||||
this.memoryRefreshTimer = 0;
|
||||
let heroCount = 0;
|
||||
ecs.query(this.heroViewMatcher).forEach(() => {
|
||||
heroCount++;
|
||||
});
|
||||
let skillCount = 0;
|
||||
ecs.query(this.skillViewMatcher).forEach(() => {
|
||||
skillCount++;
|
||||
});
|
||||
const monPool = Monster.getPoolStats();
|
||||
const skillPool = Skill.getPoolStats();
|
||||
const tooltipPool = Tooltip.getPoolStats();
|
||||
const layerNodes = this.getBattleLayerNodeCount();
|
||||
const perf = (globalThis as any).performance;
|
||||
const heapBytes = perf && perf.memory ? perf.memory.usedJSHeapSize : 0;
|
||||
let heapMB = heapBytes > 0 ? heapBytes / 1024 / 1024 : -1;
|
||||
if (heapMB > 0 && this.heapBaseMB < 0) {
|
||||
this.heapBaseMB = heapMB;
|
||||
this.heapPeakMB = heapMB;
|
||||
this.heapTrendBaseMB = heapMB;
|
||||
this.heapTrendTimer = 0;
|
||||
}
|
||||
if (heapMB > this.heapPeakMB) {
|
||||
this.heapPeakMB = heapMB;
|
||||
}
|
||||
this.heapTrendTimer += 0.5;
|
||||
if (heapMB > 0 && this.heapTrendBaseMB > 0 && this.heapTrendTimer >= 10) {
|
||||
const deltaMB = heapMB - this.heapTrendBaseMB;
|
||||
this.heapTrendPerMinMB = (deltaMB / this.heapTrendTimer) * 60;
|
||||
this.heapTrendBaseMB = heapMB;
|
||||
this.heapTrendTimer = 0;
|
||||
}
|
||||
const heapText = heapMB > 0 ? heapMB.toFixed(1) : "N/A";
|
||||
const heapDeltaText = this.heapBaseMB > 0 && heapMB > 0 ? (heapMB - this.heapBaseMB).toFixed(1) : "N/A";
|
||||
const heapPeakText = this.heapPeakMB > 0 ? this.heapPeakMB.toFixed(1) : "N/A";
|
||||
const avgDt = this.perfFrameCount > 0 ? this.perfDtAcc / this.perfFrameCount : 0;
|
||||
const fps = avgDt > 0 ? 1 / avgDt : 0;
|
||||
this.perfDtAcc = 0;
|
||||
this.perfFrameCount = 0;
|
||||
const text =
|
||||
`Heap:${heapText}MB Δ:${heapDeltaText} Peak:${heapPeakText}\n` +
|
||||
`Trend:${this.heapTrendPerMinMB.toFixed(2)}MB/min\n` +
|
||||
`Perf dt:${(avgDt * 1000).toFixed(1)}ms fps:${fps.toFixed(1)}\n` +
|
||||
`Ent H:${heroCount} S:${skillCount} N:${layerNodes.heroNodes}/${layerNodes.skillNodes}\n` +
|
||||
`Pool M:${monPool.total}(${monPool.paths}) K:${skillPool.total}(${skillPool.paths}) T:${tooltipPool.total}`;
|
||||
if (text === this.lastMemoryText) return;
|
||||
this.lastMemoryText = text;
|
||||
this.memoryLabel.string = text;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** ECS 组件移除时销毁节点 */
|
||||
reset() {
|
||||
this.PhaseTime = null as any;
|
||||
|
||||
@@ -124,12 +124,11 @@ export class MissionMonCompComp extends CCComp {
|
||||
start() { }
|
||||
|
||||
/**
|
||||
* 小节开始事件回调:生成怪物列表并按节奏刷出
|
||||
* 回合开始事件回调:生成怪物列表并按节奏刷出
|
||||
* @param event 事件名
|
||||
* @param data { chapter, stage, section }
|
||||
* @param data { stage, section }
|
||||
*/
|
||||
private onSectionStart(event: string, data: any) {
|
||||
const chapter = Number(data?.chapter ?? 1);
|
||||
const stage = Number(data?.stage ?? 1);
|
||||
const section = Number(data?.section ?? 1);
|
||||
|
||||
@@ -142,15 +141,15 @@ export class MissionMonCompComp extends CCComp {
|
||||
smc.vmdata.mission_data.mon_num = 0;
|
||||
smc.vmdata.mission_data.pending_mon_num = 0;
|
||||
|
||||
// 从生成引擎获取本小节怪物列表
|
||||
const monsters = spawningEngine.generateSectionMonsters(chapter, stage, section);
|
||||
// 从生成引擎获取本回合怪物列表
|
||||
const monsters = spawningEngine.generateSectionMonsters(stage, section);
|
||||
this.sectionTargetCount = monsters.length;
|
||||
|
||||
if (TestModeConfig.enable) {
|
||||
mLogger.log(this.debugMode, 'MissionMonComp', "[MissionMonComp] 测试模式已开启");
|
||||
}
|
||||
mLogger.log(this.debugMode, 'MissionMonComp',
|
||||
`[MissionMonComp] 小节 ${chapter}-${stage}-${section} 生成完成,怪物总数: ${this.sectionTargetCount}`);
|
||||
`[MissionMonComp] 回合 ${stage}-${section} 生成完成,怪物总数: ${this.sectionTargetCount}`);
|
||||
|
||||
// 按批次拆分:batch=0 立即刷,batch=1 进入待刷队列
|
||||
const immediate: GeneratedMonster[] = [];
|
||||
|
||||
@@ -1,30 +1,32 @@
|
||||
/**
|
||||
* @file RogueConfig.ts
|
||||
* @description 关卡刷怪系统(章节-关-节三级推进)
|
||||
* @description 无限关卡刷怪系统(关-回合两级推进)
|
||||
*
|
||||
* 游戏机制:
|
||||
* - 玩家线性推进 1 章 10 关 × 每关 5 小节(一关一局,节间自动推进)。
|
||||
* - 每关节点固定:1~3 节普通(3 小怪,立即全刷)、第 4 节精英(3 精英同刷)、
|
||||
* 第 5 节 Boss(2 小怪先刷,Boss 延迟 1s 刷出)。
|
||||
* - 怪物属性 = 基础 × 0.8 × (1 + 0.05×(lv-1)) × 类型倍率(精英1.5 / Boss3.0)。
|
||||
* - 玩家单线无限推进:从第 1 关起无上限,每关 5 回合(一关一局,回合间自动推进)。
|
||||
* - 第 1~4 回合普通怪(3 小怪立即全刷),属性逐回合轻量增强(SECTION_RAMP_STEP)。
|
||||
* - 第 5 回合单 Boss 登场(无护卫,延迟 1s 刷出),超厚血量(BOSS_HP_MUL)。
|
||||
* - Boss 加载时按攻击定位(近战/中程/远程)随机取型,并随机携带大招:
|
||||
* 前期 1 个,随关卡解锁扩展至多个(BOSS_ULT_UNLOCK_EVERY / BOSS_ULT_MAX_COUNT)。
|
||||
*
|
||||
* 设计层次:
|
||||
* 1. StageSet - 关卡配置(章节/关/节 + 数值公式)
|
||||
* 2. MonSkillPool/BossSkillPool - 怪物技能池(atking / atked / dead 等全触发类型)
|
||||
* 3. StageSpawningEngine - 生成引擎(按小节配置生成怪物列表)
|
||||
* 1. StageSet - 关卡数值公式(等级/成长/回合增强/Boss 血攻倍率)
|
||||
* 2. BossPools - Boss 池(按攻击定位分组,动态从 HeroInfo 提取)
|
||||
* 3. BossUltPools - Boss 大招池(按定位分组,引用 SkillSet 6100~6204 群体大招段)
|
||||
* 4. StageSpawningEngine - 生成引擎(按回合配置生成怪物列表)
|
||||
*
|
||||
* 核心公式:
|
||||
* 最终属性 = HeroInfo 基础属性 × MON_START_COEF × (1 + MON_GROW_SLOPE×(lv-1)) × 类型倍率
|
||||
* 1 级小怪 ≈ 英雄 × 0.8,10 级小怪 ≈ 英雄 × 1.16,保持平缓成长。
|
||||
* 小怪属性 = HeroInfo 基础属性 × MON_START_COEF × (1 + MON_GROW_SLOPE×(lv-1)) × 回合增强
|
||||
* Boss 属性 = 同上 × BOSS_HP_MUL(血)/ BOSS_AP_MUL(攻),等级 = 关卡号无限成长
|
||||
*/
|
||||
|
||||
import { HeroInfo, MonType, MonTypeName, TriggerGrouped } from "../common/config/heroSet";
|
||||
import { SkillOverrides } from "../common/config/SkillSet";
|
||||
import { HeroInfo, HType, MonType, TriggerGrouped, UltCdLv, UltCdSet } from "../common/config/heroSet";
|
||||
import { SkillOverrides, SkillSet } from "../common/config/SkillSet";
|
||||
import { FacSet } from "../common/config/GameSet";
|
||||
import {
|
||||
SectionType, SectionConfig, getSectionConfig, calcMonsterAttrs,
|
||||
NORMAL_MON_COUNT, NORMAL_FIRST_SPAWN, ELITE_COUNT, BOSS_ELITE_COUNT, BOSS_DELAY,
|
||||
MON_START_COEF, MON_GROW_SLOPE, ELITE_MUL, BOSS_MUL,
|
||||
NORMAL_MON_COUNT, NORMAL_FIRST_SPAWN, BOSS_DELAY,
|
||||
MON_START_COEF,
|
||||
} from "../common/config/StageSet";
|
||||
|
||||
// ======================== 1. 战斗常量 ========================
|
||||
@@ -79,126 +81,114 @@ export function getMonsterGoldDrop(monType: number, isBoss: boolean): number {
|
||||
return Math.max(0, Math.floor(isBoss ? cfg.boss : cfg.base));
|
||||
}
|
||||
|
||||
// ======================== 3. 怪物技能池 ========================
|
||||
// ======================== 3. Boss 池(按攻击定位分组) ========================
|
||||
|
||||
/**
|
||||
* 怪物技能套装(一套完整的触发技能配置)
|
||||
* 覆盖触发时机:call / atking / atked / dead / fstart / revive
|
||||
* Boss 池:按攻击定位(近战/中程/远程)分组,动态从 HeroInfo 提取。
|
||||
* 加载时随机一个定位 → 从对应池随机 Boss;定位池为空时自动回退(如暂无中程 Boss 配置)。
|
||||
*/
|
||||
export interface MonSkillSet {
|
||||
id: string;
|
||||
export const BossPools: Record<HType, number[]> = {
|
||||
[HType.Melee]: [],
|
||||
[HType.Mid]: [],
|
||||
[HType.Long]: [],
|
||||
};
|
||||
for (const key in HeroInfo) {
|
||||
const info = HeroInfo[key];
|
||||
if (info.fac !== FacSet.MON) continue;
|
||||
if (info.monType !== MonType.MeleeBoss && info.monType !== MonType.LongBoss) continue;
|
||||
const pool = BossPools[info.type as HType];
|
||||
if (pool) pool.push(info.uuid);
|
||||
}
|
||||
|
||||
// ======================== 4. Boss 大招池 ========================
|
||||
|
||||
/** 每解锁 1 个额外大招收紧的关卡间隔(每 5 关 +1 个大招位) */
|
||||
export const BOSS_ULT_UNLOCK_EVERY = 5;
|
||||
/** Boss 同时携带大招数量上限 */
|
||||
export const BOSS_ULT_MAX_COUNT = 3;
|
||||
|
||||
/**
|
||||
* 获取指定关卡的 Boss 携带大招数量(1 个起步,随关卡解锁扩展)
|
||||
* @param stage 关卡号(1~∞)
|
||||
* @returns 大招数量(1~BOSS_ULT_MAX_COUNT)
|
||||
*/
|
||||
export function getBossUltCount(stage: number): number {
|
||||
const st = Math.max(1, Math.floor(stage));
|
||||
return Math.min(BOSS_ULT_MAX_COUNT, 1 + Math.floor((st - 1) / BOSS_ULT_UNLOCK_EVERY));
|
||||
}
|
||||
|
||||
/** Boss 大招条目(s_uuid 引用 SkillSet 6100~6204 群体大招段,按定位分组) */
|
||||
export interface BossUltEntry {
|
||||
s_uuid: number;
|
||||
name: string;
|
||||
/** 普攻技能覆盖(可选,不填则使用怪物默认普攻) */
|
||||
skill?: { s_uuid: number; cd?: number; overrides?: SkillOverrides };
|
||||
/** 召唤触发 */
|
||||
call?: TriggerGrouped;
|
||||
/** 攻击触发 */
|
||||
atking?: TriggerGrouped;
|
||||
/** 受击触发 */
|
||||
atked?: TriggerGrouped;
|
||||
/** 死亡触发 */
|
||||
dead?: TriggerGrouped;
|
||||
/** 战斗开始触发 */
|
||||
fstart?: TriggerGrouped;
|
||||
/** 复活触发 */
|
||||
revive?: TriggerGrouped;
|
||||
/** 在技能池中的抽取权重 */
|
||||
/** 抽取权重 */
|
||||
weight: number;
|
||||
/** 技能参数覆盖(伤害系数等) */
|
||||
overrides?: SkillOverrides;
|
||||
}
|
||||
|
||||
/**
|
||||
* 怪物技能池(硬编码)
|
||||
* 技能 uuid 引用 SkillSet 中的 6000~6500 段触发技能。
|
||||
* Boss 大招池(按攻击定位分组)
|
||||
* 大招注入 Boss 的 skills 表后由 SCastSystem 按 CD 自动施放(含镜头聚焦 + 技能名横幅)。
|
||||
*/
|
||||
export const MonSkillPool: Record<string, MonSkillSet> = {
|
||||
/** 狂暴:攻击触发自身攻击提升 */
|
||||
berserk: {
|
||||
id: "berserk", name: "狂暴", weight: 10,
|
||||
atking: {
|
||||
6401: [{ lv: 1, t_num: 5, overrides: { ap: 1 } }],
|
||||
},
|
||||
},
|
||||
/** 坚韧:受击获得护盾 */
|
||||
tough: {
|
||||
id: "tough", name: "坚韧", weight: 8,
|
||||
atked: {
|
||||
6301: [{ lv: 1, t_num: 3, overrides: { ap: 2 } }],
|
||||
},
|
||||
},
|
||||
/** 遗志:死亡时全队攻击提升 */
|
||||
legacy: {
|
||||
id: "legacy", name: "遗志", weight: 6,
|
||||
dead: {
|
||||
6401: [{ lv: 1, t_num: 1, overrides: { ap: 3 } }],
|
||||
},
|
||||
},
|
||||
/** 战吼:战斗开始时全队攻击提升 */
|
||||
warcry: {
|
||||
id: "warcry", name: "战吼", weight: 5,
|
||||
fstart: {
|
||||
6401: [{ lv: 1, t_num: 1, overrides: { ap: 2 } }],
|
||||
},
|
||||
},
|
||||
/** 吸血:攻击恢复生命 */
|
||||
leech: {
|
||||
id: "leech", name: "吸血", weight: 7,
|
||||
atking: {
|
||||
6302: [{ lv: 1, t_num: 4, overrides: { ap: 150 } }],
|
||||
},
|
||||
},
|
||||
export const BossUltPools: Record<HType, BossUltEntry[]> = {
|
||||
// 近战系:战士群体斩击(6100~6104 段)
|
||||
[HType.Melee]: [
|
||||
{ s_uuid: 6100, name: "寒冰斩", weight: 10, overrides: { ap: 180 } },
|
||||
{ s_uuid: 6101, name: "裂气斩", weight: 10, overrides: { ap: 180 } },
|
||||
{ s_uuid: 6102, name: "火焰斩", weight: 10, overrides: { ap: 180 } },
|
||||
{ s_uuid: 6103, name: "闪电斩", weight: 8, overrides: { ap: 180 } },
|
||||
{ s_uuid: 6104, name: "开天斩", weight: 6, overrides: { ap: 220 } },
|
||||
],
|
||||
// 中程系:射手箭雨 + 混合法术(6150~6151 / 6203~6204 段)
|
||||
[HType.Mid]: [
|
||||
{ s_uuid: 6150, name: "万箭齐发", weight: 10, overrides: { ap: 150 } },
|
||||
{ s_uuid: 6151, name: "火箭齐发", weight: 10, overrides: { ap: 150 } },
|
||||
{ s_uuid: 6203, name: "能量波", weight: 8, overrides: { ap: 150 } },
|
||||
{ s_uuid: 6204, name: "雷暴", weight: 8, overrides: { ap: 150 } },
|
||||
],
|
||||
// 远程系:法师群体法术(6200~6204 段)
|
||||
[HType.Long]: [
|
||||
{ s_uuid: 6200, name: "火球术", weight: 10, overrides: { ap: 160 } },
|
||||
{ s_uuid: 6201, name: "飓风", weight: 10, overrides: { ap: 140 } },
|
||||
{ s_uuid: 6202, name: "毒气弹", weight: 8, overrides: { ap: 150 } },
|
||||
{ s_uuid: 6203, name: "能量波", weight: 8, overrides: { ap: 150 } },
|
||||
{ s_uuid: 6204, name: "雷暴", weight: 8, overrides: { ap: 150 } },
|
||||
],
|
||||
};
|
||||
|
||||
/** Boss 专属技能池 */
|
||||
export const BossSkillPool: Record<string, MonSkillSet> = {
|
||||
/** 狂暴领主:攻击触发全队攻击提升 */
|
||||
boss_rage: {
|
||||
id: "boss_rage", name: "狂暴领主", weight: 10,
|
||||
atking: {
|
||||
6401: [{ lv: 1, t_num: 3, overrides: { ap: 3 } }],
|
||||
},
|
||||
dead: {
|
||||
6401: [{ lv: 1, t_num: 1, overrides: { ap: 5 } }],
|
||||
},
|
||||
},
|
||||
/** 铁壁领主:受击获得高额护盾 */
|
||||
boss_iron: {
|
||||
id: "boss_iron", name: "铁壁领主", weight: 8,
|
||||
atked: {
|
||||
6301: [{ lv: 1, t_num: 2, overrides: { ap: 5 } }],
|
||||
},
|
||||
},
|
||||
/** 毁灭领主:战斗开始时全队攻击大幅提升 */
|
||||
boss_doom: {
|
||||
id: "boss_doom", name: "毁灭领主", weight: 6,
|
||||
fstart: {
|
||||
6401: [{ lv: 1, t_num: 1, overrides: { ap: 8 } }],
|
||||
},
|
||||
atking: {
|
||||
6401: [{ lv: 1, t_num: 5, overrides: { ap: 2 } }],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// ======================== 4. 配置校验 ========================
|
||||
// ======================== 5. 配置校验 ========================
|
||||
|
||||
/**
|
||||
* 校验 MonSkillPool / BossSkillPool 引用一致性
|
||||
* 校验 Boss 池 / Boss 大招池引用一致性
|
||||
* 建议在游戏启动时调用一次,便于发现配置错误
|
||||
* @returns 错误信息数组,空数组表示校验通过
|
||||
*/
|
||||
export function validateRogueConfig(): string[] {
|
||||
const errors: string[] = [];
|
||||
|
||||
// 校验 Boss 类型在 MonList 中有怪
|
||||
if ((!MonList[MonType.MeleeBoss] || MonList[MonType.MeleeBoss].length === 0)
|
||||
&& (!MonList[MonType.LongBoss] || MonList[MonType.LongBoss].length === 0)) {
|
||||
errors.push("MonList 中无任何 Boss 类型(MeleeBoss/LongBoss)可用 uuid");
|
||||
// 校验至少一个定位有可用 Boss
|
||||
const hasBoss = (Object.keys(BossPools) as unknown as HType[]).some(t => BossPools[t].length > 0);
|
||||
if (!hasBoss) {
|
||||
errors.push("BossPools 中无任何可用 Boss uuid(MeleeBoss/LongBoss 均缺失)");
|
||||
}
|
||||
|
||||
// 校验大招池条目均存在于 SkillSet
|
||||
for (const key in BossUltPools) {
|
||||
const pool = BossPools[key as unknown as HType];
|
||||
const ults = BossUltPools[key as unknown as HType];
|
||||
if (!pool || pool.length === 0) continue; // 空定位池跳过(大招池无消费方)
|
||||
for (const ult of ults) {
|
||||
if (!SkillSet[ult.s_uuid]) {
|
||||
errors.push(`BossUltPools[${key}] 大招 ${ult.s_uuid}(${ult.name}) 未在 SkillSet 中定义`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
// ======================== 5. 生成结果接口 ========================
|
||||
// ======================== 6. 生成结果接口 ========================
|
||||
|
||||
/** 生成结果(传递给 MissionMonComp 用于实例化怪物) */
|
||||
export interface GeneratedMonster {
|
||||
@@ -207,10 +197,8 @@ export interface GeneratedMonster {
|
||||
hp: number;
|
||||
ap: number;
|
||||
isBoss: boolean;
|
||||
/** 是否为精英(精英关/Boss 关的精英) */
|
||||
/** 是否为精英(对象池复用实体需显式重置的标记位) */
|
||||
isElite?: boolean;
|
||||
/** 是否为 Boss 护卫队成员(供 UI/统计识别) */
|
||||
isBossGuard?: boolean;
|
||||
/** 怪物等级(驱动技能等级增量,Mon.load 第 6 参) */
|
||||
lv: number;
|
||||
spawnIndex: number;
|
||||
@@ -220,11 +208,15 @@ export interface GeneratedMonster {
|
||||
delay?: number;
|
||||
|
||||
/**
|
||||
* 怪物技能套装(覆盖全部触发时机)
|
||||
* 注入方式与 _testSkills 相同,在 Mon.load() 中写入 HeroAttrsComp
|
||||
* 怪物技能套装(技能注入通道,与 _testSkills 相同,在 Mon.load() 中写入 HeroAttrsComp)
|
||||
* - skill:替换普攻(会清空原技能表)
|
||||
* - ults:追加 Boss 大招(保留普攻,多个大招共存,SCastSystem 按 CD 轮转施放)
|
||||
* - 其余为触发技能组覆盖
|
||||
*/
|
||||
skills?: {
|
||||
skill?: { s_uuid: number; cd?: number; overrides?: SkillOverrides };
|
||||
/** Boss 大招列表(追加注入,不替换普攻) */
|
||||
ults?: { s_uuid: number; cd?: number; overrides?: SkillOverrides }[];
|
||||
call?: TriggerGrouped;
|
||||
atking?: TriggerGrouped;
|
||||
atked?: TriggerGrouped;
|
||||
@@ -234,7 +226,7 @@ export interface GeneratedMonster {
|
||||
};
|
||||
}
|
||||
|
||||
// ======================== 6. 测试模式配置 ========================
|
||||
// ======================== 7. 测试模式配置 ========================
|
||||
|
||||
export const TestModeConfig = {
|
||||
enable: false, // 默认关闭测试模式
|
||||
@@ -245,48 +237,43 @@ export const TestModeConfig = {
|
||||
spawnCount: 1,
|
||||
|
||||
skill: undefined as { s_uuid: number; cd?: number; overrides?: SkillOverrides } | undefined,
|
||||
/** 测试模式注入的大招列表(追加,不替换普攻) */
|
||||
ults: undefined as { s_uuid: number; cd?: number; overrides?: SkillOverrides }[] | undefined,
|
||||
atking: undefined as TriggerGrouped | undefined,
|
||||
atked: undefined as TriggerGrouped | undefined,
|
||||
dead: undefined as TriggerGrouped | undefined,
|
||||
fstart: undefined as TriggerGrouped | undefined,
|
||||
};
|
||||
|
||||
// ======================== 7. 生成引擎 ========================
|
||||
// ======================== 8. 生成引擎 ========================
|
||||
|
||||
/**
|
||||
* 关卡刷怪生成引擎
|
||||
* 按章节-关-节配置生成怪物列表,属性走 StageSet 数值公式
|
||||
* 无限关卡刷怪生成引擎
|
||||
* 按关-回合配置生成怪物列表,属性走 StageSet 数值公式
|
||||
*/
|
||||
export class StageSpawningEngine {
|
||||
|
||||
/**
|
||||
* 生成指定小节的怪物列表
|
||||
* @param chapter 章节号
|
||||
* @param stage 关卡号
|
||||
* @param section 小节号(1~10)
|
||||
* 生成指定回合的怪物列表
|
||||
* @param stage 关卡号(1~∞)
|
||||
* @param section 回合号(1~SECTIONS_PER_STAGE)
|
||||
* @returns 怪物列表(按刷出顺序排列)
|
||||
*/
|
||||
generateSectionMonsters(chapter: number, stage: number, section: number): GeneratedMonster[] {
|
||||
generateSectionMonsters(stage: number, section: number): GeneratedMonster[] {
|
||||
// 测试模式拦截:完全绕过生成引擎,直接返回硬编码测试怪
|
||||
if (TestModeConfig.enable) {
|
||||
return this.generateTestWave();
|
||||
}
|
||||
|
||||
const cfg = getSectionConfig(chapter, stage, section);
|
||||
const cfg = getSectionConfig(stage, section);
|
||||
if (!cfg) {
|
||||
// 配置缺失兜底:生成 3 只 Lv1 近战小怪
|
||||
return this.makeFallbackMonsters();
|
||||
}
|
||||
|
||||
switch (cfg.type) {
|
||||
case SectionType.Elite:
|
||||
return this.generateEliteSection(cfg);
|
||||
case SectionType.Boss:
|
||||
return this.generateBossSection(cfg);
|
||||
case SectionType.Normal:
|
||||
default:
|
||||
return this.generateNormalSection(cfg);
|
||||
}
|
||||
return cfg.type === SectionType.Boss
|
||||
? this.generateBossSection(cfg, stage)
|
||||
: this.generateNormalSection(cfg);
|
||||
}
|
||||
|
||||
/** 重置引擎状态(每局开始时调用,预留) */
|
||||
@@ -294,7 +281,8 @@ export class StageSpawningEngine {
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通节:NORMAL_MON_COUNT 只小怪全部立即刷出(batch=0)
|
||||
* 普通回合(1~4):NORMAL_MON_COUNT 只小怪全部立即刷出(batch=0),
|
||||
* 属性乘回合增强系数(cfg.ramp)实现逐回合轻量增强
|
||||
*/
|
||||
private generateNormalSection(cfg: SectionConfig): GeneratedMonster[] {
|
||||
const monsters: GeneratedMonster[] = [];
|
||||
@@ -304,64 +292,49 @@ export class StageSpawningEngine {
|
||||
const type = types[i % types.length];
|
||||
const mon = this.makeMonster(type, cfg.monLv, i);
|
||||
mon.batch = i < NORMAL_FIRST_SPAWN ? 0 : 1;
|
||||
// 回合内轻量增强:第 n 回合 × (1 + SECTION_RAMP_STEP×(n-1))
|
||||
mon.hp = Math.max(1, Math.round(mon.hp * cfg.ramp));
|
||||
mon.ap = Math.max(1, Math.round(mon.ap * cfg.ramp));
|
||||
monsters.push(mon);
|
||||
}
|
||||
return monsters;
|
||||
}
|
||||
|
||||
/**
|
||||
* 精英节:3 只精英同时刷出
|
||||
* Boss 回合(5):单 Boss 登场(无护卫)
|
||||
* Boss 延迟 BOSS_DELAY 秒刷出,属性由 makeBoss 按血/攻分离倍率计算(超厚血量)
|
||||
*/
|
||||
private generateEliteSection(cfg: SectionConfig): GeneratedMonster[] {
|
||||
const monsters: GeneratedMonster[] = [];
|
||||
const count = cfg.eliteCount ?? ELITE_COUNT;
|
||||
// 精英池:近战/重型/远程/刺客
|
||||
const eliteTypes = [MonType.Melee, MonType.Heavy, MonType.Long, MonType.Assassin];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const type = eliteTypes[i % eliteTypes.length];
|
||||
const mon = this.makeMonster(type, cfg.monLv, i);
|
||||
mon.isElite = true;
|
||||
mon.batch = 0;
|
||||
// 精英属性 = 普通 × ELITE_MUL
|
||||
mon.hp = Math.max(1, Math.round(mon.hp * ELITE_MUL));
|
||||
mon.ap = Math.max(1, Math.round(mon.ap * ELITE_MUL));
|
||||
monsters.push(mon);
|
||||
}
|
||||
return monsters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Boss 节:2 小怪护卫 + 1 Boss
|
||||
* 小怪先刷(batch=0),Boss 延迟刷出(batch=0, delay=BOSS_DELAY)
|
||||
*/
|
||||
private generateBossSection(cfg: SectionConfig): GeneratedMonster[] {
|
||||
const monsters: GeneratedMonster[] = [];
|
||||
const eliteCount = cfg.eliteCount ?? BOSS_ELITE_COUNT;
|
||||
const eliteTypes = [MonType.Melee, MonType.Heavy];
|
||||
|
||||
// 先刷精英
|
||||
for (let i = 0; i < eliteCount; i++) {
|
||||
const type = eliteTypes[i % eliteTypes.length];
|
||||
const mon = this.makeMonster(type, cfg.monLv, i);
|
||||
mon.isElite = true;
|
||||
mon.isBossGuard = true;
|
||||
mon.batch = 0;
|
||||
mon.hp = Math.max(1, Math.round(mon.hp * ELITE_MUL));
|
||||
mon.ap = Math.max(1, Math.round(mon.ap * ELITE_MUL));
|
||||
monsters.push(mon);
|
||||
}
|
||||
|
||||
// Boss 延迟刷出
|
||||
const boss = this.makeBoss(cfg.monLv, monsters.length);
|
||||
private generateBossSection(cfg: SectionConfig, stage: number): GeneratedMonster[] {
|
||||
const boss = this.makeBoss(cfg.monLv, stage, 0);
|
||||
boss.batch = 0;
|
||||
boss.delay = BOSS_DELAY;
|
||||
// Boss 属性 = 普通 × BOSS_MUL
|
||||
boss.hp = Math.max(1, Math.round(boss.hp * BOSS_MUL));
|
||||
boss.ap = Math.max(1, Math.round(boss.ap * BOSS_MUL));
|
||||
monsters.push(boss);
|
||||
return [boss];
|
||||
}
|
||||
|
||||
return monsters;
|
||||
/** 生成普通怪物(属性按 StageSet 公式计算) */
|
||||
private makeMonster(type: MonType, monLv: number, spawnIndex: number): GeneratedMonster {
|
||||
let uuids = MonList[type];
|
||||
if (!uuids || uuids.length === 0) {
|
||||
// 兜底 Melee
|
||||
uuids = MonList[MonType.Melee] || [6001];
|
||||
}
|
||||
const uuid = uuids[Math.floor(Math.random() * uuids.length)];
|
||||
|
||||
const baseInfo = HeroInfo[uuid];
|
||||
const baseHp = baseInfo ? baseInfo.hp : 100;
|
||||
const baseAp = baseInfo ? baseInfo.ap : 10;
|
||||
const attrs = calcMonsterAttrs(baseHp, baseAp, monLv, false);
|
||||
|
||||
return {
|
||||
uuid,
|
||||
type,
|
||||
hp: attrs.hp,
|
||||
ap: attrs.ap,
|
||||
isBoss: false,
|
||||
lv: monLv,
|
||||
spawnIndex,
|
||||
batch: 0,
|
||||
};
|
||||
}
|
||||
|
||||
/** 配置缺失兜底:3 只 Lv1 近战小怪 */
|
||||
@@ -399,6 +372,7 @@ export class StageSpawningEngine {
|
||||
batch: 0,
|
||||
skills: {
|
||||
skill: TestModeConfig.skill,
|
||||
ults: TestModeConfig.ults,
|
||||
atking: TestModeConfig.atking,
|
||||
atked: TestModeConfig.atked,
|
||||
dead: TestModeConfig.dead,
|
||||
@@ -409,77 +383,74 @@ export class StageSpawningEngine {
|
||||
return monsters;
|
||||
}
|
||||
|
||||
/** 生成 Boss(基础面板按 StageSet 公式计算) */
|
||||
private makeBoss(monLv: number, spawnIndex: number): GeneratedMonster {
|
||||
const isMeleeBoss = Math.random() < 0.5;
|
||||
const type = isMeleeBoss ? MonType.MeleeBoss : MonType.LongBoss;
|
||||
/**
|
||||
* 生成 Boss:加载时随机攻击定位 → 从对应池随机 Boss 个体 → 随机携带大招
|
||||
* 属性走 calcMonsterAttrs(isBoss=true):HP × BOSS_HP_MUL(超厚血)/ AP × BOSS_AP_MUL
|
||||
*/
|
||||
private makeBoss(monLv: number, stage: number, spawnIndex: number): GeneratedMonster {
|
||||
const range = this.pickBossRange();
|
||||
const uuid = this.pickBossUuid(range);
|
||||
|
||||
// Boss 类型兜底:若 MonList 缺失则退回 MeleeBoss
|
||||
let uuids = MonList[type];
|
||||
if (!uuids || uuids.length === 0) {
|
||||
uuids = MonList[MonType.MeleeBoss] || MonList[MonType.Melee] || [6001];
|
||||
}
|
||||
const uuid = uuids[Math.floor(Math.random() * uuids.length)];
|
||||
|
||||
// Boss 基础面板取 HeroInfo 基础值,属性由调用方乘 BOSS_MUL
|
||||
const baseInfo = HeroInfo[uuid];
|
||||
const baseHp = baseInfo ? baseInfo.hp : 600;
|
||||
const baseAp = baseInfo ? baseInfo.ap : 30;
|
||||
const attrs = calcMonsterAttrs(baseHp, baseAp, monLv, false, false);
|
||||
const attrs = calcMonsterAttrs(baseHp, baseAp, monLv, true);
|
||||
|
||||
return {
|
||||
uuid,
|
||||
type,
|
||||
type: baseInfo?.monType ?? MonType.MeleeBoss,
|
||||
hp: attrs.hp,
|
||||
ap: attrs.ap,
|
||||
isBoss: true,
|
||||
lv: monLv,
|
||||
spawnIndex,
|
||||
batch: 0,
|
||||
skills: {
|
||||
ults: this.pickBossUlts(range, stage),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** 生成普通怪物(属性按 StageSet 公式计算) */
|
||||
private makeMonster(type: MonType, monLv: number, spawnIndex: number): GeneratedMonster {
|
||||
let uuids = MonList[type];
|
||||
/**
|
||||
* 随机 Boss 攻击定位(近战/中程/远程)
|
||||
* 空池自动回退:中程暂无 Boss 配置时落到远程/近战,后续补配即自动生效
|
||||
*/
|
||||
private pickBossRange(): HType {
|
||||
const all: HType[] = [HType.Melee, HType.Mid, HType.Long];
|
||||
const first = all[Math.floor(Math.random() * all.length)];
|
||||
if (BossPools[first].length > 0) return first;
|
||||
// 回退链:随机定位空池时按剩余定位找非空池
|
||||
const fallback = all.find(t => BossPools[t].length > 0);
|
||||
return fallback ?? HType.Melee;
|
||||
}
|
||||
|
||||
/** 从指定定位池随机取 Boss uuid(含全局兜底) */
|
||||
private pickBossUuid(range: HType): number {
|
||||
let uuids = BossPools[range];
|
||||
if (!uuids || uuids.length === 0) {
|
||||
// 兜底 Melee
|
||||
uuids = MonList[MonType.Melee] || [6001];
|
||||
uuids = MonList[MonType.MeleeBoss] || MonList[MonType.Melee] || [6001];
|
||||
}
|
||||
const uuid = uuids[Math.floor(Math.random() * uuids.length)];
|
||||
|
||||
const baseInfo = HeroInfo[uuid];
|
||||
const baseHp = baseInfo ? baseInfo.hp : 100;
|
||||
const baseAp = baseInfo ? baseInfo.ap : 10;
|
||||
const attrs = calcMonsterAttrs(baseHp, baseAp, monLv, false, false);
|
||||
|
||||
return {
|
||||
uuid,
|
||||
type,
|
||||
hp: attrs.hp,
|
||||
ap: attrs.ap,
|
||||
isBoss: false,
|
||||
lv: monLv,
|
||||
spawnIndex,
|
||||
batch: 0,
|
||||
};
|
||||
return uuids[Math.floor(Math.random() * uuids.length)];
|
||||
}
|
||||
|
||||
/** 从技能池中按权重抽取一套技能 */
|
||||
private pickSkillSet(pool: string[], library: Record<string, MonSkillSet>): GeneratedMonster["skills"] | undefined {
|
||||
const valid = pool.map(id => library[id]).filter(s => s);
|
||||
if (valid.length === 0) return undefined;
|
||||
const picked = this.pickWeighted(valid);
|
||||
if (!picked) return undefined;
|
||||
return {
|
||||
skill: picked.skill,
|
||||
call: picked.call,
|
||||
atking: picked.atking,
|
||||
atked: picked.atked,
|
||||
dead: picked.dead,
|
||||
fstart: picked.fstart,
|
||||
revive: picked.revive,
|
||||
};
|
||||
/**
|
||||
* 按定位抽取 Boss 大招(不重复),数量由关卡进度决定(getBossUltCount)
|
||||
* @returns 大招配置列表;池空时返回 undefined
|
||||
*/
|
||||
private pickBossUlts(range: HType, stage: number): GeneratedMonster["skills"]["ults"] {
|
||||
const pool = [...(BossUltPools[range] ?? [])];
|
||||
const count = Math.min(getBossUltCount(stage), pool.length);
|
||||
if (count <= 0) return undefined;
|
||||
|
||||
const ults: { s_uuid: number; cd?: number; overrides?: SkillOverrides }[] = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const picked = this.pickWeighted(pool);
|
||||
if (!picked) break;
|
||||
pool.splice(pool.indexOf(picked), 1);
|
||||
// 大招 CD 取英雄同档标准档(8s),与英雄大招节奏对齐
|
||||
ults.push({ s_uuid: picked.s_uuid, cd: UltCdSet[UltCdLv.Normal].cd, overrides: picked.overrides });
|
||||
}
|
||||
return ults.length > 0 ? ults : undefined;
|
||||
}
|
||||
|
||||
/** 通用加权随机抽取 */
|
||||
@@ -496,18 +467,6 @@ export class StageSpawningEngine {
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 8. 全局单例 ========================
|
||||
// ======================== 9. 全局单例 ========================
|
||||
|
||||
export const spawningEngine = new StageSpawningEngine();
|
||||
|
||||
// 保留旧接口兼容(逐步迁移期使用)
|
||||
/** @deprecated 请使用 StageSpawningEngine.generateSectionMonsters */
|
||||
export class RogueSpawningEngine extends StageSpawningEngine {
|
||||
/** @deprecated 请使用 generateSectionMonsters */
|
||||
generateBossCombo(): GeneratedMonster[] {
|
||||
return this.generateSectionMonsters(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated 请使用 spawningEngine */
|
||||
export const rogueSpawningEngine = new RogueSpawningEngine();
|
||||
|
||||
247
assets/script/game/map/TIBoxComp.ts
Normal file
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* @file TIBoxComp.ts
|
||||
* @description 天赋详情弹窗组件(UI 视图层,TIBox.prefab 载体)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 展示天赋图标 / 名称 / 当前等级 / 条幅说明(getTalentDisplayText)。
|
||||
* 2. 展示层位需求行:前置层位名称(如:1 级天赋)、投入进度(如:5/5)、解锁勾图标(解锁亮 On,未解锁亮 Off)。
|
||||
* 3. 展示软前置行:前置天赋名称、等级进度(当前/需求,如:0/5)、前置已达成勾图标(达成亮 On,未达成亮 Off)。
|
||||
* 4. 加点按钮:仅在可加点(层位已解锁 + 前置满足 + 未满级 + 点数足够)时显示;
|
||||
* 不满足条件或已满级时隐藏,弹窗仍可正常打开查看。
|
||||
* 5. 加点成功后通过 TALENT_UPDATE 事件驱动 TalentsComp 全量刷新,并同步刷新本弹窗。
|
||||
*
|
||||
* 使用(oops.gui 模块):
|
||||
* oops.gui.open(UIID.TIBox, { uuid: 9001 });
|
||||
*
|
||||
* 依赖:
|
||||
* - TalentSet(TalentConfig 配置与校验:isTalentTierUnlocked/isTalentPrereqMet/getTalentUpgradeCost)
|
||||
* - smc —— 天赋等级表 / 点数 / upgradeTalent / 图标图集
|
||||
* - outlineRich —— RichText 条幅描边
|
||||
*/
|
||||
import { _decorator, EventTouch, Label, Node, NodeEventType, RichText, Sprite, SpriteFrame } from "cc";
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||
import { TalentSet, TalentConfig, TalentTier, TALENT_TIER_UNLOCK_THRESHOLD, getTalentTierInvestedPoints, getTalentUpgradeCost, isTalentPrereqMet, isTalentTierUnlocked } from "../common/config/TalentSet";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { HRoleName } from "../common/config/heroSet";
|
||||
import { outlineRich } from "../common/RichOutline";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/** TIBox 弹窗初始化参数 */
|
||||
export interface TIBoxParams {
|
||||
/** 天赋 uuid(TalentSet key) */
|
||||
uuid: number;
|
||||
}
|
||||
|
||||
/** TIBoxComp —— 天赋详情弹窗(任何状态均可点开,不可加点时隐藏加点按钮) */
|
||||
@ccclass('TIBoxComp')
|
||||
@ecs.register('TIBoxComp', false)
|
||||
export class TIBoxComp extends CCComp {
|
||||
|
||||
@property({ type: Sprite, tooltip: "天赋图标" })
|
||||
icon: Sprite = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "天赋名称" })
|
||||
lbl_name: Label = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "当前天赋等级(当前/满级)" })
|
||||
lbl_level: Label = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "前置天赋名称(无前置时隐藏前置行)" })
|
||||
lbl_prereq_name: Label = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "前置天赋等级进度(当前/需求,如:0/5)" })
|
||||
lbl_prereq_lv: Label = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "前置已达成勾图标(On)" })
|
||||
node_prereq_check_on: Node = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "前置未达成勾图标(Off)" })
|
||||
node_prereq_check_off: Node = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "前置行容器(无前置天赋时整体隐藏)" })
|
||||
node_prereq: Node = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "层位需求行容器(第 1 层天赋无层位需求,整体隐藏)" })
|
||||
node_tier: Node = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "前置层位名称(如:1 级天赋)" })
|
||||
lbl_tier_name: Label = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "前一层投入进度(已投入/门槛,如:5/5)" })
|
||||
lbl_tier_progress: Label = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "层位已解锁勾图标(On)" })
|
||||
node_tier_check_on: Node = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "层位未解锁勾图标(Off)" })
|
||||
node_tier_check_off: Node = null!;
|
||||
|
||||
@property({ type: RichText, tooltip: "条幅说明(当前已生效数值 / 每级引导)" })
|
||||
richtext_info: RichText = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "加点按钮(不可加点或满级时隐藏)" })
|
||||
node_add: Node = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "关闭遮罩/关闭按钮(点击关闭弹窗)" })
|
||||
node_close: Node = null!;
|
||||
|
||||
/** 当前展示的天赋 uuid */
|
||||
private talent_uuid: number = 0;
|
||||
|
||||
protected onLoad(): void {
|
||||
this.node_add?.on(NodeEventType.TOUCH_END, this.onAddTap, this);
|
||||
this.node_close?.on(NodeEventType.TOUCH_END, this.onCloseTap, this);
|
||||
}
|
||||
|
||||
protected onDestroy(): void {
|
||||
this.node_add?.targetOff(this);
|
||||
this.node_close?.targetOff(this);
|
||||
oops.message.off(GameEvent.TALENT_UPDATE, this.refresh, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* oops.gui 添加到舞台回调(框架约定入口)
|
||||
* @param params 见 TIBoxParams
|
||||
*/
|
||||
onAdded(params: TIBoxParams): void {
|
||||
this.talent_uuid = params?.uuid ?? 0;
|
||||
// 加点成功后同步刷新本弹窗(等级/按钮状态),与 TalentsComp 同一事件源
|
||||
oops.message.on(GameEvent.TALENT_UPDATE, this.refresh, this);
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
/** 全量刷新弹窗内容 */
|
||||
private refresh(): void {
|
||||
const cfg = TalentSet[this.talent_uuid];
|
||||
if (!cfg) return;
|
||||
const levels = smc.getTalentLevels();
|
||||
const lv = levels[this.talent_uuid] ?? 0;
|
||||
|
||||
// 图标:技能图标图集(gui/ui7)优先,资源目录回退(与 TalentItemComp 口径一致)
|
||||
if (this.icon && cfg.icon) {
|
||||
let frame: SpriteFrame | null = null;
|
||||
if (smc.skillIconsAtlas) {
|
||||
frame = smc.skillIconsAtlas.getSpriteFrame(cfg.icon);
|
||||
}
|
||||
if (!frame) {
|
||||
frame = oops.res.get("game/heros/cards/" + cfg.icon, SpriteFrame) as SpriteFrame;
|
||||
}
|
||||
if (frame) this.icon.spriteFrame = frame;
|
||||
}
|
||||
|
||||
if (this.lbl_name) this.lbl_name.string = cfg.name;
|
||||
if (this.lbl_level) this.lbl_level.string = `${lv}/${cfg.max_lv}`;
|
||||
// 条幅说明:已加点显示当前生效数值,未加点显示每级引导
|
||||
if (this.richtext_info) this.richtext_info.string = outlineRich(this.buildDetailText(cfg, lv));
|
||||
|
||||
// 层位需求行:第 1 层恒解锁无需求,整体隐藏;其余层展示前一层名称与投入进度(如:1 级天赋 5/5)
|
||||
const hasTierNeed = cfg.tier > TalentTier.L1;
|
||||
if (this.node_tier) this.node_tier.active = hasTierNeed;
|
||||
if (hasTierNeed) {
|
||||
const prevTier = (cfg.tier - 1) as TalentTier;
|
||||
const invested = getTalentTierInvestedPoints(levels, prevTier);
|
||||
const tierMet = isTalentTierUnlocked(levels, cfg.tier);
|
||||
if (this.lbl_tier_name) this.lbl_tier_name.string = `${prevTier} 级天赋`;
|
||||
// 进度超门槛时截断显示(如已投入 7 点仍显示 5/5,避免 7/5 的歧义观感)
|
||||
const shown = Math.min(invested, TALENT_TIER_UNLOCK_THRESHOLD);
|
||||
if (this.lbl_tier_progress) this.lbl_tier_progress.string = `${shown}/${TALENT_TIER_UNLOCK_THRESHOLD}`;
|
||||
if (this.node_tier_check_on) this.node_tier_check_on.active = tierMet;
|
||||
if (this.node_tier_check_off) this.node_tier_check_off.active = !tierMet;
|
||||
}
|
||||
|
||||
// 软前置行:无前置整体隐藏;有前置展示名称/需求等级/达成勾
|
||||
const hasPrereq = !!(cfg.prereq_uuid && cfg.prereq_lv);
|
||||
if (this.node_prereq) this.node_prereq.active = hasPrereq;
|
||||
if (hasPrereq) {
|
||||
const preCfg = TalentSet[cfg.prereq_uuid!];
|
||||
const preMet = isTalentPrereqMet(levels, cfg);
|
||||
if (this.lbl_prereq_name) this.lbl_prereq_name.string = preCfg ? preCfg.name : `天赋${cfg.prereq_uuid}`;
|
||||
// 前置等级进度(当前/需求,如:0/5);超需求时截断显示,避免 7/5 的歧义观感
|
||||
const preLv = Math.min(levels?.[cfg.prereq_uuid!] ?? 0, cfg.prereq_lv!);
|
||||
if (this.lbl_prereq_lv) this.lbl_prereq_lv.string = `${preLv}/${cfg.prereq_lv}`;
|
||||
if (this.node_prereq_check_on) this.node_prereq_check_on.active = preMet;
|
||||
if (this.node_prereq_check_off) this.node_prereq_check_off.active = !preMet;
|
||||
}
|
||||
|
||||
// 加点按钮:层位解锁 + 前置满足 + 未满级 + 点数足够时才显示
|
||||
if (this.node_add) this.node_add.active = this.canUpgrade(lv, cfg.tier, levels);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按等级精准渲染天赋 info 模板({value}/{value2} 占位替换为实际数值)。
|
||||
* Lv0 时按 1 级数值预览(引导加点)。
|
||||
* @param cfg 天赋配置
|
||||
* @param lv 当前等级
|
||||
* @returns 替换占位后的完整描述文本
|
||||
*/
|
||||
private buildPreciseText(cfg: TalentConfig, lv: number): string {
|
||||
const mult = lv > 0 ? lv : 1;
|
||||
const v1 = cfg.bonuses[0]?.per_lv ?? cfg.t_num_reduce_per_lv ?? cfg.extra_trigger_chance_per_lv ?? 0;
|
||||
const v2 = cfg.bonuses[1]?.per_lv ?? 0;
|
||||
return cfg.info
|
||||
.replace("{value}", `${v1 * mult}`)
|
||||
.replace("{value2}", `${v2 * mult}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建天赋详情条幅文本:精准描述 + 下一级预览 + 满级提示
|
||||
* @param cfg 天赋配置
|
||||
* @param lv 当前等级
|
||||
*/
|
||||
private buildDetailText(cfg: TalentConfig, lv: number): string {
|
||||
const lines: string[] = [];
|
||||
// 精准效果描述:使用 cfg.info 模板按当前等级替换数值占位
|
||||
lines.push(this.buildPreciseText(cfg, lv));
|
||||
// 未满级:追加下一级预览
|
||||
if (lv < cfg.max_lv) {
|
||||
lines.push(`<color=#E0A93D>下一级:${this.buildPreciseText(cfg, lv + 1)}</color>`);
|
||||
} else {
|
||||
lines.push(`<color=#FFD700>已满级</color>`);
|
||||
}
|
||||
// 职业限定提示
|
||||
if (cfg.role !== undefined) {
|
||||
lines.push(`<color=#AAAAAA>仅${HRoleName[cfg.role]}生效</color>`);
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前是否可加点(与 smc.upgradeTalent 校验口径一致,仅做 UI 预判定)
|
||||
* @param lv 当前等级
|
||||
* @param tier 所属层位
|
||||
* @param levels 天赋等级表
|
||||
*/
|
||||
private canUpgrade(lv: number, tier: number, levels: Record<number, number>): boolean {
|
||||
const cfg = TalentSet[this.talent_uuid];
|
||||
if (!cfg) return false;
|
||||
if (lv >= cfg.max_lv) return false;
|
||||
if (!isTalentTierUnlocked(levels, tier)) return false;
|
||||
if (!isTalentPrereqMet(levels, cfg)) return false;
|
||||
return smc.getTalentPoints() >= getTalentUpgradeCost(tier);
|
||||
}
|
||||
|
||||
/** 加点按钮点击:升级成功后由 TALENT_UPDATE 事件驱动刷新(含本弹窗) */
|
||||
private onAddTap(event?: EventTouch): void {
|
||||
if (event) event.propagationStopped = true;
|
||||
oops.audio.playEffect("music/button");
|
||||
smc.upgradeTalent(this.talent_uuid);
|
||||
}
|
||||
|
||||
/** 点击关闭 */
|
||||
private onCloseTap(event?: EventTouch): void {
|
||||
if (event) event.propagationStopped = true;
|
||||
oops.audio.playEffect("music/button");
|
||||
oops.gui.removeByNode(this.node);
|
||||
}
|
||||
|
||||
/** ECS 组件移除时销毁节点(CCComp 抽象方法实现) */
|
||||
reset(): void {
|
||||
if (this.node && this.node.isValid) {
|
||||
this.node.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/script/game/map/TIBoxComp.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "33249e41-30b1-42e3-a12e-f525b5580c37",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -1,40 +1,45 @@
|
||||
/**
|
||||
* @file TalentItemComp.ts
|
||||
* @description 天赋迷你升级卡组件(UI 视图层)
|
||||
* @description 天赋迷你升级卡组件(UI 视图层,编辑器静态摆放)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 接收 TalentsComp 下发的天赋配置 + 当前等级 + 阶位解锁态,渲染迷你点选卡。
|
||||
* 1. 通过编辑器配置的 uuid 自查询天赋配置 + 当前等级 + 层位解锁态,渲染迷你点选卡。
|
||||
* 2. 卡面自包含:图标 / 名称 / 当前已生效数值(Lv0 显示每级数值引导)/ 右下「当前/满级」角标。
|
||||
* 3. 阶位背景:普通背景节点下挂 blue / red / yellow 三个颜色子节点,按阶位激活其一(Ⅰ蓝 / Ⅱ红 / Ⅲ金)。
|
||||
* 4. 状态机:满级(MAX 金角标)/ 未激活(左上锁角标,不再做灰阶处理)。
|
||||
* 3. 层位背景:普通背景节点下挂 blue / red / yellow 三个颜色子节点,按层位映射激活其一(L1蓝 / L2红 / L3金,L4/L5 复用金)。
|
||||
* 4. 状态机:锁定(锁遮罩:层位未解锁或前置未满足;可加点时不显示,不做灰阶处理)/ 状态边框(满级 max 边框、已加点未满 active 边框,未加点均隐藏)。
|
||||
* 5. 点击回调上抛卡体点击,加点确认弹窗与升级校验统一由 TalentsComp 处理(单一决策点)。
|
||||
*
|
||||
* 依赖:
|
||||
* - TalentSet.TalentConfig / TalentTier / getTalentDisplayText —— 配置与卡面文案
|
||||
* - TalentSet(TalentConfig/TalentTier/getTalentDisplayText/isTalentTierUnlocked/isTalentPrereqMet)—— 配置与校验
|
||||
* - 背景三颜色子节点(blue / red / yellow,编辑器侧搭建)
|
||||
* - smc.uiconsAtlas —— 图标解析(缺省回退资源目录)
|
||||
* - smc —— 天赋等级表与图标图集(缺省回退资源目录)
|
||||
*/
|
||||
import { _decorator, Label, Node, NodeEventType, Sprite, SpriteFrame } from "cc";
|
||||
import { _decorator, CCInteger, Label, Node, NodeEventType, Sprite, SpriteFrame } from "cc";
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||
import { TalentConfig, TalentTier, getTalentDisplayText } from "../common/config/TalentSet";
|
||||
import { TalentSet, TalentTier, getTalentDisplayText, isTalentPrereqMet, isTalentTierUnlocked } from "../common/config/TalentSet";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/** 阶位 → 背景节点下的颜色子节点名(Ⅰ蓝 / Ⅱ红 / Ⅲ金) */
|
||||
/** 层位 → 背景节点下的颜色子节点名(L1蓝 / L2红 / L3金;L4/L5 复用金) */
|
||||
const TIER_BG_CHILD_NAMES: Record<number, string> = {
|
||||
[TalentTier.Basic]: "blue",
|
||||
[TalentTier.Specialized]: "red",
|
||||
[TalentTier.Super]: "yellow",
|
||||
[TalentTier.L1]: "blue",
|
||||
[TalentTier.L2]: "red",
|
||||
[TalentTier.L3]: "yellow",
|
||||
[TalentTier.L4]: "yellow",
|
||||
[TalentTier.L5]: "yellow",
|
||||
};
|
||||
|
||||
/** TalentItemComp —— 天赋迷你升级卡组件 */
|
||||
/** TalentItemComp —— 天赋迷你升级卡组件(编辑器静态摆放,按 uuid 自驱动渲染) */
|
||||
@ccclass('TalentItemComp')
|
||||
@ecs.register('TalentItem', false)
|
||||
export class TalentItemComp extends CCComp {
|
||||
|
||||
@property({ type: CCInteger, tooltip: "天赋 uuid(TalentSet key,编辑器侧配置)" })
|
||||
talent_uuid: number = 0;
|
||||
|
||||
@property({ type: Label, tooltip: "天赋名称" })
|
||||
lbl_name: Label = null!;
|
||||
|
||||
@@ -47,20 +52,21 @@ export class TalentItemComp extends CCComp {
|
||||
@property({ type: Sprite, tooltip: "天赋图标" })
|
||||
icon: Sprite = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "卡牌背景节点(下挂 blue / red / yellow 三颜色子节点,按阶位激活其一)" })
|
||||
@property({ type: Node, tooltip: "卡牌背景节点(下挂 blue / red / yellow 三颜色子节点,按层位激活其一)" })
|
||||
bg: Node = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "MAX 满级角标" })
|
||||
node_max: Node = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "未激活锁遮罩/锁图标(未加点或阶位未解锁)" })
|
||||
@property({ type: Node, tooltip: "锁遮罩/锁图标(层位未解锁或前置未满足时显示;可加点时隐藏)" })
|
||||
node_lock: Node = null!;
|
||||
|
||||
/** 点击回调(卡体与 + 徽标同源上抛),由父级统一校验升级 */
|
||||
public onTalentTap: ((uuid: number) => void) | null = null;
|
||||
@property({ type: Node, tooltip: "满级边框(lv 达到 max_lv 时显示)" })
|
||||
node_border_max: Node = null!;
|
||||
|
||||
/** 当前展示的天赋 uuid(回调携带) */
|
||||
private curUuid: number = 0;
|
||||
@property({ type: Node, tooltip: "已加点边框(0 < lv < max_lv 时显示)" })
|
||||
node_border_active: Node = null!;
|
||||
|
||||
|
||||
/** 点击回调(卡体点击上抛),由 TalentsComp 统一校验升级 */
|
||||
public onTalentTap: ((uuid: number) => void) | null = null;
|
||||
|
||||
protected onLoad(): void {
|
||||
this.node.on(NodeEventType.TOUCH_END, this.onTap, this);
|
||||
@@ -70,25 +76,24 @@ export class TalentItemComp extends CCComp {
|
||||
this.node.off(NodeEventType.TOUCH_END, this.onTap, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新迷你卡展示
|
||||
* @param cfg 天赋配置(TalentSet 条目)
|
||||
* @param lv 当前等级
|
||||
* @param tierUnlocked 所属阶位是否已解锁
|
||||
*/
|
||||
public updateItem(cfg: TalentConfig, lv: number, tierUnlocked: boolean): void {
|
||||
/** 刷新迷你卡展示:按编辑器配置的 uuid 自查询配置与等级,层位/前置校验内部完成 */
|
||||
public updateItem(): void {
|
||||
const cfg = TalentSet[this.talent_uuid];
|
||||
if (!cfg) return;
|
||||
this.curUuid = cfg.uuid;
|
||||
const levels = smc.getTalentLevels();
|
||||
const lv = levels[this.talent_uuid] ?? 0;
|
||||
const tierUnlocked = isTalentTierUnlocked(levels, cfg.tier);
|
||||
const prereqMet = isTalentPrereqMet(levels, cfg);
|
||||
|
||||
if (this.lbl_name) this.lbl_name.string = cfg.name;
|
||||
// 卡面自包含:已加点显示当前生效数值,未加点显示每级数值引导
|
||||
if (this.lbl_info) this.lbl_info.string = getTalentDisplayText(cfg, lv);
|
||||
if (this.lbl_lv) this.lbl_lv.string = `${lv}/${cfg.max_lv}`;
|
||||
|
||||
// 未激活(Lv0 或阶位未解锁):仅显示 node_lock 锁遮罩,不做灰阶处理
|
||||
const inactive = lv <= 0 || !tierUnlocked;
|
||||
// 锁遮罩:仅在层位未解锁或前置未满足时显示;已解锁且前置满足即可加点,不再因 Lv0 挂锁
|
||||
const locked = !tierUnlocked || !prereqMet;
|
||||
|
||||
// 阶位背景:激活对应颜色子节点(Ⅰ蓝 / Ⅱ红 / Ⅲ金)
|
||||
// 层位背景:激活对应颜色子节点(L1蓝 / L2红 / L3金)
|
||||
if (this.bg) this.applyTierBg(cfg.tier);
|
||||
|
||||
// 图标:技能图标图集(gui/ui7)优先,资源目录回退(与 SCardComp 口径一致)
|
||||
@@ -103,12 +108,15 @@ export class TalentItemComp extends CCComp {
|
||||
if (frame) this.icon.spriteFrame = frame;
|
||||
}
|
||||
|
||||
// 状态角标:满级 MAX / 未激活锁角标(未加点或阶位未解锁,置于左上角)
|
||||
if (this.node_max) this.node_max.active = lv >= cfg.max_lv;
|
||||
if (this.node_lock) this.node_lock.active = inactive;
|
||||
// 锁遮罩:层位未解锁或前置未满足时显示
|
||||
if (this.node_lock) this.node_lock.active = locked;
|
||||
|
||||
// 状态边框:满级显示 max 边框;已加点未满显示 active 边框;未加点均隐藏
|
||||
if (this.node_border_max) this.node_border_max.active = lv >= cfg.max_lv;
|
||||
if (this.node_border_active) this.node_border_active.active = lv > 0 && lv < cfg.max_lv;
|
||||
}
|
||||
|
||||
/** 按阶位激活 bg 下对应颜色子节点,其余隐藏 */
|
||||
/** 按层位激活 bg 下对应颜色子节点,其余隐藏 */
|
||||
private applyTierBg(tier: TalentTier): void {
|
||||
const curName = TIER_BG_CHILD_NAMES[tier];
|
||||
for (const [, name] of Object.entries(TIER_BG_CHILD_NAMES)) {
|
||||
@@ -120,7 +128,7 @@ export class TalentItemComp extends CCComp {
|
||||
|
||||
/** 卡体点击上抛 uuid,加点确认与升级校验由 TalentsComp 处理 */
|
||||
private onTap(): void {
|
||||
this.onTalentTap?.(this.curUuid);
|
||||
this.onTalentTap?.(this.talent_uuid);
|
||||
}
|
||||
|
||||
/** ECS 组件移除时销毁节点(CCComp 抽象方法实现) */
|
||||
|
||||
@@ -1,65 +1,39 @@
|
||||
/**
|
||||
* @file TalentsComp.ts
|
||||
* @description 天赋加点页组件(UI 视图层)
|
||||
* @description 天赋加点页组件(UI 视图层,最小容器)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 三阶页签(Ⅰ 基础 / Ⅱ 专精 / Ⅲ 超强)状态机:单屏聚焦当前阶位的迷你天赋卡。
|
||||
* 2. 页签常显解锁进度(前阶投入 x/10),点击天赋卡弹出 CommonPrompt 确认加点(smc.upgradeTalent)。
|
||||
* 3. 监听 GameEvent.TALENT_UPDATE 全量重渲染(23 条卡片,无需虚拟列表)。
|
||||
* 1. 页头展示:可用天赋点 / 天赋等级(Lv.x)/ 当前等级经验进度 / 各层已投入点数。
|
||||
* 2. 收集子树内全部 TalentItemComp(编辑器静态摆放),TALENT_UPDATE 事件驱动全量刷新。
|
||||
* 3. 卡片点击统一打开 TIBox 天赋详情弹窗;加点校验(层位/前置/满级/点数)由 TIBoxComp 内聚,
|
||||
* 不满足条件时弹窗隐藏加点按钮,仅作详情查看。
|
||||
* 4. 看广告重置入口:CommonPrompt 二次确认后调 smc.resetTalents() 退还全部点数。
|
||||
*
|
||||
* 依赖:
|
||||
* - TalentSet(TalentSet/TalentTier/isTalentTierUnlocked/getTalentTierInvestedPoints)—— 配置与阶位校验
|
||||
* - TalentItemComp —— 单张迷你升级卡
|
||||
* - TalentSet(getTalentTierInvestedPoints/getTalentLevelExp)—— 配置与统计
|
||||
* - TalentItemComp —— 单张迷你升级卡(编辑器静态摆放,按 uuid 自驱动渲染)
|
||||
* - TIBoxComp —— 天赋详情弹窗(UIID.TIBox)
|
||||
* - smc —— 天赋等级表/点数/升级/重置
|
||||
*/
|
||||
import { _decorator, instantiate, Label, Node, NodeEventType, Prefab, ProgressBar, UITransform } from "cc";
|
||||
import { _decorator, Label, Node, NodeEventType, ProgressBar } from "cc";
|
||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||
import {
|
||||
TalentSet, TalentTier,
|
||||
TALENT_TIER_UNLOCK_THRESHOLD,
|
||||
getTalentDisplayText, getTalentLevelExp, getTalentTierInvestedPoints, getTalentUpgradeCost, isTalentTierUnlocked,
|
||||
getTalentLevelExp, getTalentTierInvestedPoints,
|
||||
} from "../common/config/TalentSet";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { UIID } from "../common/config/GameUIConfig";
|
||||
import { SmallTipComp } from "./SmallTipComp";
|
||||
import { TalentItemComp } from "./TalentItemComp";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
/** 阶位页签展示文案(lockName 用于未解锁提示) */
|
||||
const TIER_TAB_TEXT: Record<number, { title: string; lockName: string }> = {
|
||||
[TalentTier.Basic]: { title: "基础天赋", lockName: "基础天赋" },
|
||||
[TalentTier.Specialized]: { title: "专精天赋", lockName: "基础天赋" },
|
||||
[TalentTier.Super]: { title: "传说天赋", lockName: "专精天赋" },
|
||||
};
|
||||
|
||||
/** 阶位页签选中高亮子节点名(可选,编辑器侧搭建) */
|
||||
const TAB_SELECTED_CHILD = "sp_on";
|
||||
|
||||
/** 阶位页签锁定图标子节点名(可选;阶位未解锁时显示) */
|
||||
const TAB_LOCKED_CHILD = "locked";
|
||||
|
||||
/** 阶位页签未选中态子节点名(可选;非当前选中页签时显示) */
|
||||
const TAB_INACTIVE_CHILD = "noactive";
|
||||
|
||||
/** 页签/卡片上的 smalltip 气泡节点名 */
|
||||
const SMALL_TIP_CHILD = "smalltip";
|
||||
|
||||
/** TalentsComp —— 天赋加点页组件(阶位 Tab 单屏聚焦) */
|
||||
/** TalentsComp —— 天赋加点页组件(最小容器:页头 + 编辑器静态卡片收集) */
|
||||
@ccclass('TalentsComp')
|
||||
@ecs.register('Talents', false)
|
||||
export class TalentsComp extends CCComp {
|
||||
|
||||
@property({ type: Node, tooltip: "当前阶位卡片列表容器(ScrollView content,Grid 三列)" })
|
||||
talents_content: Node = null!;
|
||||
|
||||
@property({ type: Prefab, tooltip: "迷你天赋卡预制(TalentItemComp)" })
|
||||
prefab_talent_item: Prefab = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "页头可用天赋点" })
|
||||
lbl_points: Label = null!;
|
||||
|
||||
@@ -69,52 +43,22 @@ export class TalentsComp extends CCComp {
|
||||
@property({ type: ProgressBar, tooltip: "当前等级经验进度条" })
|
||||
progress_exp: ProgressBar = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "一阶页签节点" })
|
||||
tab_basic: Node = null!;
|
||||
@property({ type: Label, tooltip: "当前等级经验数值(当前经验/升级所需经验)" })
|
||||
lbl_exp: Label = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "二阶页签节点" })
|
||||
tab_special: Node = null!;
|
||||
|
||||
@property({ type: Node, tooltip: "三阶页签节点" })
|
||||
tab_super: Node = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "一阶页签文案" })
|
||||
lbl_tab_basic: Label = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "二阶页签文案" })
|
||||
lbl_tab_special: Label = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "三阶页签文案" })
|
||||
lbl_tab_super: Label = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "一阶已投入点数" })
|
||||
lbl_invest_basic: Label = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "二阶已投入点数" })
|
||||
lbl_invest_special: Label = null!;
|
||||
|
||||
@property({ type: Label, tooltip: "三阶已投入点数" })
|
||||
lbl_invest_super: Label = null!;
|
||||
@property({ type: [Label], tooltip: "各层已投入点数 Label(数组索引对应第 1~5 层)" })
|
||||
lbl_tier_points: Label[] = [];
|
||||
|
||||
@property({ type: Node, tooltip: "看广告重置按钮" })
|
||||
btn_reset: Node = null!;
|
||||
|
||||
/** 当前选中的阶位(首次进入默认为已解锁的最高阶,之后由玩家切换) */
|
||||
private curTier: TalentTier = TalentTier.Basic;
|
||||
|
||||
/** 是否已完成首次默认阶位选择 */
|
||||
private inited: boolean = false;
|
||||
|
||||
/** 阶位 → 页签节点/文案/投入点数/气泡 映射(onLoad 时装配) */
|
||||
private tabNodes: Map<TalentTier, { node: Node | null; label: Label | null; invest: Label | null; tip: SmallTipComp | null }> = new Map();
|
||||
/** 页内全部天赋卡(onLoad 时自动收集子树内所有 TalentItemComp,无需编辑器拖引) */
|
||||
private talent_items: TalentItemComp[] = [];
|
||||
|
||||
protected onLoad(): void {
|
||||
this.tabNodes.set(TalentTier.Basic, { node: this.tab_basic, label: this.lbl_tab_basic, invest: this.lbl_invest_basic, tip: this.getSmallTip(this.tab_basic) });
|
||||
this.tabNodes.set(TalentTier.Specialized, { node: this.tab_special, label: this.lbl_tab_special, invest: this.lbl_invest_special, tip: this.getSmallTip(this.tab_special) });
|
||||
this.tabNodes.set(TalentTier.Super, { node: this.tab_super, label: this.lbl_tab_super, invest: this.lbl_invest_super, tip: this.getSmallTip(this.tab_super) });
|
||||
|
||||
for (const [tier, tab] of this.tabNodes) {
|
||||
tab.node?.on(NodeEventType.TOUCH_END, () => this.selectTier(tier), this);
|
||||
this.talent_items = this.node.getComponentsInChildren(TalentItemComp);
|
||||
for (const item of this.talent_items) {
|
||||
item.onTalentTap = (uuid: number) => this.onTalentTap(uuid);
|
||||
}
|
||||
this.btn_reset?.on(NodeEventType.TOUCH_END, this.onResetTap, this);
|
||||
}
|
||||
@@ -130,25 +74,30 @@ export class TalentsComp extends CCComp {
|
||||
}
|
||||
|
||||
protected onDestroy(): void {
|
||||
for (const [, tab] of this.tabNodes) {
|
||||
tab.node?.targetOff(this);
|
||||
}
|
||||
this.btn_reset?.targetOff(this);
|
||||
}
|
||||
|
||||
/** 切换阶位页签:锁定阶允许查看(卡片呈锁定态),不弹解锁提示 */
|
||||
private selectTier(tier: TalentTier): void {
|
||||
if (tier === this.curTier) return;
|
||||
this.curTier = tier;
|
||||
this.refreshUI();
|
||||
}
|
||||
|
||||
/** 全量刷新:页头点数 + 页签解锁进度 + 当前阶位卡片列表 */
|
||||
/** 全量刷新:页头点数 + 天赋等级/经验 + 全部静态卡片 */
|
||||
public refreshUI(): void {
|
||||
if (!this.talents_content || !this.prefab_talent_item) return;
|
||||
const levels = smc.getTalentLevels();
|
||||
|
||||
if (this.lbl_points) this.lbl_points.string = `${smc.getTalentPoints()}`;
|
||||
if (this.lbl_points) {
|
||||
// 剩余/总点数:总点数 = 剩余 + 各层已投入
|
||||
const remaining = smc.getTalentPoints();
|
||||
let invested = 0;
|
||||
for (let tier = 1; tier <= 5; tier++) {
|
||||
invested += getTalentTierInvestedPoints(levels, tier);
|
||||
}
|
||||
this.lbl_points.string = `${remaining}/${remaining + invested}`;
|
||||
}
|
||||
|
||||
// 各层已投入点数(数组索引对应层 1~5)
|
||||
for (let tier = 1; tier <= this.lbl_tier_points.length; tier++) {
|
||||
const lbl = this.lbl_tier_points[tier - 1];
|
||||
if (lbl) {
|
||||
lbl.string = `${getTalentTierInvestedPoints(levels, tier)}`;
|
||||
}
|
||||
}
|
||||
|
||||
// 天赋等级(Lv.x)与当前等级经验进度
|
||||
const talentLv = smc.getTalentLevel();
|
||||
@@ -160,127 +109,25 @@ export class TalentsComp extends CCComp {
|
||||
? Math.min(1, smc.getTalentExp() / needExp)
|
||||
: 1;
|
||||
}
|
||||
|
||||
// 仅首次进入时默认选中已解锁的最高阶,后续刷新保持玩家当前选择
|
||||
if (!this.inited) {
|
||||
this.inited = true;
|
||||
if (isTalentTierUnlocked(levels, TalentTier.Super)) this.curTier = TalentTier.Super;
|
||||
else if (isTalentTierUnlocked(levels, TalentTier.Specialized)) this.curTier = TalentTier.Specialized;
|
||||
if (this.lbl_exp) {
|
||||
const needExp = getTalentLevelExp(talentLv);
|
||||
// 满级后显示为 0/0,避免分母为 0
|
||||
this.lbl_exp.string = needExp > 0
|
||||
? `${smc.getTalentExp()}/${needExp}`
|
||||
: `0/0`;
|
||||
}
|
||||
|
||||
this.refreshTabs(levels);
|
||||
this.refreshGrid(levels);
|
||||
}
|
||||
|
||||
/** 页签文案 + 各阶已投入点数 + 选中高亮(sp_on)+ 锁定图标(locked)+ 未选中态(noactive) */
|
||||
private refreshTabs(levels: Record<number, number>): void {
|
||||
for (const [tier, tab] of this.tabNodes) {
|
||||
const text = TIER_TAB_TEXT[tier];
|
||||
const unlocked = isTalentTierUnlocked(levels, tier);
|
||||
if (tab.label) tab.label.string = text.title;
|
||||
// 各阶已投入点数(该阶所有天赋等级之和)
|
||||
if (tab.invest) tab.invest.string = `${getTalentTierInvestedPoints(levels, tier)}`;
|
||||
// 锁定图标:该阶未解锁时显示,解锁后隐藏(一阶恒解锁,节点可缺省)
|
||||
const locked = tab.node?.getChildByName(TAB_LOCKED_CHILD);
|
||||
if (locked) locked.active = !unlocked;
|
||||
|
||||
const selected = tier === this.curTier;
|
||||
// 未选中态节点:非当前激活页签时显示(与 sp_on 选中高亮互斥)
|
||||
const inactive = tab.node?.getChildByName(TAB_INACTIVE_CHILD);
|
||||
if (inactive) inactive.active = !selected;
|
||||
|
||||
tab.node?.getChildByName(TAB_SELECTED_CHILD)?.setPosition(0, 0);
|
||||
tab.node?.getChildByName(TAB_SELECTED_CHILD) && (tab.node.getChildByName(TAB_SELECTED_CHILD)!.active = selected);
|
||||
}
|
||||
}
|
||||
|
||||
/** 重建当前阶位的卡片列表(每阶 ≤10 条,直接全量实例化) */
|
||||
private refreshGrid(levels: Record<number, number>): void {
|
||||
this.talents_content.removeAllChildren();
|
||||
const unlocked = isTalentTierUnlocked(levels, this.curTier);
|
||||
const cfgs = Object.values(TalentSet)
|
||||
.filter(cfg => cfg.tier === this.curTier)
|
||||
.sort((a, b) => a.uuid - b.uuid);
|
||||
|
||||
let cardHeight = 0;
|
||||
for (const cfg of cfgs) {
|
||||
const lv = levels[cfg.uuid] ?? 0;
|
||||
|
||||
const itemNode = instantiate(this.prefab_talent_item);
|
||||
this.talents_content.addChild(itemNode);
|
||||
const comp = itemNode.getComponent(TalentItemComp);
|
||||
if (!comp) continue;
|
||||
comp.updateItem(cfg, lv, unlocked);
|
||||
comp.onTalentTap = (uuid: number) => this.onTalentTap(uuid);
|
||||
if (!cardHeight) cardHeight = itemNode.getComponent(UITransform)?.height ?? 0;
|
||||
}
|
||||
|
||||
// Grid 三列手算容器高度(与旧版图鉴页口径一致,spacing 15 / 上下 padding 15)
|
||||
const rows = Math.ceil(cfgs.length / 3);
|
||||
if (cardHeight > 0 && rows > 0) {
|
||||
const contentHeight = rows * cardHeight + (rows - 1) * 15 + 30;
|
||||
const uiTransform = this.talents_content.getComponent(UITransform);
|
||||
if (uiTransform) uiTransform.height = contentHeight;
|
||||
for (const item of this.talent_items) {
|
||||
item.updateItem();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取挂载点下的 smalltip 气泡组件(节点缺失或组件未挂时返回 null 并静默跳过提示)
|
||||
* @param parent 气泡挂载的父节点
|
||||
* 卡片点击统一入口:任何状态均打开 TIBox 天赋详情弹窗,加点按钮显隐由 TIBoxComp 校验
|
||||
* @param uuid 天赋 uuid
|
||||
*/
|
||||
private getSmallTip(parent: Node | null): SmallTipComp | null {
|
||||
const tipNode = parent?.getChildByName(SMALL_TIP_CHILD);
|
||||
return tipNode ? (tipNode.getComponent(SmallTipComp) ?? tipNode.addComponent(SmallTipComp)) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定节点下弹出 smalltip 气泡提示
|
||||
* @param anchor 气泡挂载的父节点(优先页签,卡片点击时传卡片节点)
|
||||
* @param text 提示文案
|
||||
*/
|
||||
private showSmallTip(anchor: Node | null, text: string): void {
|
||||
const tip = this.getSmallTip(anchor);
|
||||
tip?.show(text);
|
||||
}
|
||||
|
||||
/** 卡片点击统一入口:未解锁/已满级/点数不足走 smalltip 气泡;其余弹出 CommonPrompt 确认加点,成功后事件驱动刷新 */
|
||||
private onTalentTap(uuid: number): void {
|
||||
const cfg = TalentSet[uuid];
|
||||
if (!cfg) return;
|
||||
const levels = smc.getTalentLevels();
|
||||
|
||||
const tab = this.tabNodes.get(cfg.tier);
|
||||
if (!isTalentTierUnlocked(levels, cfg.tier)) {
|
||||
const invested = getTalentTierInvestedPoints(levels, (cfg.tier - 1) as TalentTier);
|
||||
this.showSmallTip(tab?.node ?? null, `${TIER_TAB_TEXT[cfg.tier].lockName}投入${TALENT_TIER_UNLOCK_THRESHOLD} 点解锁`);
|
||||
return;
|
||||
}
|
||||
const lv = smc.getTalentLv(uuid);
|
||||
if (lv >= cfg.max_lv) {
|
||||
this.showSmallTip(tab?.node ?? null, "该天赋已满级");
|
||||
return;
|
||||
}
|
||||
const cost = getTalentUpgradeCost(cfg.tier);
|
||||
if (cost <= 0) return;
|
||||
if (smc.getTalentPoints() < cost) {
|
||||
this.showSmallTip(tab?.node ?? null, "天赋点不足");
|
||||
return;
|
||||
}
|
||||
|
||||
// CommonPrompt 确认加点(UIID.Window)
|
||||
oops.gui.open(UIID.Window, {
|
||||
title: "天赋加点",
|
||||
content: `${cfg.name} Lv.${lv} → Lv.${lv + 1}\n消耗 <color=#E0A93D>${cost}</color> 点天赋点,获得 ${getTalentDisplayText(cfg, 1)}。是否加点?`,
|
||||
okWord: "加点",
|
||||
cancelWord: "取消",
|
||||
needCancel: true,
|
||||
maskClose: true,
|
||||
okFunc: () => {
|
||||
if (!smc.upgradeTalent(uuid)) {
|
||||
this.showSmallTip(this.tabNodes.get(cfg.tier)?.node ?? null, "天赋点不足");
|
||||
}
|
||||
},
|
||||
});
|
||||
oops.gui.open(UIID.TIBox, { uuid });
|
||||
}
|
||||
|
||||
/** 看广告重置入口:CommonPrompt 二次确认(广告接入前先直接确认重置) */
|
||||
|
||||