设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 26560|回复: 29

[RMVX发布] 技能树系统+技能投点升级(这次没那么疼了,可以直接用了

[复制链接]

Lv1.梦旅人

旅之愚者

梦石
0
星屑
240
在线时间
812 小时
注册时间
2007-7-28
帖子
2148

贵宾

发表于 2010-9-12 08:00:08 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 六祈 于 2011-1-10 21:12 编辑

意外的发现1对n技能比较符合技能树的情形,于是重新写了一个

使用方法$scene = Scene_Skill_Tree(id),这个id是角色在数据库里的id

技能树设定如图:
注意:说明里必须有skill_tree
备注里如图所写,levelx表示第几层的技能,数字是技能的id,connection里是以数组为元素的数组,表示一前一后(不可颠倒)的技能id

并且目前只支持1前置技能1后置或者1前置n后置,【不支持n前置1后置,画图的算法没想好
1.JPG

然后需要让角色一级学会这个技能树【不能在普通技能列表里看见】
3.JPG

然后是技能成长的部分,技能树里的技能备注里如图这样写:【注意使用本系统的话,不同人物习得同个技能需要多做一份,即一个id的技能只能在一支技能树中出现】
2.JPG
这部分目前即使没设定也不会出错

最后附上工程和截图

4.JPG

自动画技能树.rar (244.29 KB, 下载次数: 10767)

点评

刚想吐槽画面……能不能做出分系列的技能树效果呢  发表于 2011-1-19 10:39
脚本出错,详情六祈君请看http://bbs.66rpg.com/forum.php?mod=redirect&tid=164844&goto=lastpost#lastpost  发表于 2011-1-10 08:42
另外感谢下沉影不器的读取备注脚本,愚者拿来主义了……  发表于 2010-9-12 08:04
不许吐槽咱的美工…  发表于 2010-9-12 08:01

评分

参与人数 2星屑 +14 +2 收起 理由
一瞬间的幻觉 + 14 美工如果能华丽些就完美了
小幽的马甲 + 2

查看全部评分

Lv1.梦旅人

梦石
0
星屑
50
在线时间
140 小时
注册时间
2010-7-5
帖子
98
发表于 2010-9-12 08:03:33 | 显示全部楼层
sf么
回复 支持 反对

使用道具 举报

Lv1.梦旅人

旅之愚者

梦石
0
星屑
240
在线时间
812 小时
注册时间
2007-7-28
帖子
2148

贵宾

 楼主| 发表于 2010-9-12 08:03:52 | 显示全部楼层
本帖最后由 六祈 于 2011-1-10 21:16 编辑

连一帖发布代码

Skill_Level
  1. #技能等级

  2. #————————————注意————————————————————————
  3. #———除了本页脚本外,还需要在存读档中追加dump和load技能数据库——————
  4. #————————————注意————————————————————————
  5. module RPG
  6.   class Skill < UsableItem
  7.     #定义技能等级上限的常数
  8.     MAX_LEVEL = 10
  9.     def level
  10.       return @level.nil? ? 0 : @level
  11.     end
  12.    
  13.     def level=(level)
  14.       @level = [level , MAX_LEVEL].min
  15.     end
  16.    
  17.     def learned?
  18.       return level > 0
  19.     end
  20.    
  21.     def level_top?
  22.       return level == MAX_LEVEL
  23.     end
  24.    
  25.     def base_damage
  26.       n = @base_damage
  27.       @base_damage_plus ||= self.read_note("base_damage")
  28.       return @base_damage_plus.nil? ? n : (n + @base_damage_plus * level)
  29.     end
  30.    
  31.     def base_damage_plus
  32.       @base_damage_plus || 0
  33.     end
  34.    
  35.     def atk_f
  36.       n = @atk_f
  37.       @atk_f_plus ||= self.read_note("atk_f")
  38.       return @atk_f_plus.nil? ? n : (n + @atk_f_plus * level)
  39.     end
  40.    
  41.     def atk_f_plus
  42.       @atk_f_plus || 0
  43.     end
  44.    
  45.     def spi_f
  46.       n = @spi_f
  47.       @spi_f_plus ||= self.read_note("spi_f")
  48.       return @spi_f_plus.nil? ? n : (n + @spi_f_plus * level)
  49.     end
  50.    
  51.     def spi_f_plus
  52.       @spi_f_plus || 0
  53.     end
  54.    
  55.     def mp_cost
  56.       n = @mp_cost
  57.       @mp_cost_plus ||= self.read_note("mp_cost")
  58.       return @mp_cost_plus.nil? ? n : (n + @mp_cost_plus * level)
  59.     end
  60.    
  61.     def mp_cost_plus
  62.       @mp_cost_plus || 0
  63.     end
  64.   end
  65. end
复制代码
Skill_Leaf
  1. #在技能树图中用于表示节点的类

  2. class Skill_Leaf
  3.   attr_reader :x , :y , :id
  4.   
  5.   def initialize(skill_id)
  6.     @id = skill_id
  7.     @post_skills = []
  8.     @x = 0
  9.     @y = 0
  10.   end
  11.   
  12.   def learned?
  13.     skill.learned?
  14.   end
  15.   
  16.   def set_x(x)
  17.     @x = x
  18.   end
  19.   
  20.   def set_y(y)
  21.     @y = y
  22.   end
  23.   
  24.   def skill
  25.     $data_skills[@id]
  26.   end
  27.   
  28.   def skill_icon
  29.     $data_skills[@id].icon_index
  30.   end
  31.   
  32.   def set_pre_skill(skill_id)
  33.     @pre_skill = $data_skills[skill_id]
  34.   end
  35.   
  36.   def can_learn?
  37.     return ((@pre_skill.nil? or @pre_skill.learned?) and !skill.level_top?)
  38.   end
  39.   
  40.   def post_skills
  41.     @post_skills
  42.   end
  43.   
  44.   def add_post_skill(skill_id)
  45.     @post_skills.push(skill_id) unless @post_skills.include?(skill_id)
  46.   end

  47. end
复制代码
Skill_Help
  1. #描绘技能属性及升级变化的窗口

  2. class Window_Skill_Help < Window_Base
  3.   attr_reader :skill_id
  4.   def initialize(skill_id)
  5.     super(0 , 0 , 180 , 176)
  6.     @skill_id = skill_id
  7.     refresh
  8.   end
  9.   
  10.   def refresh
  11.     self.contents.clear
  12.     skill = $data_skills[@skill_id]
  13.     self.contents.draw_text(0 , 0 , 146 , 24 , skill.name , 1)
  14.     self.contents.draw_text(0 , 24 , 72 , 24 , "LV")
  15.     self.contents.draw_text(72 , 24 , 74 , 24 , "%3d" % skill.level + (skill.level_top? ? "" : "→" + "%3d" % (skill.level + 1)))
  16.     self.contents.draw_text(0 , 48 , 72 , 24 , "基础伤害")
  17.     self.contents.draw_text(72 , 48 , 74 , 24 , "%3d" % skill.base_damage +
  18.     (skill.level_top? ? "" : "→" + "%3d" % (skill.base_damage + skill.base_damage_plus)))
  19.     self.contents.draw_text(0 , 72 , 72 , 24 , "MP消耗")
  20.     self.contents.draw_text(72 , 72 , 74 , 24 , "%3d" % skill.mp_cost +
  21.     (skill.level_top? ? "" : "→" + "%3d" % (skill.mp_cost + skill.mp_cost_plus)))
  22.     self.contents.draw_text(0 , 96 , 72 , 24 , "攻击相关")
  23.     self.contents.draw_text(72 , 96 , 74 , 24 , "%3d" % skill.atk_f +
  24.     (skill.level_top? ? "" : "→" + "%3d" % (skill.atk_f + skill.atk_f_plus)))
  25.     self.contents.draw_text(0 , 120 , 72 , 24 , "精神相关")
  26.     self.contents.draw_text(72 , 120 , 74 , 24 , "%3d" % skill.spi_f +
  27.     (skill.level_top? ? "" : "→" + "%3d" % (skill.spi_f + skill.spi_f_plus)))
  28.   end
  29.   
  30.   def skill_id=(id)
  31.     @skill_id = id
  32.     refresh
  33.   end
  34.   
  35. end
复制代码
Window_Skill_Tree
  1. class Window_Skill_Tree < Window_Base
  2.   #连线粗细
  3.   LINE_WEIGHT = 3
  4.   #同一技能导出多个技能时x值的分散程度
  5.   WIDTH = 240
  6.   #整体y值位移(为了美观)
  7.   Y_MOVE = -20
  8.   attr_reader :x_index , :y_index
  9.   def initialize(tree_id)
  10.     super(0 , 0 , 240 , 360)
  11.     @x_index = 0
  12.     @y_index = 0
  13.     #定义连线颜色
  14.     @color = Color.new(175 , 28 , 200)
  15.     #转换技能树为各个节点
  16.     create_tree_levels(tree_id)
  17.     #计算各节点y坐标
  18.     calculate_y
  19.     #计算各节点x坐标(x过大或负值过大均会修正)
  20.     calculate_x
  21.     #刷新(描绘点和连线)
  22.     refresh
  23.     #更新选择框
  24.     update_cursor
  25.   end
  26.   
  27.   def refresh
  28.     self.contents.clear
  29.     draw_leaves
  30.     draw_branches
  31.   end
  32.   
  33.   def create_tree_levels(tree_id)
  34.     @levels = []
  35.     level = 0
  36.     @skills = {}
  37.     while(temp = $data_skills[tree_id].read_note("level_" + (level + 1).to_s))
  38.       @levels[level] = []
  39.       temp.each do |id|
  40.         @levels[level].push(@skills[id] = Skill_Leaf.new(id))
  41.       end
  42.       level += 1
  43.     end
  44.     connections = $data_skills[tree_id].read_note("connections")
  45.     connections.each do |line|
  46.       @skills[line[0]].add_post_skill(line[1])
  47.       @skills[line[1]].set_pre_skill(line[0])
  48.     end
  49.     @level_max = @levels.size
  50.   end
  51.   
  52.   def calculate_y
  53.     @delta_y = (self.height - 32) / @levels.size / 2
  54.     @levels.each_with_index do |level , i|
  55.       level.each do |skill|
  56.         skill.set_y(@delta_y * (i * 2 + 1) + Y_MOVE)
  57.       end
  58.     end
  59.   end
  60.   
  61.   def calculate_x
  62.     @levels[0].each_index do |index|
  63.       @levels[0][index].set_x((self.width - 32) / @levels[0].size * (index * 2 + 1) / 2)
  64.     end
  65.     for i in 0...@level_max - 1
  66.       @levels[i].each do |pre_skill|
  67.         size = pre_skill.post_skills.size.to_f
  68.         pre_skill.post_skills.each_with_index do |id , index|
  69.           @skills[id].set_x(pre_skill.x + (((index + 1)/ (size + 1) - 0.5)* WIDTH).to_i)
  70.         end
  71.       end
  72.     end
  73.     @levels.each do |level|
  74.       level.sort!{|a , b| a.x <=> b.x}
  75.     end
  76.     temp = @levels.flatten
  77.     middle = self.width / 2 - 16
  78.     max_x = temp.map{|leaf| (leaf.x - middle).abs}.max
  79.     if max_x > middle - 20
  80.       temp.each do |leaf|
  81.         leaf.set_x(middle + (leaf.x - middle) * (middle - 20) / max_x)
  82.       end
  83.     end
  84.   end
  85.   
  86.   def draw_leaves
  87.     @levels.each do |level|
  88.       level.each do |skill|
  89.         draw_icon(skill.skill_icon , skill.x - 12 , skill.y - 12 , skill.learned?)
  90.       end
  91.     end
  92.   end
  93.   
  94.   def draw_branches
  95.     @skills.each_value do |skill|
  96.       next if @levels[@level_max - 1].include?(skill)
  97.       draw_lines(skill)
  98.     end
  99.   end
  100.   
  101.   def draw_lines(pre_skill)
  102.     return if pre_skill.post_skills.size == 0
  103.     post_skills = pre_skill.post_skills
  104.     case post_skills.size
  105.     when 1
  106.       post_skill = @skills[post_skills[0]]
  107.       self.contents.fill_rect(pre_skill.x , pre_skill.y + 12 , LINE_WEIGHT ,
  108.        post_skill.y - pre_skill.y - 24 , color)
  109.     else
  110.       self.contents.fill_rect(pre_skill.x , pre_skill.y + 12 , LINE_WEIGHT ,
  111.        @delta_y - 12 , color)
  112.       x_start = post_skills.map{|id| @skills[id].x}.min
  113.       x_end = post_skills.map{|id| @skills[id].x}.max
  114.       self.contents.fill_rect(x_start , pre_skill.y + @delta_y ,
  115.        x_end - x_start , LINE_WEIGHT , color)
  116.       post_skills.each do |id|
  117.         self.contents.fill_rect(@skills[id].x , pre_skill.y + @delta_y ,
  118.          LINE_WEIGHT , @skills[id].y - pre_skill.y - @delta_y - 12 , color)
  119.       end
  120.     end
  121.   end

  122.   def update
  123.     super
  124.     if Input.trigger?(Input::LEFT)
  125.       Sound.play_cursor unless @levels[@y_index].size == 1
  126.       @x_index -= 1
  127.       @x_index %= @levels[@y_index].size
  128.       update_cursor
  129.       return
  130.     end
  131.     if Input.trigger?(Input::RIGHT)
  132.       Sound.play_cursor unless @levels[@y_index].size == 1
  133.       @x_index += 1
  134.       @x_index %= @levels[@y_index].size
  135.       update_cursor
  136.       return
  137.     end
  138.     if Input.trigger?(Input::UP)
  139.       Sound.play_cursor
  140.       @y_index -= 1
  141.       @y_index %= @level_max
  142.       @x_index = [@x_index , @levels[@y_index].size - 1].min
  143.       update_cursor
  144.       return
  145.     end
  146.     if Input.trigger?(Input::DOWN)
  147.       Sound.play_cursor
  148.       @y_index += 1
  149.       @y_index %= @level_max
  150.       @x_index = [@x_index , @levels[@y_index].size - 1].min
  151.       update_cursor
  152.       return
  153.     end
  154.   end
  155.   
  156.   def update_cursor
  157.     if @x_index < 0 or @y_index < 0 # 当光标位置小于0
  158.       self.cursor_rect.empty        # 隐藏光标
  159.     else
  160.       skill = @levels[@y_index][@x_index]
  161.       rect = Rect.new(skill.x - 12 , skill.y - 12 , 24 , 24)
  162.       self.cursor_rect = rect       # 更新光标矩形
  163.     end
  164.   end
  165.   
  166.   def skill_leaf
  167.     @levels[@y_index][@x_index]
  168.   end
  169.   
  170.   def color
  171.     @color
  172.   end
  173.   
  174. end
复制代码
Scene_Skill_Tree
  1. #使用方法:$scene = Scene_Skill_Tree(actor_id)

  2. class Scene_Skill_Tree < Scene_Base
  3.   def initialize(actor_id)
  4.     @actor = $game_actors[actor_id]
  5.   end
  6.   
  7.   def start
  8.     @trees = @actor.skill_trees
  9.     @tree_window = Window_Command.new(160 , @trees.map{|id| $data_skills[id].name})
  10.     @tree_window.x = 400
  11.     @skill_window = Window_Skill_Tree.new(@trees[0])
  12.     @map_spriteset = Spriteset_Map.new
  13.     @description_window = Window_Base.new(240 , 0 , 120 , 56)
  14.     refresh_description
  15.     @help_window = Window_Skill_Help.new(skill_id)
  16.     @help_window.z = 9999
  17.     @help_window.visible = false
  18.     move_help_window
  19.   end
  20.   
  21.   def update
  22.     if @tree_window.active
  23.       update_tree
  24.       return
  25.     end
  26.     if @skill_window.active
  27.       update_skill
  28.       return
  29.     end
  30.   end
  31.   
  32.   def terminate
  33.     @skill_window.dispose
  34.     @map_spriteset.dispose
  35.     @description_window.dispose
  36.     @help_window.dispose
  37.     @tree_window.dispose
  38.   end
  39.   
  40.   def update_tree
  41.     @tree_window.update
  42.     if Input.trigger?(Input::B)
  43.       Sound.play_cancel
  44.       $scene = Scene_Map.new
  45.       return
  46.     end
  47.     if Input.trigger?(Input::C)
  48.       Sound.play_decision
  49.       @skill_window = Window_Skill_Tree.new(@trees[@tree_window.index])
  50.       @help_window.visible = true
  51.       @help_window.update
  52.       @skill_window.active = true
  53.       @tree_window.active = false
  54.       return
  55.     end
  56.   end
  57.   
  58.   def update_skill
  59.     @skill_window.update
  60.     refresh_help_window
  61.     if Input.trigger?(Input::B)
  62.       Sound.play_cancel
  63.       @help_window.visible = false
  64.       @tree_window.active = true
  65.       return
  66.     end
  67.     if Input.trigger?(Input::C)
  68.       unless (@skill_window.skill_leaf.can_learn? and @actor.skill_point > 0)
  69.         Sound.play_buzzer
  70.         return
  71.       else
  72.         Sound.play_decision
  73.         @skill_window.skill_leaf.skill.level += 1
  74.         @actor.skill_point -= 1
  75.         @actor.learn_skill(skill_id)
  76.         @skill_window.refresh
  77.         refresh_description
  78.         @help_window.refresh
  79.         return
  80.       end
  81.     end
  82.   end
  83.   
  84.   def refresh_description
  85.     @description_window.contents.clear
  86.     @description_window.contents.draw_text(0 , 0 , 88 , 24 , "技能点: " + "%2d" % @actor.skill_point , 2)
  87.   end
  88.   
  89.   def skill_id
  90.     @skill_window.skill_leaf.id
  91.   end
  92.   
  93.   def refresh_help_window
  94.     if skill_id != @help_window.skill_id
  95.       @help_window.skill_id = skill_id
  96.       move_help_window
  97.     end
  98.   end
  99.   
  100.   def move_help_window
  101.     @help_window.x = @skill_window.skill_leaf.x + 48
  102.     @help_window.y = [@skill_window.skill_leaf.y + 24 , 416 - @help_window.height].min
  103.   end
  104.   
  105. end
复制代码
Game_Actor追加
  1. class Game_Actor
  2.   #每升一级获得技能点常数
  3.   SKILL_POINT_PER_LEVEL = 5
  4.   #获得技能树
  5.   def skill_trees
  6.     @skills.find_all{|skill_id| $data_skills[skill_id].description.index("skill_tree")}
  7.   end
  8.   #常规技能中排除技能树
  9.   def skills
  10.     result = []
  11.     for i in @skills
  12.       next if $data_skills[i].description.index("skill_tree")
  13.       result.push($data_skills[i])
  14.     end
  15.     return result
  16.   end
  17.   #技能点的读写
  18.   def skill_point
  19.     return @skill_point.nil? ? 0 : @skill_point
  20.   end
  21.   
  22.   def skill_point=(p)
  23.     @skill_point = p
  24.   end
  25.   #追加定义,升级获得技能点
  26.   alias :ski_lv_up :level_up
  27.   def level_up
  28.     ski_lv_up
  29.     self.skill_point += SKILL_POINT_PER_LEVEL
  30.   end
  31.   
  32. end
复制代码
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
416 小时
注册时间
2006-10-21
帖子
1245
发表于 2010-9-12 08:13:15 | 显示全部楼层
不支持n前置1后置
...我也正头疼..

点评

n前置1后置或者1前置n后置都很容易,两者混合就很头疼  发表于 2010-9-12 08:15
回复 支持 反对

使用道具 举报

Lv1.梦旅人

66RPG站长

梦石
0
星屑
54
在线时间
615 小时
注册时间
2005-10-10
帖子
5734

RMVX自由创作大赛亚军第2届短篇游戏比赛亚军第5届短篇游戏比赛冠军

发表于 2010-9-12 08:59:33 | 显示全部楼层
打岔扯两句
单机里面敢做技能树的都是对自己的数值平衡和游戏性有绝对自信,相信肯定有玩家会玩无数遍N周目,所以技能树用于让玩家每次玩时候乐趣不一样。比如diablo之流的。
除此之外貌似基本都是网游流的,技能树是为了让玩家体验不到所有内容,故意这么做以便组队配合。
我觉得以目前独立游戏做出来的RPG……剧情通关很短但是变化很多的动作类游戏另说,嗯。

点评

直接学着技能了的确没意思,我认为用技能点加或用技能书、NPC来学比较有意思  发表于 2011-1-13 10:53
看到柳大的回复真是荣幸之至~愚者做这个东西只是突然想到试一试【可能就是菜鸟的练手吧】。自己做游戏的话应该不会轻易加入这样的系统  发表于 2010-9-12 13:57
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
50
在线时间
453 小时
注册时间
2010-9-2
帖子
1289
发表于 2010-9-12 09:46:58 | 显示全部楼层
{:nm_5:}过来踩愚者的场..你做这个一晚没睡咩-v-~

点评

妈,我困~  发表于 2010-9-12 14:00

                  —.— 我不想 我不想 不想长大  为什么要变成loli大妈?
回复 支持 反对

使用道具 举报

Lv2.观梦者

酱油的

梦石
0
星屑
930
在线时间
2161 小时
注册时间
2007-12-22
帖子
3271

贵宾

发表于 2010-9-12 10:01:52 | 显示全部楼层
n對1還是很好做的,不過先要條件是父節點們(bl?)的y值一致,取直系的中點,然後全部交在一起就好了。排版甚麼的是制作者的事情,會改的自然會改,不會改的迫著也要用。因此我們根本不需要糾結~

点评

求禾西前辈指点~~因为如果夹杂n对1和1对n之后,仅仅凭技能层次和连线,似乎有点难自动作图呢【大概,没好好考虑啊】  发表于 2010-9-12 13:58
不做頭像做簽名,看我囧冏有神(多謝山人有情提供 )
回复 支持 反对

使用道具 举报

头像被屏蔽

Lv1.梦旅人 (禁止发言)

梦石
0
星屑
50
在线时间
0 小时
注册时间
2010-6-25
帖子
42
发表于 2010-9-12 10:21:53 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1015
在线时间
1564 小时
注册时间
2008-7-30
帖子
4418

贵宾

发表于 2010-9-12 13:47:59 | 显示全部楼层
UI有点小不美观{:nm_3:}
代码有点小乱{:nm_2:}
Skill_Level我很喜欢{:nm_4:}
考虑是否用图片代替Line?{:nm_6:}

点评

UI啥的咱忽略了【不是美工啊不是美工】。代码小乱请死君殿指点一下,因为愚者写代码经验不足,具体哪部分需要改进呢?用图片代替line有在思考…  发表于 2010-9-12 14:00

See FScript Here:https://github.com/DeathKing/fscript
潜心编写URG3中。
所有对URG3的疑问和勘误或者建议,请移步至发布页面。
欢迎萌妹纸催更
回复 支持 反对

使用道具 举报

Lv2.观梦者

酱油的

梦石
0
星屑
930
在线时间
2161 小时
注册时间
2007-12-22
帖子
3271

贵宾

发表于 2010-9-12 14:27:10 | 显示全部楼层
大概就是這樣吧?無論是1-n還是n-1,只要確定了相互繼承的兩點,然後就可以通過 (X1, (Y1+Y2)/2),(X2, (Y1+Y2)/2)來確認他們的兩個轉折點(不知道現在你用的是不是就是這樣的算法)。因此簡單來說,就是在畫圖的時候,我們可以把所有繼承都當作單線繼承。因為父節點的y值相等,按照上面的公式,他們的必有一個轉折點相交。因此看起來就像他們都把線集起來了。而相反,1-n的時候則像線分散開去。
sjsh.png
不做頭像做簽名,看我囧冏有神(多謝山人有情提供 )
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-3-29 20:27

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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