From 2498eb598c860d49dad52c0ffb2f63ed0433a54f Mon Sep 17 00:00:00 2001 From: pan Date: Tue, 18 Aug 2026 09:51:19 +0800 Subject: [PATCH] =?UTF-8?q?refactor(mission):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E8=8B=B1=E9=9B=84=E4=BA=8C=E5=90=88=E4=B8=80=E5=90=88=E6=88=90?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E6=94=B9=E4=B8=BA=E5=85=81=E8=AE=B8?= =?UTF-8?q?=E5=90=8C=E8=8B=B1=E9=9B=84=E5=90=8C=E5=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 删除Hero类中的mergeToBirthAndDestroy方法 2. 移除MissionHeroComp中的合成相关校验与处理逻辑 3. 简化英雄召唤流程,不再限制同uuid英雄重复召唤 4. 更新注释文档,调整相关导入依赖 --- assets/script/game/hero/Hero.ts | 30 ----- assets/script/game/map/MissionHeroComp.ts | 148 +++------------------- 2 files changed, 16 insertions(+), 162 deletions(-) diff --git a/assets/script/game/hero/Hero.ts b/assets/script/game/hero/Hero.ts index 74c44b10..491f4738 100644 --- a/assets/script/game/hero/Hero.ts +++ b/assets/script/game/hero/Hero.ts @@ -268,36 +268,6 @@ 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; - } - const body = node.getComponent(RigidBody2D); - if (body) { - body.enabled = false; - } - 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() { super.destroy(); diff --git a/assets/script/game/map/MissionHeroComp.ts b/assets/script/game/map/MissionHeroComp.ts index 159ea800..b06937d6 100644 --- a/assets/script/game/map/MissionHeroComp.ts +++ b/assets/script/game/map/MissionHeroComp.ts @@ -8,12 +8,8 @@ * * 关键设计: * - summon_queue + processSummonQueue() 确保召唤请求 **串行处理**。 - * - handleSingleSummon() 负责生成英雄;同 uuid 重复召唤走二合一合成升级。 - * - * 合成规则: - * 场上存在同 uuid 英雄时再次召唤触发二合一: - * 旧英雄移动合并销毁,新英雄以 **两者最高等级 + 1** 落地(封顶 HERO_MAX_LV), - * 等级已达上限时拒绝召唤。英雄也可通过升级卡(SpecialUpgrade)升级。 + * - spawnHeroAt 负责生成英雄;允许同 uuid 重复召唤,多个相同英雄可同时站场。 + * - 英雄可通过升级卡(SpecialUpgrade)升级。 * * 死亡机制: * 英雄为真实死亡(HeroAtkSystem.doDead → 快照至 smc.mission.dead_heroes → 实体销毁), @@ -29,10 +25,10 @@ * 依赖: * - Hero(hero/Hero.ts)—— 英雄 ECS 实体类 * - HeroAttrsComp —— 英雄属性组件 - * - HeroInfo / HeroPos / HType / HRole(heroSet)—— 英雄静态配置 + * - HeroInfo / HType(heroSet)—— 英雄静态配置 * - FightSet —— 战斗常量 */ -import { _decorator, instantiate, Prefab, v3, Vec3, BoxCollider2D } from "cc"; +import { _decorator, v3, Vec3 } from "cc"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; import { Hero } from "../hero/Hero"; @@ -42,10 +38,8 @@ import { GameEvent } from "../common/config/GameEvent"; import { HeroInfo, HType } from "../common/config/heroSet"; import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops"; import { HeroAttrsComp } from "../hero/HeroAttrsComp"; -import { FacSet, FightSet, BoxSet } from "../common/config/GameSet"; +import { FacSet, BoxSet } from "../common/config/GameSet"; import { HeroViewComp } from "../hero/HeroViewComp"; -import { FieldSkillSet, FieldSkillType } from "../common/config/SkillSet"; -import { MoveComp } from "../hero/MoveComp"; const { ccclass } = _decorator; /** @@ -186,45 +180,10 @@ export class MissionHeroComp extends CCComp { const hero_lv = Math.max(outer_lv, Math.max(1, Number(payload?.hero_lv ?? 1))); const card_lv = Math.max(1, Number(payload?.card_lv ?? 1)); - // 二合一前置校验:同 uuid 已存在且合成后等级会超上限时,直接拒绝 - if (this.isHeroAlreadySummoned(uuid)) { - const existing = this.findHeroByUuid(uuid); - const existingLv = existing ? (existing.get(HeroAttrsComp)?.lv ?? 1) : 1; - if (Math.max(existingLv, hero_lv) + 1 > FightSet.HERO_MAX_LV) { - oops.gui.toast(`该英雄已达等级上限,无法继续合成`); - return; - } - } - this.summon_queue.push({ uuid, hero_lv, card_lv }); this.processSummonQueue(); } - /** - * 检查场上是否已存在指定 uuid 的存活英雄。 - * @param uuid 英雄模板 uuid - * @returns true 表示场上已有该英雄,不可重复召唤 - */ - private isHeroAlreadySummoned(uuid: number): boolean { - return this.findHeroByUuid(uuid) !== null; - } - - /** - * 查找场上指定 uuid 的存活英雄实体。 - * @param uuid 英雄模板 uuid - * @returns 命中的 Hero 实体,未命中返回 null - */ - private findHeroByUuid(uuid: number): Hero | null { - let found: Hero | null = null; - ecs.query(ecs.allOf(HeroAttrsComp)).forEach((entity: ecs.Entity) => { - if (found) return; - const model = entity.get(HeroAttrsComp); - if (!model || model.fac !== FacSet.HERO || model.is_dead) return; - if (model.hero_uuid === uuid) found = entity as Hero; - }); - return found; - } - // ======================== 英雄生成 ======================== /** @@ -275,49 +234,27 @@ export class MissionHeroComp extends CCComp { } /** - * 生成一个英雄 ECS 实体: - * - 计算出生点(空中)和落点(地面)。 - * - 调用 hero.load() 初始化并播放掉落动画。 - * - * @param uuid 英雄 UUID - * @param hero_lv 英雄等级 - * @param card_lv 卡牌等级(驱动 bg_node 颜色) - * @returns 创建的 Hero 实体 - */ - private addHero(uuid: number = 1001, hero_lv: number = 1, card_lv: number = 1) { - return this.spawnHeroAt(uuid, hero_lv, card_lv, -1); - } - - /** - * 在指定站位生成英雄: - * - posIndex < 0 时按职业自动分配空位(三排基准点 ±20 展开)。 + * 生成一个英雄: + * - 按攻击类型自动分配三排槽位并展开落点。 * - 计算出生点(空中)和落点(地面),播放掉落动画。 * * @param uuid 英雄 UUID * @param hero_lv 英雄等级 * @param card_lv 卡牌等级(驱动 bg_node 颜色) - * @param posIndex 指定站位索引,-1 表示自动分配 * @returns 创建的 Hero 实体 */ - private spawnHeroAt(uuid: number, hero_lv: number, card_lv: number, posIndex: number, inheritPos: Vec3 | null = null) { + private spawnHeroAt(uuid: number, hero_lv: number, card_lv: number) { let hero = ecs.getEntity(Hero); let scale = 1 const type = HeroInfo[uuid]?.type ?? HType.Mid; - let finalPosIndex = posIndex; - let landingPos: Vec3; - if (inheritPos) { - // 合成继承:沿用旧英雄节点位置,posIndex 透传登记网格 - landingPos = v3(inheritPos.x, MissionHeroComp.TYPE_ROW[type]?.y ?? BoxSet.GAME_LINE, 0); - } else { - const heroes = this.getAllHeroes().filter(h => { - const m = h.get(HeroAttrsComp); - return !!m && !m.is_dead; - }); - const slot = this.pickSpawnSlotForHero(type, heroes); - finalPosIndex = slot.posIndex; - landingPos = slot.landingPos; - } + const heroes = this.getAllHeroes().filter(h => { + const m = h.get(HeroAttrsComp); + return !!m && !m.is_dead; + }); + const slot = this.pickSpawnSlotForHero(type, heroes); + const finalPosIndex = slot.posIndex; + const landingPos = slot.landingPos; let spawnPos: Vec3 = v3(landingPos.x, landingPos.y + MissionHeroComp.HERO_DROP_HEIGHT, 0); hero.load(spawnPos, scale, uuid, landingPos.y, hero_lv, card_lv, finalPosIndex); @@ -362,66 +299,13 @@ export class MissionHeroComp extends CCComp { while (this.summon_queue.length > 0) { const payload = this.summon_queue.shift(); if (!payload) continue; - await this.handleSingleSummon(payload.uuid, payload.hero_lv, payload.card_lv); + this.spawnHeroAt(payload.uuid, payload.hero_lv, payload.card_lv); } } finally { this.is_processing_queue = false; } } - /** - * 处理单次召唤: - * - 场上无同 uuid 英雄:直接生成新英雄。 - * - 场上已有同 uuid 英雄:触发二合一,旧英雄合并销毁后生成等级 +1 的新英雄。 - * - * @param uuid 英雄 UUID - * @param hero_lv 英雄等级 - * @param card_lv 卡牌等级 - */ - private async handleSingleSummon(uuid: number, hero_lv: number, card_lv: number = 1) { - const existing = this.findHeroByUuid(uuid); - if (!existing) { - this.addHero(uuid, hero_lv, card_lv); - return; - } - - const oldModel = existing.get(HeroAttrsComp); - const oldLv = oldModel?.lv ?? 1; - // 合成后等级 = 两者最高等级 + 1,封顶 HERO_MAX_LV - const mergedLv = Math.min(FightSet.HERO_MAX_LV, Math.max(oldLv, hero_lv) + 1); - // 继承旧英雄站位,避免新英雄重新抢位导致阵型跳动 - const posIndex = oldModel?.posIndex ?? -1; - - await this.mergeHeroAndRespawn(existing, uuid, mergedLv, card_lv, posIndex); - } - - /** - * 二合一合成流程: - * 1. 旧英雄播放移动合并动画并销毁(释放站位与实体)。 - * 2. 在原站位生成 mergedLv 级新英雄并播放入场动画。 - * - * @param oldHero 场上已有的同 uuid 英雄 - * @param uuid 英雄 UUID - * @param mergedLv 合成后的英雄等级 - * @param card_lv 卡牌等级 - * @param posIndex 继承的站位索引(-1 表示重新分配) - */ - private mergeHeroAndRespawn(oldHero: Hero, uuid: number, mergedLv: number, card_lv: number, posIndex: number): Promise { - return new Promise((resolve) => { - // 以旧英雄节点位置作为合并目标点,保证动画收拢到原站位 - const oldView = oldHero.get(HeroViewComp); - const oldPos = oldView?.node?.isValid ? oldView.node.getPosition() : null; - const birthPos = oldPos ?? MissionHeroComp.HERO_ROW_MID; - - oldHero.mergeToBirthAndDestroy(birthPos, () => { - // 旧实体销毁后沿用其站位与 posIndex 生成新英雄,避免阵型跳动 - this.spawnHeroAt(uuid, mergedLv, card_lv, posIndex, oldPos); - resolve(); - }); - }); - } - - /** ECS 组件移除时触发(当前不销毁节点,保留引用) */ reset() { // this.node.destroy();