[GODOT]技能系统初探

设计思路

提供一个单例脚本SkillDatabase,提供关于此技能的固定数据,如技能id, 技能名称技能最大等级,技能描述,技能升级消耗等。

提供一个抽象节点,此节点用于描述一个技能,我将此节点注册为一个GoDot新的类型,开发者通过扩展脚本功能完成技能的开发。

SkillDatabase

SkillDatabase 提供get_skill_arg函数来提取技能固定数据,实现如下:

#技能数据库 用于提取技能信息
extends Node

var skills:Dictionary = {}

func _ready():
    init_skill_dic()
    pass

func init_skill_dic() :
    #在此处初始化技能信息, 可以从其他数据库,excel等载体中读取,此处为了示例直接写在代码里
    #请这些技能信息:并非完整的数值信息和伤害逻辑
    skills = {        #id
                    "skill_0000001":{        
                    #最大等级
                    "max_leve": 20,
                    #名称
                    "name":"普通射击",
                    #描述 体现你的伤害逻辑
                    "desp":"对目标位置进行射击, 造成 {base_damage} 物理伤害,如果目标处于眩晕、虚弱、减速等移动受限状态,则伤害提高 {ext_increment}%",
                    #等级提升所需消耗 此处只消耗一项经验值 可以自行扩展为字典,用以消耗多个资源
                    "leve_up_cost": [10,10,10,20,20,20,30,30,50,50,100,100,100,150,150,150,200,300,400]
                },

                "skill_0000002":{
                    #最大等级
                    "max_leve": 30,
                    #名称
                    "name":"精准射击",
                    #描述
                    "desp":"花费时间对这一击精心准备,短暂延迟后,对目标进行精确打击,造成 {base_damage} + {ext_incremnt}%额外物理伤害{damage_out} 此攻击无视目标闪避率",
                    #等级提升所需消耗 此处只消耗一项经验值 可以自行扩展为字典,用以消耗多个资源
                    "leve_up_cost": [10,10,10,20,20,20,30,30,50,50,100,100,100,150,150,150,200,300,400]        
                }
            }
    pass


func get_skill_arg(arg_name:String, id:String) :
    return skills[id][arg_name]

SkillBase

###############技能模型########################
#继承此脚本用以创建新的技能
#需要你初始化的变量 skill_id , skill_level
#需要你重新实现的函数:
#    _replace_skill_var 
##############################################
extends Node
class_name SkillBase
###########以下成员继承后需要子类进行初始化#################
onready var skill_id:String = "x"
onready var skill_level:int  = 0

#技能面板上展示的技能名称
func _get_skill_title() -> String:
    return SkillDatabase.get_skill_arg("name",skill_id) + "(LV" + String(skill_level) + ")"
    pass

#如果你的技能描述中存在变量,例如 : 造成 {base_damage} 物理伤害
#则你必须重写此函数 将_skill_raw_desp 中的 变量 {base_damage} 替换为此技能的实际数值
#默认的实现仅仅返回参数而不做任何事
#func _replace_skill_var(_skill_raw_desp : String) ->String:
#     return _skill_desp.format({"base_damage":20})
func _replace_skill_var(_skill_raw_desp : String) ->String:
    return _skill_raw_desp
    pass


func get_desp_string() -> String:
    var raw_desp:String =  SkillDatabase.get_skill_arg("desp", skill_id)
    return _replace_skill_var(raw_desp)
    pass


#计算技能影响乘区 请根据技能伤害逻辑在子类中实现伤害计算
func _get_skill_damage() -> float :
    return 0.0

#如果是需要选中目标的技能 则返回最大目标数
func _get_skill_target_count() -> int :
    return 0

实现一个技能

新建一个节点,选择新增的 SkillBase 节点

更改节点名称为 Skill_0001(实际项目不要这样取名字...),并选择扩展脚本

按照父节点要求,我们进行如下实现:
在这个脚本中,我们会实现一个简单的技能,技能会拥有完整说明

extends SkillBase

var base_damage :=  0.0
var target_state := "眩晕"

func _ready():
    skill_id = "skill_0000001"
    skill_level = 1
    pass


#计算技能影响乘区 请根据技能伤害逻辑在子类中实现伤害计算
#"对目标位置进行射击, 造成 {base_damage} 物理伤害,如果目标处于眩晕、虚弱、减速等移动受限状态,则伤害提高 {ext_increment}%",
func _get_skill_damage() -> float :
    base_damage = calc_base_damage() #此处可计算其他逻辑 比如伤害加成 什么的。。。。

    #注意 由于只演示技能系统 因此代码与其他系统交互存在不完善, 如此处 ["眩晕","减速","虚弱"] 仅仅是示例, 
    #应该提供一个函数返回所有 移动受限状态
    #且 target_state 应由战斗系统给出 此处仅做示例!!
    if ["眩晕","减速","虚弱"].has(target_state) :
        base_damage += base_damage * calc_ext_increment() / 100.0 
    return 0.0

#如果你的技能描述中存在变量,例如 : 造成 {base_damage} 物理伤害
#则你必须重写此函数 将 skill_var_list 中的 变量 {base_damage} 替换为此技能的实际数值
#默认的实现仅仅返回参数而不做任何事
#func _replace_skill_var(_skill_raw_desp : String) ->String:
#     return _skill_desp.format({"base_damage":20})
func _replace_skill_var(_skill_raw_desp : String) ->String:
    _skill_raw_desp.format({"base_damage":calc_base_damage()})
    _skill_raw_desp.format({"ext_increment":calc_ext_increment()})
    return _skill_raw_desp
    pass


#如果是需要选中目标的技能 则返回最大目标数
func _get_skill_target_count() -> int :
    #只演示最简单的情况
    match skill_level :
        1,5 :
            return 1
        6,20 :
            return 2

    return 0


func calc_base_damage() -> float:
    return skill_level * 15.0
func calc_ext_increment() -> float:
    return 20.0

测试

在场景中添加一个Sprite并添加以下脚本进行测试

extends Sprite
onready var skill = preload("res://Scene/Skill_0001.tscn").instance()

func _ready():    
    print("sprite ready")    
    add_child(skill)
    skill.skill_level = 1

    pass

func _process(delta):
    if Input.is_action_just_pressed("ui_accept") :
        print(skill.skill_id)
        print(skill.skill_level)
        print("技能名称: ",skill._get_skill_title())
        print("技能输出: ",skill._get_skill_damage())
        print("技能描述: ",skill.get_desp_string())
        print("技能目标数: ", skill._get_skill_target_count())


    if Input.is_action_just_pressed("ui_page_up") :
        skill.skill_level += 1
        print("技能升级!")

点击空格键 输出技能信息, 然后我们连续升级,再查看技能信息:

结果符合预期

posted @ 2021-11-02 19:36  Smalldy  阅读(399)  评论(0编辑  收藏  举报