feat: 重构英雄编队逻辑,优化出生与排队规则
1. 移除英雄出生落点偏移,改为按职业优先级从右向左排队 2. 重构英雄卡点击逻辑,支持点击整张卡牌选取 3. 新增英雄血量背景预制体与UI按钮样式 4. 优化AOE技能目标选取逻辑,使用中排基准点
This commit is contained in:
@@ -17,10 +17,11 @@
|
||||
* revive 系技能为"濒死回血"(血量归零时消耗次数回血续命),不触发真死。
|
||||
*
|
||||
* 出生点规则:
|
||||
* 按攻击类型(HType)分三排:近战 → 前排(x=-200,最靠右迎敌),
|
||||
* 按攻击类型(HType)落排:近战 → 前排(x=-200,最靠右迎敌),
|
||||
* 中距 → 中排(x=-260),远程 → 后排(x=-320,最靠左)。
|
||||
* 同一类型重复召唤时,从该类型基准点向两侧 ±SLOT_OFFSET 依次交替展开,避免落点重叠。
|
||||
* posIndex 取 heroGrid 全局空闲下标(0~9)用于网格登记/索敌,落点偏移与 posIndex、职业均解耦。
|
||||
* 同类型落点不再做 ± 偏移展开,落点重叠由 MoveSystem 的编队排队解决
|
||||
* (准备阶段按职业优先级 坦克→战士→刺客→射手→法师→辅助 从最右向左排开)。
|
||||
* posIndex 取 heroGrid 全局空闲下标(0~9)用于网格登记/索敌,与落点解耦。
|
||||
*
|
||||
* 依赖:
|
||||
* - Hero(hero/Hero.ts)—— 英雄 ECS 实体类
|
||||
@@ -39,7 +40,7 @@ import { HeroInfo, HType } from "../common/config/heroSet";
|
||||
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { FacSet, BoxSet } from "../common/config/GameSet";
|
||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||
import { MoveComp } from "../hero/MoveComp";
|
||||
const { ccclass } = _decorator;
|
||||
|
||||
/**
|
||||
@@ -63,19 +64,9 @@ export class MissionHeroComp extends CCComp {
|
||||
public static readonly HERO_ROW_MID = v3(-260, BoxSet.GAME_LINE, 0)
|
||||
public static readonly HERO_ROW_BACK = v3(-320, BoxSet.GAME_LINE, 0)
|
||||
|
||||
/**
|
||||
* 英雄登场占位点(兼容旧引用,等价于后/中/前三排基准点):
|
||||
* - index 0=后排、1=中排、2=前排。
|
||||
*/
|
||||
public static readonly HERO_POSITIONS: Vec3[] = [
|
||||
MissionHeroComp.HERO_ROW_BACK,
|
||||
MissionHeroComp.HERO_ROW_MID,
|
||||
MissionHeroComp.HERO_ROW_FRONT,
|
||||
];
|
||||
|
||||
/**
|
||||
* 攻击类型 → 出生排映射:
|
||||
* 近战 → 前排,中距 → 中排,远程 → 后排。
|
||||
* 近战 → 前排,中距 → 中排(优先中间位),远程 → 后排。
|
||||
*/
|
||||
private static readonly TYPE_ROW: Record<HType, Vec3> = {
|
||||
[HType.Melee]: MissionHeroComp.HERO_ROW_FRONT,
|
||||
@@ -83,9 +74,6 @@ export class MissionHeroComp extends CCComp {
|
||||
[HType.Long]: MissionHeroComp.HERO_ROW_BACK,
|
||||
};
|
||||
|
||||
/** 同类型重复召唤时的落点横向间隔(像素) */
|
||||
private static readonly SLOT_OFFSET = 30
|
||||
|
||||
/** 英雄出生时的掉落高度(从空中落到地面的像素差) */
|
||||
private static readonly HERO_DROP_HEIGHT = 260
|
||||
|
||||
@@ -103,6 +91,8 @@ export class MissionHeroComp extends CCComp {
|
||||
is_processing_queue: boolean = false
|
||||
/** 召唤请求队列:保证召唤按顺序串行执行 */
|
||||
summon_queue: { uuid: number; hero_lv: number; card_lv: number }[] = []
|
||||
/** 英雄出生序计数器(编队排队/渲染排序的稳定决胜) */
|
||||
private heroSpawnOrder = 0
|
||||
/** 预留英雄列表 */
|
||||
heros: any = []
|
||||
|
||||
@@ -188,42 +178,26 @@ export class MissionHeroComp extends CCComp {
|
||||
|
||||
/**
|
||||
* 为英雄分配出生槽位:
|
||||
* 按攻击类型取三排基准点(近战前排、中距中排、远程后排),
|
||||
* 同类型第 1 个落基准点,之后按 ±SLOT_OFFSET 交替展开(0, +30, -30, +60, -60 …)。
|
||||
* 按攻击类型取三排基准点(近战前排、中距优先中排、远程后排),同类型不再做横向偏移展开;
|
||||
* 落点重叠由 MoveSystem 的编队排队(按职业优先级从最右向左排开)负责分开。
|
||||
*
|
||||
* 槽位编码:posIndex 直接取 heroGrid 的全局空闲下标(0~9),与落点无映射。
|
||||
* 落点偏移由「同攻击类型已占位英雄的 x 偏移」推展开序计算,与 posIndex、职业均解耦。
|
||||
*
|
||||
* @param type 英雄攻击类型(HType,决定所属排)
|
||||
* @param heroes 当前存活英雄列表(spawnHeroAt 在实体创建前快照,避免复用池残留实体干扰槽位判定)
|
||||
* @param heroes 当前存活英雄列表(spawnHeroAt 在实体创建前快照,避免复用池残留实体干扰网格判定)
|
||||
* @returns { posIndex heroGrid 空闲下标(-1 表示满员未登记), landingPos 落地点 }
|
||||
*/
|
||||
private pickSpawnSlotForHero(type: HType, heroes: Hero[]): { posIndex: number; landingPos: Vec3 } {
|
||||
const basePos = MissionHeroComp.TYPE_ROW[type] ?? MissionHeroComp.HERO_ROW_MID;
|
||||
|
||||
// 同攻击类型已占位的 x 偏移集合(依据落点 x 反推,与 posIndex 解耦)
|
||||
const usedOffsets = new Set<number>();
|
||||
// 已登记的网格下标集合(仅用于 posIndex 分配)
|
||||
const occupiedGrid = new Set<number>();
|
||||
for (const h of heroes) {
|
||||
const m = h.get(HeroAttrsComp)!;
|
||||
if (m.posIndex >= 0) occupiedGrid.add(m.posIndex);
|
||||
if (m.type !== type) continue;
|
||||
const view = h.get(HeroViewComp);
|
||||
if (view?.node?.isValid) {
|
||||
usedOffsets.add(Math.round(view.node.position.x - basePos.x));
|
||||
}
|
||||
}
|
||||
|
||||
// 展开序 n:0=居中,1=+30,2=-30,3=+60 …,找到第一个未被同类型占用的偏移
|
||||
// 上限取 heroGrid 容量,同类型超过该数量时复用基准点(不再向外展开)
|
||||
let offsetX = 0;
|
||||
for (let n = 0; n < smc.mission.heroGrid.length; n++) {
|
||||
const step = Math.ceil(n / 2);
|
||||
const dir = n % 2 === 1 ? 1 : -1;
|
||||
const candidate = n === 0 ? 0 : dir * step * MissionHeroComp.SLOT_OFFSET;
|
||||
if (!usedOffsets.has(candidate)) { offsetX = candidate; break; }
|
||||
}
|
||||
const landingPos = v3(basePos.x + offsetX, basePos.y, 0);
|
||||
const landingPos = v3(basePos.x, basePos.y, 0);
|
||||
|
||||
// posIndex 取 heroGrid 全局空闲下标,仅用于网格登记/索敌,与落点无映射
|
||||
let posIndex = -1;
|
||||
@@ -235,8 +209,9 @@ export class MissionHeroComp extends CCComp {
|
||||
|
||||
/**
|
||||
* 生成一个英雄:
|
||||
* - 按攻击类型自动分配三排槽位并展开落点。
|
||||
* - 按攻击类型落排基准点(近战前排 / 中距中排 / 远程后排),不做横向偏移。
|
||||
* - 计算出生点(空中)和落点(地面),播放掉落动画。
|
||||
* - 落地后由 MoveSystem 按职业优先级从最右向左排队分开。
|
||||
*
|
||||
* @param uuid 英雄 UUID
|
||||
* @param hero_lv 英雄等级
|
||||
@@ -259,6 +234,12 @@ export class MissionHeroComp extends CCComp {
|
||||
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);
|
||||
|
||||
// 登记出生序,供编队排队/渲染排序做稳定决胜
|
||||
const move = hero.get(MoveComp);
|
||||
if (move) {
|
||||
move.spawnOrder = ++this.heroSpawnOrder;
|
||||
}
|
||||
|
||||
// 召唤完成后,派发事件以更新英雄面板
|
||||
const model = hero.get(HeroAttrsComp);
|
||||
if (model) {
|
||||
|
||||
Reference in New Issue
Block a user