feat(卡牌系统): 重构卡牌选择逻辑并添加属性卡类型支持
- 在GameSet枚举中添加Attr卡牌类型 - 在GameEvent中添加UseAttrCard事件 - 重构CardSet模块,统一使用GameSet中的CardType枚举 - 重构MissionCardComp模块,支持混合模式卡牌选择和强制类型获取 - 添加等级升级事件处理,优化卡牌获取逻辑
This commit is contained in:
@@ -2,16 +2,7 @@ import { AttrCards, AttrInfo, CanSelectAttrs } from "./AttrSet";
|
||||
import { talConf, ItalConf, CanSelectTalents } from "./TalSet";
|
||||
import { SkillSet, SkillConfig, CanSelectSkills } from "./SkillSet";
|
||||
import { HeroInfo, heroInfo, CanSelectHeros } from "./heroSet";
|
||||
|
||||
/**
|
||||
* 卡牌类型枚举
|
||||
*/
|
||||
export enum CardType {
|
||||
Skill = 1, // 技能
|
||||
Talent = 2, // 天赋
|
||||
Attr = 3, // 属性
|
||||
Hero = 4 // 英雄(伙伴)
|
||||
}
|
||||
import { CardType } from "./GameSet";
|
||||
|
||||
/**
|
||||
* 统一卡牌信息接口 (用于UI显示和逻辑处理)
|
||||
@@ -58,7 +49,7 @@ export const LevelPoolConfigs: Record<number, IPoolConfig[]> = {
|
||||
3: [{ type: CardType.Talent, poolWeight: 50 }, { type: CardType.Attr, poolWeight: 50, tag: "special" }], // 天赋或特殊属性
|
||||
4: [{ type: CardType.Attr, poolWeight: 100 }],
|
||||
5: [{ type: CardType.Talent, poolWeight: 100 }],
|
||||
6: [{ type: CardType.Hero, poolWeight: 100 }], // 伙伴节点
|
||||
6: [{ type: CardType.Partner, poolWeight: 100 }], // 伙伴节点
|
||||
7: [{ type: CardType.Attr, poolWeight: 80 }, { type: CardType.Skill, poolWeight: 20 }],
|
||||
8: [{ type: CardType.Attr, poolWeight: 80 }, { type: CardType.Skill, poolWeight: 20 }],
|
||||
9: [{ type: CardType.Attr, poolWeight: 50, tag: "special" }, { type: CardType.Talent, poolWeight: 50 }],
|
||||
@@ -110,7 +101,7 @@ function getCardBaseInfo(type: CardType, uuid: number): ICardInfo | null {
|
||||
desc = baseInfo.info;
|
||||
icon = baseInfo.icon;
|
||||
break;
|
||||
case CardType.Hero:
|
||||
case CardType.Partner:
|
||||
baseInfo = HeroInfo[uuid];
|
||||
if (!baseInfo) return null;
|
||||
name = baseInfo.name;
|
||||
@@ -175,7 +166,7 @@ function getDefaultPool(type: CardType, level: number = 1): IPoolItem[] {
|
||||
Object.keys(SkillSet).forEach(key => items.push({ id: Number(key), weight: 80 }));
|
||||
}
|
||||
break;
|
||||
case CardType.Hero:
|
||||
case CardType.Partner:
|
||||
// 优先使用 CanSelectHeros 中的配置
|
||||
if (CanSelectHeros[level]) {
|
||||
CanSelectHeros[level].forEach(id => items.push({ id, weight: 100 }));
|
||||
@@ -199,11 +190,14 @@ function getDefaultPool(type: CardType, level: number = 1): IPoolItem[] {
|
||||
* @param level 当前等级
|
||||
* @param count 选项数量 (默认3个)
|
||||
* @param excludeUuids 排除的卡牌UUID列表 (用于去重或排除已拥有)
|
||||
* @param forcedType 强制指定卡牌类型 (用于特殊获取,如商店、技能书等)
|
||||
*/
|
||||
export function getCardOptions(level: number, count: number = 3, excludeUuids: number[] = []): ICardInfo[] {
|
||||
export function getCardOptions(level: number, count: number = 3, excludeUuids: number[] = [], forcedType?: CardType): ICardInfo[] {
|
||||
// 1. 获取该等级的池配置
|
||||
// 必须复制一份,因为我们可能需要修改它(比如移除空的池子)
|
||||
const initialPoolConfigs = LevelPoolConfigs[level] || [{ type: CardType.Attr, poolWeight: 100 }];
|
||||
// 如果强制指定类型,则构造一个只包含该类型的配置
|
||||
const initialPoolConfigs = forcedType
|
||||
? [{ type: forcedType, poolWeight: 100 }]
|
||||
: (LevelPoolConfigs[level] || [{ type: CardType.Attr, poolWeight: 100 }]);
|
||||
|
||||
const result: ICardInfo[] = [];
|
||||
const excludeSet = new Set(excludeUuids);
|
||||
|
||||
@@ -49,6 +49,7 @@ export enum GameEvent {
|
||||
TalentSelect = "TalentSelect",
|
||||
UseTalentCard = "UseTalentCard",
|
||||
UseItemCard = "UseItemCard",
|
||||
UseAttrCard = "UseAttrCard",
|
||||
NewWave = "NewWave",
|
||||
AD_BACK_TRUE = "AD_BACK_TRUE",
|
||||
AD_BACK_FALSE = "AD_BACK_FALSE",
|
||||
|
||||
@@ -26,7 +26,8 @@ export enum CardType {
|
||||
Talent = 1,
|
||||
Skill = 2,
|
||||
Potion = 3,
|
||||
Partner = 4
|
||||
Partner = 4,
|
||||
Attr = 5
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,15 +3,17 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec
|
||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { talConf, ItalConf } from "../common/config/TalSet";
|
||||
import { CanSelectHeros, HeroInfo } from "../common/config/heroSet";
|
||||
import { CanSelectSkills, SkillSet } from "../common/config/SkillSet";
|
||||
import { ItemSet } from "../common/config/ItemSet";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { CardType } from "../common/config/GameSet";
|
||||
import { getCardOptions, ICardInfo } from "../common/config/CardSet";
|
||||
|
||||
const { ccclass, property } = _decorator;
|
||||
|
||||
interface ICardEvent {
|
||||
type?: CardType;
|
||||
level?: number;
|
||||
}
|
||||
|
||||
/** 视图层对象 */
|
||||
@ccclass('MissionCardComp')
|
||||
@ecs.register('MissionCard', false)
|
||||
@@ -36,13 +38,13 @@ export class MissionCardComp extends CCComp {
|
||||
@property(Node)
|
||||
noStop: Node = null!
|
||||
|
||||
card1_data:any = null!
|
||||
card2_data:any = null!
|
||||
card3_data:any = null!
|
||||
card4_data:any = null!
|
||||
card1_data: ICardInfo = null!
|
||||
card2_data: ICardInfo = null!
|
||||
card3_data: ICardInfo = null!
|
||||
card4_data: ICardInfo = null!
|
||||
|
||||
// 当前卡片类型
|
||||
curCardType: CardType = CardType.Talent;
|
||||
// 当前卡片类型 (用于特殊获取模式)
|
||||
curCardType: CardType | null = null;
|
||||
|
||||
// 是否处于锁定状态
|
||||
private isLocked: boolean = true;
|
||||
@@ -60,6 +62,7 @@ export class MissionCardComp extends CCComp {
|
||||
oops.message.on(GameEvent.MissionStart, this.onMissionStart, this);
|
||||
oops.message.on(GameEvent.MissionEnd, this.onMissionEnd, this);
|
||||
oops.message.on(GameEvent.ToCallFriend, this.onCallFriend, this);
|
||||
oops.message.on(GameEvent.CanUpdateLv, this.onLevelUp, this);
|
||||
|
||||
}
|
||||
|
||||
@@ -74,6 +77,7 @@ export class MissionCardComp extends CCComp {
|
||||
oops.message.off(GameEvent.MissionStart, this.onMissionStart, this);
|
||||
oops.message.off(GameEvent.MissionEnd, this.onMissionEnd, this);
|
||||
oops.message.off(GameEvent.ToCallFriend, this.onCallFriend, this);
|
||||
oops.message.off(GameEvent.CanUpdateLv, this.onLevelUp, this);
|
||||
|
||||
this.ent.destroy();
|
||||
}
|
||||
@@ -130,25 +134,31 @@ export class MissionCardComp extends CCComp {
|
||||
private hasSelected: boolean = false;
|
||||
|
||||
// 事件队列
|
||||
private eventQueue: CardType[] = [];
|
||||
private eventQueue: ICardEvent[] = [];
|
||||
|
||||
private onShopOpen(event: string, args: any) {
|
||||
this.eventQueue.push(CardType.Potion);
|
||||
this.eventQueue.push({ type: CardType.Potion });
|
||||
this.checkQueue();
|
||||
}
|
||||
|
||||
private onTalentSelect(event: string, args: any) {
|
||||
this.eventQueue.push(CardType.Talent);
|
||||
this.eventQueue.push({ type: CardType.Talent });
|
||||
this.checkQueue();
|
||||
}
|
||||
|
||||
private onHeroSkillSelect(event: string, args: any) {
|
||||
this.eventQueue.push(CardType.Skill);
|
||||
this.eventQueue.push({ type: CardType.Skill });
|
||||
this.checkQueue();
|
||||
}
|
||||
|
||||
private onCallFriend(event: string, args: any) {
|
||||
this.eventQueue.push(CardType.Partner);
|
||||
this.eventQueue.push({ type: CardType.Partner });
|
||||
this.checkQueue();
|
||||
}
|
||||
|
||||
private onLevelUp(event: string, args: any) {
|
||||
// args.lv 是当前等级
|
||||
this.eventQueue.push({ level: args.lv });
|
||||
this.checkQueue();
|
||||
}
|
||||
|
||||
@@ -156,18 +166,42 @@ export class MissionCardComp extends CCComp {
|
||||
if (this.node.active) return;
|
||||
if (this.eventQueue.length === 0) return;
|
||||
|
||||
const type = this.eventQueue.shift();
|
||||
if (type) {
|
||||
this.showCardType(type);
|
||||
const event = this.eventQueue.shift();
|
||||
if (event) {
|
||||
if (event.type !== undefined) {
|
||||
this.showCardType(event.type);
|
||||
} else if (event.level !== undefined) {
|
||||
this.showLevelCards(event.level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示指定类型的卡牌(特殊获取模式)
|
||||
*/
|
||||
private showCardType(type: CardType) {
|
||||
this.curCardType = type;
|
||||
// 获取当前英雄等级作为参考,或者默认1级
|
||||
const level = smc.vmdata.hero.lv || 1;
|
||||
this.fetchCards(level, type);
|
||||
this.openUI();
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示等级对应的卡牌(正常升级模式)
|
||||
*/
|
||||
private showLevelCards(level: number) {
|
||||
this.curCardType = null; // 混合模式,无单一类型
|
||||
this.fetchCards(level);
|
||||
this.openUI();
|
||||
}
|
||||
|
||||
private openUI() {
|
||||
this.node.active = true;
|
||||
this.hasSelected = false;
|
||||
this.curCardType = type;
|
||||
|
||||
// 根据锁定状态显示 Lock 节点
|
||||
// 根据锁定状态显示 Lock 节点 (仅在特殊模式下可能需要锁定?或者统一逻辑)
|
||||
// 原逻辑:Lock.active = this.isLocked
|
||||
if (this.Lock) {
|
||||
this.Lock.active = this.isLocked;
|
||||
}
|
||||
@@ -184,9 +218,9 @@ export class MissionCardComp extends CCComp {
|
||||
}
|
||||
|
||||
this.resetCardStates();
|
||||
this.refCards();
|
||||
this.playShowAnimation();
|
||||
}
|
||||
|
||||
checkNoStop(){
|
||||
this.noStop.getChildByName("no").active=!smc.data.noStop
|
||||
|
||||
@@ -212,42 +246,30 @@ export class MissionCardComp extends CCComp {
|
||||
});
|
||||
}
|
||||
|
||||
refCards(){
|
||||
// 根据当前类型获取数据
|
||||
let allData: any[] = [];
|
||||
|
||||
if (this.curCardType === CardType.Talent) {
|
||||
allData = Object.values(talConf);
|
||||
} else if (this.curCardType === CardType.Skill) {
|
||||
// 过滤掉怪物技能 (uuid >= 6200)
|
||||
// allData = Object.values(SkillSet).filter((s:any) => s.uuid < 6200);
|
||||
allData = CanSelectSkills.map(id => SkillSet[id]);
|
||||
} else if (this.curCardType === CardType.Partner) {
|
||||
allData = CanSelectHeros.map(id => HeroInfo[id]);
|
||||
} else if (this.curCardType === CardType.Potion) {
|
||||
allData = Object.values(ItemSet);
|
||||
}
|
||||
// 后续扩展其他类型
|
||||
// else if (this.curCardType === CardType.Skill) { ... }
|
||||
/**
|
||||
* 专门的获取卡牌方法
|
||||
* @param level 等级
|
||||
* @param forcedType 强制类型 (可选)
|
||||
*/
|
||||
fetchCards(level: number, forcedType?: CardType){
|
||||
// 使用 CardSet 的 getCardOptions 获取卡牌
|
||||
// 这里我们要获取 4 张卡牌
|
||||
const options = getCardOptions(level, 4, [], forcedType);
|
||||
|
||||
const result: any[] = [];
|
||||
const temp = [...allData];
|
||||
// 更新卡片数据
|
||||
if (options.length > 0) this.updateCardData(1, options[0]);
|
||||
if (options.length > 1) this.updateCardData(2, options[1]);
|
||||
if (options.length > 2) this.updateCardData(3, options[2]);
|
||||
if (options.length > 3) this.updateCardData(4, options[3]);
|
||||
|
||||
// 简单的随机抽取算法
|
||||
for (let i = 0; i < 4 && temp.length > 0; i++) {
|
||||
const index = Math.floor(Math.random() * temp.length);
|
||||
result.push(temp[index]);
|
||||
temp.splice(index, 1);
|
||||
}
|
||||
|
||||
// 更新卡片
|
||||
if (result.length > 0) this.updateCardData(1, result[0]);
|
||||
if (result.length > 1) this.updateCardData(2, result[1]);
|
||||
if (result.length > 2) this.updateCardData(3, result[2]);
|
||||
if (result.length > 3) this.updateCardData(4, result[3]);
|
||||
// 如果获取不足4张,隐藏多余的卡片节点 (UI可能需要处理空数据)
|
||||
if (options.length < 4 && this.card4) this.card4.active = false;
|
||||
if (options.length < 3 && this.card3) this.card3.active = false;
|
||||
if (options.length < 2 && this.card2) this.card2.active = false;
|
||||
if (options.length < 1 && this.card1) this.card1.active = false;
|
||||
}
|
||||
|
||||
updateCardInfo(card:Node, data:any){
|
||||
updateCardInfo(card:Node, data: ICardInfo){
|
||||
if(!card) return
|
||||
card.active = true;
|
||||
// 隐藏选中状态
|
||||
@@ -260,24 +282,13 @@ export class MissionCardComp extends CCComp {
|
||||
}
|
||||
let info = card.getChildByName("info")?.getChildByName("Label")
|
||||
if(info){
|
||||
// 根据类型显示不同描述,目前天赋用desc
|
||||
let desc = "";
|
||||
if (this.curCardType === CardType.Talent) {
|
||||
desc = data.desc || "";
|
||||
} else if (this.curCardType === CardType.Skill) {
|
||||
desc = data.info || "";
|
||||
} else if (this.curCardType === CardType.Partner) {
|
||||
desc = data.info || "";
|
||||
} else {
|
||||
desc = data.desc || "";
|
||||
}
|
||||
|
||||
info.getComponent(Label)!.string = desc;
|
||||
// ICardInfo 已经标准化了 desc,直接使用
|
||||
info.getComponent(Label)!.string = data.desc || "";
|
||||
}
|
||||
}
|
||||
|
||||
updateCardData(index: number, data: any) {
|
||||
// 使用动态属性访问,简化 switch 冗余代码
|
||||
updateCardData(index: number, data: ICardInfo) {
|
||||
// 使用动态属性访问
|
||||
(this as any)[`card${index}_data`] = data;
|
||||
this.updateCardInfo((this as any)[`card${index}`], data);
|
||||
}
|
||||
@@ -288,13 +299,13 @@ export class MissionCardComp extends CCComp {
|
||||
// 如果已经选择过,则不再处理
|
||||
if (this.hasSelected) return;
|
||||
|
||||
// 动态获取数据和节点,简化 switch 逻辑
|
||||
let selectedData: any = (this as any)[`card${_index}_data`];
|
||||
// 动态获取数据和节点
|
||||
let selectedData: ICardInfo = (this as any)[`card${_index}_data`];
|
||||
let selectedCardNode: Node | null = (this as any)[`card${_index}`];
|
||||
|
||||
if (selectedData && selectedCardNode) {
|
||||
this.hasSelected = true;
|
||||
console.log("选择卡片:", selectedData.name, "类型:", this.curCardType);
|
||||
console.log("选择卡片:", selectedData.name, "类型:", selectedData.type);
|
||||
|
||||
// 未选中的卡片缩小
|
||||
const cards = [this.card1, this.card2, this.card3, this.card4];
|
||||
@@ -319,18 +330,27 @@ export class MissionCardComp extends CCComp {
|
||||
.delay(0.5)
|
||||
.call(() => {
|
||||
// 根据类型发送不同事件
|
||||
if (this.curCardType === CardType.Talent) {
|
||||
smc.addTalentRecord(selectedData.uuid);
|
||||
oops.message.dispatchEvent(GameEvent.UseTalentCard, selectedData.uuid);
|
||||
} else if (this.curCardType === CardType.Skill) {
|
||||
smc.addSkillRecord(selectedData.uuid);
|
||||
oops.message.dispatchEvent(GameEvent.UseSkillCard, selectedData.uuid);
|
||||
} else if (this.curCardType === CardType.Partner) {
|
||||
oops.message.dispatchEvent(GameEvent.CallFriend, { uuid: selectedData.uuid });
|
||||
} else if (this.curCardType === CardType.Potion) {
|
||||
oops.message.dispatchEvent(GameEvent.UseItemCard, selectedData.id);
|
||||
switch (selectedData.type) {
|
||||
case CardType.Talent:
|
||||
smc.addTalentRecord(selectedData.uuid);
|
||||
oops.message.dispatchEvent(GameEvent.UseTalentCard, selectedData.uuid);
|
||||
break;
|
||||
case CardType.Skill:
|
||||
smc.addSkillRecord(selectedData.uuid);
|
||||
oops.message.dispatchEvent(GameEvent.UseSkillCard, selectedData.uuid);
|
||||
break;
|
||||
case CardType.Partner:
|
||||
oops.message.dispatchEvent(GameEvent.CallFriend, { uuid: selectedData.uuid });
|
||||
break;
|
||||
case CardType.Potion:
|
||||
// Potion 在 CardSet 中也是 uuid
|
||||
oops.message.dispatchEvent(GameEvent.UseItemCard, selectedData.uuid);
|
||||
break;
|
||||
case CardType.Attr:
|
||||
oops.message.dispatchEvent(GameEvent.UseAttrCard, selectedData.uuid);
|
||||
break;
|
||||
}
|
||||
// 后续扩展其他类型事件
|
||||
|
||||
this.close();
|
||||
})
|
||||
.start();
|
||||
@@ -449,4 +469,4 @@ export class MissionCardComp extends CCComp {
|
||||
reset() {
|
||||
this.node.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user