From 61261b97c38c4b372231cb911011e8aa0f6278a6 Mon Sep 17 00:00:00 2001 From: walkpan Date: Sun, 22 Mar 2026 21:26:55 +0800 Subject: [PATCH] =?UTF-8?q?refactor(hero):=20=E9=87=8D=E6=9E=84=E6=8A=80?= =?UTF-8?q?=E8=83=BD=E6=96=BD=E6=94=BE=E7=B3=BB=E7=BB=9F=EF=BC=8C=E5=88=86?= =?UTF-8?q?=E7=A6=BB=E6=95=8C=E5=8F=8B=E6=96=B9=E6=95=88=E6=9E=9C=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 applyPrimaryEffect 拆分为 applyEnemySkillEffects 和 applyFriendlySkillEffects,明确职责边界 - 友方技能现在统一在 applyFriendlySkillEffects 中处理治疗、护盾和 buff 效果 - 移除冗余的 applyExtraEffects 方法,简化逻辑流程 - 为关键方法添加详细注释,提升代码可读性 --- assets/script/game/hero/SCastSystem.ts | 91 +++++++++++++++++++++----- 1 file changed, 73 insertions(+), 18 deletions(-) diff --git a/assets/script/game/hero/SCastSystem.ts b/assets/script/game/hero/SCastSystem.ts index 73294052..b9b402b3 100644 --- a/assets/script/game/hero/SCastSystem.ts +++ b/assets/script/game/hero/SCastSystem.ts @@ -23,9 +23,14 @@ 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, skillLv: 1, isFriendly: false, targetPos: null as Vec3 | null, targetEids: [] as number[] }; + /** 近战英雄默认施法射程 */ private readonly meleeCastRange = 64; + /** 查询缓存:避免每帧重复创建 matcher */ private heroMatcher: ecs.IMatcher | null = null; + + /** 获取英雄查询条件(包含属性与视图组件) */ private getHeroMatcher(): ecs.IMatcher { if (!this.heroMatcher) { this.heroMatcher = ecs.allOf(HeroAttrsComp, HeroViewComp); @@ -33,10 +38,17 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate return this.heroMatcher; } + /** 系统过滤器:仅处理英雄实体 */ filter(): ecs.IMatcher { return this.getHeroMatcher(); } + /** + * 每帧更新: + * 1. 战斗状态校验 + * 2. 英雄施法CD更新与显示 + * 3. 选取本帧可施放技能并执行施法 + */ update(e: ecs.Entity): void { if(!smc.mission.play ) return; if(smc.mission.pause) return @@ -52,6 +64,11 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate this.castSkill(castPlan, heroAttrs, heroView); } + /** + * 选择当前应释放的技能。 + * 选择顺序:技能候选列表顺序 + 条件过滤(CD、目标可达、目标类型匹配)。 + * 返回内容同时包含“对敌施法”和“友方施法”两种执行所需数据。 + */ private pickCastSkill(heroAttrs: HeroAttrsComp, heroView: HeroViewComp): { skillId: number; skillLv: number; isFriendly: boolean; targetPos: Vec3 | null; targetEids: number[] } { const type = heroAttrs.type as HType; const maxRange = this.resolveMaxCastRange(heroAttrs, type); @@ -82,6 +99,12 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate return this.emptyCastPlan; } + /** + * 执行施法: + * - 播放前摇与技能动作 + * - 延迟到出手时机后,按技能目标类型分发到对敌/友方效果处理 + * - 触发技能CD + */ private castSkill(castPlan: { skillId: number; skillLv: number; isFriendly: boolean; targetPos: Vec3 | null; targetEids: number[] }, heroAttrs: HeroAttrsComp, heroView: HeroViewComp) { const s_uuid = castPlan.skillId; const skillLv = castPlan.skillLv; @@ -102,21 +125,25 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate if (castPlan.isFriendly) { const friendlyTargets = this.resolveFriendlyTargets(castPlan.targetEids, heroAttrs.fac); if (friendlyTargets.length === 0) return; - this.applyPrimaryEffect(s_uuid, skillLv, config, heroView,heroAttrs, friendlyTargets, null); - this.applyExtraEffects(config, friendlyTargets); + this.applyFriendlySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, friendlyTargets, null); return; } - this.applyPrimaryEffect(s_uuid, skillLv, config, heroView,heroAttrs, [], castPlan.targetPos); + this.applyEnemySkillEffects(s_uuid, skillLv, config, heroView, heroAttrs, castPlan.targetPos); }, delay); heroAttrs.triggerSkillCD(s_uuid); } + /** 构建技能尝试顺序:优先主动技能,其次普攻 */ private buildSkillCandidates(skillIds: number[]): number[] { if (!skillIds || skillIds.length === 0) return []; if (skillIds.length === 1) return [skillIds[0]]; return [...skillIds.slice(1), skillIds[0]]; } + /** + * 创建技能实体(投射物/范围体等)。 + * 仅用于对敌伤害技能的实体化表现与碰撞伤害分发。 + */ private createSkillEntity(s_uuid: number, skillLv: number, caster: HeroViewComp,cAttrsComp: HeroAttrsComp, targetPos: Vec3) { if (!caster.node || !caster.node.isValid) return; const parent = caster.node.parent; @@ -126,31 +153,36 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate skill.load(caster.node.position.clone(), parent, s_uuid, targetPos.clone(), caster, cAttrsComp, skillLv, 0); } - private applyPrimaryEffect(s_uuid: number, skillLv: number, config: SkillConfig, heroView: HeroViewComp, cAttrsComp: HeroAttrsComp,targets: HeroViewComp[], targetPos: Vec3 | null) { + /** + * 对敌技能效果处理。 + * 当前职责:仅处理伤害技能并创建技能实体。 + */ + private applyEnemySkillEffects(s_uuid: number, skillLv: number, config: SkillConfig, heroView: HeroViewComp, cAttrsComp: HeroAttrsComp, targetPos: Vec3 | null) { const kind = config.kind ?? SkillKind.Damage; - if (kind === SkillKind.Damage) { - if (config.ap <= 0 || !targetPos) return; - this.createSkillEntity(s_uuid, skillLv, heroView,cAttrsComp, targetPos); - return; - } + if (kind !== SkillKind.Damage) return; + if (config.ap <= 0 || !targetPos) return; + this.createSkillEntity(s_uuid, skillLv, heroView, cAttrsComp, targetPos); + } + + /** + * 友方技能效果处理。 + * 当前职责: + * 1. 处理治疗与护盾 + * 2. 处理 buffs 配置追加 + * 3. 保留完整施法信息参数,便于后续扩展更多友方效果 + */ + private applyFriendlySkillEffects(_s_uuid: number, _skillLv: number, config: SkillConfig, _heroView: HeroViewComp, _cAttrsComp: HeroAttrsComp, targets: HeroViewComp[], _targetPos: Vec3 | null) { + const kind = config.kind ?? SkillKind.Support; for (const target of targets) { if (!target.ent) continue; const model = target.ent.get(HeroAttrsComp); if (!model || model.is_dead) continue; if (kind === SkillKind.Heal && config.ap !== 0) { - let addHp = model.add_hp(config.ap, false); + const addHp = model.add_hp(config.ap, false); target.health(addHp); } else if (kind === SkillKind.Shield && config.ap !== 0) { model.add_shield(config.ap, false); } - } - } - //应用额外效果 - private applyExtraEffects(config: SkillConfig, targets: HeroViewComp[]) { - for (const target of targets) { - if (!target.ent) continue; - const model = target.ent.get(HeroAttrsComp); - if (!model || model.is_dead) continue; if (!config.buffs || config.buffs.length === 0) continue; for (const buffConf of config.buffs) { if (!buffConf) continue; @@ -159,6 +191,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate } } + /** 根据目标 eid 列表解析出有效友方视图目标 */ private resolveFriendlyTargets(targetEids: number[], fac: number): HeroViewComp[] { const targets: HeroViewComp[] = []; for (const eid of targetEids) { @@ -174,6 +207,10 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate return targets; } + /** + * 收集可作为友方技能目标的实体 eid。 + * includeSelf 控制是否包含施法者自身。 + */ private collectFriendlyTargetEids(fac: number, selfEid: number | undefined, includeSelf: boolean): number[] { const eids: number[] = []; ecs.query(this.getHeroMatcher()).forEach(entity => { @@ -189,20 +226,27 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate return eids; } + /** 判定施法计划是否具备有效目标 */ private hasCastTarget(castPlan: { skillId: number; skillLv: 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 { return group === TGroup.Team || group === TGroup.Ally; } + /** 是否为自我目标技能 */ private isSelfSkill(group: TGroup): boolean { return group === TGroup.Self; } + /** + * 在施法距离内查找最近敌人。 + * 用于单体技能与基础目标参考。 + */ private findNearestEnemyInRange(heroAttrs: HeroAttrsComp, heroView: HeroViewComp, maxRange: number): HeroViewComp | null { if (!heroView.node) return null; const currentX = heroView.node.position.x; @@ -223,6 +267,10 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate return nearest; } + /** + * 在施法距离内查找“最前排”敌人。 + * 依据施法者面向方向选择 x 轴上更前的目标。 + */ private findFrontEnemyInRange(heroAttrs: HeroAttrsComp, heroView: HeroViewComp, maxRange: number, nearestEnemy: HeroViewComp): HeroViewComp | null { if (!heroView.node || !nearestEnemy.node) return null; const currentX = heroView.node.position.x; @@ -250,6 +298,11 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate return frontEnemy; } + /** + * 解析对敌技能目标点: + * - 非范围技能:按施法方向生成目标点 + * - 范围技能:优先前排敌人位置 + */ private resolveEnemyCastTargetPos(config: SkillConfig, heroAttrs: HeroAttrsComp, heroView: HeroViewComp, nearestEnemy: HeroViewComp, maxRange: number): Vec3 | null { if (config.DTType !== DTType.range) { return this.buildEnemyCastTargetPos(heroView, nearestEnemy, maxRange); @@ -259,6 +312,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate return frontEnemy.node.position.clone(); } + /** 计算英雄最大施法距离(优先缓存,其次按职业类型) */ private resolveMaxCastRange(heroAttrs: HeroAttrsComp, type: HType): number { const cached = heroAttrs.getCachedMaxSkillDistance(); if (cached > 0) return cached; @@ -267,6 +321,7 @@ export class SCastSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate return this.meleeCastRange; } + /** 生成沿目标方向的施法目标坐标 */ private buildEnemyCastTargetPos(caster: HeroViewComp, target: HeroViewComp, castRange: number): Vec3 { const casterPos = caster.node.position; const targetPos = target.node.position;