refactor(map): 优化槽位检测逻辑并新增满槽提示

1. 为MissEquipComp和MissSkillsComp新增静态实例缓存和isFull方法,避免强引用查询
2. 修复槽位坐标的空格格式问题
3. 扩展showSmallTip的参数类型,新增多种面板满槽提示场景
4. 在英雄、装备、技能面板开启逻辑中添加满槽校验和对应提示
This commit is contained in:
pan
2026-08-06 10:44:42 +08:00
parent 98135dc5a4
commit 7436944752
4 changed files with 1883 additions and 1196 deletions

File diff suppressed because it is too large Load Diff

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;
@@ -62,16 +75,17 @@ export class MissEquipComp extends CCComp {
* 预定义的 6 个槽位坐标(单行):
*/
private slots: SkillBoxSlot[] = [
{ x: -310, y: BoxSet.GAME_LINE-70, used: false, node: null },
{ x: -230, y: BoxSet.GAME_LINE-70, used: false, node: null },
{ x: -150, y: BoxSet.GAME_LINE-70, used: false, node: null },
{ x: -70, y: BoxSet.GAME_LINE-70, used: false, node: null },
{ x: 10, y: BoxSet.GAME_LINE-70, used: false, node: null },
{ x: 90, y: BoxSet.GAME_LINE-70, used: false, node: null },
{ x: -310, y: BoxSet.GAME_LINE - 70, used: false, node: null },
{ x: -230, y: BoxSet.GAME_LINE - 70, used: false, node: null },
{ x: -150, y: BoxSet.GAME_LINE - 70, used: false, node: null },
{ x: -70, y: BoxSet.GAME_LINE - 70, used: false, node: null },
{ x: 10, y: BoxSet.GAME_LINE - 70, used: false, node: null },
{ x: 90, y: BoxSet.GAME_LINE - 70, used: false, node: null },
];
/** 注册事件监听 */
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;
@@ -65,16 +78,17 @@ export class MissSkillsComp extends CCComp {
* 预定义的 6 个槽位坐标(单行):
*/
private slots: SkillBoxSlot[] = [
{ x: -310, y: BoxSet.GAME_LINE+300, used: false, node: null },
{ x: -240, y: BoxSet.GAME_LINE+300, used: false, node: null },
{ x: -170, y: BoxSet.GAME_LINE+300, used: false, node: null },
{ x: -100, y: BoxSet.GAME_LINE+300, used: false, node: null },
{ x: -30, y: BoxSet.GAME_LINE+300, used: false, node: null },
{ x: 40, y: BoxSet.GAME_LINE+300, used: false, node: null },
{ x: -310, y: BoxSet.GAME_LINE + 300, used: false, node: null },
{ x: -240, y: BoxSet.GAME_LINE + 300, used: false, node: null },
{ x: -170, y: BoxSet.GAME_LINE + 300, used: false, node: null },
{ x: -100, y: BoxSet.GAME_LINE + 300, used: false, node: null },
{ x: -30, y: BoxSet.GAME_LINE + 300, used: false, node: null },
{ x: 40, y: BoxSet.GAME_LINE + 300, used: false, node: null },
];
/** 注册事件监听 */
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);