import { _decorator, Component, Node } from 'cc'; import { Monster } from './Monster'; import { GEvent } from 'db://assets/mx/module/event/GEvent'; import { GBundle } from '../../game/ConfigRes'; import { BossSkill } from './BossSkill'; const { ccclass, property } = _decorator; @ccclass('Boss') export class Boss extends Component { @property(Node) startPosNode: Node = null; monster: Monster; protected onEnable(): void { GEvent.Ins.on(GEvent.tetriGameStart, this.onBossStart, this); GEvent.Ins.on(GEvent.BattleWarnTimeStart, this.onBattleWarnTimeStart, this); } protected onDisable(): void { GEvent.Ins.off(GEvent.tetriGameStart, this.onBossStart, this); GEvent.Ins.off(GEvent.BattleWarnTimeStart, this.onBattleWarnTimeStart, this); } setMonster(monster: Monster) { this.monster = monster; this.playWaitAnim(); // 预热 Boss 投掷物,避免 useskillwave 触发时 getNode 同步未命中返回 null void gg.res.ensurePrefab('bossWeapon1', 'prefab/武器/', GBundle.BattleGameWeapon); void gg.res.ensurePrefab('砖块爆炸', 'prefab/爆炸/', GBundle.BattleGameWeapon); } /**战斗警告时间开始 */ onBattleWarnTimeStart() { this.scheduleOnce(() => { if (!this.monster?.Data?.useskillwave) return; let wNum = gg.game.CurentBattle.CurentWaveNum; if (this.monster.Data.useskillwave.includes(wNum)) { this.playAttackAnim(() => { this.playWaitAnim(); }); void this.atk(); } }, 4.8); } onBossStart() { if (!this.monster) return; this.playSummonAnim(() => { this.playWaitAnim(); }); } async atk() { const battle = gg.game?.CurentBattle; if (!battle) return; const parent = battle.SkillController?.node?.isValid ? battle.SkillController.node : battle.TetraMap?._gameRoot?.isValid ? battle.TetraMap._gameRoot : null; if (!parent) { console.warn('[Boss.atk] SkillController / GameRoot 均不可用,跳过投掷'); return; } let startPos = this.startPosNode ? this.startPosNode.worldPosition : this.node.worldPosition; let targetPos = this.getHighestBlockWorldPos(); let n = await gg.res.getNodeAsync('prefab/武器/', 'bossWeapon1', GBundle.BattleGameWeapon); if (!n?.isValid) { console.warn('[Boss.atk] bossWeapon1 加载失败'); return; } n.setParent(parent, true); n.worldPosition = startPos; let comp = n.getComponent(BossSkill); if (!comp) { console.warn('[Boss.atk] bossWeapon1 缺少 BossSkill'); gg.res.putNode(n); return; } comp.setData(this.monster, targetPos); } /**获取当前堆叠的方块中最高的那个方块的世界坐标 */ getHighestBlockWorldPos() { let nodes = gg.game.CurentBattle?.TetraMap?._tetrisTable?.children; if (!nodes?.length) { return this.startPosNode ? this.startPosNode.worldPosition.clone() : this.node.worldPosition.clone(); } let highestBlock = nodes.reduce((max, node) => { return node.worldPosition.y > max.worldPosition.y ? node : max; }, nodes[0]); return highestBlock.worldPosition; } /**播放待机动画 */ playWaitAnim() { this.playSpine('1待机', null, 1, true); } /**播放抛完待机 */ playAfterThrowWaitAnim() { this.playSpine('4抛完待机', null, 1, true); } /**播放召唤动画 */ playSummonAnim(callback: Function = null) { gg.audio.playEffect({ name: 'BOSS吼叫', path: 'sound/武器音效2/' }); this.playSpine('2召唤', callback, 1, false); } /**播放攻击动画 */ playAttackAnim(callback: Function = null) { this.playSpine('3攻击', callback, 1, false); } /**播放Spine动画 */ playSpine(name: string, callback: Function = null, timeScale = 1, loop = true) { if (!this.monster.anim) { if (callback) callback(); return; } this.monster.anim.timeScale = timeScale * gg.game.CurentBattle.TimeScale; this.monster.anim.setAnimation(0, name, loop); if (callback) { this.monster.anim.setCompleteListener(() => { this.monster.anim.setCompleteListener(null); callback(); }); } } }