- 移除 SingletonModuleComp 中的 role 字段及相关设置 - 在 MissionComp 中移除重置 role 的代码 - 修改 Hero 类的销毁方法,不再清理 role 引用 - 在 MissionCardComp 中通过 HeroMasterComp 查询来定位主角实体 - 增加详细调试日志以追踪天赋、技能等组件的添加过程
669 lines
25 KiB
TypeScript
669 lines
25 KiB
TypeScript
import { mLogger } from "../common/Logger";
|
||
import { _decorator, Label, Node, tween, Vec3, Color, Sprite, Tween, SpriteAtlas, resources } 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, FightSet, CardKind } from "../common/config/GameSet";
|
||
import { getCardOptions, ICardInfo } from "../common/config/CardSet";
|
||
import { TalComp } from "../hero/TalComp";
|
||
import { HeroSkillsComp } from "../hero/HeroSkills";
|
||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||
import { BuffConf } from "../common/config/SkillSet";
|
||
import { BType } from "../common/config/HeroAttrs";
|
||
import { AttrCards, PotionCards } from "../common/config/AttrSet";
|
||
|
||
import { HeroMasterComp } from "../hero/HeroMasterComp";
|
||
|
||
const { ccclass, property } = _decorator;
|
||
|
||
interface ICardEvent {
|
||
type?: CardType;
|
||
level?: number;
|
||
}
|
||
|
||
/** 视图层对象 */
|
||
@ccclass('MissionCardComp')
|
||
@ecs.register('MissionCard', false)
|
||
export class MissionCardComp extends CCComp {
|
||
@property({ tooltip: "是否启用调试日志" })
|
||
private debugMode: boolean = true;
|
||
|
||
/** 视图层逻辑代码分离演示 */
|
||
@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;
|
||
|
||
// 图标图集缓存
|
||
private uiconsAtlas: SpriteAtlas | null = null;
|
||
|
||
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.AttrSelect, this.onAttrSelect, 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);
|
||
|
||
}
|
||
|
||
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.AttrSelect, this.onAttrSelect, 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);
|
||
|
||
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 onAttrSelect(event: string, args: any) {
|
||
this.eventQueue.push({ type: CardType.Attr });
|
||
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 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);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 显示指定类型的卡牌(特殊获取模式)
|
||
*/
|
||
private showCardType(type: CardType) {
|
||
this.curCardType = type;
|
||
// 获取当前英雄等级作为参考,或者默认1级
|
||
const level = smc.vmdata.hero.lv || 1;
|
||
this.fetchCards(level, type);
|
||
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);
|
||
mLogger.log(this.debugMode, 'MissionCard', `[MissionCard] 获取到的卡牌选项: ${JSON.stringify(options)}`);
|
||
// 更新卡片数据
|
||
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 || "";
|
||
}
|
||
|
||
// 先隐藏所有类型标识
|
||
const typeNodes = ["Atk", "Atked", "Buff", "Attr", "Skill", "Hp", "Dead", "Partner"];
|
||
|
||
// 1. 处理 card 直接子节点
|
||
typeNodes.forEach(nodeName => {
|
||
const node = card.getChildByName(nodeName);
|
||
if (node) node.active = false;
|
||
});
|
||
|
||
// 2. 处理 card/type 下的子节点
|
||
const typeContainer = card.getChildByName("type");
|
||
if (typeContainer) {
|
||
typeNodes.forEach(nodeName => {
|
||
const node = typeContainer.getChildByName(nodeName);
|
||
if (node) node.active = false;
|
||
});
|
||
}
|
||
|
||
// 根据 kind 激活对应节点
|
||
let activeNodeName = "";
|
||
switch (data.kind) {
|
||
case CardKind.Atk:
|
||
activeNodeName = "Atk";
|
||
break;
|
||
case CardKind.Atted:
|
||
activeNodeName = "Atked";
|
||
break;
|
||
case CardKind.Buff:
|
||
activeNodeName = "Buff";
|
||
break;
|
||
case CardKind.Attr:
|
||
activeNodeName = "Attr";
|
||
break;
|
||
case CardKind.Skill:
|
||
activeNodeName = "Skill";
|
||
break;
|
||
case CardKind.Hp:
|
||
activeNodeName = "Hp";
|
||
break;
|
||
case CardKind.Dead:
|
||
activeNodeName = "Dead";
|
||
break;
|
||
case CardKind.Partner:
|
||
activeNodeName = "Partner";
|
||
break;
|
||
}
|
||
|
||
if (activeNodeName) {
|
||
// 激活 card 下的节点
|
||
const activeNode = card.getChildByName(activeNodeName);
|
||
if (activeNode) activeNode.active = true;
|
||
|
||
// 激活 card/type 下的节点
|
||
if (typeContainer) {
|
||
const activeTypeNode = typeContainer.getChildByName(activeNodeName);
|
||
if (activeTypeNode) activeTypeNode.active = true;
|
||
}
|
||
}
|
||
|
||
// 更新图标 (如果存在 icon 节点)
|
||
// 注意:根据 Prefab 分析,icon 可能在 card/Mask/icon 路径下,也可能在各个分类节点下
|
||
// 这里尝试统一查找 icon 节点
|
||
let iconNode: Node | null = null;
|
||
|
||
// 1. 尝试查找通用的 mask/icon (根据之前 card.prefab 分析,有个 Mask/icon 节点)
|
||
const maskNode = card.getChildByName("Mask");
|
||
if (maskNode) {
|
||
iconNode = maskNode.getChildByName("icon");
|
||
}
|
||
|
||
if (iconNode && data.icon) {
|
||
this.updateIcon(iconNode, data.icon);
|
||
}
|
||
}
|
||
|
||
private updateIcon(node: Node, iconId: string) {
|
||
if (!node || !iconId) return;
|
||
|
||
const sprite = node.getComponent(Sprite);
|
||
if (!sprite) return;
|
||
|
||
if (this.uiconsAtlas) {
|
||
const frame = this.uiconsAtlas.getSpriteFrame(iconId);
|
||
if (frame) {
|
||
sprite.spriteFrame = frame;
|
||
}
|
||
} else {
|
||
// 加载图集
|
||
resources.load("gui/uicons", SpriteAtlas, (err, atlas) => {
|
||
if (err) {
|
||
mLogger.error(this.debugMode, 'MissionCard', "[MissionCardComp] Failed to load uicons atlas", err);
|
||
return;
|
||
}
|
||
this.uiconsAtlas = atlas;
|
||
const frame = atlas.getSpriteFrame(iconId);
|
||
if (frame) {
|
||
sprite.spriteFrame = frame;
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
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) {
|
||
mLogger.log(this.debugMode, 'MissionCard', "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;
|
||
mLogger.log(this.debugMode, 'MissionCard', "选择卡片:", 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(() => {
|
||
// 使用 HeroMasterComp 查找主角实体
|
||
// @ts-ignore
|
||
const entities = ecs.query(ecs.allOf(HeroMasterComp));
|
||
let role = entities.length > 0 ? entities[0] : null;
|
||
|
||
if (!role) {
|
||
mLogger.log(this.debugMode, 'MissionCard', `[MissionCard] 未找到挂载 HeroMasterComp 的主角实体`);
|
||
} else {
|
||
mLogger.log(this.debugMode, 'MissionCard', `[MissionCard] 成功定位主角实体: ${role.eid}`);
|
||
}
|
||
|
||
if (role) {
|
||
switch (selectedData.type) {
|
||
case CardType.Talent:
|
||
smc.addTalentRecord(selectedData.uuid);
|
||
// 直接调用 TalComp 添加天赋
|
||
const talComp = role.get(TalComp);
|
||
if (talComp) {
|
||
const beforeCount = Object.keys(talComp.Tals).length;
|
||
mLogger.log(this.debugMode, 'MissionCard', `[MissionCard] Talent Before: Count=${beforeCount}, Tals=${JSON.stringify(talComp.Tals)}`);
|
||
talComp.addTal(selectedData.uuid);
|
||
const afterCount = Object.keys(talComp.Tals).length;
|
||
mLogger.log(this.debugMode, 'MissionCard', `[MissionCard] Talent After: Count=${afterCount}, Added=${selectedData.uuid}, Tals=${JSON.stringify(talComp.Tals)}`);
|
||
}
|
||
break;
|
||
case CardType.Skill:
|
||
smc.addSkillRecord(selectedData.uuid);
|
||
// 直接调用 HeroSkillsComp 添加技能
|
||
const skillComp = role.get(HeroSkillsComp);
|
||
if (skillComp) {
|
||
const beforeCount = Object.keys(skillComp.skills).length;
|
||
mLogger.log(this.debugMode, 'MissionCard', `[MissionCard] Skill Before: Count=${beforeCount}, Skills=${JSON.stringify(skillComp.skills)}`);
|
||
skillComp.addSkill(selectedData.uuid);
|
||
const afterCount = Object.keys(skillComp.skills).length;
|
||
mLogger.log(this.debugMode, 'MissionCard', `[MissionCard] Skill After: Count=${afterCount}, Added=${selectedData.uuid}, Skills=${JSON.stringify(skillComp.skills)}`);
|
||
}
|
||
break;
|
||
case CardType.Partner:
|
||
// 伙伴是召唤新实体,依然适合用事件,或者直接调用 summon 方法
|
||
oops.message.dispatchEvent(GameEvent.CallFriend, { uuid: selectedData.uuid });
|
||
break;
|
||
case CardType.Potion:
|
||
// 药水直接作用于 HeroAttrsComp
|
||
const attrsComp = role.get(HeroAttrsComp);
|
||
if (attrsComp) {
|
||
const potion = PotionCards[selectedData.uuid];
|
||
if (potion) {
|
||
const beforeVal = attrsComp.Attrs[potion.attr] || 0;
|
||
mLogger.log(this.debugMode, 'MissionCard', `[MissionCard] Potion Before: Attr[${potion.attr}]=${beforeVal}, Attrs=${JSON.stringify(attrsComp.Attrs)}`);
|
||
|
||
const buffConf: BuffConf = {
|
||
buff: potion.attr,
|
||
value: potion.value,
|
||
BType: BType.RATIO,
|
||
time: potion.duration,
|
||
chance: 1,
|
||
};
|
||
attrsComp.addBuff(buffConf);
|
||
smc.updateHeroInfo(attrsComp);
|
||
|
||
mLogger.log(this.debugMode, 'MissionCard', `[MissionCard] Potion Applied: ${potion.desc}, Value=${potion.value}, Attrs=${JSON.stringify(attrsComp.Attrs)}`);
|
||
oops.gui.toast(potion.desc);
|
||
}
|
||
}
|
||
break;
|
||
case CardType.Attr:
|
||
// 属性卡:更新全局属性并刷新主角
|
||
const attrCard = AttrCards[selectedData.uuid];
|
||
if (attrCard) {
|
||
let globalBefore = 0;
|
||
if (smc.global_attrs[attrCard.attr]) {
|
||
globalBefore = smc.global_attrs[attrCard.attr][0];
|
||
}
|
||
const roleAttrs = role.get(HeroAttrsComp);
|
||
let roleBefore = 0;
|
||
if (roleAttrs) {
|
||
roleBefore = roleAttrs.Attrs[attrCard.attr] || 0;
|
||
}
|
||
mLogger.log(this.debugMode, 'MissionCard', `[MissionCard] Attr Before: Global=${globalBefore}, Hero=${roleBefore}, Attrs=${JSON.stringify(roleAttrs.Attrs)}`);
|
||
|
||
if (!smc.global_attrs[attrCard.attr]) {
|
||
smc.global_attrs[attrCard.attr] = [0, 0];
|
||
}
|
||
const current = smc.global_attrs[attrCard.attr];
|
||
current[0] += attrCard.value;
|
||
current[1] += 1;
|
||
|
||
// 直接触发主角属性重算
|
||
const attrsComp = role.get(HeroAttrsComp);
|
||
if (attrsComp) {
|
||
attrsComp.recalculateSingleAttr(attrCard.attr);
|
||
smc.updateHeroInfo(attrsComp);
|
||
|
||
const roleAfter = attrsComp.Attrs[attrCard.attr] || 0;
|
||
mLogger.log(this.debugMode, 'MissionCard', `[MissionCard] Attr After: Global=${current[0]}, Hero=${roleAfter}, Attrs=${JSON.stringify(attrsComp.Attrs)}`);
|
||
}
|
||
oops.gui.toast(attrCard.desc);
|
||
}
|
||
break;
|
||
}
|
||
} else {
|
||
mLogger.log(this.debugMode, 'MissionCard', `[MissionCard] 主角实体无效,无法应用卡牌效果`);
|
||
}
|
||
|
||
// 记录已获取的卡牌
|
||
oops.message.dispatchEvent(GameEvent.UpdateMissionGet, {
|
||
uuid: selectedData.uuid,
|
||
icon: selectedData.icon,
|
||
kind: selectedData.kind
|
||
});
|
||
|
||
this.close();
|
||
})
|
||
.start();
|
||
}
|
||
}
|
||
|
||
/** 看广告关闭 Lock */
|
||
watchAdCloseLock() {
|
||
// TODO: 此处接入 IAA 广告 SDK
|
||
mLogger.log(this.debugMode, 'MissionCard', "播放激励视频广告...");
|
||
|
||
// 模拟广告播放成功回调
|
||
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();
|
||
}
|
||
}
|