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

@@ -119,6 +119,9 @@ export class VictoryComp extends CCComp {
// 计算总分
this.calculateTotalScore();
// 渲染分数UI和亮点标签
this.renderScores();
// 显示MVP英雄
const mvp = this.getMVPHero();
@@ -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);
});
}
// ======================== 操作入口 ========================
/** 退出战斗:清理数据 → 触发任务结束 → 关闭弹窗 */