diff --git a/assets/resources/gui/element/mission.prefab b/assets/resources/gui/element/mission.prefab index 3d5f12f1..5278908f 100644 --- a/assets/resources/gui/element/mission.prefab +++ b/assets/resources/gui/element/mission.prefab @@ -11895,7 +11895,7 @@ ], "value": { "__type__": "cc.Vec3", - "x": 0, + "x": -90, "y": 0.117999999999995, "z": 0 } @@ -12213,7 +12213,7 @@ "propertyPath": [ "_active" ], - "value": false + "value": true }, { "__type__": "cc.TargetInfo", @@ -12241,7 +12241,7 @@ }, "_contentSize": { "__type__": "cc.Size", - "width": 150, + "width": 330, "height": 110 }, "_anchorPoint": { @@ -12269,8 +12269,8 @@ }, "_alignFlags": 42, "_target": null, - "_left": 285, - "_right": 285, + "_left": 195, + "_right": 195, "_top": 340.279, "_bottom": -521.315, "_horizontalCenter": 0, diff --git a/assets/script/game/map/MissionCardComp.ts b/assets/script/game/map/MissionCardComp.ts index 1c494446..8d26e0fd 100644 --- a/assets/script/game/map/MissionCardComp.ts +++ b/assets/script/game/map/MissionCardComp.ts @@ -99,7 +99,7 @@ export class MissionCardComp extends CCComp { nock_node: Node = null! - /** 英雄面板显示按钮 */ + /** 英雄抽卡面板显示按钮 */ @property(Node) showHeros: Node = null! @property(Node) @@ -191,6 +191,14 @@ export class MissionCardComp extends CCComp { private readonly panelHideScale: Vec3 = new Vec3(0, 0, 1); /** 是否已初始化面板布局 */ private hasInitPanelLayout: boolean = false; + /** 英雄抽卡面板是否处于展开状态(驱动 showHeros 按钮 active 高亮) */ + private isCardPanelShown: boolean = false; + /** 抽卡面板开启初始金币费用 */ + private static readonly PANEL_OPEN_BASE_COST = 5; + /** 抽卡面板每抽 1 次的费用递增 */ + private static readonly PANEL_OPEN_COST_STEP = 5; + /** 各抽卡面板当前开启费用 [英雄抽卡, 装备, 技能, 药品] */ + private panelOpenCosts: number[] = []; /** 是否已缓存卡牌面板基准缩放 */ private hasCachedCardsBaseScale: boolean = false; /** 卡牌面板基准缩放(从场景读取) */ @@ -280,6 +288,7 @@ export class MissionCardComp extends CCComp { this.layoutCardSlots(); this.clearAllCards(); this.resetButtonScale(this.cards_chou); + this.resetPanelOpenCosts(); this.updateCoinAndCostUI(); this.updateHeroNumUI(false, false); if (this.node && this.node.isValid) { @@ -507,6 +516,9 @@ export class MissionCardComp extends CCComp { */ private onShowSkillsClick() { oops.audio.playEffect("music/button"); + if (this.isOverlayPanelShown(2)) return; + // 开启技能面板需支付金币,金币不足则提示并中止 + if (!this.tryPayPanelOpenCost(2)) return; this.slideToPanel(2); } @@ -517,6 +529,9 @@ export class MissionCardComp extends CCComp { */ private onShowShopClick() { oops.audio.playEffect("music/button"); + if (this.isOverlayPanelShown(3)) return; + // 开启药品面板需支付金币,金币不足则提示并中止 + if (!this.tryPayPanelOpenCost(3)) return; this.slideToPanel(3); } @@ -866,6 +881,16 @@ export class MissionCardComp extends CCComp { return [this.showHeros, this.showEquips, this.showSkills, this.showShop]; } + /** + * 判断覆盖面板(index≥1)当前是否处于展开状态,避免重复开启导致重复扣费。 + * @param index 面板下标(1=装备 2=技能 3=药品) + */ + private isOverlayPanelShown(index: number): boolean { + if (this.currentPanelIndex !== index) return false; + const node = this.getPanelNodes()[index]; + return !!node && node.isValid && node.active; + } + /** * 初始化面板布局: * 1. 英雄面板(index=0)为常驻基准面板,始终显示。 @@ -961,7 +986,9 @@ export class MissionCardComp extends CCComp { /** * 更新面板 tab 按钮的 active 子节点状态。 - * 当前激活面板对应的按钮 active 高亮,其余关闭。 + * 装备/技能/药品按钮按 currentPanelIndex 高亮; + * 英雄抽卡面板(cardPanNode)不在覆盖面板数组内, + * showHeros 按钮按 isCardPanelShown 高亮:面板展开时显示 active,关闭时隐藏。 */ private updatePanelButtonStates() { const buttons = this.getPanelShowButtons(); @@ -970,7 +997,8 @@ export class MissionCardComp extends CCComp { if (!btn || !btn.isValid) continue; const activeChild = btn.getChildByName("active"); if (activeChild) { - activeChild.active = (i === this.currentPanelIndex); + const shouldActive = i === 0 ? this.isCardPanelShown : (i === this.currentPanelIndex); + activeChild.active = shouldActive; } } } @@ -989,11 +1017,20 @@ export class MissionCardComp extends CCComp { } /** - * 英雄面板按钮回调:收起覆盖面板,回到英雄面板(index=0)。 + * 英雄面板按钮回调: + * 英雄面板(herosPanNode)为常驻基准面板,固定不动; + * 点击按钮收起装备/技能/药品覆盖面板,并显示英雄抽卡面板(cardPanNode)。 */ private onShowHerosClick() { oops.audio.playEffect("music/button"); + // 已展开则不重复开启(不重复扣费) + if (this.isCardPanelShown) return; + // 开启英雄抽卡面板需支付金币,金币不足则提示并中止 + if (!this.tryPayPanelOpenCost(0)) return; + // 收起装备/技能/药品覆盖面板 this.slideToPanel(0); + // 显示英雄抽卡面板(缩放 0→1,并点亮按钮 active 高亮) + this.showCardsPanel(); } // ======================== 英雄信息盒(herosBoxNode) ======================== @@ -1061,12 +1098,59 @@ export class MissionCardComp extends CCComp { } } + /** + * 支付抽卡面板开启费用: + * 金币足够则扣除当前费用,并将该面板费用递增 PANEL_OPEN_COST_STEP; + * 不足则弹出"金币不足"小提示并返回 false。 + * @param panelIndex 面板下标(0=英雄抽卡 1=装备 2=技能 3=药品) + * @returns 是否支付成功 + */ + private tryPayPanelOpenCost(panelIndex: number): boolean { + const cost = this.panelOpenCosts[panelIndex] ?? MissionCardComp.PANEL_OPEN_BASE_COST; + if (!MissionEconomy.spendCoin(cost)) { + oops.message.dispatchEvent(GameEvent.ShowSmallTip, "buy_coin"); + return false; + } + this.panelOpenCosts[panelIndex] = cost + MissionCardComp.PANEL_OPEN_COST_STEP; + this.updatePanelOpenCostUI(); + return true; + } + + /** 重置 4 个抽卡面板开启费用为初始值(任务开始时调用) */ + private resetPanelOpenCosts() { + this.panelOpenCosts = [ + MissionCardComp.PANEL_OPEN_BASE_COST, + MissionCardComp.PANEL_OPEN_BASE_COST, + MissionCardComp.PANEL_OPEN_BASE_COST, + MissionCardComp.PANEL_OPEN_BASE_COST + ]; + this.updatePanelOpenCostUI(); + } + + /** 刷新 4 个显示按钮上的开启费用显示(按钮下无 cost/num 标签子节点时自动跳过) */ + private updatePanelOpenCostUI() { + const buttons = this.getPanelShowButtons(); + for (let i = 0; i < buttons.length; i++) { + const btn = buttons[i]; + if (!btn || !btn.isValid) continue; + const costNode = btn.getChildByName("cost") ?? btn.getChildByName("num"); + const label = costNode ? costNode.getComponent(Label) : null; + if (label) { + label.string = `${this.panelOpenCosts[i] ?? MissionCardComp.PANEL_OPEN_BASE_COST}`; + } + } + } + /** * 显示卡牌面板:缩放从 0 动画放大到 1 */ private onShowCardsClick() { oops.audio.playEffect("music/button"); - this.showOverlayPanel(this.cardPanNode); + // 已展开则不重复开启(不重复扣费) + if (this.isCardPanelShown) return; + // 空槽位点开英雄抽卡面板同样需支付金币 + if (!this.tryPayPanelOpenCost(0)) return; + this.showCardsPanel(); } /** @@ -1077,9 +1161,21 @@ export class MissionCardComp extends CCComp { this.hideCardsPanel(); } - /** 隐藏卡牌面板:缩放缩小到 0(不含按钮音效,供系统逻辑复用) */ + /** + * 显示卡牌面板:缩放 0→1,并点亮 showHeros 按钮的 active 高亮。 + * 统一开合入口,供按钮点击与系统逻辑复用。 + */ + private showCardsPanel() { + this.isCardPanelShown = true; + this.showOverlayPanel(this.cardPanNode); + this.updatePanelButtonStates(); + } + + /** 隐藏卡牌面板:缩放缩小到 0,同时隐藏 showHeros 按钮的 active 高亮 */ private hideCardsPanel() { + this.isCardPanelShown = false; this.hideOverlayPanelNode(this.cardPanNode); + this.updatePanelButtonStates(); } /** @@ -1105,6 +1201,9 @@ export class MissionCardComp extends CCComp { */ private onShowEquipsClick() { oops.audio.playEffect("music/button"); + if (this.isOverlayPanelShown(1)) return; + // 开启装备面板需支付金币,金币不足则提示并中止 + if (!this.tryPayPanelOpenCost(1)) return; this.slideToPanel(1); } @@ -1503,9 +1602,9 @@ export class MissionCardComp extends CCComp { } // 刷新所有刷新按钮的费用显示(含刷新石/金币切换与置灰状态) this.updateDrawCostUI(); - // 显示卡牌面板(默认进入准备阶段时展开,缩放放大到 1) + // 显示卡牌面板(默认进入准备阶段时展开,缩放放大到 1,点亮按钮 active 高亮) if (this.cardPanNode && this.cardPanNode.isValid) { - this.showOverlayPanel(this.cardPanNode); + this.showCardsPanel(); mLogger.log(this.debugMode, "MissionCardComp", "enterPreparePhase cardPanNode", { active: this.cardPanNode.active, position: this.cardPanNode.position,