feat(victory): 添加得分条和亮点标签的渲染逻辑

在 VictoryComp 中新增 renderScores 和 renderHighlights 方法,用于在结算界面展示各维度得分进度条和基于游戏数据的成就标签。同时添加了对应的 highlight.prefab 资源作为标签的 UI 模板。

- renderScores 方法渲染总分及各维度(战斗、输出、防御等)的得分条。
- renderHighlights 方法根据本局数据(如暴击次数、死亡触发次数等)匹配并生成最多3个亮点成就标签。
- 新增 highlight.prefab 作为标签的 UI 预制体,包含图标和文本。
This commit is contained in:
walkpan
2026-04-25 22:34:25 +08:00
parent b588fd06a0
commit b97ea5027d
4 changed files with 9481 additions and 8615 deletions

View File

@@ -0,0 +1,400 @@
[
{
"__type__": "cc.Prefab",
"_name": "highlight",
"_objFlags": 0,
"__editorExtras__": {},
"_native": "",
"data": {
"__id__": 1
},
"optimizationPolicy": 0,
"persistent": false
},
{
"__type__": "cc.Node",
"_name": "highlight",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": null,
"_children": [
{
"__id__": 2
},
{
"__id__": 8
}
],
"_active": true,
"_components": [
{
"__id__": 14
}
],
"_prefab": {
"__id__": 16
},
"_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": "icon",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 3
},
{
"__id__": 5
}
],
"_prefab": {
"__id__": 7
},
"_lpos": {
"__type__": "cc.Vec3",
"x": -49.62,
"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__": 2
},
"_enabled": true,
"__prefab": {
"__id__": 4
},
"_contentSize": {
"__type__": "cc.Size",
"width": 32,
"height": 32
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "5fJ3wyWeRFN7kPc9OuAXmV"
},
{
"__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__": "cb93c900-b440-4571-91d1-7da1636e3d73@846cc",
"__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": null,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "d6OnY0P9tJC4k9RdVsxNpm"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "0eDkgu/69LuKtcD32qwUbN",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.Node",
"_name": "Label",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 9
},
{
"__id__": 11
}
],
"_prefab": {
"__id__": 13
},
"_lpos": {
"__type__": "cc.Vec3",
"x": -24.655,
"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__": 8
},
"_enabled": true,
"__prefab": {
"__id__": 10
},
"_contentSize": {
"__type__": "cc.Size",
"width": 100,
"height": 50.4
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "99pcVUFvRDqbDRk7G8XlSo"
},
{
"__type__": "cc.Label",
"_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
},
"_string": "暴击大师",
"_horizontalAlign": 0,
"_verticalAlign": 1,
"_actualFontSize": 21,
"_fontSize": 20,
"_fontFamily": "Arial",
"_lineHeight": 40,
"_overflow": 2,
"_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": "14kI2KPGNNkr7zcLFslGP+"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "33KfRxefJMI47rEEufEkMV",
"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": 100,
"height": 100
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "0aAqXsadlAkrim8Re1CWIN"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "3aBcBjdQdI9LIyPDmuxuPb",
"targetOverrides": null
}
]

View File

@@ -0,0 +1,13 @@
{
"ver": "1.1.50",
"importer": "prefab",
"imported": true,
"uuid": "12df63de-cda7-4be2-8e23-ea387fbba6f5",
"files": [
".json"
],
"subMetas": {},
"userData": {
"syncNodeName": "highlight"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -120,6 +120,9 @@ export class VictoryComp extends CCComp {
// 计算总分
this.calculateTotalScore();
// 渲染分数UI和亮点标签
this.renderScores();
// 显示MVP英雄
const mvp = this.getMVPHero();
this.renderMVPHero(mvp);
@@ -397,6 +400,91 @@ export class VictoryComp extends CCComp {
});
}
/**
* 渲染得分条与亮点标签
* 依赖各维度对应的UI节点需要在Cocos Creator中拖入绑定
*/
private renderScores() {
const s = smc.vmdata.scores;
// 渲染总分
if (this.total_score_label) {
this.total_score_label.string = `${s.score}`;
}
// 通用渲染单个维度的函数
const renderDim = (node: Node, score: number, maxScore: number) => {
if (!node) return;
const lab = node.getChildByName("score_label")?.getComponent(Label);
if (lab) lab.string = `${score}`;
const bar = node.getChildByName("progress_bar")?.getComponent(Sprite);
if (bar) {
// 根据该维度得分占“预期满分”的比例设置进度条fillRange
bar.fillRange = Math.min(1, Math.max(0, score / maxScore));
}
};
// TODO: 进度条的最大值可按设计期望自行调整,目前为占位预估值
renderDim(this.combat_node, s.score_combat, 3000);
renderDim(this.output_node, s.score_output, 3000);
renderDim(this.defense_node, s.score_defense, 1500);
renderDim(this.build_node, s.score_build, 1000);
renderDim(this.efficiency_node, s.score_efficiency, 200);
// 渲染成就亮点标签
this.renderHighlights();
}
/**
* 根据当前局数据匹配并生成对应的亮点标签(成就)
*/
private renderHighlights() {
if (!this.highlights_container || !this.highlight_prefab) return;
// 先清空原有的标签
this.highlights_container.removeAllChildren();
const s = smc.vmdata.scores;
const tags: { name: string, desc: string }[] = [];
// 按照 scoring-system.md 设计的触发条件判定
if (s.crt_count >= 40) tags.push({ name: "🔥 暴击大师", desc: `暴击${s.crt_count}` });
if (s.dead_trigger_count >= 25) tags.push({ name: "💀 送死达人", desc: `死亡触发${s.dead_trigger_count}` });
if (s.shield_block_count >= 30) tags.push({ name: "🛡️ 铁壁铜墙", desc: `格挡${s.shield_block_count}` });
if (s.wf_count >= 20) tags.push({ name: "⚡ 风暴之王", desc: `风怒${s.wf_count}` });
if (s.highest_dmg >= 200) tags.push({ name: "🎯 一击必杀", desc: `单次伤害${Math.floor(s.highest_dmg)}` });
if (s.heal_total >= 500) tags.push({ name: "💊 治愈之光", desc: `治疗总量${Math.floor(s.heal_total)}` });
// 🏆 完美通关通关且20回合全员存活
if (s.passed_wave_20 && s.wave_all_alive_count >= 20) {
tags.push({ name: "🏆 完美通关", desc: "20回合全胜" });
}
// 效率类判定
const refreshRatio = s.refresh_count > 0 ? (s.refresh_hit_count / s.refresh_count) : 0;
if (refreshRatio >= 0.8) {
tags.push({ name: "🎲 欧皇附体", desc: `刷新命中率${Math.floor(refreshRatio * 100)}%` });
}
const goldRatio = s.gold_earned > 0 ? (s.gold_spent / s.gold_earned) : 0;
if (goldRatio >= 0.95) {
tags.push({ name: "💰 节俭玩家", desc: `金币使用率${Math.floor(goldRatio * 100)}%` });
}
// 最多显示前3个亮点
const displayTags = tags.slice(0, 3);
displayTags.forEach(tag => {
const tagNode = instantiate(this.highlight_prefab);
// 尝试获取自身或者名为 "label" 的子节点上的 Label 组件
const lab = tagNode.getComponent(Label) || tagNode.getChildByName("label")?.getComponent(Label);
if (lab) {
lab.string = `${tag.name} (${tag.desc})`;
}
this.highlights_container.addChild(tagNode);
});
}
// ======================== 操作入口 ========================
/** 退出战斗:清理数据 → 触发任务结束 → 关闭弹窗 */