refactor(map): 重构抽卡逻辑与卡牌渲染规则
1. 实现升级卡轮询机制,按英雄UUID升序循环切换必出升级卡 2. 重构buildDrawCards抽卡流程,分离必出升级卡与随机抽取逻辑 3. 移除抽卡池内的刷新功能卡,调整特殊卡渲染逻辑 4. 统一英雄卡与升级卡的交互与渲染表现
This commit is contained in:
@@ -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