From 4594f673b468a6fe1845cff8527b1d517f499732 Mon Sep 17 00:00:00 2001 From: pan Date: Wed, 12 Aug 2026 11:04:59 +0800 Subject: [PATCH] =?UTF-8?q?feat(hero):=20=E6=96=B0=E5=A2=9E=E8=8B=B1?= =?UTF-8?q?=E9=9B=84=E8=81=8C=E4=B8=9A=E5=AE=9A=E4=BD=8D=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E7=BC=96=E9=98=9F=E7=AB=99=E4=BD=8D?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增HRole枚举与角色定位配置,解耦成长类型与阵容职能 2. 重构移动系统的编队优先级计算,基于职业定位重新排序站位 3. 重写单行编队站位算法,根据队伍人数自动适配紧凑/松散排布 4. 为所有预设英雄配置对应职业定位 --- assets/script/game/common/config/heroSet.ts | 76 ++++++---- assets/script/game/hero/Hero.ts | 1 + assets/script/game/hero/HeroAttrsComp.ts | 5 +- assets/script/game/hero/MoveComp.ts | 150 +++++++++++--------- 4 files changed, 141 insertions(+), 91 deletions(-) diff --git a/assets/script/game/common/config/heroSet.ts b/assets/script/game/common/config/heroSet.ts index 0e29cabe..c8ca8231 100644 --- a/assets/script/game/common/config/heroSet.ts +++ b/assets/script/game/common/config/heroSet.ts @@ -128,6 +128,29 @@ export const HERO_GROW_COEF: Record = { [HGrowType.Support]: { hp: 1.1, ap: 0.7 }, }; +/** + * 英雄位置类型(职业定位)。 + * Why: grow_type 仅驱动数值成长曲线,无法表达"这个英雄在阵容里干什么"; + * role 面向 UI 展示与阵容推荐(如 HeroComboSet 的铁三角校验),与成长解耦。 + */ +export enum HRole { + Tank = 0, // 坦克:前排承伤,受击发动机 + Warrior = 1, // 战士:前排输出/献祭位 + Assassin = 2, // 刺客:近战爆发主C + Archer = 3, // 射手:远程物理主C + Mage = 4, // 法师:远程先手增益 + Support = 5, // 辅助:光环/治疗 +} + +export const HRoleName: Record = { + [HRole.Tank]: "坦克", + [HRole.Warrior]: "战士", + [HRole.Assassin]: "刺客", + [HRole.Archer]: "射手", + [HRole.Mage]: "法师", + [HRole.Support]: "辅助", +}; + /** * 计算英雄在目标等级下的累计属性成长增量(线性:每级加一份"基础属性×系数")。 * 公式:累计 = 基础属性 × 类型系数 × (lv - 1)。 @@ -282,6 +305,7 @@ export interface heroInfo { card_lv?: number; // 卡牌等级(驱动 bg_node 颜色:1=green 2=blue 3=purple 4=red 5=yellow) type: HType; // 攻击定位(近战/中程/远程) grow_type?: HGrowType; // 成长类型(决定每级 hp/ap 标准增量,默认 Warrior) + role?: HRole; // 位置类型/职业定位(英雄专用,怪物用 monType 表达) monType?: MonType; // 怪物专属类型 hp: number; // 生命值上限 ap: number; // 攻击力 @@ -378,7 +402,7 @@ export const HeroInfo: Record = { // 5001 铁壁战士 — atked 护盾(标杆,原5011) 5001: { - uuid: 5001, name: "铁壁战士", path: "hk1", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, hp: 300, ap: 28, + uuid: 5001, name: "铁壁战士", path: "hk1", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: 300, ap: 28, skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow3].cd, ccd: 0 } }, atked: { 6301: [ @@ -391,7 +415,7 @@ export const HeroInfo: Record = { }, // 5002 影袭刺客 — atking 自身攻击 5002: { - uuid: 5002, name: "影袭刺客", path: "hc1", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Assassin, hp: 300, ap: 28, + uuid: 5002, name: "影袭刺客", path: "hc1", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Assassin, role: HRole.Assassin, hp: 300, ap: 28, skills: { 6003: { uuid: 6003, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast2].cd, ccd: 0 } }, atking: { 6401: [ @@ -404,7 +428,7 @@ export const HeroInfo: Record = { }, // 5003 遗志将军 — dead 全队攻击 5003: { - uuid: 5003, name: "遗志将军", path: "hk2", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, hp: 300, ap: 28, + uuid: 5003, name: "遗志将军", path: "hk2", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: 300, ap: 28, skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow3].cd, ccd: 0 } }, dead: { 6401: [ @@ -417,7 +441,7 @@ export const HeroInfo: Record = { }, // 5004 破晓先知 — fstart 全队攻击 5004: { - uuid: 5004, name: "破晓先知", path: "hm1", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 143, ap: 40, + uuid: 5004, name: "破晓先知", path: "hm1", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: 143, ap: 40, skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid3].cd, ccd: 0 } }, fstart: { 6401: [ @@ -430,7 +454,7 @@ export const HeroInfo: Record = { }, // 5005 战歌法师 — field 攻击光环 5005: { - uuid: 5005, name: "战歌法师", path: "hm2", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 143, ap: 40, + uuid: 5005, name: "战歌法师", path: "hm2", fac: FacSet.HERO, card_lv: 1, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Support, hp: 143, ap: 40, skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid3].cd, ccd: 0 } }, field: [ { lv: 1, uuids: [{ uuid: 7002, value: 0.1 }] }, @@ -444,7 +468,7 @@ export const HeroInfo: Record = { // 5101 不死斗士 — atked 回血(更高数值) 5101: { - uuid: 5101, name: "不死斗士", path: "hk3", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, hp: 600, ap: 57, + uuid: 5101, name: "不死斗士", path: "hk3", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: 600, ap: 57, skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow3].cd, ccd: 0 } }, atked: { 6302: [ @@ -457,7 +481,7 @@ export const HeroInfo: Record = { }, // 5102 致命杀手 — atking 暴击(更高数值) 5102: { - uuid: 5102, name: "致命杀手", path: "hc2", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Melee, grow_type: HGrowType.Assassin, hp: 600, ap: 57, + uuid: 5102, name: "致命杀手", path: "hc2", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Melee, grow_type: HGrowType.Assassin, role: HRole.Assassin, hp: 600, ap: 57, skills: { 6003: { uuid: 6003, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast2].cd, ccd: 0 } }, atking: { 6403: [ @@ -470,7 +494,7 @@ export const HeroInfo: Record = { }, // 5103 殉道勇士 — dead 全队护盾(更高数值) 5103: { - uuid: 5103, name: "殉道勇士", path: "hk4", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, hp: 600, ap: 57, + uuid: 5103, name: "殉道勇士", path: "hk4", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: 600, ap: 57, skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow3].cd, ccd: 0 } }, dead: { 6301: [ @@ -483,7 +507,7 @@ export const HeroInfo: Record = { }, // 5104 圣光祭司 — fstart 全队护盾(更高数值) 5104: { - uuid: 5104, name: "圣光祭司", path: "hm3", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 287, ap: 80, + uuid: 5104, name: "圣光祭司", path: "hm3", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: 287, ap: 80, skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow1].cd, ccd: 0 } }, fstart: { 6301: [ @@ -496,7 +520,7 @@ export const HeroInfo: Record = { }, // 5105 风怒先知 — field 攻速光环 5105: { - uuid: 5105, name: "风怒先知", path: "hm1", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 287, ap: 80, + uuid: 5105, name: "风怒先知", path: "hm1", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Support, hp: 287, ap: 80, skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid2].cd, ccd: 0 } }, field: [ { lv: 1, uuids: [{ uuid: 7006, value: 0.1 }] }, @@ -507,7 +531,7 @@ export const HeroInfo: Record = { }, // 5106 破甲射手 — atking 自身穿透伤害(计时buff增强) 5106: { - uuid: 5106, name: "破甲射手", path: "ha1", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Long, grow_type: HGrowType.Assassin, hp: 287, ap: 80, + uuid: 5106, name: "破甲射手", path: "ha1", fac: FacSet.HERO, card_lv: 2, lv: 1, type: HType.Long, grow_type: HGrowType.Assassin, role: HRole.Archer, hp: 287, ap: 80, skills: { 6008: { uuid: 6008, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid2].cd, ccd: 0 } }, atking: { 6512: [ @@ -523,7 +547,7 @@ export const HeroInfo: Record = { // 5201 怒血勇士 — atked 全队攻击(范围扩大) 5201: { - uuid: 5201, name: "怒血勇士", path: "hk5", fac: FacSet.HERO, card_lv: 3, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, hp: 900, ap: 85, + uuid: 5201, name: "怒血勇士", path: "hk5", fac: FacSet.HERO, card_lv: 3, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: 900, ap: 85, skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow3].cd, ccd: 0 } }, atked: { 6401: [ @@ -536,7 +560,7 @@ export const HeroInfo: Record = { }, // 5202 援护射手 — atking 队友攻击(范围扩大) 5202: { - uuid: 5202, name: "援护射手", path: "ha1", fac: FacSet.HERO, card_lv: 3, lv: 1, type: HType.Long, grow_type: HGrowType.Assassin, hp: 430, ap: 120, + uuid: 5202, name: "援护射手", path: "ha1", fac: FacSet.HERO, card_lv: 3, lv: 1, type: HType.Long, grow_type: HGrowType.Assassin, role: HRole.Archer, hp: 430, ap: 120, skills: { 6008: { uuid: 6008, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal2].cd, ccd: 0 } }, atking: { 6401: [ @@ -549,7 +573,7 @@ export const HeroInfo: Record = { }, // 5203 传承卫士 — dead 全队生命(范围扩大) 5203: { - uuid: 5203, name: "传承卫士", path: "hk1", fac: FacSet.HERO, card_lv: 3, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, hp: 900, ap: 85, + uuid: 5203, name: "传承卫士", path: "hk1", fac: FacSet.HERO, card_lv: 3, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: 900, ap: 85, skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow3].cd, ccd: 0 } }, dead: { 6402: [ @@ -562,7 +586,7 @@ export const HeroInfo: Record = { }, // 5204 晨光贤者 — fstart 全队暴击(范围扩大) 5204: { - uuid: 5204, name: "晨光贤者", path: "hm2", fac: FacSet.HERO, card_lv: 3, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 430, ap: 120, + uuid: 5204, name: "晨光贤者", path: "hm2", fac: FacSet.HERO, card_lv: 3, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: 430, ap: 120, skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid3].cd, ccd: 0 } }, fstart: { 6403: [ @@ -575,7 +599,7 @@ export const HeroInfo: Record = { }, // 5205 精准术士 — field 暴击光环(范围扩大) 5205: { - uuid: 5205, name: "精准术士", path: "hm3", fac: FacSet.HERO, card_lv: 3, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 430, ap: 120, + uuid: 5205, name: "精准术士", path: "hm3", fac: FacSet.HERO, card_lv: 3, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Support, hp: 430, ap: 120, skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid2].cd, ccd: 0 } }, field: [ { lv: 1, uuids: [{ uuid: 7004, value: 0.1 }] }, @@ -589,7 +613,7 @@ export const HeroInfo: Record = { // 5301 复仇守护者 — atked 全队暴击(范围+数值) 5301: { - uuid: 5301, name: "复仇守护者", path: "hk2", fac: FacSet.HERO, card_lv: 4, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, hp: 1200, ap: 113, + uuid: 5301, name: "复仇守护者", path: "hk2", fac: FacSet.HERO, card_lv: 4, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: 1200, ap: 113, skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow1].cd, ccd: 0 } }, atked: { 6403: [ @@ -602,7 +626,7 @@ export const HeroInfo: Record = { }, // 5302 破灭游侠 — atking 队友暴伤(范围+数值) 5302: { - uuid: 5302, name: "破灭游侠", path: "ha2", fac: FacSet.HERO, card_lv: 4, lv: 1, type: HType.Long, grow_type: HGrowType.Assassin, hp: 573, ap: 160, + uuid: 5302, name: "破灭游侠", path: "ha2", fac: FacSet.HERO, card_lv: 4, lv: 1, type: HType.Long, grow_type: HGrowType.Assassin, role: HRole.Archer, hp: 573, ap: 160, skills: { 6008: { uuid: 6008, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal1].cd, ccd: 0 } }, atking: { 6404: [ @@ -615,7 +639,7 @@ export const HeroInfo: Record = { }, // 5303 亡语刺客 — dead 全队暴击+暴伤(双效果) 5303: { - uuid: 5303, name: "亡语刺客", path: "hc3", fac: FacSet.HERO, card_lv: 4, lv: 1, type: HType.Melee, grow_type: HGrowType.Assassin, hp: 1200, ap: 113, + uuid: 5303, name: "亡语刺客", path: "hc3", fac: FacSet.HERO, card_lv: 4, lv: 1, type: HType.Melee, grow_type: HGrowType.Assassin, role: HRole.Assassin, hp: 1200, ap: 113, skills: { 6003: { uuid: 6003, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast3].cd, ccd: 0 } }, dead: { 6403: [ @@ -633,7 +657,7 @@ export const HeroInfo: Record = { }, // 5304 战吼术士 — fstart 全队攻击+生命(双效果) 5304: { - uuid: 5304, name: "战吼术士", path: "hm1", fac: FacSet.HERO, card_lv: 4, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 573, ap: 160, + uuid: 5304, name: "战吼术士", path: "hm1", fac: FacSet.HERO, card_lv: 4, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: 573, ap: 160, skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid1].cd, ccd: 0 } }, fstart: { 6401: [ @@ -651,7 +675,7 @@ export const HeroInfo: Record = { }, // 5305 领域贤者 — field 暴伤+攻速光环(双效果) 5305: { - uuid: 5305, name: "领域贤者", path: "hm2", fac: FacSet.HERO, card_lv: 4, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 573, ap: 160, + uuid: 5305, name: "领域贤者", path: "hm2", fac: FacSet.HERO, card_lv: 4, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Support, hp: 573, ap: 160, skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Mid2].cd, ccd: 0 } }, field: [ { lv: 1, uuids: [{ uuid: 7005, value: 0.2 }, { uuid: 7006, value: 0.1 }] }, @@ -665,7 +689,7 @@ export const HeroInfo: Record = { // 5401 不灭战魂 — atked 攻击 + revive(双技能) 5401: { - uuid: 5401, name: "不灭战魂", path: "hk3", fac: FacSet.HERO, card_lv: 5, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, hp: 1500, ap: 142, + uuid: 5401, name: "不灭战魂", path: "hk3", fac: FacSet.HERO, card_lv: 5, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: 1500, ap: 142, skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow3].cd, ccd: 0 } }, atked: { 6401: [ @@ -683,7 +707,7 @@ export const HeroInfo: Record = { }, // 5402 战歌游侠 — atking 攻击 + field 攻速光环(双技能) 5402: { - uuid: 5402, name: "战歌游侠", path: "ha3", fac: FacSet.HERO, card_lv: 5, lv: 1, type: HType.Long, grow_type: HGrowType.Assassin, hp: 717, ap: 200, + uuid: 5402, name: "战歌游侠", path: "ha3", fac: FacSet.HERO, card_lv: 5, lv: 1, type: HType.Long, grow_type: HGrowType.Assassin, role: HRole.Archer, hp: 717, ap: 200, skills: { 6008: { uuid: 6008, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Fast3].cd, ccd: 0 } }, atking: { 6401: [ @@ -701,7 +725,7 @@ export const HeroInfo: Record = { }, // 5403 凤凰祭司 — dead 攻击+护盾 + revive(双技能) 5403: { - uuid: 5403, name: "凤凰祭司", path: "hk4", fac: FacSet.HERO, card_lv: 5, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, hp: 1500, ap: 142, + uuid: 5403, name: "凤凰祭司", path: "hk4", fac: FacSet.HERO, card_lv: 5, lv: 1, type: HType.Melee, grow_type: HGrowType.Warrior, role: HRole.Warrior, hp: 1500, ap: 142, skills: { 6001: { uuid: 6001, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Slow3].cd, ccd: 0 } }, dead: { 6401: [ @@ -724,7 +748,7 @@ export const HeroInfo: Record = { }, // 5404 涅槃贤者 — fstart 护盾+攻击 + revive(双技能) 5404: { - uuid: 5404, name: "涅槃贤者", path: "hm3", fac: FacSet.HERO, card_lv: 5, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, hp: 717, ap: 200, + uuid: 5404, name: "涅槃贤者", path: "hm3", fac: FacSet.HERO, card_lv: 5, lv: 1, type: HType.Long, grow_type: HGrowType.Mage, role: HRole.Mage, hp: 717, ap: 200, skills: { 6013: { uuid: 6013, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal3].cd, ccd: 0 } }, fstart: { 6301: [ @@ -747,7 +771,7 @@ export const HeroInfo: Record = { }, // 5405 圣言诗人 — atking 治疗 + field 生命光环(双技能) 5405: { - uuid: 5405, name: "圣言诗人", path: "hh1", fac: FacSet.HERO, card_lv: 5, lv: 1, type: HType.Long, grow_type: HGrowType.Support, hp: 717, ap: 200, + uuid: 5405, name: "圣言诗人", path: "hh1", fac: FacSet.HERO, card_lv: 5, lv: 1, type: HType.Long, grow_type: HGrowType.Support, role: HRole.Support, hp: 717, ap: 200, skills: { 6015: { uuid: 6015, lv: 1, cd: AtkSpeedSet[AtkSpeedLv.Normal2].cd, ccd: 0 } }, atking: { 6302: [ diff --git a/assets/script/game/hero/Hero.ts b/assets/script/game/hero/Hero.ts index f942ccf3..99f62d72 100644 --- a/assets/script/game/hero/Hero.ts +++ b/assets/script/game/hero/Hero.ts @@ -120,6 +120,7 @@ export class Hero extends ecs.Entity { model.base_card_lv = hero.card_lv ?? 1; model.type = hero.type; model.grow_type = hero.grow_type; + model.role = hero.role; model.fac = FacSet.HERO; model.dis = hero.dis ?? 720; model.posIndex = posIndex; diff --git a/assets/script/game/hero/HeroAttrsComp.ts b/assets/script/game/hero/HeroAttrsComp.ts index 3931dc94..a40557fc 100644 --- a/assets/script/game/hero/HeroAttrsComp.ts +++ b/assets/script/game/hero/HeroAttrsComp.ts @@ -1,5 +1,5 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; -import { HeroDisVal, HeroInfo, HSkillInfo, HType, SkillTriggerType, TriggerGrouped, LvFieldEntry, LvReviveEntry, LvBonusEntry, FieldEntry } from "../common/config/heroSet"; +import { HeroDisVal, HeroInfo, HSkillInfo, HType, SkillTriggerType, TriggerGrouped, LvFieldEntry, LvReviveEntry, LvBonusEntry, FieldEntry, HRole } from "../common/config/heroSet"; import { mLogger } from "../common/Logger"; import { FacSet, FightSet } from "../common/config/GameSet"; import { FieldSkillSet, FieldSkillType, SkillOverrides } from "../common/config/SkillSet"; @@ -29,6 +29,7 @@ export class HeroAttrsComp extends ecs.Comp { type: number = 0; // 0近战 1远程 2辅助 fac: number = 0; // 0:hero 1:monster grow_type?: number; // 成长类型(HGrowType),驱动每级 hp/ap 线性成长 + role?: HRole; // 位置类型/职业定位(驱动编队站位优先级) // ==================== 基础属性(有初始值) ==================== base_ap: number = 0; // 原始基础攻击(无任何加成) base_hp: number = 0; // 原始基础血量(无任何加成) @@ -563,6 +564,8 @@ export class HeroAttrsComp extends ecs.Comp { this.lv = 1; this.type = 0; this.fac = 0; + this.grow_type = undefined; + this.role = undefined; this.base_ap = 0; this.base_hp = 0; this.ap = 0; diff --git a/assets/script/game/hero/MoveComp.ts b/assets/script/game/hero/MoveComp.ts index d4d94fca..7d7308aa 100644 --- a/assets/script/game/hero/MoveComp.ts +++ b/assets/script/game/hero/MoveComp.ts @@ -3,7 +3,7 @@ import { HeroViewComp } from "./HeroViewComp"; import { HeroAttrsComp } from "./HeroAttrsComp"; import { smc } from "../common/SingletonModuleComp"; import { BoxSet, FacSet } from "../common/config/GameSet"; -import { HeroDisVal, HType } from "../common/config/heroSet"; +import { HeroDisVal, HType, HRole } from "../common/config/heroSet"; import { BoxCollider2D, Node } from "cc"; import { MonMoveComp } from "./MonMoveComp"; @@ -46,8 +46,6 @@ interface MoveFacConfig { retreatBackX: number; } -import { MissionHeroComp } from "../map/MissionHeroComp"; - @ecs.register('MoveSystem') export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { private readonly heroFrontAnchorX = -200; @@ -106,7 +104,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate update(e: ecs.Entity) { /** 战斗未开始/暂停时不驱动移动 */ if (!smc.mission.play || smc.mission.pause) return; - + const model = e.get(HeroAttrsComp); const move = e.get(MoveComp); const view = e.get(HeroViewComp); @@ -125,55 +123,37 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate move.baseY = slot.targetY; move.targetX = slot.targetX; - // 战斗阶段不移动 - const canMove = !smc.mission.in_fight; - - // 2. 平滑 Y 轴换路 + // 2. 平滑 Y 轴换路(不分阶段,立即响应编队变化) let isChangingLane = false; - if (canMove) { - if (Math.abs(view.node.position.y - move.baseY) > 2) { - const currentY = view.node.position.y; - const deltaY = move.baseY - currentY; - const step = 400 * this.dt; // 换路速度 - const newY = currentY + Math.sign(deltaY) * Math.min(Math.abs(deltaY), step); - view.node.setPosition(view.node.position.x, newY, 0); - isChangingLane = true; - } else { - view.node.setPosition(view.node.position.x, move.baseY, 0); - } + if (Math.abs(view.node.position.y - move.baseY) > 2) { + const currentY = view.node.position.y; + const deltaY = move.baseY - currentY; + const step = 400 * this.dt; // 换路速度 + const newY = currentY + Math.sign(deltaY) * Math.min(Math.abs(deltaY), step); + view.node.setPosition(view.node.position.x, newY, 0); + isChangingLane = true; + } else { + view.node.setPosition(view.node.position.x, move.baseY, 0); } - + // 渲染层级重排 this.updateRenderOrder(); const nearestEnemy = this.findNearestEnemy(e); if (nearestEnemy) { - /** 有敌人:进入战斗位移逻辑 */ - if (canMove) { - this.processCombatLogic(e, move, view, model, nearestEnemy); - } else { - model.is_atking = true; // 战斗中不移动,但保持攻击状态 - } + /** 有敌人:进入战斗位移逻辑(立即向编队目标移动) */ + this.processCombatLogic(e, move, view, model, nearestEnemy); this.syncCombatTarget(model, view, nearestEnemy); } else { /** 无敌人:清目标并回归编队站位 */ this.clearCombatTarget(model); - if (canMove) { - this.moveToSlot(view, move, model, move.targetX); - } + this.moveToSlot(view, move, model, move.targetX); model.is_atking = false; } - if (canMove) { - // 如果只在 Y 轴移动,也要播放 move 动画 - if (isChangingLane && view.status !== "move" && view.status !== "atk") { - view.status_change("move"); - } - } else { - // 战斗阶段如果不移动,确保不在攻击时恢复 idle 状态 - if (!model.is_atking && view.status === "move") { - view.status_change("idle"); - } + // 如果只在 Y 轴移动,也要播放 move 动画 + if (isChangingLane && view.status !== "move" && view.status !== "atk") { + view.status_change("move"); } } @@ -252,14 +232,10 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate allAllies.sort((a, b) => { const attrsA = a.get(HeroAttrsComp); const attrsB = b.get(HeroAttrsComp); - const priorityA = attrsA ? this.getCombatPriority(attrsA) : 0; - const priorityB = attrsB ? this.getCombatPriority(attrsB) : 0; + const priorityA = attrsA ? this.getFormationPriority(attrsA) : 0; + const priorityB = attrsB ? this.getFormationPriority(attrsB) : 0; if (priorityA !== priorityB) return priorityB - priorityA; - const deadA = (attrsA?.dead && attrsA.dead.length > 0) ? 1 : 0; - const deadB = (attrsB?.dead && attrsB.dead.length > 0) ? 1 : 0; - if (deadA !== deadB) return deadB - deadA; - const lvA = attrsA?.lv ?? 1; const lvB = attrsB?.lv ?? 1; if (lvA !== lvB) return lvB - lvA; @@ -271,20 +247,48 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate return a.eid - b.eid; }); - const slotIndex = Math.max(0, allAllies.findIndex(entity => entity === self)); - - // 优先中前(1) -> 上前(0) -> 下前(2) -> 中后(4) -> 上后(3) -> 下后(5) - const slotPriority = [1, 0, 2, 4, 3, 5]; - const posIndex = slotPriority[slotIndex % 6]; - const pos = MissionHeroComp.HERO_POSITIONS[posIndex]; - - return { targetX: pos.x, targetY: pos.y }; + // allAllies 按优先级降序(索引 0 = 最高优先级 = 最靠右/最先接敌), + // 反转为"从左侧起的排位"后再分配 X:最高优先级 → 最右 + const priorityRank = Math.max(0, allAllies.findIndex(entity => entity === self)); + const rankFromLeft = allAllies.length - 1 - priorityRank; + const targetX = this.calcSlotX(rankFromLeft, allAllies.length); + + return { targetX, targetY: BoxSet.GAME_LINE }; + } + + // ==================== 编队站位(方案 A:单行横向分布) ==================== + /** 编队左端起点(最靠后/最后接敌) */ + private static readonly FORMATION_LEFT_X = -320; + /** 编队右端终点(最靠前/最先接敌) */ + private static readonly FORMATION_RIGHT_X = 100; + /** 固定步进间距(人数较少时按此从左侧逐位右排) */ + private static readonly FORMATION_STEP_X = 60; + + /** + * 计算某个槽位的目标 X。 + * Why: 单行站位避免横版拥挤——人少时按 60 固定步进从 -320 起步逐位右排(保持松散), + * 人多到 60 步进装不下时,改为在 [-320, 100] 区间均分(利用全宽)。 + * @param rankFromLeft 从左侧起的排位(0=最靠左/最后,越大越靠右/越先接敌) + * @param total 当前存活英雄总数 + */ + private calcSlotX(rankFromLeft: number, total: number): number { + const left = MoveSystem.FORMATION_LEFT_X; + const right = MoveSystem.FORMATION_RIGHT_X; + const step = MoveSystem.FORMATION_STEP_X; + if (total <= 1) return left; + // 固定步进能容纳的最大人数:相邻 60,且最右不超过 right + const maxStepCount = Math.floor((right - left) / step) + 1; + if (total <= maxStepCount) { + return left + rankFromLeft * step; + } + // 超出后均分整段区间(含左右端点) + return left + (right - left) * (rankFromLeft / (total - 1)); } private moveToSlot(view: HeroViewComp, move: MoveComp, model: HeroAttrsComp, targetX: number) { const currentX = view.node.position.x; const currentY = view.node.position.y; - + // 当 X 和 Y 都到达目标时,才算真正到达 if (Math.abs(currentX - targetX) <= 2 && Math.abs(currentY - move.baseY) <= 2) { view.node.setPosition(targetX, move.baseY, 0); @@ -307,7 +311,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate const moveMaxX = Math.max(cfg.moveBackX, cfg.moveFrontX); const currentX = view.node.position.x; const currentY = view.node.position.y; - + const delta = speed * this.dt * direction; let newX = view.node.position.x + delta; if (currentX < moveMinX && direction < 0) { @@ -345,12 +349,30 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate view.status_change("move"); } - private getCombatPriority(model: HeroAttrsComp): number { - /** 数值越大越靠前:近战 > 中程 > 远程 */ + /** + * 编队站位优先级(数值越大越靠前/越靠右)。 + * Why: 阵容职能决定承伤顺序——死亡触发英雄需最先阵亡以触发遗志, + * 其次坦克承伤,再次战士/刺客,远程射手/法师/辅助依次靠后保护。 + * 排序档位:死亡触发 > 坦克 > 战士 > 刺客 > 射手 > 法师 > 辅助 + */ + private getFormationPriority(model: HeroAttrsComp): number { + // 死亡触发英雄最高优先:需要先死以发动遗志/献祭 + if (model.dead && Object.keys(model.dead).length > 0) return 100; + if (model.role !== undefined) { + switch (model.role) { + case HRole.Tank: return 90; + case HRole.Warrior: return 80; + case HRole.Assassin: return 70; + case HRole.Archer: return 60; + case HRole.Mage: return 50; + case HRole.Support: return 40; + } + } + // 兜底:未配置 role 时按攻击定位(近战 > 中程 > 远程) const rangeType = model.type as HType.Melee | HType.Mid | HType.Long; - if (rangeType === HType.Melee) return 3; - if (rangeType === HType.Mid) return 2; - return 1; + if (rangeType === HType.Melee) return 30; + if (rangeType === HType.Mid) return 20; + return 10; } private resolveCombatRange(model: HeroAttrsComp, defaultMin: number, defaultMax: number): [number, number] { @@ -364,13 +386,13 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate private findNearestEnemy(entity: ecs.Entity): HeroViewComp | null { const currentView = entity.get(HeroViewComp); if (!currentView?.node) return null; - + const currentPos = currentView.node.position; const myFac = entity.get(HeroAttrsComp).fac; - + let nearest: HeroViewComp | null = null; let minDis = Infinity; - + /** 遍历筛出最近敌人:以 X 轴距离为主,Y 轴距离作为同排的决胜权重,使角色优先攻击同路的敌人 */ ecs.query(this.getHeroViewMatcher()).forEach(e => { const m = e.get(HeroAttrsComp); @@ -405,7 +427,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate const actorView = e.get(HeroViewComp); if (!attrs || !actorView?.node || attrs.is_dead) return; if (attrs.fac !== FacSet.HERO && attrs.fac !== FacSet.MON) return; - + if (actorView.node.parent !== actorRoot) { actorView.node.parent = actorRoot; }