|
|
@@ -104,6 +104,12 @@ export class EnemyInstance extends Component {
|
|
|
// 暂停状态标记
|
|
|
private isPaused: boolean = false;
|
|
|
|
|
|
+ // 当前播放的动画名称,用于避免重复播放
|
|
|
+ private currentAnimationName: string = '';
|
|
|
+
|
|
|
+ // 攻击状态下的动画管理
|
|
|
+ private isPlayingAttackAnimation: boolean = false;
|
|
|
+
|
|
|
|
|
|
start() {
|
|
|
// 初始化敌人
|
|
|
@@ -861,20 +867,14 @@ export class EnemyInstance extends Component {
|
|
|
const enemyComponent = this.getComponent(EnemyComponent);
|
|
|
const attackRange = enemyComponent ? enemyComponent.getAttackRange() : 30;
|
|
|
|
|
|
- if (attackRange <= 0) {
|
|
|
- // 近战攻击:在攻击状态下停止移动
|
|
|
- const enemySprite = this.node.getChildByName('EnemySprite');
|
|
|
- if (enemySprite) {
|
|
|
- const rigidBody = enemySprite.getComponent(RigidBody2D);
|
|
|
- if (rigidBody) {
|
|
|
- // 停止物理移动
|
|
|
- rigidBody.linearVelocity = new Vec2(0, 0);
|
|
|
- }
|
|
|
+ // 无论近战还是远程攻击,在攻击状态下都停止移动
|
|
|
+ const enemySprite = this.node.getChildByName('EnemySprite');
|
|
|
+ if (enemySprite) {
|
|
|
+ const rigidBody = enemySprite.getComponent(RigidBody2D);
|
|
|
+ if (rigidBody) {
|
|
|
+ // 停止物理移动
|
|
|
+ rigidBody.linearVelocity = new Vec2(0, 0);
|
|
|
}
|
|
|
- } else {
|
|
|
- // 远程攻击:继续移动,但不需要在这里播放行走动画
|
|
|
- // 攻击动画会在performRangedAttack中播放,完成后会根据状态切换回行走动画
|
|
|
- this.updateMovement(deltaTime);
|
|
|
}
|
|
|
|
|
|
this.attackTimer -= deltaTime;
|
|
|
@@ -885,6 +885,11 @@ export class EnemyInstance extends Component {
|
|
|
|
|
|
// 重置攻击计时器
|
|
|
this.attackTimer = this.attackInterval;
|
|
|
+ } else {
|
|
|
+ // 攻击冷却期间播放待机动画(只有在不播放攻击动画时)
|
|
|
+ if (!this.isPlayingAttackAnimation) {
|
|
|
+ this.playIdleAnimationSafe();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -959,6 +964,9 @@ export class EnemyInstance extends Component {
|
|
|
if (animation) {
|
|
|
// 播放攻击动画(不循环)
|
|
|
this.skeleton.setAnimation(0, attackName, false);
|
|
|
+ this.currentAnimationName = attackName;
|
|
|
+ this.isPlayingAttackAnimation = true;
|
|
|
+ console.log(`[EnemyInstance] 播放远程攻击动画: ${attackName}`);
|
|
|
|
|
|
// 动画切换后延迟更新血条位置,确保动画尺寸已生效
|
|
|
this.scheduleOnce(() => {
|
|
|
@@ -977,11 +985,12 @@ export class EnemyInstance extends Component {
|
|
|
|
|
|
// 动画完成后根据当前状态切换动画
|
|
|
this.scheduleOnce(() => {
|
|
|
- if (this.state === EnemyState.IDLE) {
|
|
|
- // 如果是待机状态,切换回待机动画
|
|
|
+ this.isPlayingAttackAnimation = false;
|
|
|
+ if (this.state === EnemyState.IDLE || this.state === EnemyState.ATTACKING) {
|
|
|
+ // 如果是待机状态或攻击状态,切换回待机动画
|
|
|
this.playIdleAnimation();
|
|
|
- } else if (this.state === EnemyState.ATTACKING) {
|
|
|
- // 如果还在攻击状态(移动中攻击),切换回行走动画
|
|
|
+ } else {
|
|
|
+ // 其他状态切换回行走动画
|
|
|
this.playWalkAnimation();
|
|
|
}
|
|
|
}, animationDuration);
|
|
|
@@ -1053,11 +1062,18 @@ export class EnemyInstance extends Component {
|
|
|
const walkName = anims.walk ?? 'walk';
|
|
|
const idleName = anims.idle ?? 'idle';
|
|
|
|
|
|
+ let animationToPlay = '';
|
|
|
if (this.skeleton.findAnimation(walkName)) {
|
|
|
- this.skeleton.setAnimation(0, walkName, true);
|
|
|
- // 行走音效已移除
|
|
|
+ animationToPlay = walkName;
|
|
|
} else if (this.skeleton.findAnimation(idleName)) {
|
|
|
- this.skeleton.setAnimation(0, idleName, true);
|
|
|
+ animationToPlay = idleName;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (animationToPlay && this.currentAnimationName !== animationToPlay) {
|
|
|
+ this.skeleton.setAnimation(0, animationToPlay, true);
|
|
|
+ this.currentAnimationName = animationToPlay;
|
|
|
+ this.isPlayingAttackAnimation = false;
|
|
|
+ console.log(`[EnemyInstance] 播放行走动画: ${animationToPlay}`);
|
|
|
}
|
|
|
|
|
|
// 动画切换后延迟更新血条位置,确保动画尺寸已生效
|
|
|
@@ -1073,10 +1089,11 @@ export class EnemyInstance extends Component {
|
|
|
const anims2 = enemyComp2?.getAnimations ? enemyComp2.getAnimations() : {};
|
|
|
const attackName = anims2.attack ?? 'attack';
|
|
|
|
|
|
- // 移除频繁打印
|
|
|
-
|
|
|
- if (this.skeleton.findAnimation(attackName)) {
|
|
|
+ if (this.skeleton.findAnimation(attackName) && this.currentAnimationName !== attackName) {
|
|
|
this.skeleton.setAnimation(0, attackName, true);
|
|
|
+ this.currentAnimationName = attackName;
|
|
|
+ this.isPlayingAttackAnimation = true;
|
|
|
+ console.log(`[EnemyInstance] 播放攻击动画: ${attackName}`);
|
|
|
}
|
|
|
|
|
|
// 动画切换后延迟更新血条位置,确保动画尺寸已生效
|
|
|
@@ -1092,8 +1109,11 @@ export class EnemyInstance extends Component {
|
|
|
const anims = enemyComp?.getAnimations ? enemyComp.getAnimations() : {};
|
|
|
const idleName = anims.idle ?? 'idle';
|
|
|
|
|
|
- if (this.skeleton.findAnimation(idleName)) {
|
|
|
+ if (this.skeleton.findAnimation(idleName) && this.currentAnimationName !== idleName) {
|
|
|
this.skeleton.setAnimation(0, idleName, true);
|
|
|
+ this.currentAnimationName = idleName;
|
|
|
+ this.isPlayingAttackAnimation = false;
|
|
|
+ console.log(`[EnemyInstance] 播放待机动画: ${idleName}`);
|
|
|
}
|
|
|
|
|
|
// 动画切换后延迟更新血条位置,确保动画尺寸已生效
|
|
|
@@ -1102,6 +1122,26 @@ export class EnemyInstance extends Component {
|
|
|
}, 0.1);
|
|
|
}
|
|
|
|
|
|
+ // 安全播放待机动画(避免重复调用)
|
|
|
+ private playIdleAnimationSafe() {
|
|
|
+ if (!this.skeleton) return;
|
|
|
+ const enemyComp = this.getComponent('EnemyComponent') as any;
|
|
|
+ const anims = enemyComp?.getAnimations ? enemyComp.getAnimations() : {};
|
|
|
+ const idleName = anims.idle ?? 'idle';
|
|
|
+
|
|
|
+ // 只有当前不是待机动画时才播放
|
|
|
+ if (this.skeleton.findAnimation(idleName) && this.currentAnimationName !== idleName && !this.isPlayingAttackAnimation) {
|
|
|
+ this.skeleton.setAnimation(0, idleName, true);
|
|
|
+ this.currentAnimationName = idleName;
|
|
|
+ console.log(`[EnemyInstance] 安全播放待机动画: ${idleName}`);
|
|
|
+
|
|
|
+ // 动画切换后延迟更新血条位置,确保动画尺寸已生效
|
|
|
+ this.scheduleOnce(() => {
|
|
|
+ this.updateHPBarPosition();
|
|
|
+ }, 0.1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 播放攻击动画并在动画结束时造成伤害
|
|
|
private playAttackAnimationWithDamage() {
|
|
|
if (!this.skeleton) {
|
|
|
@@ -1118,6 +1158,9 @@ export class EnemyInstance extends Component {
|
|
|
if (animation) {
|
|
|
// 播放攻击动画(不循环)
|
|
|
this.skeleton.setAnimation(0, attackName, false);
|
|
|
+ this.currentAnimationName = attackName;
|
|
|
+ this.isPlayingAttackAnimation = true;
|
|
|
+ console.log(`[EnemyInstance] 播放近战攻击动画: ${attackName}`);
|
|
|
|
|
|
// 动画切换后延迟更新血条位置,确保动画尺寸已生效
|
|
|
this.scheduleOnce(() => {
|
|
|
@@ -1131,9 +1174,10 @@ export class EnemyInstance extends Component {
|
|
|
// 使用定时器在动画结束时造成伤害
|
|
|
this.scheduleOnce(() => {
|
|
|
this.dealDamageToWall();
|
|
|
+ this.isPlayingAttackAnimation = false;
|
|
|
// 动画完成后根据当前状态切换动画
|
|
|
- if (this.state === EnemyState.IDLE) {
|
|
|
- // 如果是待机状态,切换回待机动画
|
|
|
+ if (this.state === EnemyState.IDLE || this.state === EnemyState.ATTACKING) {
|
|
|
+ // 如果是待机状态或攻击状态,切换回待机动画
|
|
|
this.playIdleAnimation();
|
|
|
} else {
|
|
|
// 其他状态切换回行走动画
|