Project1

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

作者: 945127391    时间: 2013-2-23 23:37
标题: 【渣作品】VA脚本教程(二)<2013.2.26完结>
本帖最后由 945127391 于 2013-3-9 00:39 编辑

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

如果你把上面的给看完了,就可以就绪看下去了。
玖肆伍的脚本教程(二)
好了,我们开始讲课……等等!
上次的课后作业还没有说呢,现在就把答案揭晓了吧!
①:
这个要在Window_MapStatus里新建一个方法,内容如下:
  1. #----------------------------------------------------------------------------
  2. # * 描绘名称
  3. #----------------------------------------------------------------------------
  4. def draw_actor_name(actor, x, y, width = 112)
  5.   color = Color.new(0, 0, 0)
  6.   color = crisis_color if actor.hp < actor.mhp /
  7.   color = knockout_color if actor.hp == 0
  8.   change_color(color)
  9.   draw_text(x, y, width, line_height, actor.name)
  10. end
复制代码
你写对了吗?
(PS:你直接写成以下的样子其实也没错:
  1. #----------------------------------------------------------------------------
  2. # * 描绘名称
  3. #----------------------------------------------------------------------------
  4. def draw_actor_name(actor, x, y, width = 112)
  5.   change_color(Color.new(0, 0, 0))
  6.   draw_text(x, y, width, line_height, actor.name)
  7. end
复制代码

②:
嗯……其实这个作业不需要显示的,只用写出窗口的代码就行了,答案如下:
  1. class Window_MapXY < Window_Base
  2.   #----------------------------------------------------------------------------
  3.   # * 初始化
  4.   #----------------------------------------------------------------------------
  5.   def initialize
  6.     super(0, 0, 273, 72)
  7.     refresh
  8.   end
  9.   #----------------------------------------------------------------------------
  10.   # * 刷新画面
  11.   #----------------------------------------------------------------------------
  12.   def update
  13.     super
  14.     refresh
  15.   end
  16.   #----------------------------------------------------------------------------
  17.   # * 更新内容
  18.   #----------------------------------------------------------------------------
  19.   def refresh
  20.     self.contents.clear
  21.     self.contents.draw_text(0, 0, self.contents.width, 24, "角色所在位置:")
  22.     self.contents.draw_text(0, 24, self.contents.width, 24, "(#{$game_player.x},#{$game_player.y})", 2)
  23.   end
  24. end
复制代码
好了,作业讲完了,我们就继续来讲课吧!
上次把头像名称和等级给描绘出来了,接下来我们就要描绘状态了。
想要描绘出状态的图标,我们首先要知道应该如何描绘图标,描绘图标一般使用draw_icon方法:
draw_icon(icon_index, x, y[, enabled])
在(x, y)处描绘icon_index号图标。
enabled是有效标志,可不填,默认为true。为false时半透明绘制。

这个东东的XY坐标计算和描绘头像的draw_face差不多,只不过它这里运用到了一个新的知识点:填充度。在draw_icon里有一句:
  1. contents.blt(x, y, bitmap, rect, enabled ? 255 : translucent_alpha)
复制代码
首先,我们看到contents,就要立刻想到它相当于self.contents
然后,后面的那句enabled ? 255 : translucent_alpha,其实和
  1. if enabled
  2.   return 255
  3. else return translucent_alpha
  4. end
复制代码
的效果差不过,而第一句if enabled其实少掉了== true,但是也不会错,因为这是个偷懒方法(喂!)
然后在这里的话translucent_alpha其实是返回160,所以说当enabledfalse时,描绘出来的图标的填充度就是160,也就造成了“半透明”的效果。
现在,你就知道了吧,填充度就相当于透明度。
然后我们知道了如何描绘图标,我们还要知道该如何获取对应的状态的图标ID。
其实每一个状态都由与其对应的一个RPG::State来管理,而在RPG::State里有一个叫icon_index的属性,来储存图标ID,而在游戏中,系统自动帮我们生成了一个叫$data_states的变量,这个变量其实是由许多RPG::State的实例组成的,所以我们使用以下脚本,就可以知道ID号状态的图标ID了:
  1. $data_states[id].icon_index
复制代码
但是,我们这个状态的ID并不是没有目标的,而是可以从特定的地方获取的。
由于我们要描绘的是角色(领队)的状态,于是我们就要用以下的脚本来获取领队的状态的图标ID:
  1. $game_party.members[0].state_icons + $game_party.members[0].buff_icons
复制代码
其实这句话的返回值其实是一个储存了$game_party.members[0](也就是领队)所有状态的图标ID的数组。
而我们要全部描绘,就要用到for...in...end这个循环了。
我们需要不断的循环描绘状态的图标,而且必须要有个只随着循环的次数而增加,那么最好的选择就是for...in...end了。
于是乎,先把以下的内容扔进refresh里:
  1.     icons = $game_party.members[0].state_icons + $game_party.members[0].buff_icons
  2.     for i in 0...icons.size
  3.       draw_icon(icons[i], i * 24, 72)
  4.     end
复制代码
效果就会如下:

但是,这样就出现了一个问题:当状态数量大于4的时候,显示的图标就会超过头像的范围,如下:

但是旁边的那个地方我们要留着画血槽的啊泥煤!
所以我们要限定描绘的那个状态的数量,于是就要用到数组的一个方法:self[start, length]
self[start, length]
返回由从self[start]开始length个元素组成的数组。

F1里是这样说的:
返回从 start 算起,包含 length 个元素的数组。若 start 为负值,则从尾部开始算起(最后一个元素的索引为 -1)。若 length 超出从 start 算起的数组剩余长度,则忽略超出的部分。若 length 为负值则返回 nil。

于是,我们要知道现在能够描绘的数组有多少个。
其实这是个固定的量:头像宽度/图标宽度,也就是96/24=4。
所以我们要要在icons = $game_party.members[0].state_icons + $game_party.members[0].buff_icons下面新增这样一句话:
  1. icons = icons[0, 4]
复制代码
很明显,这句话就获取了icons里开头的4个元素,然后再代入到icons这个变量里。

嗯……现在效果不错。
但其实描绘状态可以使用draw_actor_icons来描绘角色的状态。
draw_actor_icons(actor, x, y[, width])
在(x, y)处描绘actor的状态。
width是描绘的长度,可以不填,默认为96。

所以呢,我们把刚才写的那一堆全都换成:
  1. draw_actor_icons($game_party.members[0], 0, 72)
复制代码
呐,状态就描绘完了。我们就要描绘HP、MP、TP和EXP槽了~
描绘HP、MP和TP槽都有自己专用的方法,下面就逐个介绍:
draw_actor_hp(actor, x, y[, width])
在(x, y)处描绘actor的HP槽。
width为宽度,可不填,默认为124。
draw_actor_mp(actor, x, y[, width])
在(x, y)处描绘actor的MP槽。
width为宽度,可不填,默认为124。
draw_actor_tp(actor, x, y[, width])
在(x, y)处描绘actor的TP槽。
width为宽度,可不填,默认为124。
所以我们在refresh里新增以下三句话:
  1. draw_actor_hp($game_party.members[0], 101, 24, self.contents.width - 101)
  2. draw_actor_mp($game_party.members[0], 101, 48, self.contents.width - 101)
  3. draw_actor_tp($game_party.members[0], 101, 72, self.contents.width - 101)
复制代码
效果就会如下图所示:

唔……效果不错,但是不是太乏味了一点呢?
于是乎,我们接下来就要改造一下血槽了~~
首先,我们要知道,在draw_actor_hpdraw_actor_mpdraw_actor_tp里头都用到了同一个方法来描绘值槽,那就是draw_gauge,所以我首先要对draw_gauge这个方法动工。
首先,来个最基本的:在窗口的脚本里添加这样一个新的方法:
  1. def draw_gauge(x, y, width, rate, color1, color2)
  2. end
复制代码
其实,在Window_Base里也定义了这个方法,只不过我们在这里把这个方法重新定义了一遍,所以在这个窗口内调用draw_gauge这个方法的时候,就会按照这里定义的来执行,而在其他地方调用这个方法的时候,就会按照Window_Base或者那里所定义的draw_gauge来执行。所以说,这样做是一个十分安全的方法。
然后,我们在draw_gauge里添加一句话:
  1. fill_w = (width * rate).to_i
复制代码
其实这个是用来计算要填充的宽度的,但是这个rate是怎么计算出来的呢?
嗯……这是我们培优班的内容了,让我们推后再说。
然后,我们要添加这样两句话:
  1. self.contents.gradient_fill_rect(x, y+12, fill_w, 6, color1, color2, true)
  2. self.contents.gradient_fill_rect(x, y+18, fill_w, 6, color2, color1, true)
复制代码
这里又有个新方法:gradient_fill_rect。其实这个是用来描绘渐变色的,介绍如下:
gradient_fill_rect(x, y, width, height, color1, color2[, vertical])
在(x, y)处描绘宽度为width,高度为height,由color1渐变到color2的渐变色。
vertical用于设定渐变方向,true为纵向,可不填。默认为横向。

F1里是这样说的:
将位图区域 (x, y, width, height) 或矩形(Rect 矩形类) 填满从颜色 color1Color 色彩类) 至 color2(Color 色彩类)的渐层色彩。
将 vertical 设为 true 生成纵向的渐层色彩,预设为横向渐层。

然后呢,描绘出来的效果就是这样:

嗯……虽然比以前好很多了,但是看起来还是怪怪的啊……对了!我们不如描个边吧!
但是,要怎么画线呢?
其实,在RM里,每一个点都可以视为1像素*1像素的正方形,而线是由许多个点组成的,也就可以看成 (1*长度)像素*(1*宽度)像素 的长方形了。
理清了思路以后,我们就要开始描绘了。
首先,描绘第一条线:在self.contents.gradient_fill_rect(x, y+18, fill_w, 6, color2, color1, true)之后添加这样一句话:
  1. self.contents.fill_rect(x, y+12, width, 2, Color.new(255, 255, 255))
复制代码
好了,这样就把第一条线给描绘出来了。我们先别急着看效果,先把这句话分析一下:
首先,通过前面的self.contents,我们能够知道fill_rect也是一个位图类的方法。
那这个方法具体的参数和说明是怎样的呢?让我来告诉大家吧!
fill_rect(x, y, width, height, color)
在(x, y)处描绘一个宽度为width,高度为height,填充了颜色color的矩形。

F1的说法是:
将位图区域 (x, y, width, height) 或矩形(Rect 矩形类 )填满指定的颜色 color (Color 色彩类 )。

于是乎,我们刚才写的那句话其实就是在(x, y)处描绘了一个 width * 2 的长方形。
(P.S请弄清楚上面的那一句x、y以及width和蓝字里的x、y、width其实是不同的两个变量,虽然名字相同。)
那剩下的三条线你们会画了吧,你们不如先自己写出来,再看答案吧!

答案如下:
  1. self.contents.fill_rect(x, y+22, width, 2, Color.new(255, 255, 255))
  2. self.contents.fill_rect(x, y+14, 2, 8, Color.new(255, 255, 255))
  3. self.contents.fill_rect(x+width-2, y+14, 2, 8, Color.new(255, 255, 255))
复制代码
恩恩,这样子这些槽看起来就漂亮多了~~(众:有吗?)
最终预览图如下:

好了,这样子的话整个窗口就画完啦!
写到最后,窗口的代码就是这样啦~你写对了吗?
  1. #==============================================================================
  2. # ** Window_MapStatus
  3. #==============================================================================
  4. class Window_MapStatus < Window_Base
  5.   #----------------------------------------------------------------------------
  6.   # * 初始化
  7.   #----------------------------------------------------------------------------
  8.   def initialize
  9.     super(0, 0, 273, 144)
  10.     refresh
  11.   end
  12.   #----------------------------------------------------------------------------
  13.   # * 刷新画面
  14.   #----------------------------------------------------------------------------
  15.   def update
  16.     super
  17.     refresh
  18.   end
  19.   #----------------------------------------------------------------------------
  20.   # * 更新内容
  21.   #----------------------------------------------------------------------------
  22.   def refresh
  23.     self.contents.clear
  24.     draw_actor_face($game_party.members[0], 0, 0)
  25.     draw_actor_name($game_party.members[0], 0, 0)
  26.     draw_actor_level($game_party.members[0], 101, 0)
  27.     draw_actor_icons($game_party.members[0], 0, 72)
  28.     draw_actor_hp($game_party.members[0], 101, 24, self.contents.width - 101)
  29.     draw_actor_mp($game_party.members[0], 101, 48, self.contents.width - 101)
  30.     draw_actor_tp($game_party.members[0], 101, 72, self.contents.width - 101)
  31.   end
  32.   #----------------------------------------------------------------------------
  33.   # * 描绘值槽
  34.   #----------------------------------------------------------------------------
  35.   def draw_gauge(x, y, width, rate, color1, color2)
  36.     fill_w = (width * rate).to_i
  37.     self.contents.gradient_fill_rect(x, y+12, fill_w, 6, color1, color2, true)
  38.     self.contents.gradient_fill_rect(x, y+18, fill_w, 6, color2, color1, true)
  39.     self.contents.fill_rect(x, y+12, width, 2, Color.new(255, 255, 255))
  40.     self.contents.fill_rect(x, y+22, width, 2, Color.new(255, 255, 255))
  41.     self.contents.fill_rect(x, y+14, 2, 8, Color.new(255, 255, 255))
  42.     self.contents.fill_rect(x+width-2, y+14, 2, 8, Color.new(255, 255, 255))
  43.   end
  44. end
复制代码
同学甲(你终于出现了……):EXP条呢?
呐,EXP条就留给大家作为作业啦!(光速秒逃)
总结
嗯……这节课我们学习了一些方法,包括:
名称
LZ的说明
F1/默认脚本里的说明
self.contents.fill_rect(x, y, width, height, color)
在(x, y)处描绘一个宽度为width,高度为height,填充了颜色color的矩形。
将位图区域 (x, y, width, height) 或矩形(Rect 矩形类 )填满指定的颜色 color (Color 色彩类 )。
self.contents.gradient_fill_rect(x, y, width, height, color1, color2[, vertical])
在(x, y)处描绘宽度为width,高度为height,由color1渐变到color2的渐变色。
vertical用于设定渐变方向,true为纵向,可不填。默认为横向。
将位图区域 (x, y, width, height) 或矩形(Rect 矩形类) 填满从颜色 color1Color 色彩类) 至 color2(Color 色彩类)的渐层色彩。

名称
LZ的说明
F1/默认脚本的说明
draw_icon(icon_index, x, y[, enabled])
在(x, y)处描绘icon_index号图标。
enabled是有效标志,可不填,默认为true。为false时半透明绘制。
——
draw_actor_hp(actor, x, y[, width])
在(x, y)处描绘actor的HP槽。
width为宽度,可不填,默认为124。
——
draw_actor_mp(actor, x, y[, width])
在(x, y)处描绘actor的MP槽。
width为宽度,可不填,默认为124。
——
draw_actor_tp(actor, x, y[, width])
在(x, y)处描绘actor的TP槽。
width为宽度,可不填,默认为124。
——

对了,大家不觉得这一个窗口皮肤似乎太枯燥了吗?
我们可以给它放上个背景吧!
恩恩!我们下节课不仅要把窗口的显示转为“正式版”,还要给它许多人性化的功能呢!
所以下节课可能要说很多东西,大家注意喽~~
好了,可爱的作业又来了~
课后作业(一道必做,一道可选)
所谓的“必做”,不是指你一定要把答案告诉我,而是指你至少要在脑袋里把答案给想出来。
①(必做)draw_icon是在___________里定义的方法。
②这个作业就是要描绘EXP槽了。
你可以在Window_MapStatus里定义一个叫draw_actor_exp的方法,然后在refresh里调用哦!
这次是特别大酬宾= =,有预览图哦:

就是上面这样的效果啦~
提示:一.角色当前经验:actor.exp
               升到下一级所需经验:actor.next_level_exp
          二.比率的计算请看培优班;
          三.范例里的颜色分别是Color.new(0, 255, 0)和Color.new(100, 255, 100)。

不会很难吧~
培优班
培优班要说什么来着?
啊,我想起来了~是要说描绘血槽的时候的rate(比率)是怎么算出来的吧。
其实很简单:在Game_BattlerBase里有一个叫hp_rate的方法(517~519),它的定义是这样滴:
  1. def hp_rate
  2.   @hp.to_f / mhp
  3. end
复制代码
头尾的那两句不用我说了吧,主要就在中间那一句:
他那里面的@hp和mhp我们可以理解为获取战斗着的HP和最大HP(MHP),而用HP除以MHP,就可以得到HP占MHP的多少,然后再乘上width,要描绘的宽度就出来了。
(P.S 实际上,Game_Actor,也就是掌管角色的类的父类的父类就是Game_BattlerBase,所以Game_BattlerBase里的方法都被继承到Game_Actor里去了。)
但是,那个to_f是啥呢?
我们都知道,在RM中,整数运算一定得整数。而HP永远小于或等于MHP(正常来说是这样滴),所以如果用整数来算(也就是HP和MHP都为整数)的话,得数永远只有两个数:0和1!
所以那句to_f就起到了一个很重要的作用:把整数转换为浮点数,这样算出来的数也会出现浮点数了。
同样的,也有mp_rate(523~525)和tp_rate(529~531)这两个方法,有兴趣的可以去看一下。
Q&A
这里用来放一些读者在回复中提的问题以及我的回答。
暂时还没有,似乎。
后记
花了几天,终于把这给写完了。
拖这么多天真是很抱歉,因为要上学了,所以也忙了起来。
以后的更新可能要等很久了,我尽量吧。
谢谢大家的支持 +^+
作者: jerrypan    时间: 2013-2-24 14:37
等到第二期了,占位观摩。{:2_284:}
作者: xixifilm    时间: 2013-2-25 11:40
观摩学习
作者: 神秘来客3    时间: 2013-2-25 16:12
本帖最后由 神秘来客3 于 2013-2-26 11:48 编辑

(二)来了!
作者: 神秘来客3    时间: 2013-2-25 16:25
哇哇哇,不错不错,下期学会了正式窗口显示(geng)就(hao)了
作者: 神秘来客3    时间: 2013-2-25 17:15
{:2_270:}{:2_286:}为毛状态显示木反应?
作者: 神秘来客3    时间: 2013-2-26 11:32
  1.     icons = $game_party.members[0].state_icons + $game_party.members[0].buff_icons
  2.     for i in 0...icons.size
  3.       draw_icon(icons[i], i * 24, 72)
  4.     end
复制代码
这句话无效,但是一行的那句有效
作者: 千昭    时间: 2013-2-26 19:14
很好  我又来受教了
作者: 神秘来客3    时间: 2013-3-8 17:26
{:2_270:}快出(三)~
作者: 战斗的双手    时间: 2016-3-21 20:46
描绘状态不显示,代码整个复制过来也不显示,不知道什么原因!




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