import { Node, sp } from 'cc'; import { MergeEventType, type MergeEvent } from 'db://assets/mx/module/merge'; import type { BattleBagSession } from '../../battle/bag/BattleBagSession'; import { BattleSpinePlayback } from '../../battle/presentation/BattleSpinePlayback'; import { RankDataManager } from '../../manager/RankDataManager'; /** 引导手指 Spine 动画 */ const FINGER_ANIM = '点击'; /** 步骤节点父名 */ const STEPS_NODE = 'steps'; /** 第一步:点召唤 */ const STEP_SUMMON = '2'; /** 第二步:拖字上阵 */ const STEP_DRAG = '3'; /** 手指节点名 */ const FINGER_NODE = '引导手指'; /** * 新玩家首次进战弱引导:点召唤 → 拖字上阵。 */ export class BattleFirstGuidePresenter { /** 引导根 */ private _root: Node | null = null; /** 点召唤文案 */ private _stepSummon: Node | null = null; /** 拖字文案 */ private _stepDrag: Node | null = null; /** 手指 */ private _finger: Node | null = null; /** 手指 Spine */ private _fingerSk: sp.Skeleton | null = null; /** 本机背包 */ private _bag: BattleBagSession | null = null; /** 当前步:0 未开 / 2 点召唤 / 3 拖字 */ private _step = 0; /** * 绑定并按存档决定是否展示第一步。 * @param root ui_guide * @param bag 本机背包会话 */ bind(root: Node | null, bag: BattleBagSession | null): void { this.unbind(); if (!root?.isValid) { console.error('[BattleFirstGuide] ui_guide 缺失'); return; } root.active = false; if (!RankDataManager.shouldShowFirstBattleGuide()) return; const steps = root.getChildByName(STEPS_NODE); this._stepSummon = steps?.getChildByName(STEP_SUMMON) ?? null; this._stepDrag = steps?.getChildByName(STEP_DRAG) ?? null; this._finger = root.getChildByName(FINGER_NODE) ?? null; this._fingerSk = this._finger?.getComponent(sp.Skeleton) ?? null; if (!this._stepSummon?.isValid || !this._stepDrag?.isValid || !this._finger?.isValid) { console.error('[BattleFirstGuide] ui_guide 子节点缺失'); return; } if (!bag) { console.error('[BattleFirstGuide] bagSession 未就绪'); return; } this._root = root; this._bag = bag; this._bag.on(MergeEventType.TilePlaced, this._onPlayerDrag); this._bag.on(MergeEventType.TileMoved, this._onPlayerDrag); this._showSummon(); } /** 召唤刷新成功:藏手指,切到拖字提示 */ onSummonOk(): void { if (this._step !== 2) return; this._showDrag(); const curWaveNum = gg.game.CurentBattle.CurentWaveNum; gg.sdk.reportDY('inLevel', `${gg.game.getReportDYBattleCountLabel(curWaveNum)}-新手引导1点召唤`); } /** 停动画、解监听、藏根 */ unbind(): void { if (this._bag) { this._bag.off(MergeEventType.TilePlaced, this._onPlayerDrag); this._bag.off(MergeEventType.TileMoved, this._onPlayerDrag); } this._stopFinger(); if (this._root?.isValid) this._root.active = false; this._root = null; this._stepSummon = null; this._stepDrag = null; this._finger = null; this._fingerSk = null; this._bag = null; this._step = 0; } /** 第一步:手指点召唤 + 文案 2 */ private _showSummon(): void { const root = this._root; if (!root?.isValid) return; this._step = 2; root.active = true; if (this._stepSummon) this._stepSummon.active = true; if (this._stepDrag) this._stepDrag.active = false; if (this._finger) this._finger.active = true; this._playFinger(); } /** 第二步:只留拖字文案 */ private _showDrag(): void { this._step = 3; if (this._stepSummon) this._stepSummon.active = false; if (this._stepDrag) this._stepDrag.active = true; this._stopFinger(); if (this._finger) this._finger.active = false; } /** 玩家拖到地图:结束引导 */ private readonly _onPlayerDrag = (_event: MergeEvent): void => { if (this._step !== 3) return; RankDataManager.markFirstBattleGuideDone(); this.unbind(); const curWaveNum = gg.game.CurentBattle.CurentWaveNum; gg.sdk.reportDY('inLevel', `${gg.game.getReportDYBattleCountLabel(curWaveNum)}-新手引导2拖字上阵`); }; /** 循环播手指点击 */ private _playFinger(): void { const sk = this._fingerSk; if (!sk?.isValid) { console.error('[BattleFirstGuide] 引导手指缺少 Spine'); return; } BattleSpinePlayback.play(sk, FINGER_ANIM, { loop: true }); } /** 停手指 Spine */ private _stopFinger(): void { const sk = this._fingerSk; if (!sk?.isValid) return; BattleSpinePlayback.clearPendingComplete(sk); BattleSpinePlayback.resetTracks(sk); } }