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 { Skill } from "../skill/Skill";
|
||||||
import { smc } from "../common/SingletonModuleComp";
|
import { smc } from "../common/SingletonModuleComp";
|
||||||
import { GameConst } from "../common/config/GameConst";
|
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";
|
import { HType } from "../common/config/heroSet";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,7 +23,7 @@ import { HType } from "../common/config/heroSet";
|
|||||||
@ecs.register('SCastSystem')
|
@ecs.register('SCastSystem')
|
||||||
export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||||||
debugMode: boolean = false; // 是否启用调试模式
|
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;
|
private readonly meleeCastRange = 64;
|
||||||
|
|
||||||
filter(): ecs.IMatcher {
|
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;
|
if (heroAttrs.is_dead || heroAttrs.is_reviving || heroAttrs.isStun() || heroAttrs.isFrost()) return;
|
||||||
heroAttrs.updateCD(this.dt);
|
heroAttrs.updateCD(this.dt);
|
||||||
const castPlan = this.pickCastSkill(heroAttrs, heroView);
|
const castPlan = this.pickCastSkill(heroAttrs, heroView);
|
||||||
if (castPlan.skillId === 0 || castPlan.targets.length === 0) return;
|
if (!this.hasCastTarget(castPlan)) return;
|
||||||
this.castSkill(e, castPlan, heroAttrs, heroView);
|
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 type = heroAttrs.type as HType;
|
||||||
const maxRange = this.resolveMaxCastRange(heroAttrs, type);
|
const maxRange = this.resolveMaxCastRange(heroAttrs, type);
|
||||||
const target = this.findNearestEnemyInRange(heroAttrs, heroView, maxRange);
|
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_skill) continue;
|
||||||
if (!isMainSkill && !heroAttrs.can_atk) continue;
|
if (!isMainSkill && !heroAttrs.can_atk) continue;
|
||||||
if (this.isFriendlySkill(config.TGroup)) {
|
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;
|
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;
|
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 s_uuid = castPlan.skillId;
|
||||||
const config = SkillSet[s_uuid];
|
const config = SkillSet[s_uuid];
|
||||||
if (!config) return;
|
if (!config) return;
|
||||||
@@ -81,18 +81,13 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
|||||||
heroView.scheduleOnce(() => {
|
heroView.scheduleOnce(() => {
|
||||||
if (!heroView.node || !heroView.node.isValid || heroAttrs.is_dead) return;
|
if (!heroView.node || !heroView.node.isValid || heroAttrs.is_dead) return;
|
||||||
if (castPlan.isFriendly) {
|
if (castPlan.isFriendly) {
|
||||||
oops.message.dispatchEvent(GameEvent.CastHeroSkill, {
|
const friendlyTargets = this.resolveFriendlyTargets(castPlan.targetEids, heroAttrs.fac);
|
||||||
casterEid: entity.eid,
|
if (friendlyTargets.length === 0) return;
|
||||||
s_uuid,
|
this.applyPrimaryEffect(s_uuid, config, heroView, friendlyTargets, null);
|
||||||
fac: heroAttrs.fac,
|
this.applyExtraEffects(config, friendlyTargets);
|
||||||
targetEids: castPlan.targets.map(target => target.ent?.eid).filter((eid): eid is number => typeof eid === "number")
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const validTargets = this.filterValidTargets(castPlan.targets);
|
this.applyPrimaryEffect(s_uuid, config, heroView, [], castPlan.targetPos);
|
||||||
if (validTargets.length === 0) return;
|
|
||||||
this.applyPrimaryEffect(entity, s_uuid, config, heroView, validTargets);
|
|
||||||
this.applyExtraEffects(config, validTargets);
|
|
||||||
}, delay);
|
}, delay);
|
||||||
if (isMainSkill) {
|
if (isMainSkill) {
|
||||||
heroAttrs.triggerSkillCD();
|
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);
|
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;
|
const kind = config.kind ?? SkillKind.Damage;
|
||||||
if (kind === SkillKind.Damage) {
|
if (kind === SkillKind.Damage) {
|
||||||
if (config.ap > 0) {
|
if (config.ap <= 0 || !targetPos) return;
|
||||||
this.createSkillEntity(s_uuid, heroView, targets[0].node.position);
|
this.createSkillEntity(s_uuid, heroView, targetPos);
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const target of targets) {
|
for (const target of targets) {
|
||||||
@@ -154,14 +148,25 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private filterValidTargets(targets: HeroViewComp[]): HeroViewComp[] {
|
private resolveFriendlyTargets(targetEids: number[], fac: number): HeroViewComp[] {
|
||||||
return targets.filter(target => {
|
const targets: HeroViewComp[] = [];
|
||||||
if (!target || !target.node || !target.node.isValid) return false;
|
for (const eid of targetEids) {
|
||||||
if (!target.ent) return false;
|
const entity = ecs.getEntityByEid(eid);
|
||||||
const model = target.ent.get(HeroAttrsComp);
|
if (!entity) continue;
|
||||||
if (!model || model.is_dead || model.is_reviving) return false;
|
const model = entity.get(HeroAttrsComp);
|
||||||
return true;
|
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 {
|
private isFriendlySkill(group: TGroup): boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user