feat(mission): 添加抽卡面板付费开启与按钮高亮逻辑

1. 重构任务面板抽卡相关逻辑,为四个抽卡/商店面板添加开启费用机制,每次使用后费用递增
2. 新增面板重复开启校验,避免重复扣费
3. 优化英雄抽卡按钮的高亮状态,与面板展开状态绑定
4. 调整预设文件中任务面板UI元素的位置与尺寸适配新逻辑
5. 新增费用显示UI更新,在按钮上展示当前开启成本
This commit is contained in:
panFD
2026-08-06 08:08:36 +08:00
parent 4d6f1493b2
commit 6542da6a61
2 changed files with 112 additions and 13 deletions

View File

@@ -11895,7 +11895,7 @@
], ],
"value": { "value": {
"__type__": "cc.Vec3", "__type__": "cc.Vec3",
"x": 0, "x": -90,
"y": 0.117999999999995, "y": 0.117999999999995,
"z": 0 "z": 0
} }
@@ -12213,7 +12213,7 @@
"propertyPath": [ "propertyPath": [
"_active" "_active"
], ],
"value": false "value": true
}, },
{ {
"__type__": "cc.TargetInfo", "__type__": "cc.TargetInfo",
@@ -12241,7 +12241,7 @@
}, },
"_contentSize": { "_contentSize": {
"__type__": "cc.Size", "__type__": "cc.Size",
"width": 150, "width": 330,
"height": 110 "height": 110
}, },
"_anchorPoint": { "_anchorPoint": {
@@ -12269,8 +12269,8 @@
}, },
"_alignFlags": 42, "_alignFlags": 42,
"_target": null, "_target": null,
"_left": 285, "_left": 195,
"_right": 285, "_right": 195,
"_top": 340.279, "_top": 340.279,
"_bottom": -521.315, "_bottom": -521.315,
"_horizontalCenter": 0, "_horizontalCenter": 0,

View File

@@ -99,7 +99,7 @@ export class MissionCardComp extends CCComp {
nock_node: Node = null! nock_node: Node = null!
/** 英雄面板显示按钮 */ /** 英雄抽卡面板显示按钮 */
@property(Node) @property(Node)
showHeros: Node = null! showHeros: Node = null!
@property(Node) @property(Node)
@@ -191,6 +191,14 @@ export class MissionCardComp extends CCComp {
private readonly panelHideScale: Vec3 = new Vec3(0, 0, 1); private readonly panelHideScale: Vec3 = new Vec3(0, 0, 1);
/** 是否已初始化面板布局 */ /** 是否已初始化面板布局 */
private hasInitPanelLayout: boolean = false; 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; private hasCachedCardsBaseScale: boolean = false;
/** 卡牌面板基准缩放(从场景读取) */ /** 卡牌面板基准缩放(从场景读取) */
@@ -280,6 +288,7 @@ export class MissionCardComp extends CCComp {
this.layoutCardSlots(); this.layoutCardSlots();
this.clearAllCards(); this.clearAllCards();
this.resetButtonScale(this.cards_chou); this.resetButtonScale(this.cards_chou);
this.resetPanelOpenCosts();
this.updateCoinAndCostUI(); this.updateCoinAndCostUI();
this.updateHeroNumUI(false, false); this.updateHeroNumUI(false, false);
if (this.node && this.node.isValid) { if (this.node && this.node.isValid) {
@@ -507,6 +516,9 @@ export class MissionCardComp extends CCComp {
*/ */
private onShowSkillsClick() { private onShowSkillsClick() {
oops.audio.playEffect("music/button"); oops.audio.playEffect("music/button");
if (this.isOverlayPanelShown(2)) return;
// 开启技能面板需支付金币,金币不足则提示并中止
if (!this.tryPayPanelOpenCost(2)) return;
this.slideToPanel(2); this.slideToPanel(2);
} }
@@ -517,6 +529,9 @@ export class MissionCardComp extends CCComp {
*/ */
private onShowShopClick() { private onShowShopClick() {
oops.audio.playEffect("music/button"); oops.audio.playEffect("music/button");
if (this.isOverlayPanelShown(3)) return;
// 开启药品面板需支付金币,金币不足则提示并中止
if (!this.tryPayPanelOpenCost(3)) return;
this.slideToPanel(3); this.slideToPanel(3);
} }
@@ -866,6 +881,16 @@ export class MissionCardComp extends CCComp {
return [this.showHeros, this.showEquips, this.showSkills, this.showShop]; 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为常驻基准面板始终显示。 * 1. 英雄面板index=0为常驻基准面板始终显示。
@@ -961,7 +986,9 @@ export class MissionCardComp extends CCComp {
/** /**
* 更新面板 tab 按钮的 active 子节点状态。 * 更新面板 tab 按钮的 active 子节点状态。
* 当前激活面板对应的按钮 active 高亮,其余关闭。 * 装备/技能/药品按钮按 currentPanelIndex 高亮;
* 英雄抽卡面板cardPanNode不在覆盖面板数组内
* showHeros 按钮按 isCardPanelShown 高亮:面板展开时显示 active关闭时隐藏。
*/ */
private updatePanelButtonStates() { private updatePanelButtonStates() {
const buttons = this.getPanelShowButtons(); const buttons = this.getPanelShowButtons();
@@ -970,7 +997,8 @@ export class MissionCardComp extends CCComp {
if (!btn || !btn.isValid) continue; if (!btn || !btn.isValid) continue;
const activeChild = btn.getChildByName("active"); const activeChild = btn.getChildByName("active");
if (activeChild) { 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() { private onShowHerosClick() {
oops.audio.playEffect("music/button"); oops.audio.playEffect("music/button");
// 已展开则不重复开启(不重复扣费)
if (this.isCardPanelShown) return;
// 开启英雄抽卡面板需支付金币,金币不足则提示并中止
if (!this.tryPayPanelOpenCost(0)) return;
// 收起装备/技能/药品覆盖面板
this.slideToPanel(0); this.slideToPanel(0);
// 显示英雄抽卡面板(缩放 0→1并点亮按钮 active 高亮)
this.showCardsPanel();
} }
// ======================== 英雄信息盒herosBoxNode ======================== // ======================== 英雄信息盒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 * 显示卡牌面板:缩放从 0 动画放大到 1
*/ */
private onShowCardsClick() { private onShowCardsClick() {
oops.audio.playEffect("music/button"); 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(); this.hideCardsPanel();
} }
/** 隐藏卡牌面板:缩放缩小到 0不含按钮音效供系统逻辑复用 */ /**
* 显示卡牌面板:缩放 0→1并点亮 showHeros 按钮的 active 高亮。
* 统一开合入口,供按钮点击与系统逻辑复用。
*/
private showCardsPanel() {
this.isCardPanelShown = true;
this.showOverlayPanel(this.cardPanNode);
this.updatePanelButtonStates();
}
/** 隐藏卡牌面板:缩放缩小到 0同时隐藏 showHeros 按钮的 active 高亮 */
private hideCardsPanel() { private hideCardsPanel() {
this.isCardPanelShown = false;
this.hideOverlayPanelNode(this.cardPanNode); this.hideOverlayPanelNode(this.cardPanNode);
this.updatePanelButtonStates();
} }
/** /**
@@ -1105,6 +1201,9 @@ export class MissionCardComp extends CCComp {
*/ */
private onShowEquipsClick() { private onShowEquipsClick() {
oops.audio.playEffect("music/button"); oops.audio.playEffect("music/button");
if (this.isOverlayPanelShown(1)) return;
// 开启装备面板需支付金币,金币不足则提示并中止
if (!this.tryPayPanelOpenCost(1)) return;
this.slideToPanel(1); this.slideToPanel(1);
} }
@@ -1503,9 +1602,9 @@ export class MissionCardComp extends CCComp {
} }
// 刷新所有刷新按钮的费用显示(含刷新石/金币切换与置灰状态) // 刷新所有刷新按钮的费用显示(含刷新石/金币切换与置灰状态)
this.updateDrawCostUI(); this.updateDrawCostUI();
// 显示卡牌面板(默认进入准备阶段时展开,缩放放大到 1 // 显示卡牌面板(默认进入准备阶段时展开,缩放放大到 1,点亮按钮 active 高亮
if (this.cardPanNode && this.cardPanNode.isValid) { if (this.cardPanNode && this.cardPanNode.isValid) {
this.showOverlayPanel(this.cardPanNode); this.showCardsPanel();
mLogger.log(this.debugMode, "MissionCardComp", "enterPreparePhase cardPanNode", { mLogger.log(this.debugMode, "MissionCardComp", "enterPreparePhase cardPanNode", {
active: this.cardPanNode.active, active: this.cardPanNode.active,
position: this.cardPanNode.position, position: this.cardPanNode.position,