refactor(mission): 重构卡牌系统为英雄卡槽组件
1. 新增CHeroComp作为英雄卡槽专用组件,替换原CardComp 2. 调整mission.prefab布局与预制体引用,适配新卡槽组件 3. 优化MissionCardComp的卡槽缓存与布局逻辑 4. 更新所有相关注释与类型引用,统一代码语义
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
* @description 卡牌系统核心控制器(战斗 UI 层 + 业务逻辑层)
|
||||
*
|
||||
* 职责:
|
||||
* 1. **卡牌分发管理** —— 从卡池抽取 3 张卡,分发到 3 个 CardComp 槽位。
|
||||
* 1. **卡牌分发管理** —— 从卡池抽取 3 张卡,分发到 3 个 CHeroComp 槽位。
|
||||
* 抽卡规则:场上已有英雄时按权重混合"对应英雄的升级卡" + "其他英雄卡" + "刷新卡";
|
||||
* 场上无英雄时仅抽取英雄卡和刷新卡。
|
||||
* 2. **金币费用管理** —— 抽卡费用(refreshCost)的扣除。
|
||||
@@ -15,11 +15,11 @@
|
||||
* 6. **准备/战斗阶段切换** —— 控制卡牌面板的 展开/收起 动画。
|
||||
*
|
||||
* 关键设计:
|
||||
* - 3 个 CardComp 由 cardPrefab 动态实例化生成,通过 cacheCardComps() 映射为有序数组 cardComps[],
|
||||
* - 3 个 CHeroComp 由 cardPrefab 动态实例化生成,通过 cacheCardComps() 映射为有序数组 cardComps[],
|
||||
* 之后所有分发、清空操作均通过此数组进行。
|
||||
* - buildDrawCards() 动态合并升级卡池和基础卡池后抽取 3 张,不足时循环补齐。
|
||||
* - 英雄上限校验(onUseHeroCard)采用 guard/cancel 模式:
|
||||
* CardComp 发出 UseHeroCard 事件并传入 guard 对象,
|
||||
* CHeroComp 发出 UseHeroCard 事件并传入 guard 对象,
|
||||
* 本组件可通过 guard.cancel=true 阻止使用。
|
||||
*
|
||||
* 历史:
|
||||
@@ -28,7 +28,7 @@
|
||||
* - 英雄升级仅通过升级卡(SpecialUpgrade)触发,按 UUID 精确升级场上对应英雄。
|
||||
*
|
||||
* 依赖:
|
||||
* - CardComp —— 单卡槽位
|
||||
* - CHeroComp —— 单卡槽位
|
||||
* - HInfoComp —— 英雄信息面板
|
||||
* - CardSet 模块 —— 卡池配置、抽卡规则、特殊卡数据
|
||||
* - HeroAttrsComp —— 英雄属性(升级)
|
||||
@@ -43,7 +43,7 @@ import { CardConfig, CardPoolList, CardType, drawCardsByRule, SpecialRefreshCard
|
||||
import { drawSkillCards } from "../common/config/SCardSet";
|
||||
import { drawEquipCards } from "../common/config/EquipSet";
|
||||
import { drawItemCards } from "../common/config/ICardSet";
|
||||
import { CardComp } from "./CardComp";
|
||||
import { CHeroComp } from "./CHeroComp";
|
||||
import { SCardComp } from "./SCardComp";
|
||||
import { EquipListComp } from "./EquipListComp";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
@@ -188,8 +188,8 @@ export class MissionCardComp extends CCComp {
|
||||
|
||||
// ======================== 运行时状态 ========================
|
||||
|
||||
/** 三个槽位对应的 CardComp 控制器缓存(有序数组) */
|
||||
private cardComps: CardComp[] = [];
|
||||
/** 三个槽位对应的 CHeroComp 控制器缓存(有序数组) */
|
||||
private cardComps: CHeroComp[] = [];
|
||||
/** 技能卡槽控制器缓存 */
|
||||
private skillCardComps: SCardComp[] = [];
|
||||
/** 是否已召唤过英雄(用于控制其他面板按钮是否可点击) */
|
||||
@@ -237,7 +237,7 @@ export class MissionCardComp extends CCComp {
|
||||
/**
|
||||
* 组件加载:
|
||||
* 1. 绑定生命周期事件和按钮交互事件。
|
||||
* 2. 缓存 3 个 CardComp 子控制器引用。
|
||||
* 2. 缓存 3 个 CHeroComp 子控制器引用。
|
||||
* 3. 计算并设置槽位水平布局。
|
||||
* 4. 初始化卡牌面板缩放参数。
|
||||
* 5. 初始化面板轮播布局。
|
||||
@@ -767,7 +767,7 @@ export class MissionCardComp extends CCComp {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用英雄卡的 guard 校验(由 CardComp 通过 UseHeroCard 事件调用):
|
||||
* 使用英雄卡的 guard 校验(由 CHeroComp 通过 UseHeroCard 事件调用):
|
||||
* - 当前英雄数 < 上限 → 允许使用。
|
||||
* - 已满 → 阻止使用(cancel=true),弹 toast。
|
||||
*
|
||||
@@ -823,7 +823,7 @@ export class MissionCardComp extends CCComp {
|
||||
|
||||
/**
|
||||
* 单张卡牌被成功使用后的整池刷新回调:
|
||||
* - payload 为该卡槽组件实例(CardComp 或 SCardComp)。
|
||||
* - payload 为该卡槽组件实例(CHeroComp 或 SCardComp)。
|
||||
* - 命中英雄卡槽 → 重新构建 3 张英雄池卡牌并分发到所有英雄槽。
|
||||
* - 命中技能卡槽 → 重新构建 3 张技能卡并分发到所有技能槽。
|
||||
* - 未命中任何槽位 → 忽略。
|
||||
@@ -831,7 +831,7 @@ export class MissionCardComp extends CCComp {
|
||||
* Why: 购买一张卡后立即刷新整个卡池(不扣金币),让玩家持续从新池中挑选;
|
||||
* 英雄卡池与技能卡池遵循同一逻辑。
|
||||
* SpecialRefresh 自身效果(onUseSpecialCard 中的 tryRefreshHeroCards)
|
||||
* 已是整池刷新,因此 CardComp 对其不派发 CardUsed,避免双重刷新。
|
||||
* 已是整池刷新,因此 CHeroComp 对其不派发 CardUsed,避免双重刷新。
|
||||
*/
|
||||
private onCardUsed(event: string, args: any) {
|
||||
const source = args;
|
||||
@@ -1175,8 +1175,19 @@ export class MissionCardComp extends CCComp {
|
||||
this.populateShopItems();
|
||||
}
|
||||
|
||||
/** 将 cardPrefab 实例化为 3 个卡槽并映射为 CardComp,形成固定顺序控制数组 */
|
||||
/** 将 cardPrefab 实例化为 3 个卡槽并映射为 CHeroComp,形成固定顺序控制数组(幂等:已缓存则不重复实例化) */
|
||||
private cacheCardComps() {
|
||||
// 幂等保护:卡槽已存在且节点有效时,仅刷新 skillCardComps 缓存,不重复实例化英雄卡槽
|
||||
const hasValidHeroComps = this.cardComps.length === 3
|
||||
&& this.cardComps.every(c => c && c.node && c.node.isValid);
|
||||
if (hasValidHeroComps) {
|
||||
const skillNodes = [this.skill_card1, this.skill_card2, this.skill_card3];
|
||||
this.skillCardComps = skillNodes
|
||||
.map(node => node?.getComponent(SCardComp))
|
||||
.filter((comp): comp is SCardComp => !!comp);
|
||||
return;
|
||||
}
|
||||
|
||||
// 清理旧卡槽(如果存在)
|
||||
for (const comp of this.cardComps) {
|
||||
if (comp && comp.node && comp.node.isValid) {
|
||||
@@ -1190,7 +1201,7 @@ export class MissionCardComp extends CCComp {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const node = instantiate(this.cardPrefab);
|
||||
this.cards_node.addChild(node);
|
||||
const comp = node.getComponent(CardComp) || node.addComponent(CardComp);
|
||||
const comp = node.getComponent(CHeroComp) || node.addComponent(CHeroComp);
|
||||
this.cardComps.push(comp);
|
||||
mLogger.log(this.debugMode, "MissionCardComp", "cacheCardComps instantiate", {
|
||||
index: i,
|
||||
@@ -1524,7 +1535,7 @@ export class MissionCardComp extends CCComp {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** 全量分发给 3 槽;每个槽位是否接收由 CardComp 自己判断(锁定可跳过) */
|
||||
/** 全量分发给 3 槽;每个槽位是否接收由 CHeroComp 自己判断(锁定可跳过) */
|
||||
private dispatchCardsToSlots(cards: CardConfig[]) {
|
||||
if (!this.cardComps) return;
|
||||
for (let i = 0; i < this.cardComps.length; i++) {
|
||||
@@ -1851,8 +1862,8 @@ export class MissionCardComp extends CCComp {
|
||||
this.resetButtonScale(this.cards_chou);
|
||||
|
||||
// 关键:在 reset/销毁 时将 Map 置空,彻底切断引用
|
||||
this.cardComps = [] as any;
|
||||
this.skillCardComps = [] as any;
|
||||
this.cardComps = [];
|
||||
this.skillCardComps = [];
|
||||
this.purchasedEquipUuids.clear();
|
||||
this.purchasedItemUuids.clear();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user