Project1

标题: 【渣作品】VA脚本教程(三)<2013.3.21 完结> [打印本页]

作者: 945127391    时间: 2013-3-9 02:44
标题: 【渣作品】VA脚本教程(三)<2013.3.21 完结>
本帖最后由 945127391 于 2013-3-21 22:19 编辑

注意事项
一.本教程提供给一些已经有一点脚本基础的学习者们(至少你要知道变量啊函数啊什么的),如果你没有达到,那我希望你打开着VA的F1文档来看这篇教程;
二.如果你已经有一点脚本基础了,我也希望你打开着F1来看,因为我将在以下的教程中引用到许多F1里的内容;
三.本教程不会太多的说一些理论性的东西(比如浮点数是什么啊之类的),免得说多错多= =;
四.本人由于第一次写教程,所以有(fei)点(chang)乱,请多多包容;
五.如果有什么疑问或者发现了什么错误之处,又或者有什么意见或建议,欢迎回复,毕竟我也是个学习者而已。

如果你把上面的给看完了,就可以就绪看下去了。
玖肆伍的脚本教程(三)
之前太忙了,所以拖到现在才说……实在很抱歉……
然后,这是这个脚本教程系列的最后一章了……也许……
好吧,现在把昨天的作业给说一下:
①draw_icon是在Window_Base里定义的方法。
②先在refresh里添加一句:
  1. draw_actor_exp($game_party.members[0], 0, 96, self.contents.width)
复制代码
然后在窗口的脚本里添加以下这一个方法:
  1. #----------------------------------------------------------------------------
  2. # * 描绘EXP槽
  3. #----------------------------------------------------------------------------
  4. def draw_actor_exp(actor, x, y, width=124)
  5.   rate = actor.exp.to_f / actor.next_level_exp.to_f
  6.   draw_gauge(x, y, width, rate, Color.new(0, 255, 0), Color.new(100, 255, 100))
  7.   self.contents.font.color = text_color(16)
  8.   self.contents.draw_text(x, y, 56, 24, "EXP")
  9.   self.contents.font.color = Color.new(255, 255, 255)
  10.   en = "#{actor.exp}/#{actor.next_level_exp}"
  11.   self.contents.draw_text(x, y, width, 24, en, 2)
  12. end
复制代码
至于原理……我就不说了,自己慢慢吃透吧……
嗯……这次我们要说的是关于窗口的各种属性,比如visible啊、opacity啥的。
但在这之前,我们要先把Window_MapStatus显示到地图上来。
先来分析一下我们之前用来显示出口的方法,其实重点就在几句脚本里。
  1. $w = Window_MapStatus.new
复制代码
这句脚本其实是把Window_MapStatus的一个实例代入$w这个变量里,方便对其进行修改而又不会污染Window_MapStatus里的代码。
  1. $w.update
复制代码
这是用来更新窗口的,本质上是调用了$w(也就是Window_MapStatus)里的update方法。
仔细看看,我们写的代码里,也有update这个方法,且定义如下:
  1. def update
  2.   super
  3.   refresh
  4. end
复制代码
这里头有一个super,是用来调用父类的同名方法的,我们目前不需要知道的那么清楚,只需要知道在这里,他是调用了父类(Window_Base)里的update方法。
然后,我们看到第三行——refresh这句话上面。
我们之前的那两课都一直在写显示窗口的内容,其实都是在refresh方法里写的。
一般来说,描绘窗口的内容的代码都可以写在refresh里。但是要注意的是,Window_Base里并没有refresh这个方法,所以你的窗口如果是直接继承Window_Base的话,就不要用super了。
于是,我们就能看出,在update里调用refresh,是为了让它每一次刷新的时候都重绘一次窗口。这是最简单的方法,如果你的窗口十分简单,就可以这样。但是如果你的窗口很复杂(= =),每帧调用会很卡的。
基本上,显示窗口都脱离不开这两个方法。
理论讲完了,我们来实践一下吧!
新建一个脚本页,在里面输入:
  1. class Scene_Map < Scene_Base
  2.   #----------------------------------------------------------------------------
  3.   # * 重命名方法
  4.   #----------------------------------------------------------------------------
  5.   alias ms_sta start
  6.   #----------------------------------------------------------------------------
  7.   # * 开始处理
  8.   #----------------------------------------------------------------------------
  9.   def start
  10.     ms_sta
  11.   end
  12. end
复制代码
这是为Scene_Map添加东东而做准备。而这里有一个很重要的知识点——alias。
这是给方法起别名的(话说我为什么没有在可爱的F1里找到关于这个的说明!?),好吧,那就凭自己的理解来说明这个方法……
比如说,有以下语句:
  1. @i = 0
  2. def a
  3.   @i += 1
  4. end
  5. alias a2 a
  6. def b
  7.   a2
  8.   @i *= 15
  9. end
  10. p b
复制代码
最后的结果是什么呢?0?还是15?
很明显的,结果是15。
为什么呢,@i的初始值是0,而方法b里有一句@i *= 15,不应该是0*15=0吗?????
因为第5行给方法a起了一个别名a2,因为执行了这个操作,所以以后调用a和调用a2都是一样的——执行方法a里的内容。
所以实际上,在方法b的开头就给@i加上了1,所以正确的运算其实是(@i + 1) * 15 = 15。
我们要记住alias的正确使用方法:
alias 别名 方法
(注意空格)
但是,我还是没有看出alias有什么重要啊~?我直接把原方法里的内容复制黏贴过去不就可以了吗?
不可以哦,我们试想一下,有一天我们把脚本发去给别人用,而别人的其他外挂脚本里头有没有用到alias,这样子就会导致不可预知的错误(冲突)。原因是其他的脚本里定义到了一些东西,而你的脚本里的方法又覆盖了它定义的东西,这和把他的那个方法删掉了没什么区别,自然就会出错。而如果大家都使用alias的话,脚本的兼容性就会增强很多。
所以说,aliassuper都是两个很重要的东西。
好了,脱轨这么久,我们回到原来的内容上。
根据刚才对alias的解释,大家都应该知道alias ms_sta start是啥意思吧,没错,就是用来防止原来的Scene_Map里的start被覆盖的。
好了,然我们进行下一步:在start方法里加上一句:
  1. @mapstatus_window = Window_MapStatus.new
复制代码
然后再把显示窗口的那个事件删掉,然后再运行……

哇哇!出现了呢!
来,我们来升升级,哇!升到99级了呢!
好好玩~(= =)
但是,为什么我们没有用到update呢?
根据RMVA的脚本RGSS里的Scene_Base里,updatedispose的写法来说,窗口updatedispose都是自动的,说以就节省了制作者的很多心思。
抱歉我一开始忘了这一点,所以开头的脚本有一点错误,现已纠正,抱歉。
好了好了,一般来说这样就可以用了~
但是为什么好像好卡的样子!?
那是因为每帧刷新,而刷新的时候顺便重绘内容的原因。因为本来描绘文字就需要一段时间,现在还要每帧都描绘这么多文字,自然就要卡喽~
那要怎么解决呢?
首先,先把Window_MapStatusupdate内的refresh改成:
  1. refresh if $refresh
复制代码
实际上,这句话是给调用refresh方法设了个条件:当$refreshtrue时。也就相当于以下这段脚本:
  1. if $refresh == true
  2.   refresh
  3. end
复制代码
但是,全局变量的初始值是nil,而我们又不给它更改数值的话,他永远都不会是true
于是乎,我们就要设定它在哪儿变成true,哪儿又变回false
变回false就比较简单了,直接在refresh if $refresh后面加上一句:
  1. $refresh = false
复制代码
就可以了。
但是,它要在哪里变成true呢?
我们这个窗口里,要描绘的是头像、名字、状态、HP槽、MP槽、TP槽和EXP槽。所以我们就要考虑到在更改角色、更变状态、改变HP/MP/TP/EXP的时候刷新,也就是把$refresh变为true
p.s 更周全的是要考虑到更变名称和头像时刷新,但是我很懒……
而这些家伙几乎全都在Game_BaseBatterGame_Actor还有Game_Party里,以下是脚本:
  1. class Game_Actor < Game_Battler
  2.   #----------------------------------------------------------------------------
  3.   # * 重命名方法
  4.   #----------------------------------------------------------------------------
  5.   alias ms_refresh refresh
  6.   alias ms_tp tp=
  7.   alias ms_add_state add_state
  8.   #--------------------------------------------------------------------------
  9.   # * 刷新
  10.   #--------------------------------------------------------------------------
  11.   def refresh
  12.     ms_refresh
  13.     $refresh = true
  14.   end
  15.   #----------------------------------------------------------------------------
  16.   # * 更改 TP
  17.   #----------------------------------------------------------------------------
  18.   def tp=(tp)
  19.     ms_tp(tp)
  20.     $refresh = true
  21.   end
  22.   #----------------------------------------------------------------------------
  23.   # * 附加状态
  24.   #----------------------------------------------------------------------------
  25.   def add_state(state_id)
  26.     ms_add_state(state_id)
  27.     $refresh = true
  28.   end
  29. end

  30. class Game_Party
  31.   #----------------------------------------------------------------------------
  32.   # * 重命名方法
  33.   #----------------------------------------------------------------------------
  34.   alias ms_swap_order swap_order
  35.   #----------------------------------------------------------------------------
  36.   # * 交换顺序
  37.   #----------------------------------------------------------------------------
  38.   def swap_order(index1, index2)
  39.     ms_swap_order(index1, index2)
  40.     $refresh = true
  41.   end
  42. end
复制代码
(因为时间关系,我就不详细说了,不过我相信根据注释,也不难看懂吧……)
这种用变量判断刷新的方法,不是最好的方法,却是最简单的方法。
测试一下,已经不卡了,看~我多厉害~(众:滚!!)
好吧,我们现在要开始介绍Window的属性了。
首先第一个,当然是最最重要的opacity啦~
opacity其实是用来控制窗口内除了描绘内容以外的的其它地方(背景+边框)的不透明度的,也就是说,想要窗口只显示内容,把opacity设为0就好了。
F1里是这样说的:
窗口的不透明度(0~255)。超出此范围的数值会自动修正。

一般l来说,初始化窗口的属性都是在initialize里初始化的,所以我们可以在initialize里加一句话:
  1. self.opacity = 0
复制代码
看看效果~

真的把背景给隐藏起来了呢!看吧,这比之前的简单多了~
但是呢,这个窗口这么大,好像出现了一些问题呢,比如说~

主角呢?主角去哪儿了?
很明显,他被埃里克的头像挡住了。
那我们要怎么办呢?对了!我们可以把内容调成半透明!
好啊,试试看吧:在initialize里加上下面这句话:
  1. self.contents_opacity = 75
复制代码
看看效果吧:

啊,这下主角就看得很清楚了,所以你也知道contents_opacity的功能了吧,没错,就是修改窗口的内容的不透明度。
照例放上F1:
窗口内容的不透明度(0~255)。超出此范围的数值会自动修正。默认值为255。

但是这样子的话,不会导致窗口看不清楚吗?
所以,我们要使角色走上去才变成半透明,也就是说,又要开始写一大堆脚本了。
先把刚刚添上那句self.contents_opacity = 75删掉,然后再update里添上这样一段脚本:
  1. if $game_player.screen_x >= 0 and $game_player.screen_x <= self.width and
  2.        $game_player.screen_y >= 0 and $game_player.screen_y <= self.height
  3.       self.contents_opacity = 75
  4.     else self.contents_opacity = 255
  5.     end
复制代码
我相信,通过之前的学习,这段脚本里唯一需要解释的就是$game_player.screen_x$game_player.screen_y了吧。
顾名思义,这是用来获取玩家在画面上的x、y坐标的。
这个就是用来判断玩家是否走到了窗口的范围里,如果是,就半透明窗口,否则窗口恢复原状。
这样就人性化很多了吧!
说到这里,这节课就讲完了。现在,我们的窗口脚本就像以下这样了:
  1. class Game_Actor < Game_Battler
  2.   #----------------------------------------------------------------------------
  3.   # * 重命名方法
  4.   #----------------------------------------------------------------------------
  5.   alias ms_refresh refresh
  6.   alias ms_tp tp=
  7.   alias ms_add_state add_state
  8.   #--------------------------------------------------------------------------
  9.   # * 刷新
  10.   #--------------------------------------------------------------------------
  11.   def refresh
  12.     ms_refresh
  13.     $refresh = true
  14.   end
  15.   #----------------------------------------------------------------------------
  16.   # * 更改 TP
  17.   #----------------------------------------------------------------------------
  18.   def tp=(tp)
  19.     ms_tp(tp)
  20.     $refresh = true
  21.   end
  22.   #----------------------------------------------------------------------------
  23.   # * 附加状态
  24.   #----------------------------------------------------------------------------
  25.   def add_state(state_id)
  26.     ms_add_state(state_id)
  27.     $refresh = true
  28.   end
  29. end
  30. class Game_Party
  31.   #----------------------------------------------------------------------------
  32.   # * 重命名方法
  33.   #----------------------------------------------------------------------------
  34.   alias ms_swap_order swap_order
  35.   #----------------------------------------------------------------------------
  36.   # * 交换顺序
  37.   #----------------------------------------------------------------------------
  38.   def swap_order(index1, index2)
  39.     ms_swap_order(index1, index2)
  40.     $refresh = true
  41.   end
  42. end
  43. #==============================================================================
  44. # ** Window_MapStatus
  45. #==============================================================================
  46. class Window_MapStatus < Window_Base
  47.   #----------------------------------------------------------------------------
  48.   # * 初始化
  49.   #----------------------------------------------------------------------------
  50.   def initialize
  51.     super(0, 0, 273, 144)
  52.     self.opacity = 0
  53.     refresh
  54.   end
  55.   #----------------------------------------------------------------------------
  56.   # * 刷新画面
  57.   #----------------------------------------------------------------------------
  58.   def update
  59.     super
  60.     refresh if $refresh
  61.     $refresh = false
  62.     if $game_player.screen_x >= 0 and $game_player.screen_x <= self.width and
  63.        $game_player.screen_y >= 0 and $game_player.screen_y <= self.height
  64.       self.contents_opacity = 75
  65.     else self.contents_opacity = 255
  66.     end
  67.   end
  68.   #----------------------------------------------------------------------------
  69.   # * 更新内容
  70.   #----------------------------------------------------------------------------
  71.   def refresh
  72.     self.contents.clear
  73.     draw_actor_face($game_party.members[0], 0, 0)
  74.     draw_actor_name($game_party.members[0], 0, 0)
  75.     draw_actor_level($game_party.members[0], 101, 0)
  76.     draw_actor_icons($game_party.members[0], 0, 72)
  77.     draw_actor_hp($game_party.members[0], 101, 24, self.contents.width - 101)
  78.     draw_actor_mp($game_party.members[0], 101, 48, self.contents.width - 101)
  79.     draw_actor_tp($game_party.members[0], 101, 72, self.contents.width - 101)
  80.     draw_actor_exp($game_party.members[0], 0, 96, self.contents.width)
  81.   end
  82.   #----------------------------------------------------------------------------
  83.   # * 描绘EXP槽
  84.   #----------------------------------------------------------------------------
  85.   def draw_actor_exp(actor, x, y, width=124)
  86.     rate = actor.exp.to_f / actor.next_level_exp.to_f
  87.     draw_gauge(x, y, width, rate, Color.new(0, 255, 0), Color.new(100, 255, 100))
  88.     self.contents.font.color = text_color(16)
  89.     self.contents.draw_text(x, y, 56, 24, "EXP")
  90.     self.contents.font.color = Color.new(255, 255, 255)
  91.     en = "#{actor.exp}/#{actor.next_level_exp}"
  92.     self.contents.draw_text(x, y, width, 24, en, 2)
  93.   end
  94.   #----------------------------------------------------------------------------
  95.   # * 描绘值槽
  96.   #----------------------------------------------------------------------------
  97.   def draw_gauge(x, y, width, rate, color1, color2)
  98.     fill_w = (width * rate).to_i
  99.     self.contents.gradient_fill_rect(x, y+12, fill_w, 6, color1, color2, true)
  100.     self.contents.gradient_fill_rect(x, y+18, fill_w, 6, color2, color1, true)
  101.     self.contents.fill_rect(x, y+12, width, 2, Color.new(255, 255, 255))
  102.     self.contents.fill_rect(x, y+22, width, 2, Color.new(255, 255, 255))
  103.     self.contents.fill_rect(x, y+14, 2, 8, Color.new(255, 255, 255))
  104.     self.contents.fill_rect(x+width-2, y+14, 2, 8, Color.new(255, 255, 255))
  105.   end
  106. end
  107. class Scene_Map < Scene_Base
  108.   #----------------------------------------------------------------------------
  109.   # * 重命名方法
  110.   #----------------------------------------------------------------------------
  111.   alias ms_sta start
  112.   #----------------------------------------------------------------------------
  113.   # * 开始处理
  114.   #----------------------------------------------------------------------------
  115.   def start
  116.     ms_sta
  117.     @mapstatus_window = Window_MapStatus.new
  118.   end
  119. end
复制代码
你写对了吗?
以下是范例:
http://pan.baidu.com/share/link?shareid=416364&uk=2735273937
总结
在这节课,我们主要学了以下的东西:
名称
LZ的说明
F1/默认脚本里的说明
alias 旧方法名 新方法名
给旧方法名的方法起一个别名(新方法名)
可以给一个方法或全局变量指定其别名。指定的方法名称可以是标识符或符号(不可使用如 obj.method 这样的表达式)。调用方法时不会计算别名的参数表达式。
使用方法别名时,既使重新定义该方法,该方法的原有定义依然会被保留。当想要改变方法的行为,又要在新定义的方法内使用旧定义方法的结果时可以使用。
super
调用父类同名方法的内容。
呼叫超类中正由当前方法所覆盖的函数。若是省略了括号和参数,当前方法的参数则原封不动的传递给超类中的同名方法。若是调用超类方法而不想使用当前参数时,用空的括号如: super( )。

名称
LZ的说明
F1/默认脚本里的说明
window.opacity
窗口内除了内容以外其他所有元素的不透明度。
窗口的不透明度(0~255)。超出此范围的数值会自动修正。
window.contents_opacity
窗口内容的不透明度。
窗口内容的不透明度(0~255)。超出此范围的数值会自动修正。默认值为255。
关于窗口的三个主要方法,我们放到培优班再说。
培优班
窗口的newupdatedispose.
这三个方法是十分重要的,在VA里,对于写脚本的我们来说,update和dispose都是可以忽略的,因为根据Scene_Base的内容,所有的窗口都是会自动刷新和释放的,所以一般都是无视这两个家伙的。我在这里就说一说他们的功能吧!
window.new是最基础的,用于生成一个window的实例,没有它,后面的一切都没有用。而这个生成的实例,一般都会代入到某个变量中,方便后来对其修改。比如说,我们首次接触的就是:
  1. $w = Window_MapStatus.new
复制代码
它的意义就是把Window_Status的实例代入到$w里,然后才能使用$w.update来刷新窗口。
window.update其实就是调用了窗口内一个叫update的方法。原则上,这个方法是每帧调用的,所以有什么要刷新的一般都写到这个方法内。
window.dispose是调用了dispose这个方法。这个方法是用来释放窗口的,就相当于这个窗口不用了,把它扔进垃圾桶是一样的。
现在,我们就学了关于窗口类的三个基本方法:
名称
LZ的说明
F1/默认脚本里的说明
window.new
生成window的实例。
——
window.update
刷新window。

实际是调用了update这个方法。

刷新光标的闪烁和暂停标记的动画。原则上每一帧都会调用一次。
window.dispose
释放window。

实际上是调用了dispose这个方法。

释放窗口。若窗口已释放则什么都不做。
后记
从9号写到21好,足足用了12天,想必这是我偷懒的结果吧……
当初的那一份热情似乎已经不见了呢,所以这一篇写得格外马虎。
有神马问题可以问我。
还有,这是最后一篇了……
作者: 神秘来客3    时间: 2013-3-9 20:12
等死了终于来了。。。快抢一楼。。。
作者: 1985520777    时间: 2013-3-10 01:39
赶上直播了么·
作者: yuyuyuyui    时间: 2013-8-11 20:29
按SAVE時STATUS跑到存檔上面了0.0/~是什麼問題?
作者: yuyuyuyui    时间: 2013-8-12 19:53
yuyuyuyui 发表于 2013-8-11 20:29
按SAVE時STATUS跑到存檔上面了0.0/~是什麼問題?

保上圖片

science game1 - 複製.jpg (111.43 KB, 下载次数: 19)

science game1 - 複製.jpg

作者: 倾灬城    时间: 2013-9-4 15:24
本帖最后由 倾灬城 于 2013-9-5 13:42 编辑

现在回复算挖坟吗=-=——左边没有白字

太懒所以没认真读前面的教程=-=直接拿了最后的脚本=-=
所以当角色升级后会发生数字重叠的现象……

还需要改哪里求帮助QAQ

______________________________________
可以讲一下吗?还需要修改哪里QAQ?@945127391  

QQ图片20130904154005.jpg (19.91 KB, 下载次数: 13)

QQ图片20130904154005.jpg

作者: pahk2006    时间: 2013-9-20 04:51
那麼如果我想顯示隊伍內所有的人呢? 要弄5個這樣的腳本嗎 OTZ||||
而且如果隊伍沒人的話就不顯示的 腳本是怎樣?
作者: 战斗的双手    时间: 2016-3-21 22:46
本帖最后由 战斗的双手 于 2016-3-21 22:48 编辑

多谢!!!!!!!!!!!!!!!!!!!!!




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1