import { mLogger } from "../common/Logger"; import { _decorator, Label, Node, NodeEventType, SpriteAtlas } from "cc"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; import { GameEvent } from "../common/config/GameEvent"; import { CARD_POOL_INIT_LEVEL, CARD_POOL_MAX_LEVEL, CardConfig, CardInitCoins, CardsUpSet, getCardsByLv } from "../common/config/CardSet"; import { smc } from "../common/SingletonModuleComp"; import { CardComp } from "./CardComp"; import { oops } from "db://oops-framework/core/Oops"; const { ccclass, property } = _decorator; /** 视图层对象 */ @ccclass('MissionCardComp') @ecs.register('MissionCard', false) export class MissionCardComp extends CCComp { private debugMode: boolean = true; private readonly cardWidth: number = 175; /** 四个插卡槽位(固定顺序分发:1~4) */ @property(Node) card1:Node = null! @property(Node) card2:Node = null! @property(Node) card3:Node = null! @property(Node) card4:Node = null! @property(Node) cards_chou:Node = null! @property(Node) cards_up:Node = null! @property(Node) coins:Node = null! /** 预留图集缓存(后续接入按钮/卡面图标时复用) */ private uiconsAtlas: SpriteAtlas | null = null; /** 四个槽位对应的单卡控制器缓存 */ private cardComps: CardComp[] = []; /** 当前卡池等级(仅影响抽卡来源,不直接改卡槽现有内容) */ private poolLv: number = CARD_POOL_INIT_LEVEL; onLoad() { /** 绑定事件 -> 缓存子控制器 -> 初始化UI状态 */ this.bindEvents(); this.cacheCardComps(); this.layoutCardSlots(); this.onMissionStart(); mLogger.log(this.debugMode, "MissionCardComp", "onLoad init", { slots: this.cardComps.length, poolLv: this.poolLv }); } onDestroy() { this.unbindEvents(); } init(){ this.onMissionStart(); } /** 任务开始时:重置卡池等级、清空4槽、显示面板 刷新一次卡池*/ onMissionStart() { this.poolLv = CARD_POOL_INIT_LEVEL; smc.vmdata.mission_data.coin=CardInitCoins //这里负责卡牌相关数据舒适化 this.layoutCardSlots(); this.clearAllCards(); if (this.cards_up) { this.cards_up.active = true; } this.updatePoolLvUI(); this.updateCoinUI(); this.node.active = true; const cards = this.buildDrawCards(); this.dispatchCardsToSlots(cards); mLogger.log(this.debugMode, "MissionCardComp", "mission start", { poolLv: this.poolLv }); } /** 任务结束时:清空4槽并隐藏面板 */ onMissionEnd() { this.clearAllCards(); this.node.active = false; } start() { } /** 关闭面板(不销毁数据模型,仅隐藏) */ close() { this.node.active = false; } /** 只处理UI层事件,不做卡牌效果分发 */ private bindEvents() { /** 生命周期事件 */ this.on(GameEvent.MissionStart, this.onMissionStart, this); this.on(GameEvent.MissionEnd, this.onMissionEnd, this); this.on(GameEvent.CoinAdd, this.onCoinAdd, this); /** 按钮事件:抽卡与卡池升级 */ this.cards_chou?.on(NodeEventType.TOUCH_END, this.onClickDraw, this); this.cards_up?.on(NodeEventType.TOUCH_END, this.onClickUpgrade, this); } private onCoinAdd(args:any){ this.updatePoolLvUI(); this.updateCoinUI(); } /** 解除按钮监听,避免节点销毁后回调泄漏 */ private unbindEvents() { this.cards_chou?.off(NodeEventType.TOUCH_END, this.onClickDraw, this); this.cards_up?.off(NodeEventType.TOUCH_END, this.onClickUpgrade, this); } /** 将四个卡槽节点映射为 CardComp,形成固定顺序控制数组 */ private cacheCardComps() { const nodes = [this.card1, this.card2, this.card3, this.card4]; this.cardComps = nodes .map(node => node?.getComponent(CardComp)) .filter((comp): comp is CardComp => !!comp); } /** 抽卡按钮:每次固定抽4张,然后顺序分发给4个单卡脚本 */ private onClickDraw() { mLogger.log(this.debugMode, "MissionCardComp", "click draw", { poolLv: this.poolLv }); this.layoutCardSlots(); const cards = this.buildDrawCards(); this.dispatchCardsToSlots(cards); } /** 升级按钮:仅提升卡池等级,卡槽是否更新由下一次抽卡触发 */ private onClickUpgrade() { if (this.poolLv >= CARD_POOL_MAX_LEVEL) { mLogger.log(this.debugMode, "MissionCardComp", "pool already max", this.poolLv); return; } const cost = this.getUpgradeCost(this.poolLv); const currentCoin = smc.vmdata.mission_data.coin ?? 0; if (currentCoin < cost) { oops.gui.toast(`金币不足,升级需要${cost}`); this.updatePoolLvUI(); mLogger.log(this.debugMode, "MissionCardComp", "pool upgrade coin not enough", { poolLv: this.poolLv, currentCoin, cost }); return; } smc.vmdata.mission_data.coin = currentCoin - cost; this.poolLv += 1; this.updateCoinUI(); this.updatePoolLvUI(); mLogger.log(this.debugMode, "MissionCardComp", "pool level up", { poolLv: this.poolLv, cost, leftCoin: smc.vmdata.mission_data.coin }); } /** 构建本次抽卡结果,保证最终可分发4条数据 */ private buildDrawCards(): CardConfig[] { const cards = getCardsByLv(this.poolLv); /** 正常情况下直接取前4 */ if (cards.length >= 4) return cards.slice(0, 4); /** 兜底:当返回不足4张时循环补齐,保证分发不缺位 */ const filled = [...cards]; while (filled.length < 4) { const fallback = getCardsByLv(this.poolLv); if (fallback.length === 0) break; filled.push(fallback[filled.length % fallback.length]); } return filled; } /** 全量分发给4槽;每个槽位是否接收由 CardComp 自己判断(锁定可跳过) */ private dispatchCardsToSlots(cards: CardConfig[]) { for (let i = 0; i < this.cardComps.length; i++) { const accepted = this.cardComps[i].applyDrawCard(cards[i] ?? null); mLogger.log(this.debugMode, "MissionCardComp", "dispatch card", { index: i, card: cards[i]?.uuid ?? 0, accepted }); } } /** 系统清空4槽(用于任务切换) */ private clearAllCards() { this.cardComps.forEach(comp => comp.clearBySystem()); } private layoutCardSlots() { const count = this.cardComps.length; if (count === 0) return; const startX = -((count - 1) * this.cardWidth) / 2; for (let i = 0; i < count; i++) { const x = startX + i * this.cardWidth; this.cardComps[i].setSlotPosition(x); } mLogger.log(this.debugMode, "MissionCardComp", "layout card slots", { count, cardWidth: this.cardWidth, startX }); } private canUpPool() { if (this.poolLv >= CARD_POOL_MAX_LEVEL) return false; const currentCoin = smc.vmdata.mission_data.coin ?? 0; return currentCoin >= this.getUpgradeCost(this.poolLv); } /** 更新升级按钮上的等级文案,反馈当前卡池层级 */ private updatePoolLvUI() { if (!this.cards_up) return; const nobg = this.cards_up.getChildByName("nobg"); if (nobg) { nobg.active = !this.canUpPool(); } const label = this.cards_up.getChildByName("coin").getChildByName("num").getComponent(Label); if (!label) return; if (this.poolLv >= CARD_POOL_MAX_LEVEL) { label.string = `0`; } else { label.string = `${this.getUpgradeCost(this.poolLv)}`; } mLogger.log(this.debugMode, "MissionCardComp", "pool lv ui update", { poolLv: this.poolLv, cost: this.getUpgradeCost(this.poolLv) }); } private updateCoinUI() { if (!this.coins) return; const label = this.coins.getChildByName("num")?.getComponent(Label); if (!label) return; label.string = `${smc.vmdata.mission_data.coin ?? 0}`; } private getUpgradeCost(lv: number): number { return CardsUpSet[lv] ?? 0; } /** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */ reset() { this.node.destroy(); } }