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

Project1

 找回密码
 注册会员
搜索
查看: 2881|回复: 4
打印 上一主题 下一主题

[原创发布] 【教程】装备附带技能实现过程

[复制链接]

Lv4.逐梦者 (版主)

梦石
0
星屑
9532
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

跳转到指定楼层
1
发表于 2014-4-11 19:57:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

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

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

x
本帖最后由 RyanBern 于 2014-12-12 17:33 编辑

前言
装备附带技能这一名词听起来并不陌生,顾名思义,让角色装备某特定的装备,该角色就能习得这个装备中的技能。卸下装备时,角色就遗忘这个技能。这对于一个RPG游戏来说,是一个很不错的自定义设定。但是很遗憾,我们的RM并没有“自带”这一功能的实现方法(至少RMXP是这样,不知道VX和VA是不是有),因此大家便采取各种方式来实现这个设定。我想,因为这个设定容易被大多数人想到,实现起来又不是很困难,又是一个很值得加入RPG游戏的一个小插件,现在6R的论坛上已经有各种各样的“装备附带技能脚本”,或者“装备附带技能的解决方法”,总会有一个合适的方法可以实现这个功能。
那么既然如此,为什么还要提起这件事情呢?我们可以看到,虽然实现的效果基本相同,但是从实现过程来看,各种方法却能分得出优劣来。在这里,优劣是有评判规则的,我们说一个方法好还是不好,可以从以下几个方面来看:方法的适应性如何,对异常情况的处理如何,对特殊情况考虑是否周全,运行效率如何,使用起来是否方便,和其他的方法是否冲突(主要是脚本)等等。这就激发出我们“不满现状”的欲望,看到解决的办法有瑕疵,就要反思其解决过程,然后不断优化解决方案。这不但是方法的转变,更是编程思想的转变,反思此过程很有意义。
装备附带技能的问题,Ryan在很久以前(大概是五年前?)就已经尝试着解决,到现在,一共进行了几次反思,共有三种不同的解决方案,而且个人感觉后面经过反思得到的新方案远远高于旧的方案。而且我感觉每个人解决这个问题的思路应该跟我的差不多。不说废话了,开始正文。

方案一:事件法
这是我最初想到的事件来处理装备附带技能问题的方法,对于当年年少无知的Ryan,不懂脚本,用事件也是被逼无奈。不管怎么说,勉强实现了这一过程。
[思路]
利用并行处理的事件,不断对角色当前的装备状态进行检查。如果发现有特定的装备就为其增加技能,否则移除技能。
[实现过程]
事件类型:公共事件
事件开始条件:并行处理
事件条件开关:开关[0001]为ON
事件内容:
条件分歧 [角色1] 为 [武器1] 装备中
       增减特技:[角色1], +[特技1]
    除此以外的场合:
       增减特技:[角色1], -[特技1]
分歧结束

如果需要多个就不断添加条件分歧即可。

[反思]
1.这种方法容易想到,而且对于不会脚本的人来说,已经足够了。
2.由于事件只能存在于地图上,因此切换到别的场景的时候,事件不起作用。例如在装备场景更换装备后,不回到地图,立即打开特技场景查看特技,你会发现装备附带的技能并没有加上,只有你退出到地图然后再去特技场景查看特技,装备附带的特技才会显现出来。
3.并行处理的事件在满足条件的情况下反复执行,这就意味着游戏地图会变卡,特别是地图里面并行比较多的时候。实际上,角色在地图上是没有办法更换装备的,就更不用谈监视装备变化了。角色实际上是在装备界面上更改装备,但是却到地图画面上才监视,增减特技。这样的处理方法可以说是莫名其妙。
4.此方法无法处理复杂情况,即如果不同的装备附带同一个特技,这么判断肯定是要出麻烦的。

总之,事件法处理装备附带技能问题的思路很简单,操作起来很容易也很好理解,但是我们可以看出事件法处理问题的种种弊端。因为说到底,事件就是把一些常用的命令拿出来,它们经过组合,虽然可以处理很多的问题,但是还有很多的问题在组合的范围之外。因此,我们不得不把注意力放到脚本上。

方案二:装备同步学习技能法(脚本)
在初步掌握脚本之后,就有拿脚本来替代事件来实现这个功能的想法。这是一个脚本方法,也是最容易想到的脚本方法。用它来代替事件,可以说是一大进步。
[思路]
既然更换装备的时候就已经决定了角色应该习得哪些技能,那么就不应该再拖到地图场景判断。应该在装备的同时,就完成技能的同步。这就是所谓的“装备同步学习技能”。具体的方法就是找到负责更换装备的方法(应该是Game_Actor里面的equip方法),在里面插入类似于学习技能的语句。穿上一个装备就习得其中的技能,卸下一个装备就遗忘其中的技能,这些内容都在equip方法里面添加。
刚才搜了一下6R的帖子,晨露曾经问过这样的问题,当时的解决方案是在Scene_Equip上面改动,虽然装备过程是在Scene_Equip内完成,但是说到底,实现装备过程还是equip方法的功劳,那样改其实是有问题的,因为无法对初期装备的技能进行学习。因为初期装备的设置不在Scene_Equip中进行,因此也就没有办法习得装备中的技能了。
解决了装备监视问题,我们还要解决数据设置问题。因为既然上升到了脚本的高度,那么就有必要将其规范化。虽然可以逐个设置,但是在这里并不推荐。于是我们想到了以下设置方式:
  1. EQUIP_SKILLS = {[0,1]=>[1,2,3],[1,1]=>[4],[1,2]=>[5,6]}
复制代码

在这里采用了Hash表进行数据设置,说白了就是这事Hash常量,将装备和技能对应起来。当然,这种东西只有自己才能看懂,因此给人用的时候必须加以详细说明。
例如这里,EQUIP_SKILLS的主键是一个二元的数组[a,b],a表示装备的类型,0为武器,1为防具;b表示表示装备的ID。EQUIP_SKILLS中主键对应的值是技能ID的数组,这里考虑到一个装备可能对应多个技能。因此[0,1]=>[1,2,3]的意思就是1号武器附带ID为1-3的技能。
[实现过程]
根据以上的分析,可以修改equip的方法如下(在这里仅以武器为例):
  1. def equip(equip_type, id)
  2.     case equip_type
  3.     when 0  # 武器
  4.       if id == 0 or $game_party.weapon_number(id) > 0
  5.         $game_party.gain_weapon(@weapon_id, 1)
  6.         if id == 0 # 卸下武器
  7.           if EQUIP_SKILLS[[0,@weapon_id]] != nil
  8.             for i in EQUIP_SKILLS[[0,@weapon_id]]
  9.               forget_skill(i)
  10.             end
  11.           end
  12.         else # 装备武器
  13.           if EQUIP_SKILLS[[0,@weapon_id]] != nil
  14.             for i in EQUIP_SKILLS[[0,@weapon_id]]
  15.               learn_skill(i)
  16.             end
  17.           end
  18.         end
  19.         @weapon_id = id
  20.         $game_party.lose_weapon(id, 1)
  21.       end
  22.     end
  23.   end
复制代码


[反思]
1.相对于事件法,这种方法把执行的过程放到了变更装备的方法里面。相比较而言,思路变得自然很多。因此,事件法处理的一些弊端在这个方法里面得到了解决。
2.设置过程虽然比较简洁(事件法需要不断做判断,这将会带来大量的复制粘贴,而这恰恰是难以维护的地方),但是却很抽象,在某些条件下也是很恼人的。试想在设置的时候,要不断在数据库——脚本编辑器中切换,换成谁都会略微不爽的。
3.此方法也只能处理简单的情形,即多个装备不能共享相同的技能,也不能处理角色和装备共享技能的情况(即装备中附带的技能该角色已经通过其他方式(如升级)等学习到,按理说这是不能被覆盖的)。虽然通过处理,可以处理多装备共享技能的问题,例如换装备时,可以先脱下所有装备,然后再穿上新的装备,但是这样的处理十分不自然。

总之,这个方法对于事件法来说,已经有很多改进的地方,但是仍然是比较初等的解决方案,维护起来不容易,而且遗留了很多问题。这就促使我们想出下面的方法。

方案三:改进的脚本法
抱歉实在不知道应该给这个方法起什么名字,就凑合听吧。其实这个方法是对脚本法的改进。说是改进,实际上却是抛弃了原有思路,从另一个全新的角度解决问题。解决了目前发现的所有问题。
另外,这个方案下方的脚本是成熟的,可以直接复制到Main前来实现功能。
[思路]
我们在描述一个角色时,不关心他“有什么特技”,而是关心他“学没学会某个特技”。前者是从整体来说的,后者是从局部来说的。上一个脚本的处理方法着重于整体,那么这个脚本的处理方法更有局部处理的特色。我们并不需要让角色在更换装备的时候学习一个特技,而是需要能正确判断角色是否学会了某个特技。方案二脚本的重大缺陷在于,它没有有效地区分“自己领悟的特技”和“装备中习得的特技”,因此导致没有办法处理特技共享的问题。我们知道,多一个实变量就多一分维护的难度,因此我们应该把注意力放到方法的处理过程中去。这样说起来有些别扭,实际上就是重写skill_learn?方法和learn_skill方法。
另外,我们还有必要说一下数据库设置问题。方案二用了一个Hash表来设置,但是这样做对于数据编辑很不方便,首先是对应关系不直观,然后就是设置起来非常麻烦。因此我们有必要采取另外的设置方式:说明(名称)扩充法。其实这种方法已经很普及,例如在黑暗圣剑传说中,采取“特技名,数值”的方法设置特技的最大伤害;装备颜色脚本中,采取“说明,@颜色编号”来设置装备的颜色。而去更改RPG模块相应类的name和description方法,采用split来处理字符串。这个懂的人应该知道。但是split你也用,他也用,难免会造成冲突。在这里我们采取另外一种方式:scan替换法。个人感觉这个比split的兼容性要好一些。具体的实现过程在代码中可以体现。
[实现过程]
  1. #============================================================================
  2. # 装备附带技能
  3. #   By:RyanBern
  4. #----------------------------------------------------------------------------
  5. # 设置方法:
  6. #   在数据库中进行设置,在装备的说明中输入%w特技ID,即可完成一个特技的关联
  7. #   位置可以任意,但是最好在结尾。多个特技关联直接连写就行。
  8. # 例:将1号武器(铜剑)关联1号技能和2号技能
  9. #   在说明中更改:青铜制造的剑。战士可以装备。%w1%w2
  10. #============================================================================

  11. module RPG
  12.   class Weapon
  13.     alias ryan_des description
  14.     def description
  15.       return ryan_des.gsub(/%w\d+/,"")
  16.     end
  17.     def skills
  18.       if @skills.nil?
  19.         @skills = []
  20.         @description.scan(/%w([0-9]+)/){|s| @skills.push(s[0].to_i)}
  21.       end
  22.       return @skills
  23.     end
  24.   end
  25.   class Armor
  26.     alias ryan_des description
  27.     def description
  28.       return ryan_des.gsub(/%w\d+/,"")
  29.     end
  30.     def skills
  31.       if @skills.nil?
  32.         @skills = []
  33.         @description.scan(/%w([0-9]+)/){|s| @skills.push(s[0].to_i)}
  34.       end
  35.       return @skills
  36.     end
  37.   end
  38. end

  39. class Game_Actor
  40.   # 重写 learn_skill
  41.   def learn_skill(skill_id)
  42.     if skill_id > 0 and not @skills.include?(skill_id)
  43.       @skills.push(skill_id)
  44.     end
  45.   end
  46.   # 重写 skill_learn?
  47.   def skill_learn?(skill_id)
  48.     result = @skills.include?(skill_id)
  49.     if @weapon_id != 0
  50.       result ||= $data_weapons[@weapon_id].skills.include?(skill_id)
  51.     end
  52.     if @armor1_id != 0
  53.       result ||= $data_armors[@armor1_id].skills.include?(skill_id)
  54.     end
  55.     if @armor2_id != 0
  56.       result ||= $data_armors[@armor2_id].skills.include?(skill_id)
  57.     end
  58.     if @armor3_id != 0
  59.       result ||= $data_armors[@armor3_id].skills.include?(skill_id)
  60.     end
  61.     if @armor4_id != 0
  62.       result ||= $data_armors[@armor4_id].skills.include?(skill_id)
  63.     end
  64.     return result
  65.   end
  66. end
  67. class Window_Skill
  68.   # 重写 refresh
  69.   def refresh
  70.     if self.contents != nil
  71.       self.contents.dispose
  72.       self.contents = nil
  73.     end
  74.     @data = []
  75.     for i in 1...$data_skills.size
  76.       skill = $data_skills[i]
  77.       if @actor.skill_learn?(i)
  78.         @data.push(skill)
  79.       end
  80.     end
  81.     # 如果项目数不是 0 就生成位图、重新描绘全部项目
  82.     @item_max = @data.size
  83.     if @item_max > 0
  84.       self.contents = Bitmap.new(width - 32, row_max * 32)
  85.       for i in 0...@item_max
  86.         draw_item(i)
  87.       end
  88.     end
  89.   end
  90. end
复制代码


[反思]
1.解决了装备之间享特技的问题,即如果装备1和装备2同时附带技能1,那么装备任意一个角色就可习得此技能,脱下所有才能忘记技能。
2.解决了角色和装备特技的共享问题,即如果角色已经学会了技能1,装备1也附带技能1,那么角色不穿这个装备时,不会遗忘特技。
3.采用正则表达式+scan处理方法,能够降低冲突发生几率。

总之,装备附带技能的脚本又发展了一步。

另外看了2L的帖子,感觉2L给出的链接是目前我见过的最好的装备附带技能的脚本之一,在这儿顺便帮着做个广告吧。

Lv1.梦旅人

路人党员

梦石
0
星屑
52
在线时间
2276 小时
注册时间
2010-12-30
帖子
3225
2
发表于 2014-4-11 23:07:10 | 只看该作者
http://rpg.blue/thread-314767-1-1.html
以前写过一个脚本解决了你的各种反思==
本人擅长XP,如果有脚本或者Ruby方面的问题欢迎发电邮到[email protected]咨询,本人很少检查电邮所以不一定会及时回复,本人不会直接出手解决问题只会提供一个方向,所以谢绝伸手党
回复 支持 反对

使用道具 举报

Lv4.逐梦者 (版主)

梦石
0
星屑
9532
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

3
 楼主| 发表于 2014-4-12 09:26:58 | 只看该作者
英顺的马甲 发表于 2014-4-11 23:07
http://rpg.blue/thread-314767-1-1.html
以前写过一个脚本解决了你的各种反思==

昨天写的时候还想找一下你这个帖子参考的,可惜没找到TAT。
在这儿主要是把设置搬到数据库中了,在脚本中写多了那些设置感觉很有违和感……
回复 支持 反对

使用道具 举报

Lv1.梦旅人

路人党员

梦石
0
星屑
52
在线时间
2276 小时
注册时间
2010-12-30
帖子
3225
4
发表于 2014-4-12 09:38:19 | 只看该作者
RyanBern 发表于 2014-4-12 09:26
昨天写的时候还想找一下你这个帖子参考的,可惜没找到TAT。
在这儿主要是把设置搬到数据库中了,在脚本中 ...

主要是一般上会附加特技的装备也就那几样,没必要弄在数据库吧==
至于这种累死人不偿命的写法是因为柳大先开头这么写的,然后没其他人想过要换个角度看世界==

点评

帮你的帖子做了个广告+塞100糖~这么好的脚本应该给很多糖才是。  发表于 2014-4-12 10:15
本人擅长XP,如果有脚本或者Ruby方面的问题欢迎发电邮到[email protected]咨询,本人很少检查电邮所以不一定会及时回复,本人不会直接出手解决问题只会提供一个方向,所以谢绝伸手党
回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2024-11-18 14:21

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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