From 6fe91e01049f1d59d5af1927ae1cefae0929ebb3 Mon Sep 17 00:00:00 2001 From: panw Date: Fri, 27 Mar 2026 14:33:00 +0800 Subject: [PATCH] =?UTF-8?q?feat(hero):=20=E6=B7=BB=E5=8A=A0=E8=8B=B1?= =?UTF-8?q?=E9=9B=84=E5=90=88=E5=B9=B6=E6=97=B6=E7=9A=84=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E5=8A=A8=E7=94=BB=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实现英雄合并时的平滑移动动画,避免直接销毁的突兀感。为 Hero 类新增 mergeToBirthAndDestroy 方法,使英雄在销毁前移动到生成点。在 MissionHeroComp 中,合并逻辑改为异步等待动画完成,并添加防重复合并标志。 --- assets/script/game/hero/Hero.ts | 27 ++++++++++++ assets/script/game/map/MissionHeroComp.ts | 52 +++++++++++++++++------ 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/assets/script/game/hero/Hero.ts b/assets/script/game/hero/Hero.ts index 65cb7d85..69152d8b 100644 --- a/assets/script/game/hero/Hero.ts +++ b/assets/script/game/hero/Hero.ts @@ -151,6 +151,33 @@ export class Hero extends ecs.Entity { }) .start(); } + + mergeToBirthAndDestroy(birthPos: Vec3, onDone?: () => void) { + const view = this.get(HeroViewComp); + const node = view?.node; + if (!node || !node.isValid) { + this.destroy(); + if (onDone) onDone(); + return; + } + const collider = node.getComponent(BoxCollider2D); + if (collider) { + collider.enabled = false; + collider.apply(); + } + const currentPos = node.getPosition(); + const targetPos = v3(birthPos.x, birthPos.y, 0); + const moveDistance = Vec3.distance(currentPos, targetPos); + const moveDuration = Math.max(0.12, Math.min(0.3, moveDistance / 1200)); + Tween.stopAllByTarget(node); + tween(node) + .to(moveDuration, { position: targetPos }) + .call(() => { + this.destroy(); + if (onDone) onDone(); + }) + .start(); + } /** 重置入口:复用 destroy 的释放流程 */ reset() { diff --git a/assets/script/game/map/MissionHeroComp.ts b/assets/script/game/map/MissionHeroComp.ts index c3e215a9..28fc460c 100644 --- a/assets/script/game/map/MissionHeroComp.ts +++ b/assets/script/game/map/MissionHeroComp.ts @@ -20,6 +20,7 @@ export class MissionHeroCompComp extends CCComp { Friend_is_dead:boolean=false current_hero_uuid:number=0 current_hero_num:number=-1 + is_merging:boolean=false heros:any=[] onLoad(){ this.on(GameEvent.FightReady,this.fight_ready,this) @@ -55,24 +56,31 @@ export class MissionHeroCompComp extends CCComp { } - private call_hero(event: string, args: any){ + private async call_hero(event: string, args: any){ const uuid = Number(args?.uuid ?? 1001); const hero_lv = Math.max(1, Number(args?.hero_lv ?? 1)); const aliveHeroes = this.getAliveHeroes(); const mergeHeroes = this.pickMergeHeroes(aliveHeroes, uuid, hero_lv); if (mergeHeroes.length === 2) { - let sumAp = 0; - let sumHpMax = 0; - for (let i = 0; i < mergeHeroes.length; i++) { - const model = mergeHeroes[i].get(HeroAttrsComp); - if (!model) continue; - sumAp += model.ap; - sumHpMax += model.hp_max; + if (this.is_merging) return; + this.is_merging = true; + try { + let sumAp = 0; + let sumHpMax = 0; + for (let i = 0; i < mergeHeroes.length; i++) { + const model = mergeHeroes[i].get(HeroAttrsComp); + if (!model) continue; + sumAp += model.ap; + sumHpMax += model.hp_max; + } + let hero_pos = 0; + const landingPos:Vec3 = HeroPos[hero_pos].pos; + const spawnPos:Vec3 = v3(landingPos.x, landingPos.y + MissionHeroCompComp.HERO_DROP_HEIGHT, 0); + await this.mergeDestroyAtBirth(mergeHeroes, spawnPos); + this.addMergedHero(uuid, hero_lv + 1, sumAp, sumHpMax); + } finally { + this.is_merging = false; } - for (let i = 0; i < mergeHeroes.length; i++) { - mergeHeroes[i].destroy(); - } - this.addMergedHero(uuid, hero_lv + 1, sumAp, sumHpMax); return; } this.addHero(uuid, hero_lv); @@ -124,6 +132,26 @@ export class MissionHeroCompComp extends CCComp { return mergeHeroes; } + private mergeDestroyAtBirth(mergeHeroes: Hero[], spawnPos: Vec3): Promise { + return new Promise((resolve) => { + let doneCount = 0; + const total = mergeHeroes.length; + if (total <= 0) { + resolve(); + return; + } + const onDone = () => { + doneCount += 1; + if (doneCount >= total) { + resolve(); + } + }; + for (let i = 0; i < mergeHeroes.length; i++) { + mergeHeroes[i].mergeToBirthAndDestroy(spawnPos, onDone); + } + }); + } +