zoukankan      html  css  js  c++  java
  • [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("技能升级!")
    

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

    结果符合预期

  • 相关阅读:
    动态规划突破
    日志如何进行处理
    多线程相关问题
    Activity工作流框架
    修改模块
    spring多模块搭建Eureka服务器端
    springcould多模块搭建Eureka的服务器端口
    java操作elecsearch
    在elementui和MyBatis中前后端分离中使用shiro
    elementui的和前后端分离的微信登陆功能
  • 原文地址:https://www.cnblogs.com/xdblog/p/15500663.html
Copyright © 2011-2022 走看看