Files
heros/.qoder/repowiki/zh/content/技能执行机制/技能执行机制.md
2025-10-30 16:49:19 +08:00

12 KiB
Raw Blame History

技能执行机制

**本文档中引用的文件** - [SkillConComp.ts](file://assets/script/game/hero/SkillConComp.ts) - [SkillEnt.ts](file://assets/script/game/skill/SkillEnt.ts) - [SkillSet.ts](file://assets/script/game/common/config/SkillSet.ts) - [SkillViewCom.ts](file://assets/script/game/skill/SkillViewCom.ts) - [HeroViewComp.ts](file://assets/script/game/hero/HeroViewComp.ts)

目录

  1. 概述
  2. 核心组件架构
  3. 技能冷却检测机制
  4. 技能施放流程
  5. 多段连发技能机制
  6. 目标选择策略
  7. 异常处理与资源清理
  8. 性能优化考虑
  9. 最佳实践总结

概述

SkillConComp类是游戏技能控制系统的核心组件负责管理英雄的技能冷却、自动施放条件判断以及技能执行流程。该系统采用ECS架构模式结合定时器机制和节点有效性检查实现了复杂的技能逻辑控制。

核心组件架构

classDiagram
class SkillConComp {
+HeroView : HeroViewComp
+HeroEntity : any
+TALCOMP : TalComp
+skill_cd : number
-_timers : object
+init() void
+onLoad() void
+start() void
+update(dt : number) void
+castSkill(config : SkillConfig) void
-doSkill(config : SkillConfig, is_wfuny : boolean, dmg : number) void
+check_wfuny() boolean
+selectTargets(t_num : number) Vec3[]
+clear_timer() void
+reset() void
+onDestroy() void
}
class SkillEnt {
+load(startPos : Vec3, parent : Node, uuid : number, targetPos : any[], caster : HeroViewComp, dmg : number) void
+destroy() void
+init() void
}
class HeroViewComp {
+playSkillEffect(skill_id : number) void
+skills : any[]
+mp : number
+is_atking : boolean
+isStun() boolean
+isFrost() boolean
}
class SkillSet {
+SType : enum
+TGroup : enum
+SkillConfig : interface
}
SkillConComp --> HeroViewComp : "控制"
SkillConComp --> SkillEnt : "创建"
SkillConComp --> SkillSet : "使用配置"
SkillEnt --> SkillViewCom : "包含"

图表来源

章节来源

技能冷却检测机制

update循环中的冷却检测

SkillConComp的update方法实现了精确的技能冷却管理系统

flowchart TD
Start([update循环开始]) --> CheckMission{"检查游戏状态<br/>smc.mission.play && !pause"}
CheckMission --> |否| End([结束])
CheckMission --> |是| CheckStatus{"检查状态<br/>!isStun && !isFrost"}
CheckStatus --> |否| End
CheckStatus --> |是| LoopSkills["遍历技能列表"]
LoopSkills --> AddCD["累积冷却时间<br/>skills[i].cd += dt"]
AddCD --> CheckCD{"冷却完成<br/>cd > cd_max?"}
CheckCD --> |否| NextSkill["下一技能"]
CheckCD --> |是| CheckMP{"检查魔法值<br/>mp >= cost?"}
CheckMP --> |否| NextSkill
CheckMP --> |是| CheckType{"技能类型<br/>SType.damage?"}
CheckType --> |否| NextSkill
CheckType --> |是| CheckAttack{"正在攻击<br/>is_atking?"}
CheckAttack --> |否| NextSkill
CheckAttack --> |是| CastSkill["调用castSkill"]
CastSkill --> ResetCD["重置冷却<br/>skills[i].cd = 0"]
ResetCD --> ConsumeMP["消耗魔法值<br/>mp -= cost"]
ConsumeMP --> NextSkill
NextSkill --> MoreSkills{"还有技能?"}
MoreSkills --> |是| LoopSkills
MoreSkills --> |否| End

图表来源

冷却检测的关键要素

  1. 时间累积机制:每个技能的冷却时间通过skills[i].cd += dt逐步累积
  2. 阈值判断:当冷却时间超过最大冷却时间cd_max时触发
  3. 资源检查:确保魔法值充足this.HeroView.mp >= skills[i].cost
  4. 状态验证:排除眩晕和冰冻状态影响
  5. 攻击状态检查:只有在攻击状态下才允许施放伤害技能

章节来源

技能施放流程

castSkill与doSkill方法调用链

sequenceDiagram
participant Player as "玩家输入/自动触发"
participant SkillCon as "SkillConComp"
participant HeroView as "HeroViewComp"
participant SkillEnt as "SkillEnt"
participant ECS as "ECS系统"
Player->>SkillCon : castSkill(config)
SkillCon->>SkillCon : check_wfuny()
SkillCon->>SkillCon : doSkill(config, wfuny, dmg)
Note over SkillCon : 节点有效性检查
SkillCon->>SkillCon : 检查节点有效性
alt 目标组为Self
SkillCon->>SkillCon : targets = [this.node.position]
else 目标组为Enemy
SkillCon->>SkillCon : selectTargets(config.t_num)
end
SkillCon->>HeroView : playSkillEffect(config.uuid)
HeroView->>HeroView : 播放技能特效
SkillCon->>ECS : ecs.getEntity<SkillEnt>(SkillEnt)
SkillCon->>SkillCon : 创建setTimeout定时器
Note over SkillCon : 延迟执行300ms
SkillCon->>SkillCon : 定时器回调函数
SkillCon->>SkillCon : 再次检查节点有效性
SkillCon->>SkillEnt : sEnt.load(...)
SkillCon->>SkillEnt : load方法
SkillEnt->>SkillEnt : 加载技能预制体
SkillEnt->>SkillEnt : 设置节点属性
SkillEnt->>SkillEnt : 添加SkillViewCom组件
alt wfuny机制启用
SkillCon->>SkillCon : scheduleOnce(doSkill, 0.1)
end
Note over SkillCon : 保存定时器ID
SkillCon->>SkillCon : this._timers[`skill_${config.uuid}`] = timerId

图表来源

节点有效性检查机制

系统实现了双重节点有效性检查:

  1. 初始检查:在doSkill方法开头进行基础节点有效性验证
  2. 延迟检查:在定时器回调函数中再次确认节点状态

这种设计确保了即使在技能施放过程中节点被销毁,也不会导致错误操作。

章节来源

多段连发技能机制

wfuny机制实现原理

wfuny机制是一种基于概率的技能连发系统

flowchart TD
Start([doSkill开始]) --> CheckWfuny{"检查wfuny<br/>check_wfuny()"}
CheckWfuny --> |false| NormalSkill["正常技能执行"]
CheckWfuny --> |true| ScheduleOnce["scheduleOnce(doSkill, 0.1)"]
ScheduleOnce --> RecursiveCall["递归调用doSkill<br/>is_wfuny=false"]
RecursiveCall --> CheckWfuny2{"再次检查wfuny"}
CheckWfuny2 --> |false| FinalExecution["最终技能执行"]
CheckWfuny2 --> |true| ContinueRecursion["继续递归"]
ContinueRecursion --> ScheduleOnce
NormalSkill --> SaveTimer["保存定时器ID"]
FinalExecution --> SaveTimer
SaveTimer --> End([结束])

图表来源

wfuny概率计算

check_wfuny() {
    let random = Math.random() * 100
    if (random < this.HeroView.Attrs[Attrs.WFUNY]) {
        return true
    }
    return false
}

该方法:

  1. 生成0-100之间的随机数
  2. 与英雄的WFUNY属性值比较
  3. 当随机数小于WFUNY值时返回true触发连发

章节来源

目标选择策略

selectTargets方法实现

flowchart TD
Start([selectTargets开始]) --> GetEntities["获取目标实体<br/>check_target()"]
GetEntities --> CheckEmpty{"实体列表为空?"}
CheckEmpty --> |是| DefaultPos["返回默认位置<br/>t_num个相同坐标"]
DefaultPos --> Return([返回目标坐标数组])
CheckEmpty --> |否| FindFront["找到最前排目标<br/>get_front(entities)"]
FindFront --> PushFront["targets.push(frontPos)"]
PushFront --> LoopOthers["循环处理剩余目标<br/>i=1 to t_num-1"]
LoopOthers --> SelectRandom["随机选择实体<br/>Math.floor(Math.random() * entities.length)"]
SelectRandom --> GetRandomPos["获取随机实体位置"]
GetRandomPos --> PushRandom["targets.push(randomPos)"]
PushRandom --> MoreTargets{"还有目标?"}
MoreTargets --> |是| LoopOthers
MoreTargets --> |否| Return

图表来源

目标选择算法详解

  1. 实体获取:通过check_target()方法获取敌方实体列表
  2. 前排优先:第一个目标总是最前排的实体
  3. 随机分布:后续目标从所有可用实体中随机选择
  4. 重复可能:由于随机选择,可能出现重复目标
  5. 默认处理:当没有可用目标时,返回预设的默认位置

默认位置处理逻辑

const defaultPos = this.HeroView.fac === FacSet.HERO ? v3(400, 0, 0) : v3(-400, 0, 0)

系统根据施法者阵营确定默认位置:

  • 英雄阵营x=400
  • 敌人阵营x=-400

章节来源

异常处理与资源清理

定时器管理机制

classDiagram
class TimerManagement {
-_timers : object
+clear_timer() void
+reset() void
+onDestroy() void
}
class TimerOperations {
+Object.values(this._timers).forEach(clearTimeout)
+this._timers = {}
+this.off(GameEvent.CastHeroSkill)
}
TimerManagement --> TimerOperations : "执行"

图表来源

异常处理策略

  1. 节点有效性检查:在关键操作前后检查节点状态
  2. 定时器清理:确保技能执行完成后清理相关定时器
  3. 事件监听移除:在组件销毁时移除事件监听器
  4. 资源释放在组件销毁时释放ECS实体资源

资源清理最佳实践

public clear_timer() {
    Object.values(this._timers).forEach(clearTimeout);
}

reset() {
    this.clear_timer();
}

onDestroy() {
    Object.values(this._timers).forEach(clearTimeout);
    this._timers = {};
    this.off(GameEvent.CastHeroSkill);
}

这些方法确保:

  • 防止内存泄漏
  • 避免僵尸定时器
  • 清理事件监听器
  • 正确释放ECS资源

章节来源

性能优化考虑

定时器优化策略

  1. 延迟执行技能实体创建延迟300ms避免立即创建大量对象
  2. 条件检查:在每次操作前进行有效性检查,防止无效操作
  3. 批量清理:使用Object.values一次性清理所有定时器

内存管理优化

  1. 及时清理:在组件销毁时立即清理所有资源
  2. 弱引用:避免循环引用导致的内存泄漏
  3. 对象池利用ECS系统提供的实体池机制

最佳实践总结

技能系统设计原则

  1. 模块化设计SkillConComp专注于控制逻辑SkillEnt负责实体管理
  2. 事件驱动通过ECS系统实现松耦合的组件通信
  3. 容错机制:多重节点有效性检查确保系统稳定性
  4. 资源管理:完善的定时器和事件监听器清理机制

开发建议

  1. 扩展性考虑:为新的技能类型预留接口
  2. 性能监控:定期检查定时器数量和内存使用情况
  3. 调试支持:保留必要的日志输出便于问题排查
  4. 测试覆盖:确保各种边界情况都有相应的测试用例

这个技能执行机制展现了现代游戏开发中复杂系统的设计精髓,通过合理的架构设计和完善的异常处理,实现了稳定可靠的技能控制系统。