2 Commits

Author SHA1 Message Date
pan
407973655a refactor(HeroBoxComp): 替换手动格式化逻辑为NumberFormatter
统一大数值展示格式,使用千分位缩写避免溢出标签,同时保留小数位数的原有逻辑
2026-08-06 11:13:48 +08:00
pan
7436944752 refactor(map): 优化槽位检测逻辑并新增满槽提示
1. 为MissEquipComp和MissSkillsComp新增静态实例缓存和isFull方法,避免强引用查询
2. 修复槽位坐标的空格格式问题
3. 扩展showSmallTip的参数类型,新增多种面板满槽提示场景
4. 在英雄、装备、技能面板开启逻辑中添加满槽校验和对应提示
2026-08-06 10:44:42 +08:00
5 changed files with 1886 additions and 1198 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@ import { GameEvent } from "../common/config/GameEvent";
import { HeroInfo } from "../common/config/heroSet";
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
import { Hero } from "../hero/Hero";
import { FacSet, FightSet, getLvColor } from "../common/config/GameSet";
import { FacSet, FightSet, getLvColor, NumberFormatter } from "../common/config/GameSet";
import { buildSkillDesc, ISkillDescSource } from "../common/config/HeroSkillDesc";
import { MissionEconomy } from "./MissionEconomy";
import { UIID } from "../common/config/GameUIConfig";
@@ -592,7 +592,8 @@ export class HeroBoxComp extends CCComp {
* @param decimals 保留小数位数(默认 0取整
*/
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)}`;
// 整数数值统一走 NumberFormatter 千分位缩写(如 12.3k),避免大数值溢出标签
const fmt = (v: number) => decimals > 0 ? v.toFixed(decimals) : NumberFormatter.formatNumber(Math.floor(v));
if (allLabel && allLabel.isValid) {
allLabel.string = `${fmt(total)}${suffix}`;
}

View File

@@ -55,6 +55,19 @@ export class MissEquipComp extends CCComp {
/** 调试日志开关 */
private debugMode: boolean = true;
/** 当前活跃实例(供其他系统查询槽位占用,避免直接 find 强引用) */
private static instance: MissEquipComp | null = null;
/**
* 查询场上装备槽是否已全部占用。
* @returns 无空闲槽位时返回 true实例不存在时返回 false
*/
public static isFull(): boolean {
const inst = MissEquipComp.instance;
if (!inst) return false;
return inst.slots.every(slot => slot.used);
}
/** 技能卡 Prefab在编辑器中赋值 */
@property({ type: Prefab })
private equip_box: Prefab = null;
@@ -72,6 +85,7 @@ export class MissEquipComp extends CCComp {
/** 注册事件监听 */
onLoad() {
MissEquipComp.instance = this;
oops.message.on(GameEvent.UseEquipCard, this.onUseEquipCard, this);
oops.message.on(GameEvent.RemoveEquipBox, this.onRemoveEquipBox, this);
}
@@ -79,6 +93,9 @@ export class MissEquipComp extends CCComp {
/** 移除事件监听 */
onDestroy() {
super.onDestroy();
if (MissEquipComp.instance === this) {
MissEquipComp.instance = null;
}
oops.message.off(GameEvent.UseEquipCard, this.onUseEquipCard, this);
oops.message.off(GameEvent.RemoveEquipBox, this.onRemoveEquipBox, this);
}

View File

@@ -57,6 +57,19 @@ export class MissSkillsComp extends CCComp {
/** 调试日志开关 */
private debugMode: boolean = true;
/** 当前活跃实例(供其他系统查询槽位占用,避免直接 find 强引用) */
private static instance: MissSkillsComp | null = null;
/**
* 查询场上技能槽是否已全部占用。
* @returns 无空闲槽位时返回 true实例不存在时返回 false
*/
public static isFull(): boolean {
const inst = MissSkillsComp.instance;
if (!inst) return false;
return inst.slots.every(slot => slot.used);
}
/** 技能卡 Prefab在编辑器中赋值 */
@property({ type: Prefab })
private skill_box: Prefab = null;
@@ -75,6 +88,7 @@ export class MissSkillsComp extends CCComp {
/** 注册事件监听 */
onLoad() {
MissSkillsComp.instance = this;
oops.message.on(GameEvent.UseSkillCard, this.onUseSkillCard, this);
oops.message.on(GameEvent.UseItemCard, this.onUseItemCard, this);
oops.message.on(GameEvent.RemoveSkillBox, this.onRemoveSkillBox, this);
@@ -83,6 +97,9 @@ export class MissSkillsComp extends CCComp {
/** 移除事件监听 */
onDestroy() {
super.onDestroy();
if (MissSkillsComp.instance === this) {
MissSkillsComp.instance = null;
}
oops.message.off(GameEvent.UseSkillCard, this.onUseSkillCard, this);
oops.message.off(GameEvent.UseItemCard, this.onUseItemCard, this);
oops.message.off(GameEvent.RemoveSkillBox, this.onRemoveSkillBox, this);

View File

@@ -47,6 +47,8 @@ import { CHeroComp } from "./CHeroComp";
import { EquipListComp } from "./EquipListComp";
import { HeroBoxComp } from "./HeroBoxComp";
import { SCardComp } from "./SCardComp";
import { MissEquipComp } from "./MissEquipComp";
import { MissSkillsComp } from "./MissSkillsComp";
import { oops } from "db://oops-framework/core/Oops";
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
import { smc } from "../common/SingletonModuleComp";
@@ -474,9 +476,12 @@ export class MissionCardComp extends CCComp {
/**
* 在目标节点上弹出 smalltip 气泡(缩放动画)。
* @param type 提示类型(决定挂载到哪个节点)
* - refresh_coin / buy_coin / hero_full挂在抽卡按钮 / 金币节点 / 英雄数量节点
* - panel_hero_full / panel_equip_full / panel_skill_full / panel_shop_full
* 挂在 showHeros / showEquips / showSkills / showShop 按钮节点(按钮下需预置 smalltip 子节点)
* @param text 可选:覆盖气泡文字(默认读 prefab 中配置的文本)
*/
public showSmallTip(type: "refresh_coin" | "buy_coin" | "hero_full", text?: string) {
public showSmallTip(type: "refresh_coin" | "buy_coin" | "hero_full" | "panel_hero_full" | "panel_equip_full" | "panel_skill_full" | "panel_shop_full", text?: string) {
let targetNode: Node | null = null;
switch (type) {
case "refresh_coin":
@@ -488,6 +493,18 @@ export class MissionCardComp extends CCComp {
case "hero_full":
targetNode = this.hero_num_node;
break;
case "panel_hero_full":
targetNode = this.showHeros;
break;
case "panel_equip_full":
targetNode = this.showEquips;
break;
case "panel_skill_full":
targetNode = this.showSkills;
break;
case "panel_shop_full":
targetNode = this.showShop;
break;
}
if (targetNode && targetNode.isValid) {
const tipNode = targetNode.getChildByName("smalltip");
@@ -529,6 +546,11 @@ export class MissionCardComp extends CCComp {
private onShowSkillsClick() {
oops.audio.playEffect("music/button");
if (this.isOverlayPanelShown(2)) return;
// 技能槽位已满:气泡提示并中止,不再展开三选一,也不扣开启费用
if (MissSkillsComp.isFull()) {
this.showSmallTip("panel_skill_full", "技能槽已满");
return;
}
// 开启技能面板需支付金币,金币不足则提示并中止
if (!this.tryPayPanelOpenCost(2)) return;
this.slideToPanel(2);
@@ -1037,6 +1059,11 @@ export class MissionCardComp extends CCComp {
oops.audio.playEffect("music/button");
// 已展开则不重复开启(不重复扣费)
if (this.isCardPanelShown) return;
// 英雄槽位已满:气泡提示并中止,不再展开三选一,也不扣开启费用
if (this.getAliveHeroCount() >= this.getMissionHeroMaxNum()) {
this.showSmallTip("panel_hero_full", "英雄槽已满");
return;
}
// 开启英雄抽卡面板需支付金币,金币不足则提示并中止
if (!this.tryPayPanelOpenCost(0)) return;
// 收起装备/技能/药品覆盖面板
@@ -1218,6 +1245,11 @@ export class MissionCardComp extends CCComp {
private onShowEquipsClick() {
oops.audio.playEffect("music/button");
if (this.isOverlayPanelShown(1)) return;
// 装备槽位已满:气泡提示并中止,不再展开三选一,也不扣开启费用
if (MissEquipComp.isFull()) {
this.showSmallTip("panel_equip_full", "装备槽已满");
return;
}
// 开启装备面板需支付金币,金币不足则提示并中止
if (!this.tryPayPanelOpenCost(1)) return;
this.slideToPanel(1);