查看: 71|回复: 0

[转载发布] 技能树系统

[复制链接]
  • TA的每日心情
    开心
    7 天前
  • 签到天数: 37 天

    连续签到: 3 天

    [LV.5]常住居民I

    2028

    主题

    32

    回帖

    7260

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    VIP
    0
    卡币
    5184
    OK点
    16
    积分
    7260
    发表于 同元一千年八月四日(秋) | 显示全部楼层 |阅读模式
    不知道有没有别人做过这个东西呢……自己花一晚上写的这些,拿出来跟大家分享一下。
    具体的说明都在代码里面了,有什么地方不明白的尽管在帖子里面问啊!
    1. #==============================================================================# 技能树系统 Ver 1.0# 作者:RyanBern#------------------------------------------------------------------------------# 功能特色:#     开放技能点增加系统,每一个角色都有自己独特的技能成长历程。#     通过获得技能点来让技能变得更加强大。在学习技能的过程中,可以解锁同种技能#     的更高级别,也可以解锁威力更大的技能。#     主角的一切技能成长都遵循您的意愿!#==============================================================================# 使用方法#     在脚本的第 88 行起定义你的自定义技能树。#     注意,要一个一个角色的定义,因为不同角色的技能树肯定不同。#     核心定义脚本actor.set_data(id,ar1,ar2)#     id  :你要定义的技能ID#     ar1 :是一个数组,记录着该技能的前置技能的ID(这就意味着一个技能的前置技能#          可以有多个),角色必须学会这个技能的所有前置技能才可以学习该技能。#     ar2 :是一个数组,记录着该技能学会之后,可能开启的后置技能。#          设置ar2主要是为了描绘方便,但是会增加使用者的工作量。#     ar1和ar2可以为空,表示该技能没有前置技能或后置技能,用空的方括号[]表示#------------------------------------------------------------------------------#     定义范例:#     # 1号角色#     actor = Game_Skill_Tree.new#     actor.set_data(1,[],[2]) # 定义ID为1的技能,不需要前置技能,可能开启ID为2的技能#     actor.set_data(2,[1],[3,4])#     actor.set_data(3,[2],[4]) # 定义ID为3的技能,前置技能为ID 2,后置技能为ID 4#     actor.set_data(4,[2,3],[])#     actor.skills.sort!#     data.push(actor)#     # 1号角色定义完毕#------------------------------------------------------------------------------#  ※ 默认每个人升5级就能获得1技能点,即角色在5,10,15...级会得到技能点,如果想#     改变获得技能点的级数,请改下面的  SKILLS_PTS_STEP = 5#  ※ 默认每次打到规定登记会获得1个技能点,如果想改变每次获得的技能点个数,请#     改下面的  UPGRADE_GAIN = 1#  ※ 默认每个技能学习消耗1个技能点,这个暂时不支持更改-_-||#  ※ 角色各自的技能点保存在游戏的变量当中(也就是$game_variables中),默认保存#     的位置是 NUMBER_SHIFT + 角色的ID,即如果NUMBER_SHIFT == 0,则ID为1的角色#     的技能点数保存在1号变量中,以此类推。当然考虑到这个位置可能实现保存了编者#     的其它数据,固设置数据位移量NUMBER_SHIFT,如果你想从101号变量开始保存,#     只需要改 NUMBER_SHIFT = 100#------------------------------------------------------------------------------#  ※ 考虑到主菜单场景大家改起来不方便,可以用事件在地图上进行调用。#  ※ 方法是建立一个新事件,使用脚本$scene = Scene_Skill_Tree.new即可。#  ※ 当然会写脚本的同学可以把它融入到主菜单中。#  ※ 使用PageUP和PageDown可以在不同角色之间进行切换#==============================================================================# 界面说明:#     玩家已经习得的技能用黄色字体表示#     玩家能够学习的技能用白色表示#     没有达到学习条件的技能用灰色表示#     已经达到学习条件的,但是技能点不足,无法学习的技能,用红色表示#     在前置技能中,已经学到的技能用白色表示,并且后面有个“√”#     在前置技能中,没有学到的技能用灰色表示#==============================================================================SKILL_PTS_STEP = 5UPGRADE_GAIN = 1NUMBER_SHIFT = 0class Game_Skill_Tree  attr_accessor :skills  attr_reader   :prev_skills  attr_reader   :next_skills  def initialize    @skills = []    @prev_skills = {}    @next_skills = {}  end  #----------------------------------------------------------------------------  # 定义数据类型  # skill_id :要定义的技能id  # pre_skills :要定义技能之前置技能,是一个数组  # post_skills :要定义技能之后置技能,是一个数组  #----------------------------------------------------------------------------  def set_data(skill_id,pre_skills,post_skills)    @skills.push(skill_id)    @prev_skills[skill_id] = pre_skills    @next_skills[skill_id] = post_skills  endenddef get_skill_tree  data = [nil]  # 开始定义各个主角的技能树  # 1号角色  # 1号角色定义完毕  return data endclass Game_Actor  #--------------------------------------------------------------------------  # ● 更改 EXP  #     exp : 新的 EXP  #--------------------------------------------------------------------------  def exp=(exp)    [url=home.php?mod=space&uid=13302]@exp[/url] = [[exp, 9999999].min, 0].max    # 升级    while [url=home.php?mod=space&uid=13302]@exp[/url] >= @exp_list[@level+1] and @exp_list[@level+1] > 0      [url=home.php?mod=space&uid=22147]@level[/url] += 1      # 学会特技      for j in $data_classes[@class_id].learnings        if j.level == @level          learn_skill(j.skill_id)        end      end      # 达到技能点要求就增加技能点      if [url=home.php?mod=space&uid=22147]@level[/url] % SKILL_PTS_STEP == 0        $game_variables[NUMBER_SHIFT + self.id] += UPGRADE_GAIN      end    end    # 降级    while @exp < @exp_list[@level]      @level -= 1    end    # 修正当前的 HP 与 SP 超过最大值    @hp = [@hp, self.maxhp].min    @sp = [@sp, self.maxsp].min  end  def skill_can_learn?(skill_id)    skill_tree = $data_skilltree[self.id]    # 没有对应设置,返回false    if skill_tree == nil      return false    end    skills_need = skill_tree.prev_skills[skill_id]    # 不在技能树中的技能无法习得    if skills_need == nil      return false    end    # 逐个检查    for i in skills_need      # 如果有前置技能没有学习      unless skill_learn?(i)        return false      end    end    # 前置技能全部都学习了    return true  endend#==============================================================================# ■ Window_Skill_Tree#------------------------------------------------------------------------------#  技能树场景中,显示所有技能的窗口。#==============================================================================class Window_Skill_Tree < Window_Selectable  #--------------------------------------------------------------------------  # ● 初始化对像  #     actor : 角色  #--------------------------------------------------------------------------  def initialize(actor)    super(0, 128, 180, 352)    [url=home.php?mod=space&uid=95897]@actor[/url] = actor    @skill_tree = $data_skilltree[@actor.id]    @column_max = 1    refresh    self.index = 0  end  #--------------------------------------------------------------------------  # ● 获取特技  #--------------------------------------------------------------------------  def skill    return @data[self.index]  end  #--------------------------------------------------------------------------  # ● 刷新  #--------------------------------------------------------------------------  def refresh    if self.contents != nil      self.contents.dispose      self.contents = nil    end    @data = []    # 没有技能树,返回    if @skill_tree == nil      return    end    for i in 0...@skill_tree.skills.size      skill = $data_skills[@skill_tree.skills[i]]      if skill != nil        @data.push(skill)      end    end    # 如果项目数不是 0 就生成位图、重新描绘全部项目    @item_max = @data.size    if @item_max > 0      self.contents = Bitmap.new(width - 32, row_max * 32)      for i in 0...@item_max        draw_item(i)      end    end  end  #--------------------------------------------------------------------------  # ● 描绘项目  #     index : 项目编号  #--------------------------------------------------------------------------  def draw_item(index)    skill = @data[index]    if @actor.skill_learn?(skill.id)      self.contents.font.color = crisis_color    elsif @actor.skill_can_learn?(skill.id)      if $game_variables[NUMBER_SHIFT + @actor.id] > 0        self.contents.font.color = normal_color      else        self.contents.font.color = knockout_color      end    else      self.contents.font.color = disabled_color    end    x = 4    y = index  * 32    rect = Rect.new(x, y, self.width / @column_max - 32, 32)    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))    bitmap = RPG::Cache.icon(skill.icon_name)    opacity = self.contents.font.color == disabled_color ? 128 : 255    self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)    self.contents.draw_text(x + 28, y, 140, 32, skill.name, 0)  end  #--------------------------------------------------------------------------  # ● 刷新帮助文本  #--------------------------------------------------------------------------  def update_help    @help_window.set_text(self.skill == nil ? "" : self.skill.description)  endend#==============================================================================# ■ Window_Skill_Tree_Status#------------------------------------------------------------------------------#  技能树界面中,显示特技画面、特技使用者的窗口。#==============================================================================class Window_Skill_Tree_Status < Window_Base  #--------------------------------------------------------------------------  # ● 初始化对像  #     actor : 角色  #--------------------------------------------------------------------------  def initialize(actor)    super(0, 64, 640, 64)    self.contents = Bitmap.new(width - 32, height - 32)    [url=home.php?mod=space&uid=95897]@actor[/url] = actor    refresh  end  #--------------------------------------------------------------------------  # ● 刷新  #--------------------------------------------------------------------------  def refresh    self.contents.clear    draw_actor_name(@actor, 4, 0)    draw_actor_state(@actor, 140, 0)    self.contents.font.color = system_color    self.contents.draw_text(360, 0, 160, 32, "可用技能点:")    skill_pt = $game_variables[NUMBER_SHIFT + @actor.id]    if skill_pt == 0      self.contents.font.color = knockout_color    else      self.contents.font.color = normal_color    end    self.contents.draw_text(496, 0, 64, 32, skill_pt.to_s, 2)  endendclass Window_Skill_Prev < Window_Base  def initialize(actor,skill)    super(180, 192, 230, 288)    self.contents = Bitmap.new(width - 32, height - 32)    @actor = actor    [url=home.php?mod=space&uid=260100]@skill[/url] = skill    refresh  end  def skill=(skill)    if [url=home.php?mod=space&uid=260100]@skill[/url] != skill      @skill = skill      refresh    end  end  def refresh    self.contents.clear    skill_tree = $data_skilltree[@actor.id]    # 没有技能树,结束描绘    if skill_tree == nil or @skill == nil      return    end    skills_need = skill_tree.prev_skills[@skill.id]    skills_need.sort!    for i in 0...skills_need.size      x = 4      y = i * 32      skill = $data_skills[skills_need[i]]      if @actor.skill_learn?(skills_need[i])        self.contents.font.color = normal_color        tag = "√"        opacity = 255      else        self.contents.font.color = disabled_color        tag = ""        opacity = 128      end      bitmap = RPG::Cache.icon(skill.icon_name)      self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)      self.contents.draw_text(x + 28, y, 166, 32, skill.name + tag, 0)    end  endendclass Window_Skill_Next < Window_Base  def initialize(actor,skill)    super(410, 192, 230, 288)    self.contents = Bitmap.new(width - 32, height - 32)    @actor = actor    @skill = skill    refresh  end  def skill=(skill)    if @skill != skill      @skill = skill      refresh    end  end  def refresh    self.contents.clear    skill_tree = $data_skilltree[@actor.id]    # 没有技能树,结束描绘    if skill_tree == nil or @skill == nil      return    end    skills_next = skill_tree.next_skills[@skill.id]    skills_next.sort!    for i in 0...skills_next.size      x = 4      y = i * 32      skill = $data_skills[skills_next[i]]      self.contents.font.color = normal_color      bitmap = RPG::Cache.icon(skill.icon_name)      self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), 255)      self.contents.draw_text(x + 28, y, 166, 32, skill.name, 0)    end  endend#==============================================================================# ■ Window_Tip#------------------------------------------------------------------------------#  技能树画面提示窗口#==============================================================================class Window_Tip < Window_Selectable  #--------------------------------------------------------------------------  # ● 初始化对像  #--------------------------------------------------------------------------  def initialize    super(160, 176, 320, 128)    self.contents = Bitmap.new(width - 32, height - 32)    @item_max = 2    @column_max = 2    @commands = ["是的",  "不要"]    refresh    self.index = 0    self.z = 1000  end  #--------------------------------------------------------------------------  # ● 刷新  #--------------------------------------------------------------------------  def refresh    self.contents.clear    self.contents.font.color = system_color    self.contents.draw_text(4, 0, 328, 32, "您确定要学习该技能吗?")    self.contents.draw_text(4, 32, 328, 32, "本次学习将消耗1个技能点。")    self.contents.font.color = normal_color    for i in 0...@item_max      draw_item(i)    end  end  #--------------------------------------------------------------------------  # ● 描绘项目  #     index : 项目编号  #--------------------------------------------------------------------------  def draw_item(index)    x = 4 + index * 144    self.contents.draw_text(x, 64, 128, 32, @commands[index])  end  def update_cursor_rect    if [url=home.php?mod=space&uid=370741]@Index[/url] < 0      self.cursor_rect.empty    else      self.cursor_rect.set(@index * 144, 64, (self.width - 32) / 2, 32)    end  endend#==============================================================================# ■ Scene_Skill_Tree#------------------------------------------------------------------------------#  处理特技树画面的类。#==============================================================================class Scene_Skill_Tree  #--------------------------------------------------------------------------  # ● 初始化对像  #     actor_index : 角色索引  #--------------------------------------------------------------------------  def initialize(actor_index = 0)    @actor_index = actor_index  end  #--------------------------------------------------------------------------  # ● 主处理  #--------------------------------------------------------------------------  def main    # 获取角色    @actor = $game_party.actors[@actor_index]    # 生成帮助窗口、状态窗口、特技窗口    @title1 = Window_Base.new(180, 128, 230, 64)    @title2 = Window_Base.new(410, 128, 230, 64)    @title1.contents = Bitmap.new(198, 32)    @title1.contents.draw_text(4, 0, 120, 32, "前置技能")    @title2.contents = Bitmap.new(198, 32)    @title2.contents.draw_text(4, 0, 120, 32, "后置技能")    @help_window = Window_Help.new    @status_window = Window_Skill_Tree_Status.new(@actor)    @skill_window = Window_Skill_Tree.new(@actor)    @prev_window = Window_Skill_Prev.new(@actor,nil)    @next_window = Window_Skill_Next.new(@actor,nil)    # 关联帮助窗口    @skill_window.help_window = @help_window    # 生成信息提示窗口 (设置为不可见・不活动)    @tip_window = Window_Tip.new    @tip_window.visible = false    @tip_window.active = false    # 执行过渡    Graphics.transition    # 主循环    loop do      # 刷新游戏画面      Graphics.update      # 刷新输入信息      Input.update      # 刷新画面      update      # 如果画面切换的话就中断循环      if $scene != self        break      end    end    # 准备过渡    Graphics.freeze    # 释放窗口    @help_window.dispose    @status_window.dispose    @skill_window.dispose    @tip_window.dispose    @prev_window.dispose    @next_window.dispose    @title1.dispose    @title2.dispose  end  #--------------------------------------------------------------------------  # ● 刷新画面  #--------------------------------------------------------------------------  def update    # 刷新窗口    @help_window.update    @status_window.update    @skill_window.update    @tip_window.update    @prev_window.update    @next_window.update    @skill = @skill_window.skill    @prev_window.skill = @skill    @next_window.skill = @skill    # 特技窗口被激活的情况下: 调用 update_skill    if @skill_window.active      update_skill      return    end    # 目标窗口被激活的情况下: 调用 update_target    if @tip_window.active      update_tip      return    end  end  #--------------------------------------------------------------------------  # ● 刷新画面 (特技窗口被激活的情况下)  #--------------------------------------------------------------------------  def update_skill    # 按下 B 键的情况下    if Input.trigger?(Input::B)      # 演奏取消 SE      $game_system.se_play($data_system.cancel_se)      # 切换到菜单画面      $scene = Scene_Map.new      return    end    # 按下 C 键的情况下    if Input.trigger?(Input::C)      # 获取特技窗口现在选择的特技的数据      @skill = @skill_window.skill      # 不能使用的情况下      if @skill == nil or not @actor.skill_can_learn?(@skill.id) or $game_variables[NUMBER_SHIFT + @actor.id] == 0 or @actor.skill_learn?(@skill.id)        # 演奏冻结 SE        $game_system.se_play($data_system.buzzer_se)        return      else        # 演奏确定 SE        $game_system.se_play($data_system.decision_se)        @tip_window.visible = true        @skill_window.active = false        @tip_window.active = true        return      end    end    # 按下 R 键的情况下    if Input.trigger?(Input::R)      # 演奏光标 SE      $game_system.se_play($data_system.cursor_se)      # 移至下一位角色      @actor_index += 1      @actor_index %= $game_party.actors.size      # 切换到别的特技画面      $scene = Scene_Skill_Tree.new(@actor_index)      return    end    # 按下 L 键的情况下    if Input.trigger?(Input::L)      # 演奏光标 SE      $game_system.se_play($data_system.cursor_se)      # 移至上一位角色      @actor_index += $game_party.actors.size - 1      @actor_index %= $game_party.actors.size      # 切换到别的特技画面      $scene = Scene_Skill_Tree.new(@actor_index)      return    end  end  #--------------------------------------------------------------------------  # ● 刷新画面 (目标窗口被激活的情况下)  #--------------------------------------------------------------------------  def update_tip    # 按下 B 键的情况下    if Input.trigger?(Input::B)      # 演奏取消 SE      $game_system.se_play($data_system.cancel_se)      # 删除目标窗口      @skill_window.active = true      @tip_window.visible = false      @tip_window.active = false      @tip_window.index = 0      return    end    # 按下 C 键的情况下    if Input.trigger?(Input::C)      $game_system.se_play($data_system.decision_se)      if @tip_window.index == 0        id = @skill_window.skill.id        @actor.learn_skill(id)        $game_variables[NUMBER_SHIFT + @actor.id] -= 1      end      @tip_window.active = false      @tip_window.visible = false      @skill_window.active = true      @status_window.refresh      @skill_window.refresh      @tip_window.index = 0    end  endendclass Scene_Title  alias m main  def main    $data_skilltree = get_skill_tree    m  endend复制代码
    复制代码
    如果什么地方乱码了请及时告诉我,懂代码的朋友们请多帮帮忙。
    下面是界面,感觉比较烂,不过还能用……

    还有一个新工程的附件范例,都一并拿去吧……

    刚才看了一下,脚本第99 102 158 273 388行都出现了不该出现的东西,大家把那个什么url的删掉就好,或者直接下范例附件。
                本帖来自P1论坛作者我是羊羽我骄傲,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg.blue/forum.php?mod=viewthread&tid=333339  若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x
    天天去同能,天天有童年!
    回复 论坛版权

    使用道具 举报

    ahome_bigavatar:guest
    ahome_bigavatar:welcomelogin
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|同能RPG制作大师 ( 沪ICP备12027754号-3 )

    GMT+8, 2024-5-17 19:55 , Processed in 0.049534 second(s), 44 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表