refactor(map): 重构抽卡逻辑与卡牌渲染规则
1. 实现升级卡轮询机制,按英雄UUID升序循环切换必出升级卡 2. 重构buildDrawCards抽卡流程,分离必出升级卡与随机抽取逻辑 3. 移除抽卡池内的刷新功能卡,调整特殊卡渲染逻辑 4. 统一英雄卡与升级卡的交互与渲染表现
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@ import { mLogger } from "../common/Logger";
|
||||
import { _decorator, Animation, AnimationClip, EventTouch, Input, Label, Node, NodeEventType, Sprite, SpriteAtlas, Tween, tween, UIOpacity, Vec3, input, resources, Light, UITransform, Widget } 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 { CardConfig, CardType, SpecialRefreshCardList, SpecialUpgradeCardList, CKind, CardPoolList } from "../common/config/CardSet";
|
||||
import { CardConfig, CardType, SpecialRefreshCardList, CKind, CardPoolList } from "../common/config/CardSet";
|
||||
import { CardBgComp } from "./CardBgComp";
|
||||
import { HeroInfo } from "../common/config/heroSet";
|
||||
import { SkillSet } from "../common/config/SkillSet";
|
||||
@@ -525,9 +525,10 @@ export class CardComp extends CCComp {
|
||||
private onCardTap() {
|
||||
this.showCallBtn();
|
||||
oops.message.dispatchEvent(GameEvent.CardSelected, this);
|
||||
// 英雄卡打开信息面板(点击替代长按)
|
||||
if (this.card_type === CardType.Hero) {
|
||||
const heroUuid = this.card_uuid;
|
||||
// 英雄卡 / 升级卡打开信息面板(点击替代长按)
|
||||
const isUpgradeCard = this.card_type === CardType.SpecialUpgrade && !!this.cardData?.target_hero_uuid;
|
||||
if (this.card_type === CardType.Hero || isUpgradeCard) {
|
||||
const heroUuid = isUpgradeCard ? (this.cardData!.target_hero_uuid as number) : this.card_uuid;
|
||||
const heroLv = Math.max(1, this.cardData?.hero_lv ?? 1);
|
||||
const poolLv = Math.max(1, this.cardData?.base_pool_lv ?? this.cardData?.pool_lv ?? 1);
|
||||
oops.gui.remove(UIID.HInfo);
|
||||
@@ -638,8 +639,15 @@ export class CardComp extends CCComp {
|
||||
|
||||
this.node.setPosition(this.restPosition.x, this.restPosition.y, this.restPosition.z);
|
||||
|
||||
// 渲染参数:动态升级卡(SpecialUpgrade + target_hero_uuid)按英雄卡样式渲染,
|
||||
// 使用 target_hero_uuid 对应的英雄信息(名称/AP/HP/动画),等级显示为目标等级。
|
||||
const isUpgradeCard = this.card_type === CardType.SpecialUpgrade && !!this.cardData.target_hero_uuid;
|
||||
const renderType: CardType = isUpgradeCard ? CardType.Hero : this.card_type;
|
||||
const renderUuid: number = isUpgradeCard ? (this.cardData.target_hero_uuid as number) : this.card_uuid;
|
||||
const renderKind: CKind = isUpgradeCard ? CKind.Hero : this.cardData.kind;
|
||||
|
||||
// ---- 卡牌种类标识(近战 / 远程 / 辅助等) ----
|
||||
const kindName = CKind[this.cardData.kind];
|
||||
const kindName = CKind[renderKind];
|
||||
|
||||
if (this.BG_node) {
|
||||
const bgLv = this.cardData.base_pool_lv ?? this.cardData.pool_lv;
|
||||
@@ -714,8 +722,8 @@ export class CardComp extends CCComp {
|
||||
if (widget) widget.updateAlignment();
|
||||
}
|
||||
|
||||
if (this.card_type === CardType.Hero) {
|
||||
const hero = HeroInfo[this.card_uuid];
|
||||
if (renderType === CardType.Hero) {
|
||||
const hero = HeroInfo[renderUuid];
|
||||
const heroLv = Math.max(1, this.cardData.hero_lv ?? hero?.lv ?? 1);
|
||||
this.setLabel(this.name_node, `${hero?.name || ""}`);
|
||||
if (this.lvl_node) {
|
||||
@@ -733,27 +741,14 @@ export class CardComp extends CCComp {
|
||||
if (this.info_node) this.info_node.active = false;
|
||||
} else {
|
||||
if (this.lvl_node) this.lvl_node.node.active = false;
|
||||
// 动态升级卡:显示对应英雄名 + "升级"后缀 + 目标等级
|
||||
if (this.card_type === CardType.SpecialUpgrade && this.cardData.target_hero_uuid) {
|
||||
const targetHero = HeroInfo[this.cardData.target_hero_uuid];
|
||||
const targetLv = Math.max(1, Math.floor(this.cardData.hero_lv ?? 1));
|
||||
this.setLabel(this.name_node, `${targetHero?.name || ""} 升级`);
|
||||
if (this.info_node) {
|
||||
this.info_node.active = true;
|
||||
this.setLabel(this.info_node, `升至 Lv.${targetLv}`);
|
||||
}
|
||||
} else {
|
||||
// 特殊卡(升级 / 刷新):显示卡名 + 品质后缀 + 描述
|
||||
const specialCard = this.card_type === CardType.SpecialUpgrade
|
||||
? SpecialUpgradeCardList[this.card_uuid]
|
||||
: SpecialRefreshCardList[this.card_uuid];
|
||||
const card_lv = Math.max(1, Math.floor(this.cardData.card_lv ?? 1));
|
||||
const spSuffix = card_lv >= 2 ? "★".repeat(card_lv - 1) : "";
|
||||
this.setLabel(this.name_node, `${spSuffix}${specialCard?.name || ""}${spSuffix}`);
|
||||
if (this.info_node) {
|
||||
this.info_node.active = true;
|
||||
this.setLabel(this.info_node, specialCard?.info || "");
|
||||
}
|
||||
// 特殊卡(刷新):显示卡名 + 品质后缀 + 描述
|
||||
const specialCard = SpecialRefreshCardList[this.card_uuid];
|
||||
const card_lv = Math.max(1, Math.floor(this.cardData.card_lv ?? 1));
|
||||
const spSuffix = card_lv >= 2 ? "★".repeat(card_lv - 1) : "";
|
||||
this.setLabel(this.name_node, `${spSuffix}${specialCard?.name || ""}${spSuffix}`);
|
||||
if (this.info_node) {
|
||||
this.info_node.active = true;
|
||||
this.setLabel(this.info_node, specialCard?.info || "");
|
||||
}
|
||||
this.ap_node.active = false;
|
||||
this.hp_node.active = false;
|
||||
@@ -770,10 +765,10 @@ export class CardComp extends CCComp {
|
||||
|
||||
// ---- 图标 ----
|
||||
const iconNode = this.icon_node as Node;
|
||||
if (this.card_type === CardType.Hero) {
|
||||
if (renderType === CardType.Hero) {
|
||||
iconNode.setScale(new Vec3(-1.5, 1.5, 1));
|
||||
// 英雄卡使用 AnimationClip,加载 idle 动画
|
||||
this.updateHeroAnimation(iconNode, this.card_uuid, this.iconVisualToken);
|
||||
// 英雄卡 / 升级卡使用 AnimationClip,加载 idle 动画
|
||||
this.updateHeroAnimation(iconNode, renderUuid, this.iconVisualToken);
|
||||
return;
|
||||
}
|
||||
iconNode.setScale(new Vec3(1, 1, 1));
|
||||
|
||||
@@ -151,7 +151,12 @@ export class MissionCardComp extends CCComp {
|
||||
/** 卡牌面板收起态缩放(scale=0 隐藏) */
|
||||
private cardsHideScale: Vec3 = new Vec3(0, 0, 1);
|
||||
/** 卡牌原始定位点 */
|
||||
private cardsPos = [-240, 0, 240]
|
||||
private cardsPos = [-220, 0, 220]
|
||||
/**
|
||||
* 必出升级卡的轮询索引:每次刷新按场上可升级英雄 UUID 升序轮询选 1 张。
|
||||
* 每次 buildDrawCards 取模更新,保证多次刷新时升级卡依次切换。
|
||||
*/
|
||||
private upgradeRotationIndex: number = 0;
|
||||
|
||||
// ======================== 生命周期 ========================
|
||||
|
||||
@@ -728,17 +733,12 @@ export class MissionCardComp extends CCComp {
|
||||
/**
|
||||
* 构建本次抽卡结果,保证最终可分发 3 条数据。
|
||||
*
|
||||
* 抽卡池构成:
|
||||
* - 动态升级卡:扫描场上存活英雄,每个 UUID 至多生成一张升级卡
|
||||
* (已达到 HERO_MAX_LV 的英雄不出卡)。同 UUID 只出一张,避免重复。
|
||||
* - 基础英雄卡:所有英雄的 lv1 卡。
|
||||
* - 刷新功能卡:SpecialRefresh 卡。
|
||||
* 抽卡规则:
|
||||
* 1. **必出规则**:当场上有可升级英雄时,每次刷新必出 1 张升级卡,并放在返回数组首位(对应卡池最左侧槽位)。
|
||||
* 多次刷新时,按场上英雄 target_hero_uuid 升序循环切换升级卡(upgradeRotationIndex)。
|
||||
* 2. 其余 2 张从混合池(剩余升级卡 + 基础英雄卡)按权重抽取。
|
||||
*
|
||||
* 三类卡按 weight 权重混合抽 3 张,且升级卡之间 unique 去重。
|
||||
*
|
||||
* 特殊规则:当场存活英雄数已达 HERO_MAX_NUM 时,
|
||||
* 不再抽取基础英雄卡和刷新卡,只抽取场上已有英雄的升级卡
|
||||
* (若全部已满级则降级回混合池,避免卡池为空)。
|
||||
* 特殊规则:当场存活英雄数已达 HERO_MAX_NUM 时,全部出升级卡(若全部已满级则降级回混合池)。
|
||||
*/
|
||||
private buildDrawCards(): CardConfig[] {
|
||||
const upgradeCards = this.buildHeroUpgradeCards();
|
||||
@@ -758,21 +758,42 @@ export class MissionCardComp extends CCComp {
|
||||
}
|
||||
|
||||
const heroCards = CardPoolList.filter(c => c.type === CardType.Hero);
|
||||
const refreshCards: CardConfig[] = Object.values(SpecialRefreshCardList);
|
||||
|
||||
const mixedPool: CardConfig[] = [...upgradeCards, ...heroCards, ...refreshCards];
|
||||
// 英雄池只刷英雄卡(含动态升级卡),不再混入刷新功能卡
|
||||
const mixedPool: CardConfig[] = [...upgradeCards, ...heroCards];
|
||||
if (mixedPool.length === 0) return [];
|
||||
|
||||
const picked = this.pickMixedCards(mixedPool, 3, upgradeCards);
|
||||
if (picked.length >= 3) return picked.slice(0, 3);
|
||||
const result: CardConfig[] = [];
|
||||
const usedUpgradeTargets = new Set<number>();
|
||||
|
||||
/** 兜底:不足 3 张时循环补齐 */
|
||||
const filled = [...picked];
|
||||
while (filled.length < 3) {
|
||||
if (mixedPool.length === 0) break;
|
||||
filled.push(mixedPool[filled.length % mixedPool.length]);
|
||||
// 必出 1 张升级卡,按 UUID 升序轮询,放在返回数组首位(对应最左侧卡槽)
|
||||
if (upgradeCards.length > 0) {
|
||||
const idx = this.upgradeRotationIndex % upgradeCards.length;
|
||||
this.upgradeRotationIndex = (this.upgradeRotationIndex + 1) % upgradeCards.length;
|
||||
const mandatory = upgradeCards[idx];
|
||||
result.push(mandatory);
|
||||
usedUpgradeTargets.add(mandatory.target_hero_uuid ?? 0);
|
||||
}
|
||||
return filled;
|
||||
|
||||
// 剩余张数从混合池抽取,排除已选升级卡 target_hero_uuid
|
||||
const remainingCount = 3 - result.length;
|
||||
if (remainingCount > 0) {
|
||||
const remainingPool = mixedPool.filter(c => {
|
||||
if (c.type === CardType.SpecialUpgrade && c.target_hero_uuid) {
|
||||
return !usedUpgradeTargets.has(c.target_hero_uuid);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
const rest = this.pickMixedCards(remainingPool, remainingCount, upgradeCards);
|
||||
result.push(...rest);
|
||||
}
|
||||
|
||||
// 兜底:不足 3 张时循环补齐
|
||||
while (result.length < 3) {
|
||||
if (mixedPool.length === 0) break;
|
||||
result.push(mixedPool[result.length % mixedPool.length]);
|
||||
}
|
||||
return result.slice(0, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -850,6 +871,8 @@ export class MissionCardComp extends CCComp {
|
||||
hero_lv: lv + 1,
|
||||
});
|
||||
});
|
||||
// 按 target_hero_uuid 升序排序,保证返回顺序稳定(便于 buildDrawCards 按顺序轮询)
|
||||
result.sort((a, b) => (a.target_hero_uuid ?? 0) - (b.target_hero_uuid ?? 0));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user