feat(技能): 增加基于目标类型的智能排序逻辑

扩展技能目标选择系统,支持根据 TType 配置选择不同优先级的目标。
新增 HighestAP(最高攻击力)目标类型,并在 SCastSystem 中实现排序算法:
- Frontline(默认):最近距离优先
- Backline:最远距离优先
- LowestHP:最低血量优先
- HighestHP:最高血量优先
- HighestAP:最高攻击力优先
同时更新所有技能配置,补充缺失的 TType 字段。
This commit is contained in:
panw
2026-03-12 16:27:16 +08:00
parent d5e03d7856
commit 3ba33c5240
2 changed files with 48 additions and 16 deletions

View File

@@ -23,6 +23,8 @@ export enum TType {
LowestHP = 3, // 最低生命值
/** 生命值最高的目标 */
HighestHP = 4, // 最高生命值
/** 攻击力最高的目标 */
HighestAP = 9, // 最高攻击力
/** 近战职业目标 */
Melee =5, // 近战职业
/** 远程职业目标 */
@@ -173,6 +175,7 @@ export interface SkillConfig {
icon:string, // 图标ID
TGroup:TGroup, // 目标群体(敌方/友方/自身等)
SType:SType, // 技能类型(伤害/治疗/护盾等)
TType:TType, // 目标类型
act:string, // 角色执行的动画
DTType:DTType, // 伤害类型(单体/范围)
ap:number, // 攻击百分比(角色攻击力)
@@ -192,57 +195,57 @@ export interface SkillConfig {
}
export const SkillSet: Record<number, SkillConfig> = {
5000:{uuid:5000,name:"反伤",sp_name:"thorns",icon:"1168",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,
5000:{uuid:5000,name:"反伤",sp_name:"thorns",icon:"1168",TGroup:TGroup.Enemy,SType:SType.damage,TType:TType.Frontline,act:"atk",DTType:DTType.single,
ap:0,hit_num:1,hit:1,hitcd:0.2,speed:720,with:0,
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
buffs:[],info:"反伤",
},
// ========== 基础攻击 ========== 6001-6099
6001: {
uuid:6001,name:"近战攻击",sp_name:"atk_s1",icon:"1026",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,
uuid:6001,name:"近战攻击",sp_name:"atk_s1",icon:"1026",TGroup:TGroup.Enemy,SType:SType.damage,TType:TType.Frontline,act:"atk",DTType:DTType.single,
ap:100,hit_num:1,hit:1,hitcd:0.2,speed:720,with:0,
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
buffs:[],info:"对前方目标造成100%攻击的伤害",
},
6002: {
uuid:6002,name:"远程攻击",sp_name:"b_arrow_blue",icon:"1135",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,
uuid:6002,name:"远程攻击",sp_name:"b_arrow_blue",icon:"1135",TGroup:TGroup.Enemy,SType:SType.damage,TType:TType.Frontline,act:"atk",DTType:DTType.single,
ap:100,hit_num:1,hit:1,hitcd:0.2,speed:720,with:0,
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
buffs:[],info:"对前方单个目标造成100%攻击的伤害",
},
6003: {
uuid:6003,name:"远程攻击",sp_name:"m_water_ball_1",icon:"1126",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,
uuid:6003,name:"远程攻击",sp_name:"m_water_ball_1",icon:"1126",TGroup:TGroup.Enemy,SType:SType.damage,TType:TType.Frontline,act:"atk",DTType:DTType.single,
ap:100,hit_num:1,hit:2,hitcd:0.3,speed:720,with:90,
ready:8001,EAnm:0,DAnm:9001,RType:RType.linear,EType:EType.collision,
buffs:[],info:"对前方单个目标造成100%攻击的伤害",
},
6004: {
uuid:6004,name:"蓄力一击",sp_name:"atk_s4",icon:"1173",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,
uuid:6004,name:"蓄力一击",sp_name:"atk_s4",icon:"1173",TGroup:TGroup.Enemy,SType:SType.damage,TType:TType.Frontline,act:"atk",DTType:DTType.single,
ap:100,hit_num:1,hit:1,hitcd:0.2,speed:720,with:0,
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
buffs:[],info:"对前方目标造成150%攻击的伤害",
},
// ========== 基础buff ========== 6100-6199
6100: {
uuid:6100,name:"治疗",sp_name:"buff_wind",icon:"1292",TGroup:TGroup.Self,SType:SType.heal,act:"atk",DTType:DTType.single,
uuid:6100,name:"治疗",sp_name:"buff_wind",icon:"1292",TGroup:TGroup.Self,SType:SType.heal,TType:TType.LowestHP,act:"atk",DTType:DTType.single,
ap:30,hit_num:1,hit:1,hitcd:0.2,speed:720,with:0,
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
buffs:[],info:"治疗自己,回复30%最大生命值",
},
6101:{
uuid:6101,name:"魔法盾",sp_name:"buff_wind",icon:"1255",TGroup:TGroup.Self,SType:SType.shield,act:"atk",DTType:DTType.single,
uuid:6101,name:"魔法盾",sp_name:"buff_wind",icon:"1255",TGroup:TGroup.Self,SType:SType.shield,TType:TType.LowestHP,act:"atk",DTType:DTType.single,
ap:30,hit_num:1,hit:1,hitcd:0.2,speed:720,with:0,
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
buffs:[],info:"获得30%最大生命值的护盾,持续60秒",
},
6102:{
uuid:6102,name:"强壮",sp_name:"buff_wind",icon:"3036",TGroup:TGroup.Team,SType:SType.buff,act:"atk",DTType:DTType.single,
uuid:6102,name:"强壮",sp_name:"buff_wind",icon:"3036",TGroup:TGroup.Team,SType:SType.buff,TType:TType.HighestAP,act:"atk",DTType:DTType.single,
ap:30,hit_num:1,hit:1,hitcd:0.2,speed:720,with:0,
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
buffs:[10001],info:"增加目标10%攻击力,持续30秒",
},
6103:{
uuid:6103,name:"群体强壮",sp_name:"buff_wind",icon:"3036",TGroup:TGroup.Team,SType:SType.buff,act:"atk",DTType:DTType.range,
uuid:6103,name:"群体强壮",sp_name:"buff_wind",icon:"3036",TGroup:TGroup.Team,SType:SType.buff,TType:TType.HighestAP,act:"atk",DTType:DTType.range,
ap:30,hit_num:1,hit:1,hitcd:0.2,speed:720,with:0,
ready:0,EAnm:0,DAnm:9001,RType:RType.fixed,EType:EType.animationEnd,
buffs:[10011],info:"增加目标10%攻击力,持续30秒",
@@ -250,14 +253,14 @@ export const SkillSet: Record<number, SkillConfig> = {
// ========== 怪物基础技能 ========== 6200-6299
6201: {
uuid:6201, name:"怪物近战", sp_name:"atk_s1", icon:"3036",
TGroup:TGroup.Enemy, SType:SType.damage, act:"atk", DTType:DTType.single,
TGroup:TGroup.Enemy, SType:SType.damage, TType:TType.Frontline, act:"atk", DTType:DTType.single,
ap:100, hit_num:1, hit:1, hitcd:0.2, speed:0, with:0, // 怪物近战特殊距离
ready:0, EAnm:0, DAnm:9001, RType:RType.fixed, EType:EType.animationEnd,
buffs:[], info:"怪物基础近战攻击",
},
6203: {
uuid:6203, name:"怪物射击", sp_name:"arrow_1", icon:"3039",
TGroup:TGroup.Enemy, SType:SType.damage, act:"atk", DTType:DTType.single,
TGroup:TGroup.Enemy, SType:SType.damage, TType:TType.Frontline, act:"atk", DTType:DTType.single,
ap:80, hit_num:1, hit:1, hitcd:0.2, speed:800, with:0, // 怪物远程特殊距离
ready:0, EAnm:0, DAnm:9001, RType:RType.linear, EType:EType.collision,
buffs:[], info:"怪物基础远程攻击",

View File

@@ -2,7 +2,7 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec
import { Vec3 } from "cc";
import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroViewComp } from "./HeroViewComp";
import { BuffsList, SkillConfig, SkillSet, SType, TGroup } from "../common/config/SkillSet";
import { BuffsList, SkillConfig, SkillSet, SType, TGroup, TType } from "../common/config/SkillSet";
import { Skill } from "../skill/Skill";
import { smc } from "../common/SingletonModuleComp";
import { GameConst } from "../common/config/GameConst";
@@ -132,7 +132,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
const isAll = config.TGroup === TGroup.All;
if (isSelf) return [caster];
const currentPos = caster.node.position;
const list: { view: HeroViewComp; dis: number; lane: number }[] = [];
const list: { view: HeroViewComp; attrs: HeroAttrsComp; dis: number; lane: number }[] = [];
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(ent => {
const targetAttrs = ent.get(HeroAttrsComp);
const targetView = ent.get(HeroViewComp);
@@ -145,12 +145,41 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
const dis = Math.abs(currentPos.x - targetView.node.position.x);
if (dis > range) return;
const lane = Math.abs(currentPos.y - targetView.node.position.y);
list.push({ view: targetView, dis, lane });
list.push({ view: targetView, attrs: targetAttrs, dis, lane });
});
list.sort((a, b) => {
if (a.lane !== b.lane) return a.lane - b.lane;
return a.dis - b.dis;
// 优先检查是否在同一行 (除了特殊目标类型)
// 如果是寻找特殊目标(如最低血量),通常忽略行优先,但在范围内全搜索
// 但如果设计要求"最近的优先",则通常还是先看行。
// 这里假设 TType 优先级高于 Lane 优先级,或者在 TType 相同情况下比较 Lane
const type = config.TType ?? TType.Frontline;
switch (type) {
case TType.Backline:
// 后排:距离最远优先
if (a.lane !== b.lane) return a.lane - b.lane; // 先同行
return b.dis - a.dis;
case TType.LowestHP:
// 最低血量
if (a.attrs.hp !== b.attrs.hp) return a.attrs.hp - b.attrs.hp;
return a.dis - b.dis; // 血量相同选最近
case TType.HighestHP:
// 最高血量
if (a.attrs.hp !== b.attrs.hp) return b.attrs.hp - a.attrs.hp;
return a.dis - b.dis;
case TType.HighestAP:
// 最高攻击
if (a.attrs.ap !== b.attrs.ap) return b.attrs.ap - a.attrs.ap;
return a.dis - b.dis;
case TType.Frontline:
default:
// 前排:距离最近优先 (默认)
if (a.lane !== b.lane) return a.lane - b.lane;
return a.dis - b.dis;
}
});
const maxTargets = Math.max(GameConst.Skill.MIN_TARGET_COUNT, 1);
return list.slice(0, maxTargets).map(item => item.view);
}