Files
pixelheros/assets/script/game/map/MissionCardComp.ts
panw fe5ed952d5 fix: 修复角色控制器和任务卡片的显示问题
修复角色控制器prefab的_active属性设置为true以正确显示
将SingletonModuleComp的showInfo默认值改为true以显示信息
在MissionCardComp的onMissionStart中添加noStop.active = false以正确初始化状态
2026-01-15 15:04:44 +08:00

474 lines
15 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, Tween } 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 { 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)
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!
@property(Node)
unLock: Node = null!
@property(Node)
noStop: Node = null!
card1_data: ICardInfo = null!
card2_data: ICardInfo = null!
card3_data: ICardInfo = null!
card4_data: ICardInfo = null!
// 当前卡片类型 (用于特殊获取模式)
curCardType: CardType | null = null;
// 是否处于锁定状态
private isLocked: boolean = true;
// 是否永久解锁(本局)
private isAdUnlocked: boolean = false;
onLoad() {
if (this.btnClose) {
this.btnClose.on(Node.EventType.TOUCH_END, this.onGiveUp, this);
}
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.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);
}
onDestroy() {
if (this.btnClose) {
this.btnClose.off(Node.EventType.TOUCH_END, this.onGiveUp, this);
}
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.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();
}
init(){
this.onMissionStart();
}
/** 游戏开始初始化 */
onMissionStart() {
this.isLocked = true;
this.isAdUnlocked = false;
this.noStop.active = false;
if (this.Lock) this.Lock.active = false; // 初始不显示,等待 showCardType
if(this.unLock) this.unLock.active=false
this.eventQueue = [];
}
/** 游戏结束清理 */
onMissionEnd() {
this.eventQueue = [];
this.node.active = false;
this.hasSelected = false;
// 停止所有卡片动画
const cards = [this.card1, this.card2, this.card3, this.card4];
cards.forEach(card => {
if (card) {
Tween.stopAllByTarget(card);
const selected = card.getChildByName("selected");
if (selected) Tween.stopAllByTarget(selected);
}
});
}
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);
}
});
}
// 是否已经选择了天赋
private hasSelected: boolean = false;
// 事件队列
private eventQueue: ICardEvent[] = [];
private onShopOpen(event: string, args: any) {
this.eventQueue.push({ type: CardType.Potion });
this.checkQueue();
}
private onTalentSelect(event: string, args: any) {
this.eventQueue.push({ type: CardType.Talent });
this.checkQueue();
}
private onHeroSkillSelect(event: string, args: any) {
this.eventQueue.push({ type: CardType.Skill });
this.checkQueue();
}
private onCallFriend(event: string, args: any) {
this.eventQueue.push({ type: CardType.Partner });
this.checkQueue();
}
private onLevelUp(event: string, args: any) {
// args.lv 是当前等级
this.eventQueue.push({ level: args.lv });
this.checkQueue();
}
private checkQueue() {
if (this.node.active) return;
if (this.eventQueue.length === 0) return;
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;
// 根据锁定状态显示 Lock 节点 (仅在特殊模式下可能需要锁定?或者统一逻辑)
// 原逻辑Lock.active = this.isLocked
if (this.Lock) {
this.Lock.active = this.isLocked;
}
// 显示 noStop 节点
if (this.noStop) {
this.noStop.active = true;
this.checkNoStop()
}
// 如果没有开启 noStop则暂停怪物行动
if (!smc.data.noStop) {
smc.mission.stop_mon_action = true;
}
this.resetCardStates();
this.playShowAnimation();
}
checkNoStop(){
this.noStop.getChildByName("no").active=!smc.data.noStop
// 更新暂停状态
if (this.node.active) {
smc.mission.stop_mon_action = !smc.data.noStop;
}
}
switchNoStop(){
smc.data.noStop=!smc.data.noStop
this.checkNoStop()
}
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();
}
});
}
/**
* 专门的获取卡牌方法
* @param level 等级
* @param forcedType 强制类型 (可选)
*/
fetchCards(level: number, forcedType?: CardType){
// 使用 CardSet 的 getCardOptions 获取卡牌
// 这里我们要获取 4 张卡牌
const options = getCardOptions(level, 4, [], forcedType);
// 更新卡片数据
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]);
// 如果获取不足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: ICardInfo){
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){
// ICardInfo 已经标准化了 desc直接使用
info.getComponent(Label)!.string = data.desc || "";
}
}
updateCardData(index: number, data: ICardInfo) {
// 使用动态属性访问
(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;
// 动态获取数据和节点
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, "类型:", selectedData.type);
// 未选中的卡片缩小
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(() => {
// 根据类型发送不同事件
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();
}
}
/** 看广告关闭 Lock */
watchAdCloseLock() {
// TODO: 此处接入 IAA 广告 SDK
console.log("播放激励视频广告...");
// 模拟广告播放成功回调
this.isLocked = false;
this.isAdUnlocked = true;
if (this.Lock) {
this.Lock.active = false;
oops.gui.toast("解锁成功");
}
this.closeUnLock();
}
coinCloseLock(){
let cost = smc.vmdata.mission_data.unlockCoin;
if (smc.vmdata.gold >= cost) {
// 扣除金币
if (smc.updateGold(-cost)) {
this.isLocked = false;
if (this.Lock) {
this.Lock.active = false;
}
oops.gui.toast("解锁成功");
this.closeUnLock();
} else {
oops.gui.toast("交易失败");
}
} else {
oops.gui.toast("金币不足");
}
}
showUnLock(){
if (this.unLock) {
this.unLock.active = true;
this.unLock.setScale(Vec3.ZERO);
tween(this.unLock)
.to(0.2, { scale: new Vec3(1, 1, 1) }, { easing: 'backOut' })
.start();
}
}
closeUnLock(){
if (this.unLock && this.unLock.active) {
tween(this.unLock)
.to(0.2, { scale: Vec3.ZERO }, { easing: 'backIn' })
.call(() => {
this.unLock.active = false;
})
.start();
}
}
/** 放弃选择 */
onGiveUp() {
if (this.hasSelected) return;
this.hasSelected = true;
// 隐藏关闭按钮
if (this.btnClose) {
this.btnClose.active = false;
}
const cards = [this.card1, this.card2, this.card3, this.card4];
let delayTime = 0.2;
cards.forEach(card => {
if (card && card.active) {
tween(card).to(delayTime, { scale: Vec3.ZERO }).start();
}
});
// 动画结束后关闭
this.scheduleOnce(() => {
this.close();
}, delayTime);
}
/**
* 关闭界面
*/
close() {
this.node.active = false;
// 恢复游戏运行状态(取消暂停)
smc.mission.stop_mon_action = false;
// 关闭时隐藏按钮,避免下次打开其他类型时闪烁
if (this.btnClose) {
this.btnClose.active = false;
}
// 关闭时隐藏 Lock 节点
if (this.Lock) {
this.Lock.active = false;
}
// 关闭时隐藏 noStop 节点
if (this.noStop) {
this.noStop.active = false;
}
// 恢复锁定状态(如果没有永久解锁)
if (!this.isAdUnlocked) {
this.isLocked = true;
}
this.checkQueue();
}
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
reset() {
this.node.destroy();
}
}