From f70bf7ba14aa9c1b02abd0d549823482065bf240 Mon Sep 17 00:00:00 2001 From: richarjiang Date: Mon, 20 Oct 2025 15:38:20 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E6=89=93=E6=96=97?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bundle1/anim/player/2/stand/stand5_2.anim | 4 +- .../anim/xiaoguai/4/stand/guai_4_stand.anim | 16 +- .../anim/xiaoguai/6/stand/guai_6_stand.anim | 23 +- assets/scripts/PlayerController.ts | 198 +++++++++++++++--- 4 files changed, 189 insertions(+), 52 deletions(-) diff --git a/assets/bundle1/anim/player/2/stand/stand5_2.anim b/assets/bundle1/anim/player/2/stand/stand5_2.anim index 318240e..93b1c31 100644 --- a/assets/bundle1/anim/player/2/stand/stand5_2.anim +++ b/assets/bundle1/anim/player/2/stand/stand5_2.anim @@ -1,7 +1,7 @@ [ { "__type__": "cc.AnimationClip", - "_name": "stand_2", + "_name": "stand5_2", "_objFlags": 0, "__editorExtras__": { "embeddedPlayerGroups": [] @@ -9,7 +9,7 @@ "_native": "", "sample": 20, "speed": 1, - "wrapMode": 1, + "wrapMode": 2, "enableTrsBlending": false, "_duration": 1.25, "_hash": 500763545, diff --git a/assets/resources/anim/xiaoguai/4/stand/guai_4_stand.anim b/assets/resources/anim/xiaoguai/4/stand/guai_4_stand.anim index 0e90e1e..3e7aa88 100644 --- a/assets/resources/anim/xiaoguai/4/stand/guai_4_stand.anim +++ b/assets/resources/anim/xiaoguai/4/stand/guai_4_stand.anim @@ -7,11 +7,11 @@ "embeddedPlayerGroups": [] }, "_native": "", - "sample": 60, + "sample": 8, "speed": 1, - "wrapMode": 1, + "wrapMode": 2, "enableTrsBlending": false, - "_duration": 0.6, + "_duration": 1, "_hash": 500763545, "_tracks": [ { @@ -62,13 +62,13 @@ "__type__": "cc.ObjectCurve", "_times": [ 0, - 0.08333333333333333, - 0.16666666666666666, + 0.125, 0.25, - 0.3333333333333333, - 0.4166666666666667, + 0.375, 0.5, - 0.5833333333333334 + 0.625, + 0.75, + 0.875 ], "_values": [ { diff --git a/assets/resources/anim/xiaoguai/6/stand/guai_6_stand.anim b/assets/resources/anim/xiaoguai/6/stand/guai_6_stand.anim index f814460..74f6606 100644 --- a/assets/resources/anim/xiaoguai/6/stand/guai_6_stand.anim +++ b/assets/resources/anim/xiaoguai/6/stand/guai_6_stand.anim @@ -7,11 +7,11 @@ "embeddedPlayerGroups": [] }, "_native": "", - "sample": 60, - "speed": 1, + "sample": 20, + "speed": 0.5, "wrapMode": 2, "enableTrsBlending": false, - "_duration": 0.6, + "_duration": 0.4, "_hash": 500763545, "_tracks": [ { @@ -61,20 +61,15 @@ { "__type__": "cc.ObjectCurve", "_times": [ - 0, - 0.08333333333333333, - 0.16666666666666666, + 0.05, + 0.1, + 0.15, + 0.2, 0.25, - 0.3333333333333333, - 0.4166666666666667, - 0.5, - 0.5833333333333334 + 0.3, + 0.35 ], "_values": [ - { - "__uuid__": "78ffae32-3bfe-41cb-823f-3b0bca65732a@f9941", - "__expectedType__": "cc.SpriteFrame" - }, { "__uuid__": "8742c745-dcb8-44d8-a276-62e561e81dab@f9941", "__expectedType__": "cc.SpriteFrame" diff --git a/assets/scripts/PlayerController.ts b/assets/scripts/PlayerController.ts index 519c7bb..826e13a 100644 --- a/assets/scripts/PlayerController.ts +++ b/assets/scripts/PlayerController.ts @@ -982,46 +982,188 @@ export class PlayerController extends Component { return; } + // 检查是否是 guai_10,如果是则使用特殊战斗逻辑 + if (otherCollider.node.name === 'guai_10') { + await this.handleGuai10SpecialAttack(selfCollider, otherCollider, playerLabel, monsterLabel, playerHp, monsterHp, playerAnimation); + } else { + // 原有的普通战斗逻辑 + await this.handleNormalAttack(otherCollider, playerLabel, monsterLabel, playerHp, monsterHp, playerAnimation); + } + + this.isAttacking = false; + + // 停止攻击音效 + if (this.attackAudio) { + const audioSource = this.attackAudio.getComponent(AudioSource); + if (audioSource) { + audioSource.stop(); + console.log('停止攻击音效'); + } + } + + return true; + } + + /** + * 处理普通怪物的攻击逻辑 + */ + private async handleNormalAttack(otherCollider: Collider2D, playerLabel: Label, monsterLabel: Label, playerHp: number, monsterHp: number, playerAnimation: Animation) { // 播放玩家攻击动画(只传递基础动画名称) this.switchAnimation('attack'); // 监听玩家攻击动画结束事件 - playerAnimation.once(Animation.EventType.FINISHED, async () => { - if (!this.player || !playerLabel.isValid || !monsterLabel.isValid) { - this.isAttacking = false; - if (this.attackAudio) { - const audioSource = this.attackAudio.getComponent(AudioSource); - if (audioSource) { - audioSource.stop(); - } + return new Promise((resolve) => { + playerAnimation.once(Animation.EventType.FINISHED, async () => { + if (!this.player || !playerLabel.isValid || !monsterLabel.isValid) { + resolve(); + return; } + + // 比较生命值,判断输赢 + console.log('判定攻击结果,玩家HP:', playerHp, '怪物HP:', monsterHp); + + if (playerHp >= monsterHp) { + // 玩家获胜,直接执行后续流程,不需要播放怪物攻击动画 + await this.handlePlayerWin(otherCollider, playerLabel, monsterHp); + } else { + // 玩家输了,需要播放怪物攻击动画 + await this.handleMonsterAttack(otherCollider, playerLabel, monsterHp); + } + + resolve(); + }); + }); + } + + /** + * 处理 guai_10 的特殊攻击逻辑:玩家攻击 → 怪物还击 → 玩家再攻击 → 最终判定 + */ + private async handleGuai10SpecialAttack(selfCollider: Collider2D, otherCollider: Collider2D, playerLabel: Label, monsterLabel: Label, playerHp: number, monsterHp: number, playerAnimation: Animation) { + console.log('开始 guai_10 特殊战斗逻辑'); + + // 第一轮:玩家攻击 + console.log('第一轮:玩家攻击'); + this.switchAnimation('attack'); + + // 等待玩家攻击动画结束 + await new Promise((resolve) => { + playerAnimation.once(Animation.EventType.FINISHED, () => { + console.log('玩家第一轮攻击完成'); + resolve(); + }); + }); + + // 检查节点是否仍然有效 + if (!this.player || !otherCollider.node || !otherCollider.node.isValid || !playerLabel.isValid || !monsterLabel.isValid) { + return; + } + + // 第二轮:怪物还击 + console.log('第二轮:怪物还击'); + await this.playMonsterAttackAnimation(otherCollider); + + // 检查节点是否仍然有效 + if (!this.player || !otherCollider.node || !otherCollider.node.isValid || !playerLabel.isValid || !monsterLabel.isValid) { + return; + } + + // 确保玩家在怪物攻击后回到站立状态,然后再进行第三轮攻击 + this.switchAnimation('stand'); + + // 添加短暂延迟,让玩家站立动画播放一下 + await new Promise((resolve) => { + this.scheduleOnce(() => { + resolve(); + }, 0.2); + }); + + // 第三轮:玩家再次攻击 + console.log('第三轮:玩家再次攻击'); + this.switchAnimation('attack'); + + // 等待玩家攻击动画结束 + await new Promise((resolve) => { + playerAnimation.once(Animation.EventType.FINISHED, () => { + console.log('玩家第三轮攻击完成'); + resolve(); + }); + }); + + // 检查节点是否仍然有效 + if (!this.player || !otherCollider.node || !otherCollider.node.isValid || !playerLabel.isValid || !monsterLabel.isValid) { + return; + } + + // 最终判定:比较生命值 + console.log('最终判定,玩家HP:', playerHp, '怪物HP:', monsterHp); + + if (playerHp >= monsterHp) { + // 玩家获胜 + await this.handlePlayerWin(otherCollider, playerLabel, monsterHp); + } else { + // 玩家失败 + this.executePlayerDefeat(otherCollider, playerLabel); + } + } + + /** + * 播放怪物攻击动画 + */ + private async playMonsterAttackAnimation(otherCollider: Collider2D): Promise { + const animNode = otherCollider.node.getChildByName('Anim'); + const monsterAnimation = animNode ? animNode.getComponent(Animation) : null; + + if (monsterAnimation) { + console.log(`尝试播放怪物攻击动画: ${otherCollider.node.name}_attack`); + + // 检查动画是否存在 + const attackAnimState = monsterAnimation.getState(`${otherCollider.node.name}_attack`); + if (!attackAnimState) { + console.warn(`怪物攻击动画 ${otherCollider.node.name}_attack 不存在,跳过怪物攻击动画`); return; } - // 比较生命值,判断输赢 - console.log('判定攻击结果,玩家HP:', playerHp, '怪物HP:', monsterHp); + return new Promise((resolve) => { + // 添加超时机制,防止动画卡住 + const timeout = setTimeout(() => { + console.log('怪物攻击动画超时,强制继续'); + // 确保怪物切换回站立状态 + this.switchMonsterToStand(otherCollider.node.name, monsterAnimation); + resolve(); + }, 3000); // 3秒超时 - if (playerHp >= monsterHp) { - // 玩家获胜,直接执行后续流程,不需要播放怪物攻击动画 - await this.handlePlayerWin(otherCollider, playerLabel, monsterHp); - } else { - // 玩家输了,需要播放怪物攻击动画 - await this.handleMonsterAttack(otherCollider, playerLabel, monsterHp); - } + monsterAnimation.play(`${otherCollider.node.name}_attack`); + console.log('开始播放怪物攻击动画'); - this.isAttacking = false; + // 监听怪物攻击动画结束 + monsterAnimation.once(Animation.EventType.FINISHED, () => { + clearTimeout(timeout); + console.log('怪物攻击动画完成,切换回站立状态'); + // 怪物攻击完成后切换回站立动画 + this.switchMonsterToStand(otherCollider.node.name, monsterAnimation); + resolve(); + }); + }); + } else { + console.warn('未找到怪物动画组件,跳过怪物攻击动画'); + // 如果没有怪物动画组件,直接返回 + return; + } + } - // 停止攻击音效 - if (this.attackAudio) { - const audioSource = this.attackAudio.getComponent(AudioSource); - if (audioSource) { - audioSource.stop(); - console.log('停止攻击音效'); - } - } - }); + /** + * 将怪物切换到站立动画 + */ + private switchMonsterToStand(monsterName: string, monsterAnimation: Animation) { + const standAnimName = `${monsterName}_stand`; + const standAnimState = monsterAnimation.getState(standAnimName); - return true; + if (standAnimState) { + monsterAnimation.play(standAnimName); + console.log(`怪物切换到站立动画: ${standAnimName}`); + } else { + console.warn(`怪物站立动画 ${standAnimName} 不存在`); + } } /**