|
|
|
|
@ -29,6 +29,8 @@ export enum MonsterTag { |
|
|
|
|
const BLOOD_BAR_SORT_LAYER = 3; |
|
|
|
|
/** 血条底框 sortingOrder;进度子节点 +1,避免底框盖住填充 */ |
|
|
|
|
const BLOOD_BAR_SORT_ORDER = 8; |
|
|
|
|
/** Boss 左右朝向:累计水平位移超过此值才切面(世界像素;speed=25 时约 0.5s 内可切) */ |
|
|
|
|
const BOSS_FACE_DX_MIN = 2; |
|
|
|
|
/** 还魂丹复活特效(battleHero/prefab/skill/小怪复活效果) */ |
|
|
|
|
const REVIVE_FX_PREFAB = '小怪复活效果'; |
|
|
|
|
/** 还魂丹复活 Spine 动画 */ |
|
|
|
|
@ -108,6 +110,12 @@ export class Monster extends Component { |
|
|
|
|
/** 加速特效朝向用:上一帧世界坐标 */ |
|
|
|
|
private _accelFxLastX = Number.NaN; |
|
|
|
|
private _accelFxLastY = Number.NaN; |
|
|
|
|
/** Boss 左右朝向:上一帧世界 X */ |
|
|
|
|
private _faceLastX = Number.NaN; |
|
|
|
|
/** Boss 左右朝向:未达阈值的累计水平位移 */ |
|
|
|
|
private _faceAccX = 0; |
|
|
|
|
/** Boss 朝向:资源默认朝右,+1=朝右,-1=朝左 */ |
|
|
|
|
private _faceSign = 1; |
|
|
|
|
/** playSpine 传入的基础倍速(不含 BattleRuntime.TimeScale) */ |
|
|
|
|
private _animBaseTimeScale = 1; |
|
|
|
|
|
|
|
|
|
@ -136,6 +144,7 @@ export class Monster extends Component { |
|
|
|
|
this.useMxMovement = !!gg.game.CurentBattle?.useMxMovement; |
|
|
|
|
|
|
|
|
|
this.init(); |
|
|
|
|
this._resetMoveFacing(); |
|
|
|
|
this._lastAttackTime = 0; |
|
|
|
|
if (this.mechanismImmobile) { |
|
|
|
|
this.state = MonsterState.STOP; |
|
|
|
|
@ -155,12 +164,80 @@ export class Monster extends Component { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected update(_dt: number): void { |
|
|
|
|
if (!this._accelerateFx?.isValid || !this._accelerateFx.active) return; |
|
|
|
|
const battle = gg.game.CurentBattle; |
|
|
|
|
if (!battle || battle.IsGameOver || battle.IsGamePause) return; |
|
|
|
|
this._tickMoveFacing(); |
|
|
|
|
if (!this._accelerateFx?.isValid || !this._accelerateFx.active) return; |
|
|
|
|
this._tickAccelerateFxAngle(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Boss 按水平位移切左右朝向:只翻 skin 下怪物体节点(如 BOSS土)。 |
|
|
|
|
* 血条挂在模板 root 的 bloodPos,不受影响;受击后仰作用在 skin,也不冲掉体朝向。 |
|
|
|
|
*/ |
|
|
|
|
private _tickMoveFacing(): void { |
|
|
|
|
if (!this.Data || !MonsterDataManager.isBossType(this.Data.type)) return; |
|
|
|
|
if (this.IsDead || this.mechanismImmobile) return; |
|
|
|
|
const body = this._bossBodyNode(); |
|
|
|
|
if (!body || !this.node?.isValid) return; |
|
|
|
|
const x = this.node.worldPosition.x; |
|
|
|
|
if (!Number.isFinite(this._faceLastX)) { |
|
|
|
|
this._faceLastX = x; |
|
|
|
|
this._faceAccX = 0; |
|
|
|
|
this._applyFaceSign(body, this._faceSign); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
const dx = x - this._faceLastX; |
|
|
|
|
this._faceLastX = x; |
|
|
|
|
this._faceAccX += dx; |
|
|
|
|
if (Math.abs(this._faceAccX) >= BOSS_FACE_DX_MIN) { |
|
|
|
|
// 资源默认朝右:右移 +1,左移 -1
|
|
|
|
|
this._faceSign = this._faceAccX > 0 ? 1 : -1; |
|
|
|
|
this._faceAccX = 0; |
|
|
|
|
} |
|
|
|
|
this._applyFaceSign(body, this._faceSign); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* skin 下的怪物体节点(挂载的皮肤预制体根)。 |
|
|
|
|
*/ |
|
|
|
|
private _bossBodyNode(): Node | null { |
|
|
|
|
const skin = this.skin; |
|
|
|
|
if (!skin?.isValid) return null; |
|
|
|
|
const kids = skin.children; |
|
|
|
|
for (let i = 0; i < kids.length; i++) { |
|
|
|
|
const child = kids[i]; |
|
|
|
|
if (child?.isValid) return child; |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 写入怪物体左右朝向。 |
|
|
|
|
* @param body skin 下怪物节点 |
|
|
|
|
* @param sign ±1 |
|
|
|
|
*/ |
|
|
|
|
private _applyFaceSign(body: Node, sign: number): void { |
|
|
|
|
const s = sign < 0 ? -1 : 1; |
|
|
|
|
const sy = Math.abs(body.scale.y) || 1; |
|
|
|
|
const sz = body.scale.z || 1; |
|
|
|
|
if (Math.sign(body.scale.x || 1) === s && Math.abs(Math.abs(body.scale.x) - 1) < 1e-3) return; |
|
|
|
|
body.setScale(s, sy, sz); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 复位 Boss 朝向(出池 / 回池) */ |
|
|
|
|
private _resetMoveFacing(): void { |
|
|
|
|
this._faceLastX = Number.NaN; |
|
|
|
|
this._faceAccX = 0; |
|
|
|
|
this._faceSign = 1; |
|
|
|
|
if (this.skin?.isValid) { |
|
|
|
|
this.skin.setScale(1, Math.abs(this.skin.scale.y) || 1, this.skin.scale.z || 1); |
|
|
|
|
} |
|
|
|
|
const body = this._bossBodyNode(); |
|
|
|
|
if (!body) return; |
|
|
|
|
body.setScale(1, Math.abs(body.scale.y) || 1, body.scale.z || 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 战斗 TimeScale 变化时同步 Spine 播放倍速 */ |
|
|
|
|
private _syncAnimBattleTimeScale(): void { |
|
|
|
|
if (!this.anim?.isValid || this._isDeathAnimPlaying()) return; |
|
|
|
|
@ -1473,6 +1550,7 @@ export class Monster extends Component { |
|
|
|
|
this.clearAddHpEff(); |
|
|
|
|
this.clearHpCapEff(); |
|
|
|
|
this.clearReviveFx(); |
|
|
|
|
this._resetMoveFacing(); |
|
|
|
|
if (this.anim?.isValid) { |
|
|
|
|
BattleSpinePlayback.clearPendingComplete(this.anim); |
|
|
|
|
BattleSpinePlayback.resetTracks(this.anim); |
|
|
|
|
|