Files
pixelheros/assets/script/game/map/MissionCardComp.ts
panw 45508abca4 refactor(hero): 优化技能初始化逻辑并添加技能卡选择功能
- 移除initSkills和addSkill方法中多余的entity参数,改为使用组件内ent属性
- 在HeroSkillsComp中添加技能卡选择事件监听和处理
- 在MissionCardComp中实现技能卡选择界面和事件分发
2026-01-05 14:45:39 +08:00

345 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 { SkillSet } from "../common/config/SkillSet";
import { ItemSet } from "../common/config/ItemSet";
import { smc } from "../common/SingletonModuleComp";
const { ccclass, property } = _decorator;
export enum CardType {
Talent = 1,
Skill = 2,
Potion = 3
}
/** 视图层对象 */
@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);
}
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);
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 onShopOpen(event: string, args: any) {
this.node.active = true;
this.hasSelected = false;
this.curCardType = CardType.Potion;
this.resetCardStates();
this.refCards();
this.playShowAnimation();
}
private onTalentSelect(event: string, args: any) {
this.node.active = true;
this.hasSelected = false; // 重置选择状态
this.curCardType = CardType.Talent; // 记录当前类型为天赋
this.resetCardStates(); // 每次刷新前重置卡片状态
this.refCards();
this.playShowAnimation();
}
private onHeroSkillSelect(event: string, args: any) {
this.node.active = true;
this.hasSelected = false;
this.curCardType = CardType.Skill;
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);
}
// 后续扩展其他类型
// 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 {
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 (index) {
case 1:
this.card1_data = data
this.updateCardInfo(this.card1, data);
break;
case 2:
this.card2_data = data
this.updateCardInfo(this.card2, data);
break;
case 3:
this.card3_data = data
this.updateCardInfo(this.card3, data);
break;
case 4:
this.card4_data = data
this.updateCardInfo(this.card4, data);
break;
}
}
selectCard(e:any,index:string){
console.log("selectCard",index)
let _index = parseInt(index);
// 如果已经选择过,则不再处理
if(this.hasSelected) return;
let selectedData: any = null;
let selectedCardNode: Node | null = null;
switch (_index) {
case 1:
selectedData = this.card1_data;
selectedCardNode = this.card1;
break;
case 2:
selectedData = this.card2_data;
selectedCardNode = this.card2;
break;
case 3:
selectedData = this.card3_data;
selectedCardNode = this.card3;
break;
case 4:
selectedData = this.card4_data;
selectedCardNode = this.card4;
break;
}
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.node.active = false;
}
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) {
oops.message.dispatchEvent(GameEvent.UseTalentCard, selectedData.uuid);
} else if (this.curCardType === CardType.Skill) {
oops.message.dispatchEvent(GameEvent.UseSkillCard, selectedData.uuid);
}
// 后续扩展其他类型事件
this.node.active = false;
})
.start();
}
}
/** 看广告关闭 Lock */
watchAdCloseLock() {
// TODO: 此处接入 IAA 广告 SDK
console.log("播放激励视频广告...");
// 模拟广告播放成功回调
if (this.Lock) {
this.Lock.active = false;
oops.gui.toast("解锁成功");
}
}
/**
* 关闭界面
*/
close() {
this.node.active = false;
}
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
reset() {
this.node.destroy();
}
}