refactor(技能系统): 重构施放系统以支持位置目标和实体ID目标
- 将技能目标从 HeroViewComp 数组改为位置向量和实体ID数组的组合 - 移除对 oops 框架和 GameEvent 的依赖,改为直接处理技能效果 - 新增 resolveFriendlyTargets 方法用于解析友方目标实体 - 新增 hasCastTarget 方法统一检查施放目标有效性 - 简化 applyPrimaryEffect 方法,分离伤害技能和增益技能的处理逻辑
This commit is contained in:
@@ -6,8 +6,6 @@ import { BuffsList, SkillConfig, SkillKind, SkillSet, TGroup } from "../common/c
|
||||
import { Skill } from "../skill/Skill";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
import { GameConst } from "../common/config/GameConst";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { GameEvent } from "../common/config/GameEvent";
|
||||
import { HType } from "../common/config/heroSet";
|
||||
|
||||
/**
|
||||
@@ -25,7 +23,7 @@ import { HType } from "../common/config/heroSet";
|
||||
@ecs.register('SCastSystem')
|
||||
export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||||
debugMode: boolean = false; // 是否启用调试模式
|
||||
private readonly emptyCastPlan = { skillId: 0, targets: [] as HeroViewComp[], isFriendly: false };
|
||||
private readonly emptyCastPlan = { skillId: 0, isFriendly: false, targetPos: null as Vec3 | null, targetEids: [] as number[] };
|
||||
private readonly meleeCastRange = 64;
|
||||
|
||||
filter(): ecs.IMatcher {
|
||||
@@ -41,11 +39,11 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
if (heroAttrs.is_dead || heroAttrs.is_reviving || heroAttrs.isStun() || heroAttrs.isFrost()) return;
|
||||
heroAttrs.updateCD(this.dt);
|
||||
const castPlan = this.pickCastSkill(heroAttrs, heroView);
|
||||
if (castPlan.skillId === 0 || castPlan.targets.length === 0) return;
|
||||
this.castSkill(e, castPlan, heroAttrs, heroView);
|
||||
if (!this.hasCastTarget(castPlan)) return;
|
||||
this.castSkill(castPlan, heroAttrs, heroView);
|
||||
}
|
||||
|
||||
private pickCastSkill(heroAttrs: HeroAttrsComp, heroView: HeroViewComp): { skillId: number; targets: HeroViewComp[]; isFriendly: boolean } {
|
||||
private pickCastSkill(heroAttrs: HeroAttrsComp, heroView: HeroViewComp): { skillId: number; isFriendly: boolean; targetPos: Vec3 | null; targetEids: number[] } {
|
||||
const type = heroAttrs.type as HType;
|
||||
const maxRange = this.resolveMaxCastRange(heroAttrs, type);
|
||||
const target = this.findNearestEnemyInRange(heroAttrs, heroView, maxRange);
|
||||
@@ -58,15 +56,17 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
if (isMainSkill && !heroAttrs.can_skill) continue;
|
||||
if (!isMainSkill && !heroAttrs.can_atk) continue;
|
||||
if (this.isFriendlySkill(config.TGroup)) {
|
||||
return { skillId: s_uuid, targets: [heroView], isFriendly: true };
|
||||
const selfEid = heroView.ent?.eid;
|
||||
if (typeof selfEid !== "number") continue;
|
||||
return { skillId: s_uuid, isFriendly: true, targetPos: null, targetEids: [selfEid] };
|
||||
}
|
||||
if (!target) continue;
|
||||
return { skillId: s_uuid, targets: [target], isFriendly: false };
|
||||
return { skillId: s_uuid, isFriendly: false, targetPos: target.node.position.clone(), targetEids: [] };
|
||||
}
|
||||
return this.emptyCastPlan;
|
||||
}
|
||||
|
||||
private castSkill(entity: ecs.Entity, castPlan: { skillId: number; targets: HeroViewComp[]; isFriendly: boolean }, heroAttrs: HeroAttrsComp, heroView: HeroViewComp) {
|
||||
private castSkill(castPlan: { skillId: number; isFriendly: boolean; targetPos: Vec3 | null; targetEids: number[] }, heroAttrs: HeroAttrsComp, heroView: HeroViewComp) {
|
||||
const s_uuid = castPlan.skillId;
|
||||
const config = SkillSet[s_uuid];
|
||||
if (!config) return;
|
||||
@@ -81,18 +81,13 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
heroView.scheduleOnce(() => {
|
||||
if (!heroView.node || !heroView.node.isValid || heroAttrs.is_dead) return;
|
||||
if (castPlan.isFriendly) {
|
||||
oops.message.dispatchEvent(GameEvent.CastHeroSkill, {
|
||||
casterEid: entity.eid,
|
||||
s_uuid,
|
||||
fac: heroAttrs.fac,
|
||||
targetEids: castPlan.targets.map(target => target.ent?.eid).filter((eid): eid is number => typeof eid === "number")
|
||||
});
|
||||
const friendlyTargets = this.resolveFriendlyTargets(castPlan.targetEids, heroAttrs.fac);
|
||||
if (friendlyTargets.length === 0) return;
|
||||
this.applyPrimaryEffect(s_uuid, config, heroView, friendlyTargets, null);
|
||||
this.applyExtraEffects(config, friendlyTargets);
|
||||
return;
|
||||
}
|
||||
const validTargets = this.filterValidTargets(castPlan.targets);
|
||||
if (validTargets.length === 0) return;
|
||||
this.applyPrimaryEffect(entity, s_uuid, config, heroView, validTargets);
|
||||
this.applyExtraEffects(config, validTargets);
|
||||
this.applyPrimaryEffect(s_uuid, config, heroView, [], castPlan.targetPos);
|
||||
}, delay);
|
||||
if (isMainSkill) {
|
||||
heroAttrs.triggerSkillCD();
|
||||
@@ -109,12 +104,11 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
skill.load(caster.node.position.clone(), parent, s_uuid, targetPos.clone(), caster, 0);
|
||||
}
|
||||
|
||||
private applyPrimaryEffect(casterEntity: ecs.Entity, s_uuid: number, config: SkillConfig, heroView: HeroViewComp, targets: HeroViewComp[]) {
|
||||
private applyPrimaryEffect(s_uuid: number, config: SkillConfig, heroView: HeroViewComp, targets: HeroViewComp[], targetPos: Vec3 | null) {
|
||||
const kind = config.kind ?? SkillKind.Damage;
|
||||
if (kind === SkillKind.Damage) {
|
||||
if (config.ap > 0) {
|
||||
this.createSkillEntity(s_uuid, heroView, targets[0].node.position);
|
||||
}
|
||||
if (config.ap <= 0 || !targetPos) return;
|
||||
this.createSkillEntity(s_uuid, heroView, targetPos);
|
||||
return;
|
||||
}
|
||||
for (const target of targets) {
|
||||
@@ -154,14 +148,25 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
||||
}
|
||||
}
|
||||
|
||||
private filterValidTargets(targets: HeroViewComp[]): HeroViewComp[] {
|
||||
return targets.filter(target => {
|
||||
if (!target || !target.node || !target.node.isValid) return false;
|
||||
if (!target.ent) return false;
|
||||
const model = target.ent.get(HeroAttrsComp);
|
||||
if (!model || model.is_dead || model.is_reviving) return false;
|
||||
return true;
|
||||
});
|
||||
private resolveFriendlyTargets(targetEids: number[], fac: number): HeroViewComp[] {
|
||||
const targets: HeroViewComp[] = [];
|
||||
for (const eid of targetEids) {
|
||||
const entity = ecs.getEntityByEid(eid);
|
||||
if (!entity) continue;
|
||||
const model = entity.get(HeroAttrsComp);
|
||||
const view = entity.get(HeroViewComp);
|
||||
if (!model || !view?.node) continue;
|
||||
if (model.fac !== fac) continue;
|
||||
if (model.is_dead || model.is_reviving) continue;
|
||||
targets.push(view);
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
private hasCastTarget(castPlan: { skillId: number; isFriendly: boolean; targetPos: Vec3 | null; targetEids: number[] }): boolean {
|
||||
if (castPlan.skillId === 0) return false;
|
||||
if (castPlan.isFriendly) return castPlan.targetEids.length > 0;
|
||||
return !!castPlan.targetPos;
|
||||
}
|
||||
|
||||
private isFriendlySkill(group: TGroup): boolean {
|
||||
|
||||
Reference in New Issue
Block a user