refactor(skill): 重构技能触发逻辑,提取统一工具类
将分散在Hero、Mon、HeroAtkSystem、SCastSystem、MissionComp中的技能触发代码统一封装,集中处理触发次数加成、实体合法性校验与技能事件派发,同时新增SkillTriggerType枚举统一管理技能触发类型,简化业务调用并消除重复模板代码。
This commit is contained in:
153
assets/script/game/hero/SkillTriggerHelper.ts
Normal file
153
assets/script/game/hero/SkillTriggerHelper.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { GameEvent, SkillTriggerType } from "../common/config/GameEvent";
|
||||
import { HeroAttrsComp } from "./HeroAttrsComp";
|
||||
import { HeroViewComp } from "./HeroViewComp";
|
||||
import { FacSet } from "../common/config/GameSet";
|
||||
import { FieldSkillType } from "../common/config/SkillSet";
|
||||
import { TalentType } from "../common/config/TalentSet";
|
||||
import { smc } from "../common/SingletonModuleComp";
|
||||
|
||||
|
||||
/**
|
||||
* 特殊触发技能的统一中介者 (Mediator)
|
||||
*
|
||||
* 核心职责:
|
||||
* 1. 统一管理英雄/怪物的各类生命周期触发技能(召唤、死亡、战前、战后、攻受击)。
|
||||
* 2. 集中处理触发次数的计算(如:局内羁绊加成、局外天赋加成)。
|
||||
* 3. 作为唯一出口,通过事件总线向 SCastSystem 派发 GameEvent.TriggerSkill 事件。
|
||||
*
|
||||
* 优势:
|
||||
* - 极大地解耦了具体业务组件(Hero/Mon/HeroAtkSystem/MissionComp)与技能系统。
|
||||
* - 避免了原先散落在各处的判定逻辑和冗余的事件派发代码。
|
||||
*/
|
||||
export class SkillTriggerHelper {
|
||||
/**
|
||||
* 统一的技能触发入口
|
||||
* 根据传入的触发类型,自动分发到对应的处理函数中执行判定和加成逻辑。
|
||||
*
|
||||
* @param type 触发类型枚举 (SkillTriggerType)
|
||||
* @param model 施法者的属性数据组件 (HeroAttrsComp)
|
||||
* @param view 施法者的视图表现组件 (HeroViewComp)
|
||||
*/
|
||||
public static trigger(type: SkillTriggerType, model: HeroAttrsComp, view: HeroViewComp) {
|
||||
// 健壮性检查:若实体或节点已被销毁,直接阻断,防止空指针报错
|
||||
if (!model || !view || !view.node || !view.node.isValid) return;
|
||||
|
||||
switch (type) {
|
||||
case SkillTriggerType.Call:
|
||||
this.handleCall(model, view);
|
||||
break;
|
||||
case SkillTriggerType.Dead:
|
||||
this.handleDead(model, view);
|
||||
break;
|
||||
case SkillTriggerType.FStart:
|
||||
this.handleArrayTrigger(model.fstart, model, view, type);
|
||||
break;
|
||||
case SkillTriggerType.FEnd:
|
||||
this.handleArrayTrigger(model.fend, model, view, type);
|
||||
break;
|
||||
case SkillTriggerType.Atking:
|
||||
this.handleAtking(model, view);
|
||||
break;
|
||||
case SkillTriggerType.Atked:
|
||||
this.handleAtked(model, view);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理召唤(落地)触发技能
|
||||
* 支持受【召唤强化羁绊 (SummonCount)】和【召唤强化天赋 (TalentType.Summon)】的多次触发加成。
|
||||
*/
|
||||
private static handleCall(model: HeroAttrsComp, view: HeroViewComp) {
|
||||
if (!model.call || model.call.length === 0) return;
|
||||
|
||||
let triggerCount = 1;
|
||||
// 仅英雄享受加成,怪物始终只触发 1 次
|
||||
if (model.fac === FacSet.HERO) {
|
||||
triggerCount += HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.SummonCount);
|
||||
triggerCount += HeroAttrsComp.getTalentValue(TalentType.Summon);
|
||||
}
|
||||
triggerCount = Math.max(1, Math.floor(triggerCount)); // 确保最少触发 1 次
|
||||
|
||||
for (let i = 0; i < triggerCount; i++) {
|
||||
this.dispatchArray(model.call, model, view, SkillTriggerType.Call);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理死亡触发技能
|
||||
* 支持受【亡语强化羁绊 (DeadCount)】的多次触发加成。
|
||||
*/
|
||||
private static handleDead(model: HeroAttrsComp, view: HeroViewComp) {
|
||||
if (!model.dead || model.dead.length === 0) return;
|
||||
|
||||
let triggerCount = 1;
|
||||
if (model.fac === FacSet.HERO) {
|
||||
triggerCount += HeroAttrsComp.getFieldSkillTotalValue(FieldSkillType.DeadCount);
|
||||
// 【局内战绩评分系统】统计死亡触发技能生效次数(用于局后防守评分结算)
|
||||
smc.vmdata.scores.dead_trigger_count += model.dead.length;
|
||||
}
|
||||
triggerCount = Math.max(1, Math.floor(triggerCount));
|
||||
|
||||
for (let i = 0; i < triggerCount; i++) {
|
||||
this.dispatchArray(model.dead, model, view, SkillTriggerType.Dead);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理攻击附加技能
|
||||
* 判定逻辑:依据配置中的 t_num(触发所需普攻次数),对比当前的普攻累计次数取模判定。
|
||||
*/
|
||||
private static handleAtking(model: HeroAttrsComp, view: HeroViewComp) {
|
||||
if (!model.atking || model.atking.length === 0) return;
|
||||
model.atking.forEach(atkConfig => {
|
||||
// atk_count 代表已进行的普攻次数。当其余数刚好整除配置阈值时触发。
|
||||
if (model.atk_count > 0 && model.atk_count % atkConfig.t_num === 0) {
|
||||
this.dispatchSingle(atkConfig.s_uuid, model, view, SkillTriggerType.Atking);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理受击附加技能
|
||||
* 判定逻辑:依据配置中的 t_num(触发所需受击次数),对比当前的受击累计次数取模判定。
|
||||
*/
|
||||
private static handleAtked(model: HeroAttrsComp, view: HeroViewComp) {
|
||||
if (!model.atked || model.atked.length === 0) return;
|
||||
model.atked.forEach(atkConfig => {
|
||||
// atked_count 代表已承受的受击次数。当其余数刚好整除配置阈值时触发。
|
||||
if (model.atked_count > 0 && model.atked_count % atkConfig.t_num === 0) {
|
||||
this.dispatchSingle(atkConfig.s_uuid, model, view, SkillTriggerType.Atked);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的数组型触发器处理(适用于 FStart / FEnd 等无需额外判定的简单列表触发)
|
||||
*/
|
||||
private static handleArrayTrigger(uuids: number[] | undefined, model: HeroAttrsComp, view: HeroViewComp, type: SkillTriggerType) {
|
||||
if (!uuids || uuids.length === 0) return;
|
||||
this.dispatchArray(uuids, model, view, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量派发技能事件
|
||||
*/
|
||||
private static dispatchArray(uuids: number[], model: HeroAttrsComp, view: HeroViewComp, type: SkillTriggerType) {
|
||||
uuids.forEach(uuid => this.dispatchSingle(uuid, model, view, type));
|
||||
}
|
||||
|
||||
/**
|
||||
* 单一技能事件派发底层接口
|
||||
* 事件发出后,将由 SCastSystem 的 forceCastTriggerSkill 监听拦截并执行无视CD的强制施法
|
||||
*/
|
||||
private static dispatchSingle(s_uuid: number, model: HeroAttrsComp, view: HeroViewComp, type: SkillTriggerType) {
|
||||
oops.message.dispatchEvent(GameEvent.TriggerSkill, {
|
||||
s_uuid: s_uuid,
|
||||
heroAttrs: model,
|
||||
heroView: view,
|
||||
triggerType: type
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user