feat(ui/hero): 重构英雄属性显示逻辑,拆分总值与附加值
1. 新增12组战斗属性标签控件,分别对应攻击、生命、暴击等全量属性 2. 重构属性设置方法,将单一的AP/HP显示拆分为通用的总值+附加值显示逻辑 3. 优化空槽位时的属性标签清空逻辑,统一调用工具方法处理 4. 移除预制体中原有的精灵帧引用,替换为无图片的空状态
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2946,10 +2946,7 @@
|
||||
"b": 255,
|
||||
"a": 255
|
||||
},
|
||||
"_spriteFrame": {
|
||||
"__uuid__": "cb93c900-b440-4571-91d1-7da1636e3d73@fcdc9",
|
||||
"__expectedType__": "cc.SpriteFrame"
|
||||
},
|
||||
"_spriteFrame": null,
|
||||
"_type": 1,
|
||||
"_fillType": 0,
|
||||
"_sizeMode": 0,
|
||||
|
||||
@@ -46,6 +46,69 @@ export class HeroBoxComp extends CCComp {
|
||||
@property(Label)
|
||||
private level_label: Label = null;
|
||||
|
||||
// ======================== 战斗信息标签(总值 + 附加值) ========================
|
||||
|
||||
/** 攻击总值 */
|
||||
@property(Label)
|
||||
private ap_all_label: Label = null;
|
||||
/** 攻击附加值 */
|
||||
@property(Label)
|
||||
private ap_plus_label: Label = null;
|
||||
/** 生命总值 */
|
||||
@property(Label)
|
||||
private hp_all_label: Label = null;
|
||||
/** 生命附加值 */
|
||||
@property(Label)
|
||||
private hp_plus_label: Label = null;
|
||||
/** 暴击率总值(百分点) */
|
||||
@property(Label)
|
||||
private crt_all_label: Label = null;
|
||||
/** 暴击率附加值 */
|
||||
@property(Label)
|
||||
private crt_plus_label: Label = null;
|
||||
/** 击退率总值(百分点) */
|
||||
@property(Label)
|
||||
private knockback_all_label: Label = null;
|
||||
/** 击退率附加值 */
|
||||
@property(Label)
|
||||
private knockback_plus_label: Label = null;
|
||||
/** 风怒率总值(百分点) */
|
||||
@property(Label)
|
||||
private wfuny_all_label: Label = null;
|
||||
/** 风怒率附加值 */
|
||||
@property(Label)
|
||||
private wfuny_plus_label: Label = null;
|
||||
/** 击晕率总值(百分点) */
|
||||
@property(Label)
|
||||
private stun_all_label: Label = null;
|
||||
/** 击晕率附加值 */
|
||||
@property(Label)
|
||||
private stun_plus_label: Label = null;
|
||||
/** 攻击速度总值(攻击间隔,秒;速度提升时间隔变短,附加值为负) */
|
||||
@property(Label)
|
||||
private speed_all_label: Label = null;
|
||||
/** 攻击速度附加值 */
|
||||
@property(Label)
|
||||
private speed_plus_label: Label = null;
|
||||
/** 冰冻率总值(百分点) */
|
||||
@property(Label)
|
||||
private freeze_all_label: Label = null;
|
||||
/** 冰冻率附加值 */
|
||||
@property(Label)
|
||||
private freeze_plus_label: Label = null;
|
||||
/** 穿透率总值(百分点) */
|
||||
@property(Label)
|
||||
private puncture_all_label: Label = null;
|
||||
/** 穿透率附加值 */
|
||||
@property(Label)
|
||||
private puncture_plus_label: Label = null;
|
||||
/** 暴击伤害总值(额外暴伤,百分点) */
|
||||
@property(Label)
|
||||
private crit_dmg_all_label: Label = null;
|
||||
/** 暴击伤害附加值 */
|
||||
@property(Label)
|
||||
private crit_dmg_plus_label: Label = null;
|
||||
|
||||
// ======================== 运行时状态 ========================
|
||||
|
||||
/** 绑定的英雄实体 ID(0 表示空槽位) */
|
||||
@@ -110,7 +173,16 @@ export class HeroBoxComp extends CCComp {
|
||||
const sprite = this.icon_node.getComponent(Sprite) || this.icon_node.getComponentInChildren(Sprite);
|
||||
if (sprite) sprite.spriteFrame = null;
|
||||
}
|
||||
this.setAttrLabels(0, 0);
|
||||
this.clearStatRow(this.ap_all_label, this.ap_plus_label);
|
||||
this.clearStatRow(this.hp_all_label, this.hp_plus_label);
|
||||
this.clearStatRow(this.crt_all_label, this.crt_plus_label);
|
||||
this.clearStatRow(this.knockback_all_label, this.knockback_plus_label);
|
||||
this.clearStatRow(this.wfuny_all_label, this.wfuny_plus_label);
|
||||
this.clearStatRow(this.stun_all_label, this.stun_plus_label);
|
||||
this.clearStatRow(this.speed_all_label, this.speed_plus_label);
|
||||
this.clearStatRow(this.freeze_all_label, this.freeze_plus_label);
|
||||
this.clearStatRow(this.puncture_all_label, this.puncture_plus_label);
|
||||
this.clearStatRow(this.crit_dmg_all_label, this.crit_dmg_plus_label);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,10 +211,44 @@ export class HeroBoxComp extends CCComp {
|
||||
}
|
||||
|
||||
// ---- AP / HP ----
|
||||
this.setAttrLabels(
|
||||
Math.max(0, Math.floor(this.model.getFinalAp())),
|
||||
Math.max(0, Math.floor(this.model.getFinalHpMax()))
|
||||
);
|
||||
const finalAp = Math.max(0, Math.floor(this.model.getFinalAp()));
|
||||
const baseAp = Math.max(0, Math.floor(this.model.base_ap ?? 0));
|
||||
this.setStatRow(this.ap_all_label, this.ap_plus_label, finalAp, finalAp - baseAp);
|
||||
|
||||
const finalHp = Math.max(0, Math.floor(this.model.getFinalHpMax()));
|
||||
const baseHp = Math.max(0, Math.floor(this.model.base_hp ?? 0));
|
||||
this.setStatRow(this.hp_all_label, this.hp_plus_label, finalHp, finalHp - baseHp);
|
||||
|
||||
// ---- 暴击率 / 击退率 / 风怒率 / 击晕率(百分点,附加 = 最终 - 基础配置值) ----
|
||||
const finalCrit = this.model.getFinalCritical();
|
||||
this.setStatRow(this.crt_all_label, this.crt_plus_label, finalCrit, finalCrit - (this.model.critical ?? 0), "%");
|
||||
|
||||
const finalKnockback = this.model.getFinalKnockbackChance();
|
||||
this.setStatRow(this.knockback_all_label, this.knockback_plus_label, finalKnockback, finalKnockback - (this.model.knockback_chance ?? 0), "%");
|
||||
|
||||
const finalWfuny = this.model.getFinalWindFury();
|
||||
this.setStatRow(this.wfuny_all_label, this.wfuny_plus_label, finalWfuny, finalWfuny - (this.model.wfuny ?? 0), "%");
|
||||
|
||||
const finalStun = this.model.getFinalStunChance();
|
||||
this.setStatRow(this.stun_all_label, this.stun_plus_label, finalStun, finalStun - (this.model.stun_chance ?? 0), "%");
|
||||
|
||||
// ---- 攻击速度(攻击间隔,秒;速度提升 → 间隔变短,附加值为负) ----
|
||||
const skillIds = this.model.getSkillIds();
|
||||
const displaySkillId = skillIds[1] ?? skillIds[0] ?? 0;
|
||||
const baseCd = displaySkillId ? (this.model.skills[displaySkillId]?.cd ?? 0) : 0;
|
||||
const finalCd = displaySkillId ? this.model.getEffectiveSkillCd(displaySkillId) : 0;
|
||||
this.setStatRow(this.speed_all_label, this.speed_plus_label, finalCd, finalCd - baseCd, "s", 1);
|
||||
|
||||
// ---- 冰冻率 / 穿透率(百分点,附加 = 最终 - 基础配置值) ----
|
||||
const finalFreeze = this.model.getFinalFreezeChance();
|
||||
this.setStatRow(this.freeze_all_label, this.freeze_plus_label, finalFreeze, finalFreeze - (this.model.freeze_chance ?? 0), "%");
|
||||
|
||||
const finalPuncture = this.model.getFinalPunctureChance();
|
||||
this.setStatRow(this.puncture_all_label, this.puncture_plus_label, finalPuncture, finalPuncture - (this.model.puncture_chance ?? 0), "%");
|
||||
|
||||
// ---- 暴击伤害(额外暴伤,百分点,附加 = 最终 - 基础配置值) ----
|
||||
const finalCritDmg = this.model.getFinalCritDamage();
|
||||
this.setStatRow(this.crit_dmg_all_label, this.crit_dmg_plus_label, finalCritDmg, finalCritDmg - (this.model.crit_damage ?? 0), "%");
|
||||
|
||||
// ---- 图标(UUID 变化时重新加载首帧动画) ----
|
||||
if (hero && heroUuid !== this.iconHeroUuid) {
|
||||
@@ -155,19 +261,34 @@ export class HeroBoxComp extends CCComp {
|
||||
// ======================== 内部工具 ========================
|
||||
|
||||
/**
|
||||
* 写入 AP / HP 数值标签。
|
||||
* 兼容 herobox.prefab 节点结构(attr/ap|hp → val)。
|
||||
* 写入一行战斗信息(总值 + 附加值)。
|
||||
* 总值始终显示(0 不隐藏);附加值为 0 时隐藏,正/负分别显示 (+x) / (x)。
|
||||
*
|
||||
* @param allLabel 总值标签(可为空,空时跳过)
|
||||
* @param plusLabel 附加值标签(可为空)
|
||||
* @param total 总数值(最终生效值)
|
||||
* @param bonus 附加数值(最终值 - 基础值)
|
||||
* @param suffix 数值后缀(如 "%")
|
||||
* @param decimals 保留小数位数(默认 0,取整)
|
||||
*/
|
||||
private setAttrLabels(ap: number, hp: number) {
|
||||
const attrNode = this.node.getChildByName("attr");
|
||||
const apNode = attrNode?.getChildByName("ap");
|
||||
const hpNode = attrNode?.getChildByName("hp");
|
||||
const apLabel = apNode?.getChildByName("val")?.getComponent(Label)
|
||||
?? apNode?.getComponentInChildren(Label) ?? null;
|
||||
const hpLabel = hpNode?.getChildByName("val")?.getComponent(Label)
|
||||
?? hpNode?.getComponentInChildren(Label) ?? null;
|
||||
if (apLabel) apLabel.string = ap > 0 ? `${ap}` : "";
|
||||
if (hpLabel) hpLabel.string = hp > 0 ? `${hp}` : "";
|
||||
private setStatRow(allLabel: Label | null, plusLabel: Label | null, total: number, bonus: number, suffix: string = "", decimals: number = 0) {
|
||||
const fmt = (v: number) => decimals > 0 ? v.toFixed(decimals) : `${Math.floor(v)}`;
|
||||
if (allLabel && allLabel.isValid) {
|
||||
allLabel.string = `${fmt(total)}${suffix}`;
|
||||
}
|
||||
if (plusLabel && plusLabel.isValid) {
|
||||
if (bonus !== 0) {
|
||||
plusLabel.string = bonus > 0 ? `(+${fmt(bonus)}${suffix})` : `(${fmt(bonus)}${suffix})`;
|
||||
} else {
|
||||
plusLabel.string = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 清空一行战斗信息(空槽位时使用) */
|
||||
private clearStatRow(allLabel: Label | null, plusLabel: Label | null) {
|
||||
if (allLabel && allLabel.isValid) allLabel.string = "";
|
||||
if (plusLabel && plusLabel.isValid) plusLabel.string = "";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user