架构改良——SkillSystem
本文最后更新于16 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

为解决BattleManager和Character越来越笨重的问题 ,将这两个“总导演”拆分为不同的具体的角色

解决battlemanager——设计模式:

单例模式(Singleton Pattern)是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点来获取这个实例

因为技能和效果的处理是一项通用的服务

核心目的:

  • 控制某个类的实例数量(只允许一个)。
  • 全局访问,避免频繁创建和销毁对象。

主要特点:

  • 私有化构造函数:防止外部直接 new 创建实例。
  • 静态私有实例变量:保存类的唯一实例。
  • 静态公有方法:提供全局访问点(如 getInstance()),在该方法中创建或返回已有实例。

给Character瘦身——组件化设计,将一个庞大对象的不同功能分成一个个可以插拔的组件脚本中,character本身只作为一个组件的容器/视图层,负责管理和协调组件

项目设置—全局——自动加载可以将某个脚本作为全局的可以访问的单例

我来帮你详细分析 skill_system.gd 脚本文件。首先让我读取这个文件的内容。

toolName: view_files

status: success

filePath: d:\Desktop\Godot\course\28技能系统组件化重构\scripts\autoload\skill_system.gd

让我先了解一下项目的整体结构,以便更好地分析技能系统与其他系统的交互。

toolName: view_folder

status: success

d:\Desktop\Godot\course\28技能系统组件化重构

toolName: file_search

status: success

file_pattern: */.gd

toolName: view_files

status: success

filePath: d:\Desktop\Godot\course\28技能系统组件化重构\scripts\core\battle_manager.gd

toolName: view_files

status: success

filePath: d:\Desktop\Godot\course\28技能系统组件化重构\scripts\resources\skill_data.gd

toolName: view_files

status: success

filePath: d:\Desktop\Godot\course\28技能系统组件化重构\scripts\resources\skill_effect_data.gd

toolName: view_files

status: success

filePath: d:\Desktop\Godot\course\28技能系统组件化重构\scenes\characters\character.gd

现在让我查看一些具体的效果实现类,以便更全面地理解技能系统的工作机制。

toolName: view_files

status: success

filePath: d:\Desktop\Godot\course\28技能系统组件化重构\scripts\resources\skill_effect_data\damage_effect_data.gd

toolName: view_files

status: success

filePath: d:\Desktop\Godot\course\28技能系统组件化重构\scripts\resources\skill_effect_data\heal_effect_data.gd

toolName: view_files

status: success

filePath: d:\Desktop\Godot\course\28技能系统组件化重构\scripts\core\character\character_skill_component.gd

SkillSystem 技能系统详细分析

一、系统架构定位

1.1 在项目中的角色

skill_system.gd 作为 自动加载的单例(Autoload),是整个技能系统的核心协调器。它不直接依赖战斗系统组件,而是通过上下文(SkillExecutionContext)获取必要信息,实现了良好的解耦设计。

1.2 与其他系统的关系

┌─────────────────────────────────────────────────────────────┐
│                    BattleManager                            │
│              (战斗流程控制、回合管理)                         │
└──────────────────────┬──────────────────────────────────────┘
                       │ 调用
                       ↓
┌─────────────────────────────────────────────────────────────┐
│                   SkillSystem (单例)                         │
│            (技能执行核心逻辑、效果协调)                        │
└──────┬──────────────────────────────────────────┬───────────┘
       │                                          │
       │ 使用                                    │ 使用
       ↓                                          ↓
┌──────────────────┐                    ┌──────────────────┐
│    Character     │                    │   SkillEffectData │
│  (角色实体)       │                    │  (效果数据资源)   │
│  - 属性管理       │                    │  - 伤害效果       │
│  - 状态管理       │                    │  - 治疗效果       │
│  - 技能列表       │                    │  - 状态效果       │
└──────────────────┘                    └──────────────────┘

二、核心功能模块

2.1 技能执行上下文(SkillExecutionContext)

class SkillExecutionContext:
    var battle_manager : BattleManager

    func _init(local_battle_manager : BattleManager = null) -> void:
        battle_manager = local_battle_manager

设计目的:将战斗管理器引用封装在上下文中,避免技能系统直接依赖战斗系统,实现松耦合。

2.2 信号系统

信号名称参数触发时机
skill_execution_startedcaster, skill, targets技能开始执行
skill_execution_completedcaster, skill, targets, results技能执行完成
skill_failedcaster, skill, reason技能执行失败
effect_appliedeffect, source, target, result单个效果应用完成

这些信号允许其他系统(如UI、音效、动画系统)监听并响应技能事件。

三、核心函数详解

3.1 技能执行入口:attempt_execute_skill()

函数签名

func attempt_execute_skill(
    skill_data: SkillData, 
    caster: Character, 
    selected_targets: Array[Character], 
    context: SkillExecutionContext
) -> Dictionary

执行流程

1. 参数验证
   ├─ 检查 caster 和 skill_data 有效性
   └─ 无效则发出 skill_failed 信号并返回空字典

2. 技能可用性验证 (_validate_skill_usability)
   ├─ 检查 MP 是否足够
   ├─ 检查目标选择是否有效
   └─ 验证失败则显示错误信息并返回

3. 发出 skill_execution_started 信号

4. 消耗资源 (_consume_skill_resources)
   └─ 扣除施法者的 MP

5. 异步处理技能效果 (_process_skill_effects_async)
   └─ 使用 await 等待效果处理完成

6. 返回执行结果

关键代码分析

# 验证施法条件
var validation_result = _validate_skill_usability(skill_data, caster, selected_targets, context)
if not validation_result.is_usable:
    skill_failed.emit(caster, skill_data, validation_result.reason)
    if context.battle_manager and context.battle_manager.has_method("show_status_text"):
        context.battle_manager.show_status_text(caster, validation_result.reason, true)
    return {"error": validation_result.reason}

# 消耗资源
_consume_skill_resources(caster, skill_data)

# 异步处理效果
var result = await _process_skill_effects_async(skill_data, caster, selected_targets, context)

3.2 技能验证:_validate_skill_usability()

验证内容

  1. MP 检查
if caster.current_mp < skill.mp_cost:
    result.is_usable = false
    result.reason = "Not enough MP"
    return result
  1. 目标类型验证
    根据技能的 target_type 枚举值,验证目标选择是否合法:
目标类型验证逻辑
NONE无需目标
SELF目标为施法者自己
ENEMY_SINGLE单个敌方目标
ALLY_SINGLE单个友方目标(不含自己)
ALLY_SINGLE_INC_SELF单个友方目标(含自己)
ENEMY_ALL所有敌方目标
ALLY_ALL所有友方目标(不含自己)
ALLY_ALL_INC_SELF所有友方目标(含自己)
  1. 目标有效性验证
if not _validate_skill_targets(skill, actual_targets_for_validation):
    result.is_usable = false
    result.reason = "Invalid target(s) for skill scope"
    return result

3.3 效果处理核心:_process_skill_effects_async()

执行流程

1. 确定实际执行目标 (_determine_execution_targets)
   └─ 根据 skill.target_type 和 selected_targets 计算最终目标列表

2. 播放施法动画
   ├─ 如果 battle_manager 有 play_casting_animation 方法,调用它
   └─ 否则等待 0.5 秒模拟施法时间

3. 遍历每个目标
   └─ 对每个目标应用技能的所有效果

4. 对每个效果
   ├─ 确定效果的实际目标 (_determine_targets_for_effect)
   ├─ 应用单个效果 (_apply_single_effect)
   └─ 等待 0.1 秒使效果更自然

5. 发出 skill_execution_completed 信号

6. 返回整体结果

关键代码

# 确定实际目标
var actual_execution_targets = _determine_execution_targets(
    caster, skill_data, initial_selected_targets, context
)

# 播放施法动画
if context.battle_manager and context.battle_manager.has_method("play_casting_animation"):
    await context.battle_manager.play_casting_animation(caster, skill_data)
else:
    await get_tree().create_timer(0.5).timeout

# 处理每个效果
for target in actual_execution_targets:
    for effect in skill_data.effects:
        var effect_targets = _determine_targets_for_effect(caster, effect, [target], context)
        for effect_target in effect_targets:
            var effect_result = await _apply_single_effect(caster, effect_target, effect, context)
            overall_results[target][key] = effect_result[key]
            await get_tree().create_timer(0.1).timeout

3.4 单个效果应用:_apply_single_effect()

实现原理

func _apply_single_effect(
    caster: Character, 
    target: Character, 
    effect: SkillEffectData, 
    _context: SkillExecutionContext
) -> Dictionary:
    # 1. 参数验证
    if !is_instance_valid(caster) or !is_instance_valid(target):
        push_error("SkillSystem: 无效的角色引用")
        return {}

    if not effect:
        push_error("SkillSystem: 无效的效果引用")
        return {}

    # 2. 调用效果的处理方法(多态)
    var result = await effect.process_effect(caster, target)

    # 3. 发出效果应用信号
    effect_applied.emit(effect, caster, target, result)

    return result

多态设计SkillEffectData 是基类,具体效果(如 DamageEffectDataHealEffectData)继承并重写 process_effect() 方法。

3.5 目标确定逻辑

_determine_execution_targets()

match skill.target_type:
    SkillData.TargetType.SELF:
        final_targets.append(caster)
    SkillData.TargetType.ALLY_ALL:
        final_targets = context.battle_manager.get_valid_ally_targets(false, caster)
    SkillData.TargetType.ENEMY_ALL:
        final_targets = context.battle_manager.get_valid_enemy_targets(caster)
    # ... 其他目标类型

_determine_targets_for_effect()
支持效果级别的目标覆盖,例如:

  • self_only:效果只影响施法者
  • all_allies:效果影响所有友方
  • all_enemies:效果影响所有敌方

四、与其他系统的交互

4.1 与 BattleManager 的交互

调用方式

# 获取有效目标
context.battle_manager.get_valid_ally_targets(include_self, caster)
context.battle_manager.get_valid_enemy_targets(caster)

# 播放动画
context.battle_manager.play_casting_animation(caster, skill_data)

# 显示状态文本
context.battle_manager.show_status_text(caster, reason, is_error)

依赖关系:通过 SkillExecutionContext 间接访问,避免直接依赖。

4.2 与 Character 系统的交互

属性访问

caster.current_mp          # 当前 MP
caster.attack_power        # 攻击力
caster.defense_power       # 防御力
caster.magic_attack        # 魔法攻击
caster.is_alive            # 存活状态

方法调用

caster.use_mp(amount)      # 消耗 MP
caster.take_damage(damage) # 受到伤害
caster.heal(amount)        # 恢复生命

4.3 与 SkillEffectData 的交互

效果处理流程

SkillSystem._apply_single_effect()
    ↓
SkillEffectData.process_effect() [虚方法]
    ↓
具体效果类重写:
    ├─ DamageEffectData.process_effect()
    ├─ HealEffectData.process_effect()
    └─ ApplyStatusEffectData.process_effect()

视觉效果请求

# SkillEffectData 基类提供
_request_visual_effect("cast", caster, {})
_request_visual_effect("hit", target, {})
_request_visual_effect("heal", target, {})

4.4 与 CharacterSkillComponent 的交互

状态效果处理

# 在 CharacterSkillComponent 中
func apply_status(status_template, source_character, effect_data):
    # 应用状态效果
    # 触发初始效果
    SkillSystem.attempt_process_status_effects(
        runtime_status_instance.initial_effects,
        runtime_status_instance.source_character,
        get_parent(),
        SkillSystem.SkillExecutionContext.new()
    )

五、游戏运行时的调用机制

5.1 典型调用链

玩家选择技能
    ↓
BattleScene -> BattleManager.player_select_action()
    ↓
Character.execute_action()
    ↓
CharacterCombatComponent.execute_action()
    ↓
SkillSystem.attempt_execute_skill()
    ↓
[技能执行流程]
    ↓
返回结果
    ↓
BattleManager 检查战斗结束条件
    ↓
切换到下一个回合

5.2 异步处理机制

为什么使用异步

  • 技能效果需要按顺序播放动画
  • 需要等待视觉效果完成
  • 需要在效果之间添加延迟以增强视觉体验

异步实现

# 使用 await 等待异步操作
var result = await _process_skill_effects_async(skill_data, caster, selected_targets, context)

# 在效果处理中等待动画
await context.battle_manager.play_casting_animation(caster, skill_data)

# 在效果之间添加延迟
await get_tree().create_timer(0.1).timeout

六、设计模式和最佳实践

6.1 使用的设计模式

  1. 单例模式:作为自动加载的全局访问点
  2. 策略模式:不同的 SkillEffectData 子类实现不同的效果策略
  3. 上下文模式SkillExecutionContext 封装执行环境
  4. 观察者模式:通过信号系统实现事件通知
  5. 模板方法模式process_effect() 定义效果处理框架

6.2 代码质量特点

  1. 解耦设计:通过上下文避免直接依赖战斗系统
  2. 异步友好:使用 await 支持动画和延迟
  3. 错误处理:完善的参数验证和错误信号
  4. 可扩展性:通过继承 SkillEffectData 轻松添加新效果
  5. 可测试性:通过上下文注入依赖,便于单元测试

七、总结

skill_system.gd 是整个技能系统的核心协调器,它:

  1. 不直接依赖战斗系统,通过上下文获取必要信息
  2. 统一管理技能的执行流程,包括验证、资源消耗、效果处理
  3. 提供信号让其他系统监听和响应技能事件
  4. 支持异步处理,确保动画和效果的正确时序
  5. 易于扩展,通过继承 SkillEffectData 可以添加新的效果类型

这种设计使得技能系统既强大又灵活,能够支持复杂的技能效果组合,同时保持代码的可维护性和可扩展性。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇