|
|
|
|
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();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|