3 Commits

Author SHA1 Message Date
pan
8c421c42d4 feat: 新增技能装备详情弹窗IBox,替换旧英雄信息弹窗逻辑
1. 重构IBoxComp组件,支持技能和装备详情展示
2. 为EquipBoxComp和SkillBoxComp添加长按弹窗功能
3. 更新UI配置,修正IBox弹窗层级
4. 新增富文本工具函数生成技能装备详情文案
2026-07-31 10:55:46 +08:00
pan
bdb4602fe6 refactor(map): 移除四个卡牌组件的长按预览功能
移除了EquipListComp、SCardComp、CHeroComp、ItemListComp四个文件中的长按弹出信息框相关代码,包括事件监听、长按计时逻辑和信息框打开关闭代码,同时删除了未使用的UIID导入。
2026-07-31 10:06:40 +08:00
pan
8f3cd4777f docs(skillDesc): 优化技能富文本描述高亮规则
1. 调整数值高亮色为亮绿色,更新注释说明
2. 新增技能名蓝色高亮逻辑,自动格式化「技能名」片段
3. 同步更新函数注释与匹配正则规则
2026-07-31 09:35:22 +08:00
15 changed files with 2025 additions and 4463 deletions

View File

@@ -47,7 +47,7 @@
}
],
"_prefab": {
"__id__": 342
"__id__": 360
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -1540,7 +1540,7 @@
"a": 255
},
"_string": "词条3",
"_horizontalAlign": 0,
"_horizontalAlign": 1,
"_verticalAlign": 1,
"_actualFontSize": 18,
"_fontSize": 20,
@@ -1738,7 +1738,7 @@
"a": 255
},
"_string": "词条2",
"_horizontalAlign": 0,
"_horizontalAlign": 1,
"_verticalAlign": 1,
"_actualFontSize": 18,
"_fontSize": 20,
@@ -1936,7 +1936,7 @@
"a": 255
},
"_string": "词条3",
"_horizontalAlign": 0,
"_horizontalAlign": 1,
"_verticalAlign": 1,
"_actualFontSize": 18,
"_fontSize": 20,
@@ -6080,7 +6080,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 341
"__id__": 359
},
"_customMaterial": null,
"_srcBlendFactor": 2,
@@ -6146,14 +6146,14 @@
"_active": true,
"_components": [
{
"__id__": 338
"__id__": 356
},
{
"__id__": 310
}
],
"_prefab": {
"__id__": 340
"__id__": 358
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -6186,7 +6186,7 @@
},
{
"__type__": "cc.Node",
"_name": "cost",
"_name": "coin",
"_objFlags": 0,
"__editorExtras__": {
"mountedRoot": null
@@ -6196,7 +6196,7 @@
},
"_children": [
{
"__id__": 327
"__id__": 345
},
{
"__id__": 311
@@ -6205,14 +6205,14 @@
"_active": true,
"_components": [
{
"__id__": 333
"__id__": 351
},
{
"__id__": 335
"__id__": 353
}
],
"_prefab": {
"__id__": 337
"__id__": 355
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -6257,22 +6257,25 @@
},
{
"__id__": 312
},
{
"__id__": 320
}
],
"_active": true,
"_components": [
{
"__id__": 320
"__id__": 338
},
{
"__id__": 322
"__id__": 340
},
{
"__id__": 324
"__id__": 342
}
],
"_prefab": {
"__id__": 326
"__id__": 344
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -6464,6 +6467,442 @@
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.Node",
"_name": "stone",
"_objFlags": 0,
"__editorExtras__": {
"mountedRoot": null
},
"_parent": {
"__id__": 313
},
"_children": [
{
"__id__": 321
},
{
"__id__": 327
}
],
"_active": false,
"_components": [
{
"__id__": 333
},
{
"__id__": 335
}
],
"_prefab": {
"__id__": 337
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": -32.75,
"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": "icon",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 320
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 322
},
{
"__id__": 324
}
],
"_prefab": {
"__id__": 326
},
"_lpos": {
"__type__": "cc.Vec3",
"x": -7.5615234375,
"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.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 321
},
"_enabled": true,
"__prefab": {
"__id__": 323
},
"_contentSize": {
"__type__": "cc.Size",
"width": 27,
"height": 27
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "31GJSeBupAjL6B0JSMWEDn"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 321
},
"_enabled": true,
"__prefab": {
"__id__": 325
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": {
"__uuid__": "6165ffc9-a838-4a33-b569-bdbaaab0e6b4@66d28",
"__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__": "6165ffc9-a838-4a33-b569-bdbaaab0e6b4",
"__expectedType__": "cc.SpriteAtlas"
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "f0Ah1lXhpLIZry/aPq9YzL"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "d5mcu1TmRMYpCqlMi96hsO",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.Node",
"_name": "num",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 320
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 328
},
{
"__id__": 330
}
],
"_prefab": {
"__id__": 332
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 13.5,
"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.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 327
},
"_enabled": true,
"__prefab": {
"__id__": 329
},
"_contentSize": {
"__type__": "cc.Size",
"width": 15.123046875,
"height": 54.4
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "94OK1DwMRAl7qOBrTxG/i4"
},
{
"__type__": "cc.Label",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 327
},
"_enabled": true,
"__prefab": {
"__id__": 331
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_string": "2",
"_horizontalAlign": 1,
"_verticalAlign": 1,
"_actualFontSize": 20,
"_fontSize": 20,
"_fontFamily": "Arial",
"_lineHeight": 40,
"_overflow": 0,
"_enableWrapText": true,
"_font": null,
"_isSystemFontUsed": true,
"_spacingX": 0,
"_isItalic": false,
"_isBold": true,
"_isUnderline": false,
"_underlineHeight": 2,
"_cacheMode": 0,
"_enableOutline": true,
"_outlineColor": {
"__type__": "cc.Color",
"r": 0,
"g": 0,
"b": 0,
"a": 255
},
"_outlineWidth": 2,
"_enableShadow": false,
"_shadowColor": {
"__type__": "cc.Color",
"r": 0,
"g": 0,
"b": 0,
"a": 255
},
"_shadowOffset": {
"__type__": "cc.Vec2",
"x": 2,
"y": 2
},
"_shadowBlur": 2,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "38htj7TVBI84FdhXPqZi9Y"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "5aV+d4uupA3430zZytYs+/",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 320
},
"_enabled": true,
"__prefab": {
"__id__": 334
},
"_contentSize": {
"__type__": "cc.Size",
"width": 42.123046875,
"height": 30
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "daubq3MHBCvZhVT7CCunA4"
},
{
"__type__": "cc.Layout",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 320
},
"_enabled": true,
"__prefab": {
"__id__": 336
},
"_resizeMode": 1,
"_layoutType": 1,
"_cellSize": {
"__type__": "cc.Size",
"width": 40,
"height": 40
},
"_startAxis": 0,
"_paddingLeft": 0,
"_paddingRight": 0,
"_paddingTop": 0,
"_paddingBottom": 0,
"_spacingX": 0,
"_spacingY": 0,
"_verticalDirection": 1,
"_horizontalDirection": 0,
"_constraint": 0,
"_constraintNum": 2,
"_affectedByScale": false,
"_isAlign": false,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "867zQklidJAJ9K6dAQWCB6"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "32ZgIQHstCXYwNDGBH6HPk",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.UITransform",
"_name": "",
@@ -6474,7 +6913,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 321
"__id__": 339
},
"_contentSize": {
"__type__": "cc.Size",
@@ -6502,7 +6941,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 323
"__id__": 341
},
"_alignFlags": 45,
"_target": null,
@@ -6538,7 +6977,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 325
"__id__": 343
},
"_resizeMode": 1,
"_layoutType": 2,
@@ -6581,7 +7020,7 @@
},
{
"__type__": "cc.Node",
"_name": "gold",
"_name": "icon",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
@@ -6591,14 +7030,14 @@
"_active": true,
"_components": [
{
"__id__": 328
"__id__": 346
},
{
"__id__": 330
"__id__": 348
}
],
"_prefab": {
"__id__": 332
"__id__": 350
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -6635,11 +7074,11 @@
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 327
"__id__": 345
},
"_enabled": true,
"__prefab": {
"__id__": 329
"__id__": 347
},
"_contentSize": {
"__type__": "cc.Size",
@@ -6663,11 +7102,11 @@
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 327
"__id__": 345
},
"_enabled": true,
"__prefab": {
"__id__": 331
"__id__": 349
},
"_customMaterial": null,
"_srcBlendFactor": 2,
@@ -6725,7 +7164,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 334
"__id__": 352
},
"_contentSize": {
"__type__": "cc.Size",
@@ -6753,7 +7192,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 336
"__id__": 354
},
"_resizeMode": 1,
"_layoutType": 1,
@@ -6804,7 +7243,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 339
"__id__": 357
},
"_contentSize": {
"__type__": "cc.Size",
@@ -6851,13 +7290,13 @@
"instance": null,
"targetOverrides": [
{
"__id__": 343
"__id__": 361
},
{
"__id__": 345
"__id__": 363
},
{
"__id__": 347
"__id__": 365
}
],
"nestedPrefabInstanceRoots": [
@@ -6885,7 +7324,7 @@
"__id__": 40
},
"targetInfo": {
"__id__": 344
"__id__": 362
}
},
{
@@ -6907,7 +7346,7 @@
"__id__": 40
},
"targetInfo": {
"__id__": 346
"__id__": 364
}
},
{
@@ -6929,7 +7368,7 @@
"__id__": 121
},
"targetInfo": {
"__id__": 348
"__id__": 366
}
},
{

View File

@@ -47,7 +47,7 @@
}
],
"_prefab": {
"__id__": 355
"__id__": 373
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -1624,7 +1624,7 @@
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 23.333333333333336,
"y": 0,
"z": 0
},
"_lrot": {
@@ -1665,7 +1665,7 @@
"_contentSize": {
"__type__": "cc.Size",
"width": 190,
"height": 23.333333333333332
"height": 80
},
"_anchorPoint": {
"__type__": "cc.Vec2",
@@ -1701,12 +1701,12 @@
"a": 255
},
"_string": "词条3",
"_horizontalAlign": 0,
"_horizontalAlign": 1,
"_verticalAlign": 1,
"_actualFontSize": 18,
"_actualFontSize": 21,
"_fontSize": 20,
"_fontFamily": "Arial",
"_lineHeight": 25,
"_lineHeight": 21,
"_overflow": 2,
"_enableWrapText": true,
"_font": null,
@@ -1804,7 +1804,7 @@
"__id__": 102
},
"_children": [],
"_active": true,
"_active": false,
"_components": [
{
"__id__": 112
@@ -2002,7 +2002,7 @@
"__id__": 102
},
"_children": [],
"_active": true,
"_active": false,
"_components": [
{
"__id__": 120
@@ -2020,7 +2020,7 @@
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": -23.33333333333333,
"y": -11.666666666666666,
"z": 0
},
"_lrot": {
@@ -2206,7 +2206,7 @@
"_contentSize": {
"__type__": "cc.Size",
"width": 190,
"height": 70
"height": 80
},
"_anchorPoint": {
"__type__": "cc.Vec2",
@@ -2235,8 +2235,8 @@
"_target": null,
"_left": 20,
"_right": 20,
"_top": 144.541,
"_bottom": 85.459,
"_top": 139.541,
"_bottom": 80.459,
"_horizontalCenter": 0,
"_verticalCenter": 0,
"_isAbsLeft": true,
@@ -6241,7 +6241,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 354
"__id__": 372
},
"_customMaterial": null,
"_srcBlendFactor": 2,
@@ -6307,14 +6307,14 @@
"_active": true,
"_components": [
{
"__id__": 351
"__id__": 369
},
{
"__id__": 323
}
],
"_prefab": {
"__id__": 353
"__id__": 371
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -6347,7 +6347,7 @@
},
{
"__type__": "cc.Node",
"_name": "cost",
"_name": "coin",
"_objFlags": 0,
"__editorExtras__": {
"mountedRoot": null
@@ -6357,7 +6357,7 @@
},
"_children": [
{
"__id__": 340
"__id__": 358
},
{
"__id__": 324
@@ -6366,14 +6366,14 @@
"_active": true,
"_components": [
{
"__id__": 346
"__id__": 364
},
{
"__id__": 348
"__id__": 366
}
],
"_prefab": {
"__id__": 350
"__id__": 368
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -6418,22 +6418,25 @@
},
{
"__id__": 325
},
{
"__id__": 333
}
],
"_active": true,
"_components": [
{
"__id__": 333
"__id__": 351
},
{
"__id__": 335
"__id__": 353
},
{
"__id__": 337
"__id__": 355
}
],
"_prefab": {
"__id__": 339
"__id__": 357
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -6625,6 +6628,442 @@
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.Node",
"_name": "stone",
"_objFlags": 0,
"__editorExtras__": {
"mountedRoot": null
},
"_parent": {
"__id__": 326
},
"_children": [
{
"__id__": 334
},
{
"__id__": 340
}
],
"_active": false,
"_components": [
{
"__id__": 346
},
{
"__id__": 348
}
],
"_prefab": {
"__id__": 350
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": -32.75,
"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": "icon",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 333
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 335
},
{
"__id__": 337
}
],
"_prefab": {
"__id__": 339
},
"_lpos": {
"__type__": "cc.Vec3",
"x": -7.5615234375,
"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.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 334
},
"_enabled": true,
"__prefab": {
"__id__": 336
},
"_contentSize": {
"__type__": "cc.Size",
"width": 27,
"height": 27
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "31GJSeBupAjL6B0JSMWEDn"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 334
},
"_enabled": true,
"__prefab": {
"__id__": 338
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": {
"__uuid__": "6165ffc9-a838-4a33-b569-bdbaaab0e6b4@66d28",
"__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__": "6165ffc9-a838-4a33-b569-bdbaaab0e6b4",
"__expectedType__": "cc.SpriteAtlas"
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "f0Ah1lXhpLIZry/aPq9YzL"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "d5mcu1TmRMYpCqlMi96hsO",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.Node",
"_name": "num",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 333
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 341
},
{
"__id__": 343
}
],
"_prefab": {
"__id__": 345
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 13.5,
"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.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 340
},
"_enabled": true,
"__prefab": {
"__id__": 342
},
"_contentSize": {
"__type__": "cc.Size",
"width": 15.123046875,
"height": 54.4
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "94OK1DwMRAl7qOBrTxG/i4"
},
{
"__type__": "cc.Label",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 340
},
"_enabled": true,
"__prefab": {
"__id__": 344
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_string": "2",
"_horizontalAlign": 1,
"_verticalAlign": 1,
"_actualFontSize": 20,
"_fontSize": 20,
"_fontFamily": "Arial",
"_lineHeight": 40,
"_overflow": 0,
"_enableWrapText": true,
"_font": null,
"_isSystemFontUsed": true,
"_spacingX": 0,
"_isItalic": false,
"_isBold": true,
"_isUnderline": false,
"_underlineHeight": 2,
"_cacheMode": 0,
"_enableOutline": true,
"_outlineColor": {
"__type__": "cc.Color",
"r": 0,
"g": 0,
"b": 0,
"a": 255
},
"_outlineWidth": 2,
"_enableShadow": false,
"_shadowColor": {
"__type__": "cc.Color",
"r": 0,
"g": 0,
"b": 0,
"a": 255
},
"_shadowOffset": {
"__type__": "cc.Vec2",
"x": 2,
"y": 2
},
"_shadowBlur": 2,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "38htj7TVBI84FdhXPqZi9Y"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "5aV+d4uupA3430zZytYs+/",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 333
},
"_enabled": true,
"__prefab": {
"__id__": 347
},
"_contentSize": {
"__type__": "cc.Size",
"width": 42.123046875,
"height": 30
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "daubq3MHBCvZhVT7CCunA4"
},
{
"__type__": "cc.Layout",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 333
},
"_enabled": true,
"__prefab": {
"__id__": 349
},
"_resizeMode": 1,
"_layoutType": 1,
"_cellSize": {
"__type__": "cc.Size",
"width": 40,
"height": 40
},
"_startAxis": 0,
"_paddingLeft": 0,
"_paddingRight": 0,
"_paddingTop": 0,
"_paddingBottom": 0,
"_spacingX": 0,
"_spacingY": 0,
"_verticalDirection": 1,
"_horizontalDirection": 0,
"_constraint": 0,
"_constraintNum": 2,
"_affectedByScale": false,
"_isAlign": false,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "867zQklidJAJ9K6dAQWCB6"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "32ZgIQHstCXYwNDGBH6HPk",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.UITransform",
"_name": "",
@@ -6635,7 +7074,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 334
"__id__": 352
},
"_contentSize": {
"__type__": "cc.Size",
@@ -6663,7 +7102,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 336
"__id__": 354
},
"_alignFlags": 45,
"_target": null,
@@ -6699,7 +7138,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 338
"__id__": 356
},
"_resizeMode": 1,
"_layoutType": 2,
@@ -6742,7 +7181,7 @@
},
{
"__type__": "cc.Node",
"_name": "gold",
"_name": "icon",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
@@ -6752,14 +7191,14 @@
"_active": true,
"_components": [
{
"__id__": 341
"__id__": 359
},
{
"__id__": 343
"__id__": 361
}
],
"_prefab": {
"__id__": 345
"__id__": 363
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -6796,11 +7235,11 @@
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 340
"__id__": 358
},
"_enabled": true,
"__prefab": {
"__id__": 342
"__id__": 360
},
"_contentSize": {
"__type__": "cc.Size",
@@ -6824,11 +7263,11 @@
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 340
"__id__": 358
},
"_enabled": true,
"__prefab": {
"__id__": 344
"__id__": 362
},
"_customMaterial": null,
"_srcBlendFactor": 2,
@@ -6886,7 +7325,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 347
"__id__": 365
},
"_contentSize": {
"__type__": "cc.Size",
@@ -6914,7 +7353,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 349
"__id__": 367
},
"_resizeMode": 1,
"_layoutType": 1,
@@ -6965,7 +7404,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 352
"__id__": 370
},
"_contentSize": {
"__type__": "cc.Size",
@@ -7012,13 +7451,13 @@
"instance": null,
"targetOverrides": [
{
"__id__": 356
"__id__": 374
},
{
"__id__": 358
"__id__": 376
},
{
"__id__": 360
"__id__": 378
}
],
"nestedPrefabInstanceRoots": [
@@ -7046,7 +7485,7 @@
"__id__": 40
},
"targetInfo": {
"__id__": 357
"__id__": 375
}
},
{
@@ -7068,7 +7507,7 @@
"__id__": 40
},
"targetInfo": {
"__id__": 359
"__id__": 377
}
},
{
@@ -7090,7 +7529,7 @@
"__id__": 134
},
"targetInfo": {
"__id__": 361
"__id__": 379
}
},
{

View File

@@ -47,7 +47,7 @@
}
],
"_prefab": {
"__id__": 340
"__id__": 358
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -1444,7 +1444,7 @@
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 23.333333333333336,
"y": 0,
"z": 0
},
"_lrot": {
@@ -1485,7 +1485,7 @@
"_contentSize": {
"__type__": "cc.Size",
"width": 190,
"height": 23.333333333333332
"height": 70
},
"_anchorPoint": {
"__type__": "cc.Vec2",
@@ -1521,12 +1521,12 @@
"a": 255
},
"_string": "词条3",
"_horizontalAlign": 0,
"_horizontalAlign": 1,
"_verticalAlign": 1,
"_actualFontSize": 18,
"_actualFontSize": 21,
"_fontSize": 20,
"_fontFamily": "Arial",
"_lineHeight": 25,
"_lineHeight": 21,
"_overflow": 2,
"_enableWrapText": true,
"_font": null,
@@ -1624,7 +1624,7 @@
"__id__": 87
},
"_children": [],
"_active": true,
"_active": false,
"_components": [
{
"__id__": 97
@@ -1822,7 +1822,7 @@
"__id__": 87
},
"_children": [],
"_active": true,
"_active": false,
"_components": [
{
"__id__": 105
@@ -6061,7 +6061,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 339
"__id__": 357
},
"_customMaterial": null,
"_srcBlendFactor": 2,
@@ -6127,14 +6127,14 @@
"_active": true,
"_components": [
{
"__id__": 336
"__id__": 354
},
{
"__id__": 308
}
],
"_prefab": {
"__id__": 338
"__id__": 356
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -6167,7 +6167,7 @@
},
{
"__type__": "cc.Node",
"_name": "cost",
"_name": "coin",
"_objFlags": 0,
"__editorExtras__": {
"mountedRoot": null
@@ -6177,7 +6177,7 @@
},
"_children": [
{
"__id__": 325
"__id__": 343
},
{
"__id__": 309
@@ -6186,14 +6186,14 @@
"_active": true,
"_components": [
{
"__id__": 331
"__id__": 349
},
{
"__id__": 333
"__id__": 351
}
],
"_prefab": {
"__id__": 335
"__id__": 353
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -6238,22 +6238,25 @@
},
{
"__id__": 310
},
{
"__id__": 318
}
],
"_active": true,
"_components": [
{
"__id__": 318
"__id__": 336
},
{
"__id__": 320
"__id__": 338
},
{
"__id__": 322
"__id__": 340
}
],
"_prefab": {
"__id__": 324
"__id__": 342
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -6445,6 +6448,442 @@
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.Node",
"_name": "stone",
"_objFlags": 0,
"__editorExtras__": {
"mountedRoot": null
},
"_parent": {
"__id__": 311
},
"_children": [
{
"__id__": 319
},
{
"__id__": 325
}
],
"_active": false,
"_components": [
{
"__id__": 331
},
{
"__id__": 333
}
],
"_prefab": {
"__id__": 335
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": -32.75,
"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": "icon",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 318
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 320
},
{
"__id__": 322
}
],
"_prefab": {
"__id__": 324
},
"_lpos": {
"__type__": "cc.Vec3",
"x": -7.5615234375,
"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.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 319
},
"_enabled": true,
"__prefab": {
"__id__": 321
},
"_contentSize": {
"__type__": "cc.Size",
"width": 27,
"height": 27
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "31GJSeBupAjL6B0JSMWEDn"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 319
},
"_enabled": true,
"__prefab": {
"__id__": 323
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_spriteFrame": {
"__uuid__": "6165ffc9-a838-4a33-b569-bdbaaab0e6b4@66d28",
"__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__": "6165ffc9-a838-4a33-b569-bdbaaab0e6b4",
"__expectedType__": "cc.SpriteAtlas"
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "f0Ah1lXhpLIZry/aPq9YzL"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "d5mcu1TmRMYpCqlMi96hsO",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.Node",
"_name": "num",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 318
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 326
},
{
"__id__": 328
}
],
"_prefab": {
"__id__": 330
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 13.5,
"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.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 325
},
"_enabled": true,
"__prefab": {
"__id__": 327
},
"_contentSize": {
"__type__": "cc.Size",
"width": 15.123046875,
"height": 54.4
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "94OK1DwMRAl7qOBrTxG/i4"
},
{
"__type__": "cc.Label",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 325
},
"_enabled": true,
"__prefab": {
"__id__": 329
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_string": "2",
"_horizontalAlign": 1,
"_verticalAlign": 1,
"_actualFontSize": 20,
"_fontSize": 20,
"_fontFamily": "Arial",
"_lineHeight": 40,
"_overflow": 0,
"_enableWrapText": true,
"_font": null,
"_isSystemFontUsed": true,
"_spacingX": 0,
"_isItalic": false,
"_isBold": true,
"_isUnderline": false,
"_underlineHeight": 2,
"_cacheMode": 0,
"_enableOutline": true,
"_outlineColor": {
"__type__": "cc.Color",
"r": 0,
"g": 0,
"b": 0,
"a": 255
},
"_outlineWidth": 2,
"_enableShadow": false,
"_shadowColor": {
"__type__": "cc.Color",
"r": 0,
"g": 0,
"b": 0,
"a": 255
},
"_shadowOffset": {
"__type__": "cc.Vec2",
"x": 2,
"y": 2
},
"_shadowBlur": 2,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "38htj7TVBI84FdhXPqZi9Y"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "5aV+d4uupA3430zZytYs+/",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 318
},
"_enabled": true,
"__prefab": {
"__id__": 332
},
"_contentSize": {
"__type__": "cc.Size",
"width": 42.123046875,
"height": 30
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "daubq3MHBCvZhVT7CCunA4"
},
{
"__type__": "cc.Layout",
"_name": "",
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 318
},
"_enabled": true,
"__prefab": {
"__id__": 334
},
"_resizeMode": 1,
"_layoutType": 1,
"_cellSize": {
"__type__": "cc.Size",
"width": 40,
"height": 40
},
"_startAxis": 0,
"_paddingLeft": 0,
"_paddingRight": 0,
"_paddingTop": 0,
"_paddingBottom": 0,
"_spacingX": 0,
"_spacingY": 0,
"_verticalDirection": 1,
"_horizontalDirection": 0,
"_constraint": 0,
"_constraintNum": 2,
"_affectedByScale": false,
"_isAlign": false,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "867zQklidJAJ9K6dAQWCB6"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "32ZgIQHstCXYwNDGBH6HPk",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.UITransform",
"_name": "",
@@ -6455,7 +6894,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 319
"__id__": 337
},
"_contentSize": {
"__type__": "cc.Size",
@@ -6483,7 +6922,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 321
"__id__": 339
},
"_alignFlags": 45,
"_target": null,
@@ -6519,7 +6958,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 323
"__id__": 341
},
"_resizeMode": 1,
"_layoutType": 2,
@@ -6562,7 +7001,7 @@
},
{
"__type__": "cc.Node",
"_name": "gold",
"_name": "icon",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
@@ -6572,14 +7011,14 @@
"_active": true,
"_components": [
{
"__id__": 326
"__id__": 344
},
{
"__id__": 328
"__id__": 346
}
],
"_prefab": {
"__id__": 330
"__id__": 348
},
"_lpos": {
"__type__": "cc.Vec3",
@@ -6616,11 +7055,11 @@
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 325
"__id__": 343
},
"_enabled": true,
"__prefab": {
"__id__": 327
"__id__": 345
},
"_contentSize": {
"__type__": "cc.Size",
@@ -6644,11 +7083,11 @@
"_objFlags": 0,
"__editorExtras__": {},
"node": {
"__id__": 325
"__id__": 343
},
"_enabled": true,
"__prefab": {
"__id__": 329
"__id__": 347
},
"_customMaterial": null,
"_srcBlendFactor": 2,
@@ -6706,7 +7145,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 332
"__id__": 350
},
"_contentSize": {
"__type__": "cc.Size",
@@ -6734,7 +7173,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 334
"__id__": 352
},
"_resizeMode": 1,
"_layoutType": 1,
@@ -6785,7 +7224,7 @@
},
"_enabled": true,
"__prefab": {
"__id__": 337
"__id__": 355
},
"_contentSize": {
"__type__": "cc.Size",
@@ -6832,13 +7271,13 @@
"instance": null,
"targetOverrides": [
{
"__id__": 341
"__id__": 359
},
{
"__id__": 343
"__id__": 361
},
{
"__id__": 345
"__id__": 363
}
],
"nestedPrefabInstanceRoots": [
@@ -6866,7 +7305,7 @@
"__id__": 40
},
"targetInfo": {
"__id__": 342
"__id__": 360
}
},
{
@@ -6888,7 +7327,7 @@
"__id__": 40
},
"targetInfo": {
"__id__": 344
"__id__": 362
}
},
{
@@ -6910,7 +7349,7 @@
"__id__": 119
},
"targetInfo": {
"__id__": 346
"__id__": 364
}
},
{

View File

@@ -3512,6 +3512,10 @@
"cd_mask": {
"__id__": 138
},
"iboxPrefab": {
"__uuid__": "348ec900-f7b9-440a-911e-75f9590254c7",
"__expectedType__": "cc.Prefab"
},
"_id": ""
},
{

File diff suppressed because it is too large Load Diff

View File

@@ -3922,6 +3922,10 @@
"cd_mask": {
"__id__": 156
},
"iboxPrefab": {
"__uuid__": "348ec900-f7b9-440a-911e-75f9590254c7",
"__expectedType__": "cc.Prefab"
},
"_id": ""
},
{

View File

@@ -36,7 +36,7 @@ export var UIConfigData: { [key: number]: UIConfig } = {
[UIID.Netinstable]: { layer: LayerType.PopUp, prefab: "common/prefab/netinstable" },
[UIID.Role_Controller]: { layer: LayerType.UI, prefab: "gui/role_controller" },
[UIID.Victory]: { layer: LayerType.UI, prefab: "gui/element/victory" },
[UIID.IBox]: { layer: LayerType.UI, prefab: "gui/element/ibox" },
[UIID.IBox]: { layer: LayerType.PopUp, prefab: "gui/element/ibox" },
[UIID.Notity]: { layer: LayerType.UI, prefab: "gui/element/notity" },
// [UIID.Ranks]: { layer: LayerType.UI, prefab: "gui/element/ranks" },
// [UIID.Heros]: { layer: LayerType.UI, prefab: "gui/element/heros" },

View File

@@ -10,7 +10,7 @@
*
* 输出(双格式,供 UI 按需取用):
* - buildSkillDesc(source) → 纯文本Label 用),数值无颜色
* - buildSkillDescRich(source) → 富文本RichText 用BBCode数值用 <color> 高亮
* - buildSkillDescRich(source) → 富文本RichText 用BBCode技能名蓝色、数值绿色高亮
* 两者共用同一套结构化行构建逻辑,仅渲染阶段区分,保证纯/富文本内容严格一致。
*
* 通用性(纯配置驱动):
@@ -82,8 +82,14 @@ const ATTR_NAME: Partial<Record<Attrs, string>> = {
[Attrs.hp_max]: "最大生命",
};
/** 富文本数值高亮色(绿色,与项目绿色系同源,深色面板上清晰可读) */
const RICH_VALUE_COLOR = "#1E8449";
/** 富文本数值高亮色(绿色,与项目绿色系同源,深色面板上清晰可读) */
const RICH_VALUE_COLOR = "#27AE60";
/** 富文本技能名高亮色(蓝色,与数值绿色区分,标识技能名「」片段) */
const RICH_NAME_COLOR = "#2E86C1";
/** 技能名「」匹配模式(仅本模块行首/行中技能名片段使用) */
const SKILL_NAME_PATTERN = /「([^」]*)」/g;
/** 解析目标描述文本(与战斗 SCastSystem 目标选取语义严格一致) */
function buildTargetDesc(skill: SkillConfig): string {
@@ -308,14 +314,63 @@ export function buildSkillDesc(source: ISkillDescSource): string {
}
/**
* 富文本描述RichText 用BBCode数值用 <color> 高亮。
* 富文本描述RichText 用BBCode技能名用 <color=#2E86C1> 蓝色、数值用 <color=#27AE60> 亮绿色高亮。
* @param source 触发技能数据源(同 buildSkillDesc
* @returns 多行富文本串,数值片段包裹 <color=#1E8449>,用 \n 分隔
* @returns 多行富文本串,技能名片段包裹 <color=#2E86C1>、数值片段包裹 <color=#27AE60>,用 \n 分隔
*/
export function buildSkillDescRich(source: ISkillDescSource): string {
return buildSkillLines(source)
.map(l => l.value
? `${l.prefix}<color=${RICH_VALUE_COLOR}>${l.value}</color>${l.suffix}`
: `${l.prefix}${l.suffix}`)
.map(l => {
const prefix = l.prefix.replace(SKILL_NAME_PATTERN, `<color=${RICH_NAME_COLOR}>$1</color>`);
return l.value
? `${prefix}<color=${RICH_VALUE_COLOR}>${l.value}</color>${l.suffix}`
: `${prefix}${l.suffix}`;
})
.join("\n");
}
/**
* 单个技能详情富文本IBox 弹窗用):展示 CD/持续时间 + 结构化效果描述。
* @param skillUuid SkillSet 技能 UUID
* @param overrides 可选覆写参数(如药水卡自定义档位)
* @param lv 技能等级(仅用于展示,不影响数值计算)
* @returns 多行富文本串:第一行 CD/持续时间,第二行效果描述
*/
export function buildSingleSkillRich(skillUuid: number, overrides?: SkillOverrides, lv: number = 1): string {
const base = SkillSet[skillUuid];
if (!base) return "未知技能";
const skill = mergeSkillParams(base, overrides);
// SkillConfig 未定义 cd 字段,冷却时间由外部运行时数据传入;计时模式展示持续时间
const dur = skill.buff_duration ?? (skill.timed_buff_id !== undefined ? BuffList[skill.timed_buff_id]?.duration : undefined) ?? 0;
const cdTag = dur > 0 ? `<color=${RICH_VALUE_COLOR}>持续:${dur}s</color>` : "";
const nameTag = `「<color=${RICH_NAME_COLOR}>${skill.name}</color>」 Lv.${lv}`;
// 复用结构化效果行head 为空避免重复触发类型前缀
const line = buildEffectLine("", skill);
const prefix = line.prefix.replace(SKILL_NAME_PATTERN, `「<color=${RICH_NAME_COLOR}>$1</color>」`);
const effect = line.value
? `${prefix}<color=${RICH_VALUE_COLOR}>${line.value}</color>${line.suffix}`
: `${prefix}${line.suffix}`;
return cdTag ? `${nameTag} ${cdTag}\n${effect}` : `${nameTag}\n${effect}`;
}
/**
* 装备详情富文本IBox 弹窗用):展示装备包含的全部驻场光环词条。
* @param fieldUuids FieldSkillSet 驻场光环 UUID 数组
* @returns 多行富文本串,每行一个词条
*/
export function buildEquipRich(fieldUuids: number[]): string {
if (!fieldUuids?.length) return "无词条";
const lines: string[] = [];
for (const uuid of fieldUuids) {
const line = buildFieldLine("", uuid);
if (!line) continue;
const prefix = line.prefix.replace(SKILL_NAME_PATTERN, `「<color=${RICH_NAME_COLOR}>$1</color>」`);
const text = line.value
? `${prefix}<color=${RICH_VALUE_COLOR}>${line.value}</color>${line.suffix}`
: `${prefix}${line.suffix}`;
lines.push(text);
}
return lines.length > 0 ? lines.join("\n") : "无词条";
}

View File

@@ -24,7 +24,6 @@ import { HeroInfo } from "../common/config/heroSet";
import { oops } from "db://oops-framework/core/Oops";
import { GameEvent } from "../common/config/GameEvent";
import { smc } from "../common/SingletonModuleComp";
import { UIID } from "../common/config/GameUIConfig";
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
import { FieldSkillType } from "../common/config/SkillSet";
import { FieldSkillHelper } from "../hero/FieldSkillHelper";
@@ -121,11 +120,6 @@ export class CHeroComp extends CCComp {
this.buy_node?.on(NodeEventType.TOUCH_END, this.onBuyClick, this);
this.buy_node?.on(NodeEventType.TOUCH_CANCEL, this.onBuyTouchCancel, this);
// 卡面长按弹信息框:按下启动计时,放开/取消时关闭
this.node.on(NodeEventType.TOUCH_START, this.onInfoTouchStart, this);
this.node.on(NodeEventType.TOUCH_END, this.onInfoTouchEnd, this);
this.node.on(NodeEventType.TOUCH_CANCEL, this.onInfoTouchEnd, this);
// 缓存透明度组件(用于淡入淡出动画)
this.opacityComp = this.node.getComponent(UIOpacity) || this.node.addComponent(UIOpacity);
@@ -143,13 +137,6 @@ export class CHeroComp extends CCComp {
this.buy_node.off(NodeEventType.TOUCH_END, this.onBuyClick, this);
this.buy_node.off(NodeEventType.TOUCH_CANCEL, this.onBuyTouchCancel, this);
}
if (this.node && this.node.isValid) {
this.node.off(NodeEventType.TOUCH_START, this.onInfoTouchStart, this);
this.node.off(NodeEventType.TOUCH_END, this.onInfoTouchEnd, this);
this.node.off(NodeEventType.TOUCH_CANCEL, this.onInfoTouchEnd, this);
}
// 清理长按计时器,防止销毁后回调访问失效节点
this.unschedule(this.showInfo);
}
// ======================== 数据初始化 ========================
@@ -546,51 +533,6 @@ export class CHeroComp extends CCComp {
});
}
// ======================== 长按信息框 ========================
/** 长按时长(秒) */
private static readonly LONG_PRESS_TIME: number = 0.5;
/** 信息框是否已弹出(区分长按完成与短按取消) */
private info_shown: boolean = false;
/** 卡面按下:启动长按计时 */
private onInfoTouchStart() {
if (!this.cardData) return;
this.info_shown = false;
this.scheduleOnce(this.showInfo, CHeroComp.LONG_PRESS_TIME);
}
/** 卡面放开/取消:已弹出则关闭信息框,未弹出则取消长按计时 */
private onInfoTouchEnd() {
this.unschedule(this.showInfo);
if (this.info_shown) {
this.info_shown = false;
// oops.gui 移除信息框
oops.gui.remove(UIID.HInfo);
}
}
/**
* 长按到点:弹出英雄信息框。
* 升级卡SpecialUpgrade + target_hero_eid通过 eid 反查场上实体得到 hero_uuid
* 与 updateUI 的渲染逻辑保持一致。
*/
private showInfo() {
if (!this.cardData) return;
this.info_shown = true;
const isUpgradeCard = this.cardData.type === CardType.SpecialUpgrade && !!this.cardData.target_hero_eid;
const heroUuid = isUpgradeCard
? (this.queryHeroUuidByEid(this.cardData.target_hero_eid as number) ?? this.cardData.uuid)
: this.cardData.uuid;
const heroLv = Math.max(1, this.cardData.hero_lv ?? 1);
const poolLv = Math.max(1, this.cardData.base_card_lv ?? this.cardData.card_lv ?? 1);
// oops.gui 打开 HInfo 英雄卡预览
oops.gui.remove(UIID.HInfo);
oops.gui.open(UIID.HInfo, { heroUuid, heroLv, poolLv });
}
// ======================== 购买逻辑 ========================
/**

View File

@@ -31,7 +31,7 @@
* - smc.mission —— 游戏运行状态
*/
import { mLogger } from "../common/Logger";
import { _decorator, Node, Prefab, Sprite, Label, Vec3, resources, SpriteAtlas, tween, v3, Tween, NodeEventType } from "cc";
import { _decorator, Node, Prefab, Sprite, Label, Vec3, instantiate, tween, v3, Tween, NodeEventType } 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 { CardTriggerType } from "../common/config/CardSet";
@@ -40,7 +40,7 @@ import { SkillSet, SkillOverrides, FieldSkillSet } from "../common/config/SkillS
import { oops } from "db://oops-framework/core/Oops";
import { GameEvent } from "../common/config/GameEvent";
import { smc } from "../common/SingletonModuleComp";
import { UIID } from "../common/config/GameUIConfig";
import { IBoxComp } from "./IBoxComp";
const { ccclass, property } = _decorator;
/**
@@ -70,6 +70,13 @@ export class EquipBoxComp extends CCComp {
/** cd计时遮罩 */
@property({ type: Node })
private cd_mask: Node = null;
/** 装备详情弹窗预制体(长按图标时实例化展示) */
@property(Prefab)
private iboxPrefab: Prefab = null;
/** 当前已弹出的 IBox 实例(防止重复弹出) */
private iboxNode: Node = null;
// ======================== 技能配置 ========================
/** 技能 UUID */
@@ -149,6 +156,7 @@ export class EquipBoxComp extends CCComp {
}
// 清理长按计时器,防止销毁后回调访问失效节点
this.unschedule(this.showInfo);
this.closeInfoBox();
oops.message.off(GameEvent.NewWave, this.onNewWaveGlobal, this);
// 通知 MissEquipComp 回收该节点占用的槽位
oops.message.dispatchEvent(GameEvent.RemoveEquipBox, this.node);
@@ -156,6 +164,8 @@ export class EquipBoxComp extends CCComp {
/** 长按时长(秒) */
private static readonly LONG_PRESS_TIME: number = 0.5;
/** IBox 相对图标的 Y 轴偏移(像素) */
private static readonly IBOX_OFFSET_Y: number = 80;
/** 信息框是否已弹出(区分长按完成与短按取消) */
private info_shown: boolean = false;
@@ -171,19 +181,53 @@ export class EquipBoxComp extends CCComp {
this.unschedule(this.showInfo);
if (this.info_shown) {
this.info_shown = false;
// oops.gui 移除信息框
oops.gui.remove(UIID.HInfo);
this.closeInfoBox();
}
}
/** 长按到点:弹出信息框 */
/** 长按到点:实例化 IBox 展示装备详情 */
private showInfo() {
if (!this.initialized) return;
mLogger.log(this.debugMode, "EquipBoxComp", "showInfo", {
initialized: this.initialized,
iboxPrefab: !!this.iboxPrefab,
s_uuid: this.s_uuid,
});
if (!this.initialized || !this.iboxPrefab) return;
this.closeInfoBox();
this.info_shown = true;
oops.audio.playEffect("music/button");
// 弹出 HInfoComp从 EquipPoolList 查询配置
oops.gui.remove(UIID.HInfo);
oops.gui.open(UIID.HInfo, { heroUuid: this.s_uuid, heroLv: this.card_lv, poolLv: 1, isSkillCard: true, isEquipCard: true });
this.iboxNode = instantiate(this.iboxPrefab);
// 挂到装备图标的父节点下,使用局部坐标系
const parent = this.node.parent;
parent?.addChild(this.iboxNode);
// 弹窗宽度 720X 居中为 0Y 相对图标向上偏移
this.iboxNode.setPosition(0, this.node.position.y + EquipBoxComp.IBOX_OFFSET_Y, this.node.position.z);
mLogger.log(this.debugMode, "EquipBoxComp", "ibox instantiated", {
iboxNodeValid: this.iboxNode?.isValid,
iboxNodeActive: this.iboxNode?.active,
iboxNodePos: this.iboxNode?.position,
parentName: parent?.name,
});
const ibox = this.iboxNode.getComponent(IBoxComp);
mLogger.log(this.debugMode, "EquipBoxComp", "ibox component", {
hasIbox: !!ibox,
massageNode: ibox?.["massage_node"] ? "bound" : "null",
});
ibox?.init({
equipUuid: this.s_uuid,
});
mLogger.log(this.debugMode, "EquipBoxComp", "ibox init done", {
iboxNodePos: this.iboxNode?.position,
});
}
/** 关闭并清理已弹出的 IBox */
private closeInfoBox() {
if (this.iboxNode && this.iboxNode.isValid) {
this.iboxNode.destroy();
}
this.iboxNode = null;
}
/**

View File

@@ -21,7 +21,6 @@ import { FieldSkillSet } from "../common/config/SkillSet";
import { oops } from "db://oops-framework/core/Oops";
import { getCardIconId, setSpriteFrame } from "../common/CardIconHelper";
import { GameEvent } from "../common/config/GameEvent";
import { UIID } from "../common/config/GameUIConfig";
import { MissionEconomy } from "./MissionEconomy";
const { ccclass, property } = _decorator;
@@ -92,10 +91,6 @@ export class EquipListComp extends CCComp {
this.buy_node?.on(NodeEventType.TOUCH_START, this.onBuyTouchStart, this);
this.buy_node?.on(NodeEventType.TOUCH_END, this.onBuyClick, this);
this.buy_node?.on(NodeEventType.TOUCH_CANCEL, this.onBuyTouchCancel, this);
// 卡面长按弹信息框:按下启动计时,放开/取消时关闭
this.node.on(NodeEventType.TOUCH_START, this.onInfoTouchStart, this);
this.node.on(NodeEventType.TOUCH_END, this.onInfoTouchEnd, this);
this.node.on(NodeEventType.TOUCH_CANCEL, this.onInfoTouchEnd, this);
this.opacityComp = this.node.getComponent(UIOpacity) || this.node.addComponent(UIOpacity);
}
@@ -106,13 +101,6 @@ export class EquipListComp extends CCComp {
this.buy_node.off(NodeEventType.TOUCH_END, this.onBuyClick, this);
this.buy_node.off(NodeEventType.TOUCH_CANCEL, this.onBuyTouchCancel, this);
}
if (this.node && this.node.isValid) {
this.node.off(NodeEventType.TOUCH_START, this.onInfoTouchStart, this);
this.node.off(NodeEventType.TOUCH_END, this.onInfoTouchEnd, this);
this.node.off(NodeEventType.TOUCH_CANCEL, this.onInfoTouchEnd, this);
}
// 清理长按计时器,防止销毁后回调访问失效节点
this.unschedule(this.showInfo);
}
// ======================== 数据初始化 ========================
@@ -333,45 +321,6 @@ export class EquipListComp extends CCComp {
.start();
}
// ======================== 长按信息框 ========================
/** 长按时长(秒) */
private static readonly LONG_PRESS_TIME: number = 0.5;
/** 信息框是否已弹出(区分长按完成与短按取消) */
private info_shown: boolean = false;
/** 卡面按下:启动长按计时 */
private onInfoTouchStart() {
if (!this.cardData) return;
this.info_shown = false;
this.scheduleOnce(this.showInfo, EquipListComp.LONG_PRESS_TIME);
}
/** 卡面放开/取消:已弹出则关闭信息框,未弹出则取消长按计时 */
private onInfoTouchEnd() {
this.unschedule(this.showInfo);
if (this.info_shown) {
this.info_shown = false;
// oops.gui 移除信息框
oops.gui.remove(UIID.HInfo);
}
}
/** 长按到点:弹出装备信息框 */
private showInfo() {
if (!this.cardData) return;
this.info_shown = true;
// oops.gui 打开 HInfo 装备卡预览(复用 EquipBoxComp 的打开参数)
oops.gui.remove(UIID.HInfo);
oops.gui.open(UIID.HInfo, {
heroUuid: this.cardData.uuid,
heroLv: this.cardData.card_lv ?? 1,
poolLv: 1,
isSkillCard: true,
isEquipCard: true
});
}
// ======================== 购买逻辑 ========================
/**

View File

@@ -1,75 +1,68 @@
/**
* @file IBoxComp.ts
* @description 英雄信息弹窗组件IBoxUI 视图层)
* @description 技能/装备详情弹窗组件IBoxUI 视图层)
*
* 职责:
* 1. 作为全局弹窗,展示某个英雄的 **详细技能信息**。
* 2. 通过 onAdded(args) 接收英雄 UUID、等级和运行时技能数据。
* 3. 自动计算技能行数并动态调整弹窗背景高度和名称位置
* 1. 作为详情弹窗,展示单个技能或装备的 **功能描述详情**。
* 2. 通过 init(args) 接收技能 UUID、装备 UUID 或运行时技能数据。
* 3. 使用单个 RichText 以 BBCode 展示名称蓝色、CD/持续时间(亮绿色)、结构化效果描述
* 4. 点击弹窗任意区域关闭自身。
*
* 关键设计:
* - Line1~Line5 为预设的 5 行技能节点,按需显示/隐藏
* - 每行包含技能名、等级、CD、描述文本和类型图标近战/远程/辅助)。
* - 背景高度 = baseHeight + (行数 - 1) × extraLineHeight
* - 若传入 args.skills运行时技能优先使用否则回退到英雄静态配置
* - 复用 HeroSkillDesc 的结构化模板渲染,数值实时从配置读取,杜绝漂移
* - 技能展示名称、等级、CD、效果描述SkillDescSet 模板)。
* - 装备展示名称、全部驻场光环词条FieldDescSet 模板)
* - 不走 oops.gui由调用方手动实例化并添加到场景通过 init() 初始化
*
* 依赖:
* - HeroInfoheroSet—— 英雄静态配置
* - SkillSet / ITypeSkillSet—— 技能静态配置
* - UIID —— 在 oops.gui 系统中注册的弹窗 ID
* - HeroSkillDescbuildSingleSkillRich / buildEquipRich—— 描述生成
* - SkillSet / FieldSkillSetSkillSet—— 技能/光环静态配置
* - EquipSetfindEquipByUuid—— 装备静态配置
*/
import { _decorator, Label, Node, NodeEventType, UITransform } from "cc";
import { _decorator, Label, NodeEventType, RichText } 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 { HeroInfo } from "../common/config/heroSet";
import { IType, SkillSet } from "../common/config/SkillSet";
import { oops } from "db://oops-framework/core/Oops";
import { SkillSet, SkillOverrides } from "../common/config/SkillSet";
import { buildEquipRich, buildSingleSkillRich } from "../common/config/HeroSkillDesc";
import { findEquipByUuid } from "../common/config/EquipSet";
const { ccclass, property } = _decorator;
/** IBox 初始化参数 */
export interface IBoxInitArgs {
/** SkillSet 技能 UUID技能详情模式 */
skillUuid?: number;
/** 技能等级(默认 1 */
skillLv?: number;
/** 技能覆写参数(如药水卡自定义档位) */
overrides?: SkillOverrides;
/** EquipSet 装备 UUID装备详情模式 */
equipUuid?: number;
/** 运行时技能数据(运行时技能详情模式,取第一个技能展示) */
skills?: Record<number, { uuid: number; lv: number; cd: number; ccd: number }>;
}
/**
* IBoxComp —— 英雄信息弹窗视图组件
* IBoxComp —— 技能/装备详情弹窗视图组件
*
* 通过 oops.gui.open(UIID.IBox, { heroUuid, heroLv, skills? }) 打开
* 展示英雄技能列表,支持最多 5 行。
* 由调用方通过 instantiate + addChild 手动实例化,然后调用 init(args) 初始化
* 示例:
* const node = instantiate(this.iboxPrefab);
* this.node.addChild(node);
* node.getComponent(IBoxComp).init({ skillUuid: 6301, anchorPos: this.node.worldPosition });
*/
@ccclass('IBoxComp')
@ecs.register('IBoxComp', false)
export class IBoxComp extends CCComp {
// ======================== 编辑器绑定节点5 行技能) ========================
@property(Node)
Line1: Node = null!
@property(Node)
Line2: Node = null!
@property(Node)
Line3: Node = null!
@property(Node)
Line4: Node = null!
@property(Node)
Line5: Node = null!
// ======================== 布局常量 ========================
/** 弹窗背景基础高度(只有 1 行技能时的高度) */
private readonly baseHeight: number = 100;
/** 每增加一行技能,背景增加的高度 */
private readonly extraLineHeight: number = 50;
/** 英雄名称标签的基准 Y 坐标 */
private readonly nameBaseY: number = 50;
/** 每增加一行技能,名称标签额外上移的 Y 偏移 */
private readonly nameExtraLineOffsetY: number = 25;
// ======================== 编辑器绑定节点 ========================
@property(RichText)
massage_node: RichText = null!
/**
* ECS 实体挂载回调:接收外部传入的英雄参数并渲染
* @param args.heroUuid 英雄 UUID
* @param args.heroLv 英雄当前等级
* @param args.skills (可选)运行时技能数据,若无则使用英雄静态配置
* 初始化并渲染弹窗内容
* @param args 见 IBoxInitArgs
*/
onAdded(args: {
heroUuid?: number;
heroLv?: number;
skills?: Record<number, { uuid: number; lv: number; cd: number; ccd: number }>;
}) {
this.renderHeroInfo(args);
public init(args: IBoxInitArgs) {
this.render(args);
}
/** 绑定点击关闭事件 */
@@ -93,99 +86,73 @@ export class IBoxComp extends CCComp {
// ======================== 渲染逻辑 ========================
/**
* 主渲染方法:解析英雄数据并填充技能行
*
* 流程:
* 1. 从 args 中取英雄 UUID 和等级。
* 2. 优先使用运行时技能数据args.skills否则回退英雄静态配置。
* 3. 将每个技能映射为 { text, iType },过滤无效项。
* 4. 调用 applyLineData 渲染到 Line1~Line5。
* 主渲染方法:根据 args 模式分发到技能详情或装备详情
*/
private renderHeroInfo(args: {
heroUuid?: number;
heroLv?: number;
skills?: Record<number, { uuid: number; lv: number; cd: number; ccd: number }>;
}) {
const heroUuid = Math.floor(args?.heroUuid ?? 0);
const heroLv = Math.max(1, Math.floor(args?.heroLv ?? 1));
const hero = HeroInfo[heroUuid];
if (!hero) {
this.setHeroName("");
this.applyLineData([{ text: "暂无技能信息" }]);
private render(args: IBoxInitArgs) {
// 装备详情模式
if (args?.equipUuid !== undefined) {
this.renderEquip(args.equipUuid);
return;
}
this.setHeroName(hero.name);
// 运行时技能 vs 静态配置
const runtimeSkills = args?.skills ? Object.values(args.skills) : [];
const sourceSkills = runtimeSkills.length > 0 ? runtimeSkills : Object.values(hero.skills ?? {});
// 将每个技能转换为显示数据
const lineData = sourceSkills.map(skill => {
const skillId = Math.floor(skill?.uuid ?? 0);
if (!skillId) return null;
const config = SkillSet[skillId];
if (!config) return null;
// 运行时技能直接使用其等级;静态配置的技能等级需叠加英雄等级修正
const runtimeLv = runtimeSkills.length > 0 ? Math.max(0, Math.floor(skill.lv ?? 0)) : Math.max(0, Math.floor((skill.lv ?? 1) + heroLv - 2));
const cd = Number(skill?.cd ?? 0);
return {
text: `${config.name} Lv.${runtimeLv} CD:${cd}s ${config.info}`,
iType: config.IType
};
}).filter(item => !!item) as Array<{ text: string; iType: IType }>;
this.applyLineData(lineData.length > 0 ? lineData : [{ text: "暂无技能信息" }]);
}
/**
* 将技能数据应用到 Line1~Line5
* 1. 按顺序填充文本和类型图标。
* 2. 超出的行隐藏。
* 3. 根据显示行数调整弹窗高度和名称位置。
*
* @param skillLines 技能行数据数组
*/
private applyLineData(skillLines: Array<{ text: string; iType?: IType }>) {
const lines = [this.Line1, this.Line2, this.Line3, this.Line4, this.Line5];
const showCount = Math.max(1, Math.min(lines.length, skillLines.length));
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (!line) continue;
const active = i < showCount;
line.active = active;
if (!active) continue;
const data = skillLines[i];
const text = data?.text ?? "";
// 查找技能文本节点并设置内容
const noteNode = line.getChildByName("note");
const label = noteNode?.getComponent(Label) || noteNode?.getComponentInChildren(Label) || line.getComponentInChildren(Label);
if (label) label.string = text;
// 更新类型图标
this.updateLineTypeIcon(line, data?.iType);
// 运行时技能详情模式(取第一个技能)
if (args?.skills) {
const first = Object.values(args.skills)[0];
if (first) {
this.renderSkill(first.uuid, first.lv);
return;
}
}
// 动态调整弹窗背景高度
const targetHeight = this.baseHeight + Math.max(0, showCount - 1) * this.extraLineHeight;
this.updateIBoxHeight(targetHeight);
// 动态调整名称位置
this.updateNamePosition(showCount);
// 技能详情模式
if (args?.skillUuid !== undefined) {
this.renderSkill(args.skillUuid, args.skillLv ?? 1, args.overrides);
return;
}
this.setHeroName("");
this.setRichText("暂无信息");
}
/**
* 设置弹窗背景 Bg 节点的高度
* @param height 目标高度
* 渲染技能详情名称、等级、CD、结构化效果描述。
* @param skillUuid SkillSet 技能 UUID
* @param lv 技能等级
* @param overrides 可选覆写参数
*/
private updateIBoxHeight(height: number) {
const bgNode = this.node.getChildByName("Bg");
const bgTransform = bgNode?.getComponent(UITransform);
if (bgTransform) {
bgTransform.setContentSize(bgTransform.contentSize.width, height);
private renderSkill(skillUuid: number, lv: number, overrides?: SkillOverrides) {
const skill = SkillSet[skillUuid];
if (!skill) {
this.setHeroName("");
this.setRichText("未知技能");
return;
}
this.setHeroName(skill.name);
this.setRichText(buildSingleSkillRich(skillUuid, overrides, lv));
}
/**
* 渲染装备详情:名称、全部驻场光环词条。
* @param equipUuid EquipSet 装备 UUID
*/
private renderEquip(equipUuid: number) {
const equip = findEquipByUuid(equipUuid);
if (!equip) {
this.setHeroName("");
this.setRichText("未知装备");
return;
}
this.setHeroName(equip.name);
this.setRichText(buildEquipRich(equip.field ?? []));
}
/** 将 BBCode 文本写入 RichText */
private setRichText(text: string) {
if (this.massage_node && this.massage_node.isValid) {
this.massage_node.string = text;
}
}
/**
* 设置英雄名称标签
* @param name 英雄名称
* 设置标题名称标签
* @param name 技能/装备名称
*/
private setHeroName(name: string) {
const bgNode = this.node.getChildByName("Bg");
@@ -197,37 +164,10 @@ export class IBoxComp extends CCComp {
}
}
/**
* 根据显示行数调整名称节点的 Y 坐标。
* 行数越多,名称越往上移,保持视觉居中。
*
* @param showCount 当前显示的技能行数
*/
private updateNamePosition(showCount: number) {
const bgNode = this.node.getChildByName("Bg");
const nameNode = bgNode?.getChildByName("name");
if (!nameNode) return;
const targetY = this.nameBaseY + Math.max(0, showCount - 1) * this.nameExtraLineOffsetY;
const current = nameNode.position;
nameNode.setPosition(current.x, targetY, current.z);
}
/**
* 更新技能行的类型图标(互斥显示)。
* @param line 技能行节点
* @param iType 技能类型(近战 / 远程 / 辅助)
*/
private updateLineTypeIcon(line: Node, iType?: IType) {
const meleeNode = line.getChildByName("Melee");
const remoteNode = line.getChildByName("remote");
const supportNode = line.getChildByName("support");
if (meleeNode) meleeNode.active = iType === IType.Melee;
if (remoteNode) remoteNode.active = iType === IType.remote;
if (supportNode) supportNode.active = iType === IType.support;
}
/** 点击弹窗任意区域关闭自身 */
private onTapClose() {
oops.gui.removeByNode(this.node);
if (this.node && this.node.isValid) {
this.node.destroy();
}
}
}

View File

@@ -19,12 +19,10 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
import { CardConfig, CardTriggerType, CKind } from "../common/config/CardSet";
import { EquipPoolList } from "../common/config/EquipSet";
import { SkillCardList } from "../common/config/SCardSet";
import { FieldSkillSet, SkillSet } from "../common/config/SkillSet";
import { oops } from "db://oops-framework/core/Oops";
import { getCardIconId, setSpriteFrame } from "../common/CardIconHelper";
import { GameEvent } from "../common/config/GameEvent";
import { UIID } from "../common/config/GameUIConfig";
import { MissionEconomy } from "./MissionEconomy";
const { ccclass, property } = _decorator;
@@ -95,10 +93,6 @@ export class ItemListComp extends CCComp {
this.buy_node?.on(NodeEventType.TOUCH_START, this.onBuyTouchStart, this);
this.buy_node?.on(NodeEventType.TOUCH_END, this.onBuyClick, this);
this.buy_node?.on(NodeEventType.TOUCH_CANCEL, this.onBuyTouchCancel, this);
// 卡面长按弹信息框:按下启动计时,放开/取消时关闭
this.node.on(NodeEventType.TOUCH_START, this.onInfoTouchStart, this);
this.node.on(NodeEventType.TOUCH_END, this.onInfoTouchEnd, this);
this.node.on(NodeEventType.TOUCH_CANCEL, this.onInfoTouchEnd, this);
this.opacityComp = this.node.getComponent(UIOpacity) || this.node.addComponent(UIOpacity);
}
@@ -109,13 +103,6 @@ export class ItemListComp extends CCComp {
this.buy_node.off(NodeEventType.TOUCH_END, this.onBuyClick, this);
this.buy_node.off(NodeEventType.TOUCH_CANCEL, this.onBuyTouchCancel, this);
}
if (this.node && this.node.isValid) {
this.node.off(NodeEventType.TOUCH_START, this.onInfoTouchStart, this);
this.node.off(NodeEventType.TOUCH_END, this.onInfoTouchEnd, this);
this.node.off(NodeEventType.TOUCH_CANCEL, this.onInfoTouchEnd, this);
}
// 清理长按计时器,防止销毁后回调访问失效节点
this.unschedule(this.showInfo);
}
// ======================== 数据初始化 ========================
@@ -370,65 +357,6 @@ export class ItemListComp extends CCComp {
.start();
}
// ======================== 长按信息框 ========================
/** 长按时长(秒) */
private static readonly LONG_PRESS_TIME: number = 0.5;
/** 信息框是否已弹出(区分长按完成与短按取消) */
private info_shown: boolean = false;
/** 卡面按下:启动长按计时 */
private onInfoTouchStart() {
if (!this.cardData) return;
this.info_shown = false;
this.scheduleOnce(this.showInfo, ItemListComp.LONG_PRESS_TIME);
}
/** 卡面放开/取消:已弹出则关闭信息框,未弹出则取消长按计时 */
private onInfoTouchEnd() {
this.unschedule(this.showInfo);
if (this.info_shown) {
this.info_shown = false;
// oops.gui 移除信息框
oops.gui.remove(UIID.HInfo);
}
}
/**
* 长按到点:按卡牌类型弹出对应信息框。
* - 装备卡trigger_type=Field→ 装备预览isEquipCard
* - 商品/药品及其他 → 技能卡预览uuid 反查 SkillCardList
*/
private showInfo() {
if (!this.cardData) return;
this.info_shown = true;
const isEquip = this.cardData.trigger_type === CardTriggerType.Field;
if (isEquip) {
// oops.gui 打开 HInfo 装备卡预览(复用 EquipBoxComp 的打开参数)
oops.gui.remove(UIID.HInfo);
oops.gui.open(UIID.HInfo, {
heroUuid: this.cardData.uuid,
heroLv: this.cardData.card_lv ?? 1,
poolLv: 1,
isSkillCard: true,
isEquipCard: true
});
return;
}
// 技能/商品卡:反查 SkillCardList 拿到卡池 uuid查不到时降级为本卡 uuid
const config = SkillCardList.find(c => c.uuid === this.cardData!.uuid || c.skill === this.cardData!.uuid);
const cardUuid = config ? config.uuid : this.cardData.uuid;
oops.gui.remove(UIID.HInfo);
oops.gui.open(UIID.HInfo, {
heroUuid: cardUuid,
heroLv: this.cardData.card_lv ?? 1,
poolLv: config?.card_lv ?? 1,
isSkillCard: true
});
}
// ======================== 购买逻辑 ========================
/**

View File

@@ -21,7 +21,6 @@ import { oops } from "db://oops-framework/core/Oops";
import { getCardIconId, setSpriteFrame } from "../common/CardIconHelper";
import { GameEvent } from "../common/config/GameEvent";
import { smc } from "../common/SingletonModuleComp";
import { UIID } from "../common/config/GameUIConfig";
import { MissionEconomy } from "./MissionEconomy";
const { ccclass, property } = _decorator;
@@ -92,10 +91,6 @@ export class SCardComp extends CCComp {
this.buy_node?.on(NodeEventType.TOUCH_START, this.onBuyTouchStart, this);
this.buy_node?.on(NodeEventType.TOUCH_END, this.onBuyClick, this);
this.buy_node?.on(NodeEventType.TOUCH_CANCEL, this.onBuyTouchCancel, this);
// 卡面长按弹信息框:按下启动计时,放开/取消时关闭
this.node.on(NodeEventType.TOUCH_START, this.onInfoTouchStart, this);
this.node.on(NodeEventType.TOUCH_END, this.onInfoTouchEnd, this);
this.node.on(NodeEventType.TOUCH_CANCEL, this.onInfoTouchEnd, this);
this.opacityComp = this.node.getComponent(UIOpacity) || this.node.addComponent(UIOpacity);
}
@@ -106,13 +101,6 @@ export class SCardComp extends CCComp {
this.buy_node.off(NodeEventType.TOUCH_END, this.onBuyClick, this);
this.buy_node.off(NodeEventType.TOUCH_CANCEL, this.onBuyTouchCancel, this);
}
if (this.node && this.node.isValid) {
this.node.off(NodeEventType.TOUCH_START, this.onInfoTouchStart, this);
this.node.off(NodeEventType.TOUCH_END, this.onInfoTouchEnd, this);
this.node.off(NodeEventType.TOUCH_CANCEL, this.onInfoTouchEnd, this);
}
// 清理长按计时器,防止销毁后回调访问失效节点
this.unschedule(this.showInfo);
}
// ======================== 数据初始化 ========================
@@ -379,46 +367,6 @@ export class SCardComp extends CCComp {
return skillCard?.info || skill?.info || this.cardData.info || "";
}
// ======================== 长按信息框 ========================
/** 长按时长(秒) */
private static readonly LONG_PRESS_TIME: number = 0.5;
/** 信息框是否已弹出(区分长按完成与短按取消) */
private info_shown: boolean = false;
/** 卡面按下:启动长按计时 */
private onInfoTouchStart() {
if (!this.cardData) return;
this.info_shown = false;
this.scheduleOnce(this.showInfo, SCardComp.LONG_PRESS_TIME);
}
/** 卡面放开/取消:已弹出则关闭信息框,未弹出则取消长按计时 */
private onInfoTouchEnd() {
this.unschedule(this.showInfo);
if (this.info_shown) {
this.info_shown = false;
// oops.gui 移除信息框
oops.gui.remove(UIID.HInfo);
}
}
/** 长按到点:弹出技能卡信息框 */
private showInfo() {
if (!this.cardData) return;
this.info_shown = true;
// oops.gui 打开 HInfo 技能卡预览(复用 SkillBoxComp 的查询逻辑)
const config = SkillCardList.find(c => c.uuid === this.cardData!.uuid || c.skill === this.cardData!.uuid);
const cardUuid = config ? config.uuid : this.cardData.uuid;
oops.gui.remove(UIID.HInfo);
oops.gui.open(UIID.HInfo, {
heroUuid: cardUuid,
heroLv: this.cardData.card_lv ?? 1,
poolLv: config?.card_lv ?? 1,
isSkillCard: true
});
}
// ======================== 购买逻辑 ========================
/**

View File

@@ -30,7 +30,7 @@
* - smc.mission —— 游戏运行状态
*/
import { mLogger } from "../common/Logger";
import { _decorator, Node, Sprite, Label, Vec3, tween, v3, Tween, NodeEventType } from "cc";
import { _decorator, Node, Prefab, Sprite, Label, Vec3, instantiate, tween, v3, Tween, NodeEventType } 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 { CardTriggerType, CardConfig } from "../common/config/CardSet";
@@ -39,8 +39,8 @@ import { SkillOverrides } from "../common/config/SkillSet";
import { oops } from "db://oops-framework/core/Oops";
import { GameEvent } from "../common/config/GameEvent";
import { smc } from "../common/SingletonModuleComp";
import { UIID } from "../common/config/GameUIConfig";
import { getCardIconId, setSpriteFrame } from "../common/CardIconHelper";
import { IBoxComp } from "./IBoxComp";
const { ccclass, property } = _decorator;
/**
@@ -70,6 +70,13 @@ export class SkillBoxComp extends CCComp {
/** cd计时遮罩 */
@property({ type: Node })
private cd_mask: Node = null;
/** 技能详情弹窗预制体(长按图标时实例化展示) */
@property(Prefab)
private iboxPrefab: Prefab = null;
/** 当前已弹出的 IBox 实例(防止重复弹出) */
private iboxNode: Node = null;
// ======================== 技能配置 ========================
/** 技能 UUID */
@@ -149,6 +156,7 @@ export class SkillBoxComp extends CCComp {
}
// 清理长按计时器,防止销毁后回调访问失效节点
this.unschedule(this.showInfo);
this.closeInfoBox();
oops.message.off(GameEvent.NewWave, this.onNewWaveGlobal, this);
// 通知 MissSkillsComp 回收该节点占用的槽位
oops.message.dispatchEvent(GameEvent.RemoveSkillBox, this.node);
@@ -156,6 +164,8 @@ export class SkillBoxComp extends CCComp {
/** 长按时长(秒) */
private static readonly LONG_PRESS_TIME: number = 0.5;
/** IBox 相对图标的 Y 轴偏移(像素) */
private static readonly IBOX_OFFSET_Y: number = 80;
/** 信息框是否已弹出(区分长按完成与短按取消) */
private info_shown: boolean = false;
@@ -171,22 +181,58 @@ export class SkillBoxComp extends CCComp {
this.unschedule(this.showInfo);
if (this.info_shown) {
this.info_shown = false;
// oops.gui 移除信息框
oops.gui.remove(UIID.HInfo);
this.closeInfoBox();
}
}
/** 长按到点:弹出信息框 */
/** 长按到点:实例化 IBox 展示技能详情 */
private showInfo() {
if (!this.initialized) return;
mLogger.log(this.debugMode, "SkillBoxComp", "showInfo", {
initialized: this.initialized,
iboxPrefab: !!this.iboxPrefab,
s_uuid: this.s_uuid,
});
if (!this.initialized || !this.iboxPrefab) return;
this.closeInfoBox();
this.info_shown = true;
oops.audio.playEffect("music/button");
// 弹出 HInfoComp传入卡牌 UUID 和等级以启用预览模式
const config = SkillCardList.find(c => c.uuid === this.s_uuid || c.skill === this.s_uuid);
const cardUuid = config ? config.uuid : this.s_uuid;
oops.gui.remove(UIID.HInfo);
oops.gui.open(UIID.HInfo, { heroUuid: cardUuid, heroLv: this.card_lv, poolLv: config?.card_lv ?? 1, isSkillCard: true });
const config = SkillCardList.find(c => c.uuid === this.s_uuid || c.skill === this.s_uuid);
const skillUuid = config?.skill ?? this.s_uuid;
this.iboxNode = instantiate(this.iboxPrefab);
// 挂到技能图标的父节点下,使用局部坐标系
const parent = this.node.parent;
parent?.addChild(this.iboxNode);
// 弹窗宽度 720X 居中为 0Y 相对图标向上偏移
this.iboxNode.setPosition(0, this.node.position.y + SkillBoxComp.IBOX_OFFSET_Y, this.node.position.z);
mLogger.log(this.debugMode, "SkillBoxComp", "ibox instantiated", {
iboxNodeValid: this.iboxNode?.isValid,
iboxNodeActive: this.iboxNode?.active,
iboxNodePos: this.iboxNode?.position,
parentName: parent?.name,
});
const ibox = this.iboxNode.getComponent(IBoxComp);
mLogger.log(this.debugMode, "SkillBoxComp", "ibox component", {
hasIbox: !!ibox,
massageNode: ibox?.["massage_node"] ? "bound" : "null",
});
ibox?.init({
skillUuid,
skillLv: this.card_lv,
overrides: this.overrides,
});
mLogger.log(this.debugMode, "SkillBoxComp", "ibox init done", {
iboxNodePos: this.iboxNode?.position,
});
}
/** 关闭并清理已弹出的 IBox */
private closeInfoBox() {
if (this.iboxNode && this.iboxNode.isValid) {
this.iboxNode.destroy();
}
this.iboxNode = null;
}
/**