337 lines
12 KiB
TypeScript
337 lines
12 KiB
TypeScript
import { _decorator, Label, Node, tween, Vec3, Color, Sprite } 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 { 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";
|
||
|
||
const { ccclass, property } = _decorator;
|
||
|
||
/** 视图层对象 */
|
||
@ccclass('MissionCardComp')
|
||
@ecs.register('MissionCard', false)
|
||
export class MissionCardComp extends CCComp {
|
||
/** 视图层逻辑代码分离演示 */
|
||
@property(Node)
|
||
card1:Node = null!
|
||
@property(Node)
|
||
card2:Node = null!
|
||
@property(Node)
|
||
card3:Node = null!
|
||
@property(Node)
|
||
card4:Node = null!
|
||
|
||
@property(Node)
|
||
btnClose: Node = null!
|
||
|
||
@property(Node)
|
||
Lock: Node = null!
|
||
|
||
card1_data:any = null!
|
||
card2_data:any = null!
|
||
card3_data:any = null!
|
||
card4_data:any = null!
|
||
|
||
// 当前卡片类型
|
||
curCardType: CardType = CardType.Talent;
|
||
|
||
// 已购买的卡片槽位标记 (用于物品购买)
|
||
purchasedSlots: boolean[] = [false, false, false, false, false];
|
||
|
||
onLoad() {
|
||
oops.message.on(GameEvent.TalentSelect, this.onTalentSelect, this);
|
||
oops.message.on(GameEvent.HeroSkillSelect, this.onHeroSkillSelect, this);
|
||
oops.message.on(GameEvent.ShopOpen, this.onShopOpen, this);
|
||
oops.message.on(GameEvent.MissionStart, this.init, this);
|
||
oops.message.on(GameEvent.ToCallFriend, this.onCallFriend, this);
|
||
|
||
}
|
||
|
||
onDestroy() {
|
||
oops.message.off(GameEvent.TalentSelect, this.onTalentSelect, this);
|
||
oops.message.off(GameEvent.HeroSkillSelect, this.onHeroSkillSelect, this);
|
||
oops.message.off(GameEvent.ShopOpen, this.onShopOpen, this);
|
||
oops.message.off(GameEvent.MissionStart, this.init, this);
|
||
oops.message.off(GameEvent.ToCallFriend, this.onCallFriend, this);
|
||
|
||
this.ent.destroy();
|
||
}
|
||
init(){
|
||
this.Lock.active=true
|
||
}
|
||
start() {
|
||
// 初始隐藏或显示逻辑
|
||
this.node.active = false;
|
||
this.resetCardStates();
|
||
}
|
||
|
||
private resetCardStates() {
|
||
const cards = [this.card1, this.card2, this.card3, this.card4];
|
||
cards.forEach(card => {
|
||
if (card) {
|
||
const selected = card.getChildByName("selected");
|
||
if (selected) selected.active = false;
|
||
// 恢复缩放和颜色
|
||
card.setScale(1, 1, 1);
|
||
const sprite = card.getComponent(Sprite);
|
||
if (sprite) sprite.color = new Color(255, 255, 255);
|
||
}
|
||
});
|
||
// 重置购买状态
|
||
this.purchasedSlots = [false, false, false, false, false];
|
||
}
|
||
|
||
// 是否已经选择了天赋
|
||
private hasSelected: boolean = false;
|
||
|
||
// 事件队列
|
||
private eventQueue: CardType[] = [];
|
||
|
||
private onShopOpen(event: string, args: any) {
|
||
this.eventQueue.push(CardType.Potion);
|
||
this.checkQueue();
|
||
}
|
||
|
||
private onTalentSelect(event: string, args: any) {
|
||
this.eventQueue.push(CardType.Talent);
|
||
this.checkQueue();
|
||
}
|
||
|
||
private onHeroSkillSelect(event: string, args: any) {
|
||
this.eventQueue.push(CardType.Skill);
|
||
this.checkQueue();
|
||
}
|
||
|
||
private onCallFriend(event: string, args: any) {
|
||
this.eventQueue.push(CardType.Partner);
|
||
this.checkQueue();
|
||
}
|
||
|
||
private checkQueue() {
|
||
if (this.node.active) return;
|
||
if (this.eventQueue.length === 0) return;
|
||
|
||
const type = this.eventQueue.shift();
|
||
if (type) {
|
||
this.showCardType(type);
|
||
}
|
||
}
|
||
|
||
private showCardType(type: CardType) {
|
||
this.node.active = true;
|
||
this.hasSelected = false;
|
||
this.curCardType = type;
|
||
this.resetCardStates();
|
||
this.refCards();
|
||
this.playShowAnimation();
|
||
}
|
||
|
||
private playShowAnimation() {
|
||
const cards = [this.card1, this.card2, this.card3, this.card4];
|
||
cards.forEach((card, index) => {
|
||
if (card) {
|
||
card.setScale(Vec3.ZERO);
|
||
tween(card)
|
||
.delay(index * 0.1)
|
||
.to(0.4, { scale: new Vec3(1, 1, 1) }, { easing: 'backOut' })
|
||
.start();
|
||
}
|
||
});
|
||
}
|
||
|
||
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.Skill) { ... }
|
||
|
||
const result: any[] = [];
|
||
const temp = [...allData];
|
||
|
||
// 简单的随机抽取算法
|
||
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]);
|
||
}
|
||
|
||
updateCardInfo(card:Node, data:any){
|
||
if(!card) return
|
||
card.active = true;
|
||
// 隐藏选中状态
|
||
const selected = card.getChildByName("selected");
|
||
if(selected) selected.active = false;
|
||
|
||
let name = card.getChildByName("name")
|
||
if(name){
|
||
name.getComponent(Label)!.string = data.name
|
||
}
|
||
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 || "";
|
||
}
|
||
|
||
// 如果是物品,显示价格
|
||
if (this.curCardType === CardType.Potion && data.price) {
|
||
desc += `\n价格: ${data.price}`;
|
||
}
|
||
info.getComponent(Label)!.string = desc;
|
||
}
|
||
}
|
||
|
||
updateCardData(index: number, data: any) {
|
||
// 使用动态属性访问,简化 switch 冗余代码
|
||
(this as any)[`card${index}_data`] = data;
|
||
this.updateCardInfo((this as any)[`card${index}`], data);
|
||
}
|
||
|
||
selectCard(e: any, index: string) {
|
||
console.log("selectCard", index)
|
||
let _index = parseInt(index);
|
||
// 如果已经选择过,则不再处理
|
||
if (this.hasSelected) return;
|
||
|
||
// 动态获取数据和节点,简化 switch 逻辑
|
||
let selectedData: any = (this as any)[`card${_index}_data`];
|
||
let selectedCardNode: Node | null = (this as any)[`card${_index}`];
|
||
|
||
if (selectedData && selectedCardNode) {
|
||
// 处理物品购买逻辑
|
||
if (this.curCardType === CardType.Potion) {
|
||
if (this.purchasedSlots[_index]) {
|
||
oops.gui.toast("该物品已购买");
|
||
return;
|
||
}
|
||
|
||
if (smc.vmdata.gold < selectedData.price) {
|
||
oops.gui.toast("金币不足");
|
||
return;
|
||
}
|
||
|
||
// 扣除金币
|
||
smc.updateGold(-selectedData.price);
|
||
|
||
// 发送使用物品事件
|
||
oops.message.dispatchEvent(GameEvent.UseItemCard, selectedData.id);
|
||
|
||
// 标记已购买
|
||
this.purchasedSlots[_index] = true;
|
||
|
||
// 视觉反馈 (变灰)
|
||
const sprite = selectedCardNode.getComponent(Sprite);
|
||
if (sprite) sprite.color = new Color(150, 150, 150);
|
||
|
||
oops.gui.toast("购买成功");
|
||
|
||
// 检查是否所有卡片都已购买,如果是则关闭
|
||
let allPurchased = true;
|
||
// 检查当前显示的卡片是否都买了
|
||
if (this.card1.active && !this.purchasedSlots[1]) allPurchased = false;
|
||
if (this.card2.active && !this.purchasedSlots[2]) allPurchased = false;
|
||
if (this.card3.active && !this.purchasedSlots[3]) allPurchased = false;
|
||
if (this.card4.active && !this.purchasedSlots[4]) allPurchased = false;
|
||
|
||
if (allPurchased) {
|
||
this.close();
|
||
}
|
||
return;
|
||
}
|
||
|
||
this.hasSelected = true;
|
||
console.log("选择卡片:", selectedData.name, "类型:", this.curCardType);
|
||
|
||
// 未选中的卡片缩小
|
||
const cards = [this.card1, this.card2, this.card3, this.card4];
|
||
cards.forEach(card => {
|
||
if (card && card !== selectedCardNode) {
|
||
tween(card).to(0.2, { scale: Vec3.ZERO }).start();
|
||
}
|
||
});
|
||
|
||
// 显示当前选中的 selected 节点
|
||
const selected = selectedCardNode.getChildByName("selected");
|
||
if(selected) {
|
||
selected.active = true;
|
||
selected.setScale(Vec3.ZERO);
|
||
tween(selected).to(0.2, { scale: new Vec3(1, 1, 1) }, { easing: 'backOut' }).start();
|
||
}
|
||
|
||
// 选中卡片动效后触发逻辑
|
||
tween(selectedCardNode)
|
||
.to(0.1, { scale: new Vec3(1.1, 1.1, 1.1) })
|
||
.to(0.1, { scale: new Vec3(1, 1, 1) })
|
||
.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 });
|
||
}
|
||
// 后续扩展其他类型事件
|
||
this.close();
|
||
})
|
||
.start();
|
||
}
|
||
}
|
||
|
||
/** 看广告关闭 Lock */
|
||
watchAdCloseLock() {
|
||
// TODO: 此处接入 IAA 广告 SDK
|
||
console.log("播放激励视频广告...");
|
||
|
||
// 模拟广告播放成功回调
|
||
if (this.Lock) {
|
||
this.Lock.active = false;
|
||
oops.gui.toast("解锁成功");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 关闭界面
|
||
*/
|
||
close() {
|
||
this.node.active = false;
|
||
this.checkQueue();
|
||
}
|
||
|
||
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
||
reset() {
|
||
this.node.destroy();
|
||
}
|
||
} |