查看: 5062|回复: 14

[原创发布] CustomAdventure事件功能强化——理解与使用

[复制链接]

无节操

梦石
0
星屑
608
在线时间
795 小时
注册时间
2009-2-6
回帖
3910

开拓者贵宾

发表于 2014-6-22 10:04:43 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 moy 于 2014-6-24 10:16 编辑

为了配合@taroxd的教程活动,我打算详细的将我之前在CustomAdventure事件功能强化中发布的几个简单的外挂脚本的制作流程,包括动机,检索方式,修改方式,使用方式进行完整的介绍。由于是由浅入深的介绍,因此排布顺序与之前不同,尽请谅解。
在我们开始解说之前,首先有几个绕不过去的坎——module,class,def,哦,当然还有end。
如果你已经知道了他们的含义,那么你可以跳过我漏洞百出的解释,如果不太明白,那么就顺便一观吧。
[fold=基本概念]想必当你打开脚本编辑器时,这四个词绝对是你见到最多的词了。这几个词的详细含义我无法给你们很好的解答,但我可以告诉你们,他们一般代表着接下来正要干什么。

1. module - end:
被这个包围起来的东西一般都是一些提供给用户进行可能的修改的常量。
让我们来看看默认脚本是如何使用module的。[pre lang="ruby" line="1"]
#  定义了用语和信息。将部分资料定义为常量。用语部分来自于 $data_system 。
module Vocab
  # 商店画面
  ShopBuy         = "买入"
  ShopSell        = "卖出"
  ……
end
[/pre]这里的“买入”和“卖出”正是我们在调用商店画面时显示在选项框中的词语,就如同我们在数据库中对某些词进行修改一样,在这里我们也可以对双引号中的内容进行相应的修改。这些修改将直接体现在你的游戏当中。module有个很抽象的名字——模块。

2.class - end:
被这个包围起来的东西一般都是给用户提供特定功能的工具。
让我们来看看默认脚本时如何使用class的。[pre lang="ruby" line="1"]
class Game_Player < Game_Character
  ……
  #--------------------------------------------------------------------------
  # ● 由方向键移动
  #--------------------------------------------------------------------------
  def move_by_input
    return if !movable? || $game_map.interpreter.running?
    move_straight(Input.dir4) if Input.dir4 > 0
  end
  ……
end[/pre]这里的Game_Player代表的正是我们在操作地图上的主角时所使用到的一些工具(尽管你是无意识的),这个工具正是“使用方向键移动”。与之相似的还有Scene_Map中对于取消键的处理——
[pre lang="ruby" line="1"]
class Scene_Map < Scene_Base
  ……
  #--------------------------------------------------------------------------
  # ● 监听取消键的按下。如果菜单可用且地图上没有事件在运行,则打开菜单界面。
  #--------------------------------------------------------------------------
  def update_call_menu
    if $game_system.menu_disabled || $game_map.interpreter.running?
      @menu_calling = false
    else
      @menu_calling ||= Input.trigger?(:B)
      call_menu if @menu_calling && !$game_player.moving?
    end
  end
  #--------------------------------------------------------------------------
  # ● 打开菜单画面
  #--------------------------------------------------------------------------
  def call_menu
    Sound.play_ok
    SceneManager.call(Scene_Menu)
    Window_MenuCommand::init_command_position
  end
  ……
end[/pre]监听取消键,在满足条件时打开菜单画面,就是由这两段完成的。这些我们在有意无意中使用的工具(move_by_input或是call_menu)在术语上被叫做方法,而他们所属的class(Game_Player和Scene_Map)则被称为类。

3.def - end:
看到这估计有人已经反应过来了,没错,这个就是方法的定义方式。
这里以一个默认脚本中最为简单的例子举例。[pre lang="ruby" line="1"]
class Game_BattlerBase
  ……
  #--------------------------------------------------------------------------
  # ● 获取 TP 的最大值
  #--------------------------------------------------------------------------
  def max_tp
    return 100
  end
  ……
end[/pre]获取TP的最大值,这个方法再直白不过。抛开def和end不看,只有3个词语,分别是max_tp,return,和100。max_tp就是这个方法的名字,return 100就是他的功能。也就是说,当程序询问自己,某个战斗角色的TP上限是多少时,他就会告诉自己,哦,是100点。
看起来很简单。
那么如果我问你为什么非要用class-end把他包裹起来呢?这就牵扯到下一个问题。

4.class的实际作用
还拿刚才的max_tp说事儿。说到Game_BattlerBase可能大家还有些迷惑,那么Game_Actor和Game_Enemy可能一些会翻查默认脚本的人已经明白是啥了。后两个就是我们玩家操控角色和敌人的类,而在Game_BattlerBase中定义的方法,在这两个类内都是可以直接使用的(理由暂且不提)。
那么,让我们来看看这样会发生什么。
[pre lang="ruby" line="1"]
class Game_Actor
  def max_tp
    return 150
  end
end

class Game_Enemy
  def max_tp
    return 50
  end
end[/pre]是的,两个一模一样名字的方法,那么实际处理时,程序是怎么做的呢?
程序在询问玩家角色TP上限是多少时告诉自己是150,而询问敌人的TP上限是多少时告诉自己是50!
你看,他完美而不冲突的完成了工作。这都得益于class的限制——他将扩在其内的所有工具和变量限制在自身的范围内,使他们不会影响其他同样名字的东西。(哦,先忘了$吧)当然,这种限制还有个很绕的术语名:作用域。

5.@和$
我开玩笑的,怎么可能忘了$和@。
在默认脚本中,说到见到最多的符号,恐怕除了“=”就是这两个了,比什么加减乘除还多。
这两个符号中,可能$对于大家来说更熟悉一点,因为在提问时经常会有人给出诸如$game_variables之类的回复。然而,为了理解方便,让我们先来看看@是如何工作的。
照例先来一个默认脚本的例子,为了编辑方便,这里Game_BattlerBase的声明我就略去了。
[pre lang="ruby" line="1"]
  #--------------------------------------------------------------------------
  # ● 更改 HP
  #--------------------------------------------------------------------------
  def hp=(hp)
    @hp = hp
    refresh
  end
[/pre]可能看到这个方法,一些不熟悉的人已经开始迷惑了:卧槽为什么有4个hp?
让我们一个一个分析。
首先第一个“hp=”毫无疑问是一个方法名。
第二个括号内的“hp”则是使用这个方法时需要的值。
第三个“@hp”则是想要修改的值。
第四个“hp”则是第二个“hp”的引用。
也就是说“@hp”和另两个“hp”并不是一个东西,那么为什么要这样呢?直接hp=300不就万事大吉了吗,为啥非要定义一个方法这样绕着来?
这里又牵扯到我在第4条所提到的作用域问题。
让我来画个简单的图吧
  1. 方法外 @hp存活 hp尚不存在
  2. ——  def hp=(hp)
  3.            @hp = hp
  4.            refresh
  5. ——  end
  6. 方法外 @hp存活 hp已死亡
复制代码
也就是说,没有加@符号的hp只在方法被调用的短短的时间里是存活的(可怜的hp,我们会记住你的),而@hp才是真正的赢家,才是真正承载角色生命值的变量。它对于每个角色都是独立的,而且只要角色还存在于队伍之中,他就一直存在。这种忠实的变量,被称为实例变量。
等等,也就是说,等角色不见了,@hp也不见了,那如果我想要把离队时的hp保存,这样我过会剧情直接和这个叛变的角色战斗时,将他的hp损失体现在敌人的血量上要怎么做?
你需要$符!……当然我不是说美金。是的,应该有人想到了要使用$game_variables进行存储。于是,为什么$能做到?
因为加了$的变量被称为全局变量,也就是说,只要程序没结束,从他出现的时刻起,他就一直存在!因此你可以在各种地方对他进行修改和引用,而不用担心他是不是像可怜的hp一样出了def-end就挂了。也不用担心不好找角色时找不到@hp。
这也是早期的脚本里有一大堆$开头的全局变量的原因。(弊端暂且不表)
[/fold]
进入正题。我在CustomAdventure事件功能强化中发布的现有的6个脚本中,脉络最为清晰的莫过于最后一个更换职业补丁了。那么就以此开始介绍对默认脚本的小修改是如何达成的。为了方便比对,我在解释时会将原脚本和修改脚本都贴上,需要时可以翻看。
[fold=1.更换职业补丁][pre lang="ruby" line="1"]
#==============================================================================
#   本脚本只是用于方便的使用更改职业的全部功能,开关开启时将进行保留经验的转职。
#==============================================================================
module CA_EVENT
  CLASS_CHANGE_KEEP = 5 # 变换职业时是否保留经验值的开关
end
#==============================================================================
# ■ Interpreter
#==============================================================================
class Game_Interpreter
  include CA_EVENT
  #--------------------------------------------------------------------------
  # ● 更改职业
  #--------------------------------------------------------------------------
  def command_321
    actor = $game_actors[@params[0]]
    keep_exp = $game_switches[CLASS_CHANGE_KEEP]
    actor.change_class(@params[1],keep_exp) if actor && $data_classes[@params[1]]
  end
end
[/pre]
在我们进入话题之前,先来看看事件是怎么做的。

事件页中的更换职业

事件页中的更换职业

可以看到,在事件页的设置中,我们可以调整2个参数,分别是角色id和职业id,并没有是否保留经验等级的选项。也就是说,如果一个20级的战士,转职成狂战士后,他的等级会回到1级,因为他在狂战士这个职业中并没有获得过经验。
而如果我们更换职业的原因是为了切合游戏剧情,比如35级的圣骑士堕落成了黑骑士,我又不想让他掉到1级怎么办,尽管可以通过事件再把它拉回35级,可毕竟有个过程。
于是,我们就需要先了解事件页中的“更换职业”功能在实际运行时是怎么作用的。
所以,打开脚本编辑器,全局搜索“更换职业”。

全局搜索

全局搜索

阿咧?这是为什么。但不能就此放弃,那么搜索“职业”。

第二次搜索

第二次搜索

原来如此,原来翻译时用的词语有所区别,因此才没有找到。通过按图索骥,我们找到了实现事件页“更换职业”功能的command_321方法。
[pre lang="ruby" line="1"]
  def command_321
    actor = $game_actors[@params[0]]
    actor.change_class(@params[1]) if actor && $data_classes[@params[1]]
end
[/pre]
我们发现它的实现非常简单,首先获取参数0代表的actor,然后只要参数1有效并且actor也存在,就对这个actor使用change_class方法,传给change_class的参数则正是参数1,也就是职业id。
那么这个change_class方法又是什么呢?
再次进行搜索。这次搜索“change_class”

搜索change_class

搜索change_class

搜索的结果令人满意,除了我们在command_321中调用的change_class,就只有Game_Actor中的定义。
那么这个change_class在Game_Actor中又是怎样的呢?
[pre lang="ruby" line="1"]  
    #--------------------------------------------------------------------------
  # ● 职业变化
  #     keep_exp : 是否保留经验值
  #--------------------------------------------------------------------------
  def change_class(class_id, keep_exp = false)
    @exp[class_id] = exp if keep_exp
    @class_id = class_id
    change_exp(@exp[@class_id] || 0, false)
    refresh
  end
[/pre]我们惊讶的发现,这个方法提供了一个可以输入的是否保留经验值的参数keep_exp!而默认值false无疑提示了我们,只要将change_class的第二个参数传一个true,理所当然的就是保留经验等级的转职!
那是不是直接把command_321中change_class的参数改成(@params[1],true)就可以了呢?
这样当然可以成功,但是所有转职就都变成保留经验等级的啦。如果还需要原来的方式怎么办?
开关可以帮助使用者做到,但是如果直接使用开关的话,对其他使用者会造成困扰,毕竟不是所有人都有那个耐心从一堆字母中找到你需要改的数字:开关的id号。
那么怎么办?
较为早期的脚本大多使用的是$全局变量的方式,然而这种方式一旦重名,可以说非常难以发现,你只会感受到来自$的恶意,发现莫名其妙的失灵但是却不知道咋回事,F9又不能查看自己定义的$变量……(这也是很多人习惯使用作者名+日期+功能的命名方式的原因)
我这里使用的是module,通过模块定义常量比较容易理解和修改,因为使用者不必进行搜索去寻找某个数字…
于是一个简单的更换职业补丁就完成了。[/fold]
下面是一个看起来很简单,但是实际工程量一点也不小的改造——踩踏/置物判断。鉴于这个脚本本身糙的不行,各位看官还是关注一下思路和流程吧。
[fold=2.踩踏/置物判断][pre lang="ruby" line="1"]
#==============================================================================
#   本脚本判断一个在人物下层的事件是否被其他事件/角色踩踏
#   对本事件使用只需要在分歧脚本中使用get_character(0).stepped_on?即可。
#   判断别的事件请自行获取实例后使用。
#==============================================================================
# ■ Game_Event
#==============================================================================
class Game_Event < Game_Character
  #--------------------------------------------------------------------------
  # ● 判断本事件是否被其他事件/角色踩踏
  #--------------------------------------------------------------------------
  def stepped_on?
    stepped_by_events?(@x,@y) || stepped_by_player_characters?(@x, @y)
  end
  #--------------------------------------------------------------------------
  # ● 判断某位置是否被其他事件踩踏
  #--------------------------------------------------------------------------
  def stepped_by_events?(x, y)
    $game_map.events_xy_nt(x, y).any? do |event|
      event.normal_priority?
    end
  end
  #--------------------------------------------------------------------------
  # ● 判断某位置是否被主控角色踩踏
  #--------------------------------------------------------------------------
  def stepped_by_player_characters?(x, y)
    @priority_type == 0 && $game_player.collide?(x, y)
  end
end
[/pre]思来想去,还是将这段脚本当做第二个解释的例子了。可能这个名字取得不怎么好,但是这个脚本的本意是让对于一些踩踏开关的判断可以更方面的通过事件脚本的方式进行设置。
那么,我们先来回顾一下默认脚本和事件页的环境下,我们会如何实现一个简单的置物开关:也就是一个“通过推动箱子事件,使其停留在某特定位置来打开”的开关。
我们需要并行的获取指定的数个箱子事件的坐标(或者在推动箱子事件时进行判断,如果箱子总移动一格的话),并将获得的值与特定位置的值进行比较。
这样使用并不是不可以,但是我们会发现,为了这么个也许无足轻重的开关,我们需要占用大量的“变量”来存放箱子坐标,同时也无法很好的处理同时踩踏两个位置(或更多)才能打开的开关,更别说如果角色踩上去也生效什么的……你会发现事件设置变得异常繁琐以至于非常容易出错……
所以我们需要对操作进行适当的简化和抽象,来想想我们到底需要个什么样的东西才能完成这个工作。
于是我整理了下面这段思路转换:
0.数个位置的开关事件与数个箱子事件或是玩家的坐标重叠        # 需求↓
1.数个位置与数个事件或玩家的坐标重叠                        # 先忽略开关事件的情况,着重于位置与坐标重叠↓
2.数个位置中,每一个都与一个事件或玩家的坐标重叠        # 剔除模棱两可的语义↓
3.数个位置被事件或玩家踩踏                                # 为了使逻辑更为清晰而进行替换:{坐标重叠+隐含的条件*}→{踩踏}↓
4.某个位置被事件或玩家踩踏                                # 剔除重复雷同的条件判断↓
                                                        # 得到我们需要的逻辑上最为简化的结果
*在这里隐含的条件是,如果使用固定的事件进行判断时,为了让其他事件能够推上来,需要将事件的层设定为在人物下。
因此得出的结论是,我们需要一个判断某个位置(或是某个位置的事件)是否被其他事件或是玩家“踩踏”的。那么这样的方法在默认脚本中是否有提供,或是有没有类似的方法呢?
我们知道事件有一类是接触触发,那么这个接触触发也许可以帮助我们进行这个方法的设计。同时,事件可以设置成在角色下方或者是穿透这两种方式来使玩家可以穿过该事件。
所有的线索都指向事件→也就是Game_Event类。那么我们就在Game_Event类中寻找类似的方法试试。
[pre lang="ruby" line="1"]
  #--------------------------------------------------------------------------
  # ● 接触事件的启动判定
  #--------------------------------------------------------------------------
  def check_event_trigger_touch(x, y)
    return if $game_map.interpreter.running?
    if @trigger == 2 && $game_player.pos?(x, y)
      start if !jumping? && normal_priority?
    end
  end
[/pre]在Game_Event中我们找到了一个这样的方法,他是接触事件的启动判定。我们对其稍微进行一下分析可以很明显的看到在if判断中有一条是$game_player.pos?(x,y),很显然他在判断时是优先判断坐标是否重合。紧接我们看到了底下一句的if中,有一条是normal_priority?,不太熟悉英语和RGSS3的读者可能不太清楚这个方法的意义何在,我们可以对其进行搜索来帮助我们理解。
使用全局搜索后我们在Game_CharacterBase中找到了他的定义。
[pre lang="ruby" line="1"]
  #--------------------------------------------------------------------------
  # ● 判定优先级“与人物同层”
  #--------------------------------------------------------------------------
  def normal_priority?
    @priority_type == 1
  end
[/pre]也就是说,当@priority_type的值为1的时候,优先级就是与人物同层的,那么这个判断优先级的方法是否有被我们正在寻找的方法所调用呢?
再次进行全局搜索。

筛选

筛选

通过对搜索结果的依次筛选,我们找到两个写着“碰撞”这个词语的方法,似乎和我们的要求很接近。
分别是位于Game_CharacterBase的collide_with_events?
[pre lang="ruby" line="1"]
  #--------------------------------------------------------------------------
  # ● 判定是否与事件碰撞
  #--------------------------------------------------------------------------
  def collide_with_events?(x, y)
    $game_map.events_xy_nt(x, y).any? do |event|
      event.normal_priority? || self.is_a?(Game_Event)
    end
  end
[/pre]和Game_Event中的collide_with_player_characters?
[pre lang="ruby" line="1"]
  #--------------------------------------------------------------------------
  # ● 判定是否与玩家碰撞(包括跟随角色)
  #--------------------------------------------------------------------------
  def collide_with_player_characters?(x, y)
    normal_priority? && $game_player.collide?(x, y)
  end
[/pre]可以看到这两个方法与我们的需求看起来高度相似→传入值是一对坐标,返回值是一个布尔值
对其中第二个方法中调用的collide?方法再次进行搜索有如下的结果。其方法是在Game_Player中的collide?
[pre lang="ruby" line="1"]
  #--------------------------------------------------------------------------
  # ● 判定是否碰撞(包含跟随角色)
  #--------------------------------------------------------------------------
  def collide?(x, y)
    !@through && (pos?(x, y) || followers.collide?(x, y))
  end
[/pre]而这里以及之前都出现过的pos?则出现在Game_CharacterBase中。
[pre lang="ruby" line="1"]
  #--------------------------------------------------------------------------
  # ● 坐标一致判定
  #--------------------------------------------------------------------------
  def pos?(x, y)
    @x == x && @y == y
  end
[/pre]通过对最后两个脚本的比对,我们可以知道,collide?是一个对坐标重叠进行了一定包装的方法,除了保证角色(或跟随角色)坐标重叠以外,还需要保证主角色的穿透属性为关闭。而这种情况实际上就相当于角色撞到了一个挡路的事件,与我们的需求略有差距。
那们我们继续对包含了collide关键词的上两个方法进行分析,看看他们是否能为我们所用。
首先我们先看一下和collide?关系比较密切的collide_with_player_characters?(其中通过$game_player直接调用了collide)
可以看到,返回值由两个部分同时决定,分别是normal_priority?和collide?
根据我们之前对normal_priority的了解,其返回的是@priority_type与1是否相等,也就是是否与角色优先级相同。那么如果比角色优先级低的事件,他的@priority_type又是多少呢,根据常理应该是0,那么是不是呢?
通过搜索,我们没有找到直接判断是否为0的语句,但是我们找到了2,跳转过去后发现是飞艇的通行优先级。那么很容易推断,只要@priority_type为0,应该就是在角色下方了。
我们将这个方法复制一下并修改normal_priority?为“@priority_type == 0”然后稍微改一下名字,就叫做stepped_by_player_characters?保存备用。
然后我们在处理下关于事件的部分。
在collide_with_events?中有一个接触脚本不久尚不熟练的人都会很怵的方法,他名字叫做each……
但我们暂时不用管它。我们先针对其内部,我们比较容易理解的部分进行分析。
这部分同样由两个部分同事决定,分别为event.normal_priority?和self.is_a?(Game_Event),当这两个中有一个满足,就返回真。
那我们来仔细想想看,这个方法本来是为了判断是否有事件挡住某个角色的路的对吧,那么我们来分析一下角色和事件是怎么被事件阻挡的——通过回忆/测试,我们知道,只要阻挡事件处在与玩家同层,就能阻挡任何角色和事件。而无论一个事件是在哪一层,他都能阻挡其他事件经过他。那么我们很容易就理解了,self作为方法的主体,他是行使方法的人,那么他只要是事件,就会被任何该坐标的事件阻挡,因此self.is_a?(Game_Event)就是用来实现这个阻挡的。只要调用者是一个事件,就无条件成立,这显然不符合我们的预期,因此这句话可以删掉。那么仅留下event.normal_priority?能否完成我们的设想呢?
让我们再来强化一下我们的效果:使任何能够{踩踏}位置的——是的,没错,踩踏,不是地下的,也不是天上的,正是normal_piority的所有角色(包括玩家角色和与人物同层的事件们)。那么,这样就可以将这个方法也进行另存,取名为stepped_by_events?。
于是不管是被事件踩踏还是被角色踩踏,我们都通过修改完成了。
简单的将他们的结果拼合一下成为stepped_on?……等等,参数呢?传入值呢?在实际结果中被省略了啊?
没错,因为将这几个方法存入的是Game_Event,也就是说他们都是基于事件本体的而方法,因此这里我缺省的使用了@x和@y,这样只要直接找到一个事件,用它调用stepped_on?就可以很方便的判断他是否被踩踏。同时,对作用域和方法有所理解的人也可以很方便的进行修改和移植。
啊?什么?你说each怎么没说?
我只是想证明,即使你不理解each到底做了什么,也可以通过实践和对现有线索的推断来完成脚本的理解。
我想关于each,肯定有其他大触很有心得,我在这里就不卖丑了。

学有余力的同志们可以试着将Game_Event中的方法尝试在Game_Interpreter进行包装,使得脚本的使用更加方便。具体方法参考我在发布版本中的注释。
[/fold]
如果你对上面的章节中方法的调用以及方法名中的问号有所疑问,可以参阅下面一块。为了便于理解使用了错误的解释,刨根问底的真理强迫症患者可以不看。这种情况可以参阅@taroxd的回帖点我跳转
[fold=2*继承与约定俗成的?]
在上一个章节,我们说了关于collide?的一些事儿,可能有些读者已经注意到了一个现象,那就是pos?方法的定义是存在于Game_CharacterBase之中,并且在Game_Player中进行了调用。那么这是怎么回事呢,pos?方法里那个问号又是什么含义呢?
这里还是从类的作用域(也是一个方法可以被使用的范围)开始讨论。
就如同我在基础概念章中说到的def-end一样,class-end也隐含一个作用域。以pos?为例:(这里省略默认脚本中不必要的注释)
[pre lang="ruby" line="1"]
class Game_CharacterBase
  #--------------------------------------------------------------------------
  def pos?(x, y)
    @x == x && @y == y
  end
  #--------------------------------------------------------------------------
  def pos_nt?(x, y)
    pos?(x, y) && !@through
  end
  #--------------------------------------------------------------------------
end
[/pre]在这段脚本中,我们可以看到,同在Game_CharacterBase,pos_nt?方法内部直接使用了pos?方法,也就是说在同一个类(class)里面,方法之间的互相调用是可以直接实现的。这种嵌来套去的调用方式在VA-RGSS3的默认脚本里面可谓遍地都是。
那么,Game_Player中的collide?是为何能调用pos?的呢?
[pre lang="ruby" line="1"]
class Game_Player < Game_Character
  def collide?(x, y)
    !@through && (pos?(x, y) || followers.collide?(x, y))
  end
end
[/pre]我们注意到,在Game_Player的class-end中有一个不和谐的" < Game_Character",没错,他就是我们可以直接使用pos?的原因所在。
如果将Game_Character比作“水”这个概念的话,我们的Game_Player在经过这个" < Game_Character"之后,就也拥有了“水”的概念。
于是只要在Game_Character中能做到的事情,在Game_Player中都能做到。←这种行为就是继承。
可是,pos?是定义在Game_CharacterBase中的啊?于是我们仔细看看Game_Character……
  1. class Game_Character < Game_CharacterBase
复制代码
哦,好吧,原来它偷偷的继承了Game_CharacterBase。
那么我们用两条伪代码来看看结构是怎样的。
  1. Game_Player     < Game_Character < Game_CharacterBase
  2. Game_Follower   < Game_Character < Game_CharacterBase
复制代码
也就是说,所谓的Player和Follower他们在本质上都有很多的共性,这些共性都在他们所继承的类之中,按照种族传承习惯,我们称后面的类为父类,毕竟很多东西都是他们给的。
不过除了Player和Follower,Character一族还有许多成员,其中有一个叛逆的娃不喜欢父亲给他的pos?工具,他就是Game_Vehicle
[pre lang="ruby" line="1"]
class Game_Vehicle < Game_Character
  def pos?(x, y)
    @map_id == $game_map.map_id && super(x, y)
  end
end[/pre]我们知道,这个是交通工具的类,由于他本身可以跨地图的设置位置,因此对于地图的判断也需要纳入坐标判断之中。可是原本父亲给的pos?工具也很好用,怎么办呢?
他直接重新写了一个pos?但是是在父亲的pos?的基础上的。在这段脚本中,super一词代表着调用父类的同名方法,也就是父类的pos?方法,于是这样,Vehicle完成了对父类的pos?方法的包装,成功的痛了它!(你以为是痛车吗!)
以上就是关于继承的大致含义和作用方式。
那么,上面那块有点难啃的骨头吃完了之后,我们回头来聊聊方法后面的小尾巴——"?"
这是一个约定俗成的符号,大概就相当于你去买鞋子的时候售货员不会问你买左脚还是右脚一样。
当我们在方法后加上问号之时,我们默认,这个方法的返回值是一个布尔值——真或假。
例子有很多,比如上面一直在说的pos?,判断是否附加状态的state?,判断是否可以使用的enable?等等等等
了解这一条对于快速理解默认脚本会有很大的帮助,因此在这里就单独提了一下。

[/fold]


未完待续……

评分

参与人数 4星屑 +460 收起 理由
IamI + 200 既然来了……那
kakarot + 160 塞了馍胖很多糖感觉自己萌萌哒~.
上贺茂润 + 99 大大的差评!!!!!!!!
克莉丝 + 1 差评

查看全部评分

Brandnew day, Brandnew Life
                             规 实在  中
暂为素材区版主,版其  琢磨
应援一下~
RPG制作大师授权素材推广计划

…あたしは天

梦石
0
星屑
2308
在线时间
4033 小时
注册时间
2010-10-4
回帖
10548

开拓者贵宾

发表于 2014-6-22 10:23:17 | 显示全部楼层
本帖最后由 taroxd 于 2014-6-22 10:53 编辑
被这个包围起来的东西一般都是一些提供给用户进行可能的修改的常量。

不要无视 SceneManager 这种东西啦……
咳咳,咱不提Mix-in功能,把module命名空间的功能再解释清楚点(包括SceneManager这类的),这就是提问之一哦~
对实例变量的解释也是问题之一~ hp=(hp) 这段正是我想要看到的。



总之,你都写了这么多了,到时候一定参加活动哦~ 提的问题都很简单的。

点评

我想要的就是这样实际的解释,理论啥的谁想看  发表于 2014-6-22 10:32
moy
我还是喜欢偏实际操作一些,理论就交给你们吧!  发表于 2014-6-22 10:30
moy
所以我才说一般嘛,而且是基础,什么都解释可要说老半天了_(:з」∠)_  发表于 2014-6-22 10:29
回复

使用道具 举报

无节操

梦石
0
星屑
608
在线时间
795 小时
注册时间
2009-2-6
回帖
3910

开拓者贵宾

 楼主| 发表于 2014-6-22 10:23:58 | 显示全部楼层
更完之前就先放在水区吧

点评

这贴更新完赶快召唤版主扔到技术区去=。=  发表于 2014-6-22 10:35
Brandnew day, Brandnew Life
                             规 实在  中
暂为素材区版主,版其  琢磨
应援一下~
RPG制作大师授权素材推广计划
回复

使用道具 举报

菜鸟飞呀飞 该用户已被删除
发表于 2014-6-22 16:27:15 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

无节操

梦石
0
星屑
608
在线时间
795 小时
注册时间
2009-2-6
回帖
3910

开拓者贵宾

 楼主| 发表于 2014-6-22 17:07:16 | 显示全部楼层
菜鸟飞呀飞 发表于 2014-6-22 16:27
技术贴为啥在水区-v-,另外个人感觉XP更适合入门,VA继承关系不是很喜欢,有些方法更是无节操 一个含一个 ...

我倒觉得VA的可扩展性比XP强多了,可能我比较偏爱VA的继承吧
而且Manager的设计也非常棒

点评

你们都忽略了4L的第一句话,让我来回答:因为完工以后才移动过去  发表于 2014-6-22 17:45
moy
← ←但是说到底这是VA区的活动233,聊得是RGSS3~  发表于 2014-6-22 17:15
并没有说不好-v-,只是对于入门而已VA没有XP直观  发表于 2014-6-22 17:13

评分

参与人数 1星屑 +33 收起 理由
taroxd + 33 我很赞同

查看全部评分

Brandnew day, Brandnew Life
                             规 实在  中
暂为素材区版主,版其  琢磨
应援一下~
RPG制作大师授权素材推广计划
回复

使用道具 举报

…あたしは天

梦石
0
星屑
2308
在线时间
4033 小时
注册时间
2010-10-4
回帖
10548

开拓者贵宾

发表于 2014-6-22 17:09:12 | 显示全部楼层
菜鸟飞呀飞 发表于 2014-6-22 16:27
技术贴为啥在水区-v-,另外个人感觉XP更适合入门,VA继承关系不是很喜欢,有些方法更是无节操 一个含一个 ...

我倒是非常喜欢VA的继承方式呢~ 毕竟可扩展性,代码可重用性都高得多
回复

使用道具 举报

菜鸟飞呀飞 该用户已被删除
发表于 2014-6-22 18:50:11 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

…あたしは天

梦石
0
星屑
2308
在线时间
4033 小时
注册时间
2010-10-4
回帖
10548

开拓者贵宾

发表于 2014-6-22 18:52:19 | 显示全部楼层
菜鸟飞呀飞 发表于 2014-6-22 18:50
-v-我比较喜欢独立性自由性
比如说要写一个场景,用更上一层的逻辑直接建立场景更具有独立性,修改移植更 ...

要说入门容易当然是XP

但是知道脚本的运作原理后,VA写/改代码都更加容易。

点评

诶?我有码过教程嘛?  发表于 2014-6-22 19:14
额 如果那些不是你码的那就是错觉了  发表于 2014-6-22 19:05
诶你什么时候产生了我有码教程的错觉?呃,暑假有空也许会码吧……  发表于 2014-6-22 19:00
这倒是-v- 你们码教程的辛苦了  发表于 2014-6-22 18:59
回复

使用道具 举报

无节操

梦石
0
星屑
608
在线时间
795 小时
注册时间
2009-2-6
回帖
3910

开拓者贵宾

 楼主| 发表于 2014-6-23 00:17:23 | 显示全部楼层
本帖最后由 moy 于 2014-6-23 00:29 编辑

已更新……
明儿追加补充 2*-继承与约定俗成的?
each留给你们玩弄了lol  


思索了一下,决定作死开地图炮,锁定目标为两个帖子中留名的家伙们!擦伤勿怪!(滚
大触们求指摘,共同学习/w\
@taroxd  @菜鸟飞呀飞  @喵呜喵5 @余烬之中 @DeathKing @IamI @后知后觉 @3106345123
@克莉丝 @鑫晴 @kuerlulu @芙蕾娅 @Mic_洛洛 @正太君 @无脑之人  

点评

免疫at 100%  发表于 2014-6-24 12:42
在下只是个渣渣不时来膜拜一下  发表于 2014-6-24 11:57
艾特免疫!  发表于 2014-6-24 05:50
没有意见的...再说我哪有资格当大触?  发表于 2014-6-23 11:59
moy
不给点意见什么的吗_(:з」∠)_  发表于 2014-6-23 00:50
Brandnew day, Brandnew Life
                             规 实在  中
暂为素材区版主,版其  琢磨
应援一下~
RPG制作大师授权素材推广计划
回复

使用道具 举报

梦石
0
星屑
122
在线时间
552 小时
注册时间
2012-8-18
回帖
1392
发表于 2014-6-23 23:39:29 | 显示全部楼层
哎呀呀被@了……好吧这次受姬就不放BGM了
粗略的看了一下【受姬上排版简直崩坏】,讲的很科学嘛233
由于脑子里灌了一些奇怪的东西,说起这些东西就会挂上一堆奇怪的词汇,所以我就不点评了……
还是希望这些教程越办越好喵~☆

点评

使用Sublime Text打文字,打Tab毫无压力!  发表于 2014-6-24 05:50
moy
话说如果有时间的话能不能麻烦截图一下手机排版是什么样子的,是不是因为fold的收纳功能造成的排版崩坏?  发表于 2014-6-24 00:40
moy
因为苦逼的dz不支持tab进行排版……对一个喜欢tab来tab去的人,实在是太别扭啦!于是就偷懒没怎么排(只是懒吧。  发表于 2014-6-24 00:10
我要填坑!我要背单词!我要学日语!我要每天锻炼!
好吧呵呵= =
回复

使用道具 举报

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

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部