Files
pixelheros/assets/script/game/map/MissionCardComp.ts
walkpan d0e824e93b feat(卡牌系统): 实现任务卡牌抽卡与锁定功能
- 新增 MissionCardComp 作为卡牌面板控制器,管理四个固定卡槽
- 实现抽卡按钮逻辑,根据卡池等级抽取并分发卡牌到四个槽位
- 实现卡池升级按钮,提升抽卡品质但不影响已锁定卡牌
- 新增 CardComp 作为单卡控制器,支持卡牌使用与槽位锁定功能
- 锁定状态下卡槽将跳过抽卡更新,保持原有卡牌
- 添加任务开始/结束时的卡槽清理与界面显隐控制
- 修复预制体字段缺失问题,补充 instance 和 targetOverrides 字段
2026-03-14 09:18:45 +08:00

155 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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, getCardsByLv } from "../common/config/CardSet";
import { CardComp } from "./CardComp";
const { ccclass, property } = _decorator;
/** 视图层对象 */
@ccclass('MissionCardComp')
@ecs.register('MissionCard', false)
export class MissionCardComp extends CCComp {
private debugMode: boolean = true;
/** 四个插卡槽位固定顺序分发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!
/** 预留图集缓存(后续接入按钮/卡面图标时复用) */
private uiconsAtlas: SpriteAtlas | null = null;
/** 四个槽位对应的单卡控制器缓存 */
private cardComps: CardComp[] = [];
/** 当前卡池等级(仅影响抽卡来源,不直接改卡槽现有内容) */
private poolLv: number = CARD_POOL_INIT_LEVEL;
onLoad() {
/** 绑定事件 -> 缓存子控制器 -> 初始化UI状态 */
this.bindEvents();
this.cacheCardComps();
this.onMissionStart();
}
onDestroy() {
this.unbindEvents();
}
init(){
this.onMissionStart();
}
/** 任务开始时重置卡池等级、清空4槽、显示面板 */
onMissionStart() {
this.poolLv = CARD_POOL_INIT_LEVEL;
this.clearAllCards();
this.updatePoolLvUI();
this.node.active = true;
}
/** 任务结束时清空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.cards_chou?.on(NodeEventType.TOUCH_END, this.onClickDraw, this);
this.cards_up?.on(NodeEventType.TOUCH_END, this.onClickUpgrade, this);
}
/** 解除按钮监听,避免节点销毁后回调泄漏 */
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() {
const cards = this.buildDrawCards();
this.dispatchCardsToSlots(cards);
}
/** 升级按钮:仅提升卡池等级,卡槽是否更新由下一次抽卡触发 */
private onClickUpgrade() {
if (this.poolLv >= CARD_POOL_MAX_LEVEL) return;
this.poolLv += 1;
this.updatePoolLvUI();
mLogger.log(this.debugMode, "MissionCardComp", "pool level up", this.poolLv);
}
/** 构建本次抽卡结果保证最终可分发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++) {
this.cardComps[i].applyDrawCard(cards[i] ?? null);
}
}
/** 系统清空4槽用于任务切换 */
private clearAllCards() {
this.cardComps.forEach(comp => comp.clearBySystem());
}
/** 更新升级按钮上的等级文案,反馈当前卡池层级 */
private updatePoolLvUI() {
if (!this.cards_up) return;
const label = this.cards_up.getComponentInChildren(Label);
if (!label) return;
label.string = `卡池Lv.${this.poolLv}`;
}
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
reset() {
this.node.destroy();
}
}