赞 | 1 |
VIP | 0 |
好人卡 | 11 |
积分 | 0 |
经验 | 26243 |
最后登录 | 2014-8-4 |
在线时间 | 841 小时 |
Lv1.梦旅人
- 梦石
- 0
- 星屑
- 48
- 在线时间
- 841 小时
- 注册时间
- 2010-8-11
- 帖子
- 1135
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 945127391 于 2013-3-21 22:19 编辑
一.本教程提供给一些已经有一点脚本基础的学习者们(至少你要知道变量啊函数啊什么的),如果你没有达到,那我希望你打开着VA的F1文档来看这篇教程;
二.如果你已经有一点脚本基础了,我也希望你打开着F1来看,因为我将在以下的教程中引用到许多F1里的内容;
三.本教程不会太多的说一些理论性的东西(比如浮点数是什么啊之类的),免得说多错多= =;
四.本人由于第一次写教程,所以有(fei)点(chang)乱,请多多包容;
五.如果有什么疑问或者发现了什么错误之处,又或者有什么意见或建议,欢迎回复,毕竟我也是个学习者而已。
如果你把上面的给看完了,就可以就绪看下去了。
之前太忙了,所以拖到现在才说……实在很抱歉……
然后,这是这个脚本教程系列的最后一章了……也许……
好吧,现在把昨天的作业给说一下:
①draw_icon是在Window_Base里定义的方法。
②先在refresh里添加一句:- draw_actor_exp($game_party.members[0], 0, 96, self.contents.width)
复制代码 然后在窗口的脚本里添加以下这一个方法:- #----------------------------------------------------------------------------
- # * 描绘EXP槽
- #----------------------------------------------------------------------------
- def draw_actor_exp(actor, x, y, width=124)
- rate = actor.exp.to_f / actor.next_level_exp.to_f
- draw_gauge(x, y, width, rate, Color.new(0, 255, 0), Color.new(100, 255, 100))
- self.contents.font.color = text_color(16)
- self.contents.draw_text(x, y, 56, 24, "EXP")
- self.contents.font.color = Color.new(255, 255, 255)
- en = "#{actor.exp}/#{actor.next_level_exp}"
- self.contents.draw_text(x, y, width, 24, en, 2)
- end
复制代码 至于原理……我就不说了,自己慢慢吃透吧……
嗯……这次我们要说的是关于窗口的各种属性,比如visible啊、opacity啥的。
但在这之前,我们要先把Window_MapStatus显示到地图上来。
先来分析一下我们之前用来显示出口的方法,其实重点就在几句脚本里。- $w = Window_MapStatus.new
复制代码 这句脚本其实是把Window_MapStatus的一个实例代入$w这个变量里,方便对其进行修改而又不会污染Window_MapStatus里的代码。这是用来更新窗口的,本质上是调用了$w(也就是Window_MapStatus)里的update方法。
仔细看看,我们写的代码里,也有update这个方法,且定义如下:- def update
- super
- refresh
- end
复制代码 这里头有一个super,是用来调用父类的同名方法的,我们目前不需要知道的那么清楚,只需要知道在这里,他是调用了父类(Window_Base)里的update方法。
然后,我们看到第三行——refresh这句话上面。
我们之前的那两课都一直在写显示窗口的内容,其实都是在refresh方法里写的。
一般来说,描绘窗口的内容的代码都可以写在refresh里。但是要注意的是,Window_Base里并没有refresh这个方法,所以你的窗口如果是直接继承Window_Base的话,就不要用super了。
于是,我们就能看出,在update里调用refresh,是为了让它每一次刷新的时候都重绘一次窗口。这是最简单的方法,如果你的窗口十分简单,就可以这样。但是如果你的窗口很复杂(= =),每帧调用会很卡的。
基本上,显示窗口都脱离不开这两个方法。
理论讲完了,我们来实践一下吧!
新建一个脚本页,在里面输入:- class Scene_Map < Scene_Base
- #----------------------------------------------------------------------------
- # * 重命名方法
- #----------------------------------------------------------------------------
- alias ms_sta start
- #----------------------------------------------------------------------------
- # * 开始处理
- #----------------------------------------------------------------------------
- def start
- ms_sta
- end
- end
复制代码 这是为Scene_Map添加东东而做准备。而这里有一个很重要的知识点——alias。
这是给方法起别名的(话说我为什么没有在可爱的F1里找到关于这个的说明!?),好吧,那就凭自己的理解来说明这个方法……
比如说,有以下语句:- @i = 0
- def a
- @i += 1
- end
- alias a2 a
- def b
- a2
- @i *= 15
- end
- 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的话,脚本的兼容性就会增强很多。
所以说,alias和super都是两个很重要的东西。
好了,脱轨这么久,我们回到原来的内容上。
根据刚才对alias的解释,大家都应该知道alias ms_sta start是啥意思吧,没错,就是用来防止原来的Scene_Map里的start被覆盖的。
好了,然我们进行下一步:在start方法里加上一句:- @mapstatus_window = Window_MapStatus.new
复制代码 然后再把显示窗口的那个事件删掉,然后再运行……
哇哇!出现了呢!
来,我们来升升级,哇!升到99级了呢!
好好玩~(= =)
但是,为什么我们没有用到update呢?
根据RMVA的脚本RGSS里的Scene_Base里,update和dispose的写法来说,窗口的update与dispose都是自动的,说以就节省了制作者的很多心思。
抱歉我一开始忘了这一点,所以开头的脚本有一点错误,现已纠正,抱歉。
好了好了,一般来说这样就可以用了~
但是为什么好像好卡的样子!?
那是因为每帧刷新,而刷新的时候顺便重绘内容的原因。因为本来描绘文字就需要一段时间,现在还要每帧都描绘这么多文字,自然就要卡喽~
那要怎么解决呢?
首先,先把Window_MapStatus里update内的refresh改成:实际上,这句话是给调用refresh方法设了个条件:当$refresh为true时。也就相当于以下这段脚本:- if $refresh == true
- refresh
- end
复制代码 但是,全局变量的初始值是nil,而我们又不给它更改数值的话,他永远都不会是true!
于是乎,我们就要设定它在哪儿变成true,哪儿又变回false。
变回false就比较简单了,直接在refresh if $refresh后面加上一句:就可以了。
但是,它要在哪里变成true呢?
我们这个窗口里,要描绘的是头像、名字、状态、HP槽、MP槽、TP槽和EXP槽。所以我们就要考虑到在更改角色、更变状态、改变HP/MP/TP/EXP的时候刷新,也就是把$refresh变为true。
p.s 更周全的是要考虑到更变名称和头像时刷新,但是我很懒……
而这些家伙几乎全都在Game_BaseBatter和Game_Actor还有Game_Party里,以下是脚本:- class Game_Actor < Game_Battler
- #----------------------------------------------------------------------------
- # * 重命名方法
- #----------------------------------------------------------------------------
- alias ms_refresh refresh
- alias ms_tp tp=
- alias ms_add_state add_state
- #--------------------------------------------------------------------------
- # * 刷新
- #--------------------------------------------------------------------------
- def refresh
- ms_refresh
- $refresh = true
- end
- #----------------------------------------------------------------------------
- # * 更改 TP
- #----------------------------------------------------------------------------
- def tp=(tp)
- ms_tp(tp)
- $refresh = true
- end
- #----------------------------------------------------------------------------
- # * 附加状态
- #----------------------------------------------------------------------------
- def add_state(state_id)
- ms_add_state(state_id)
- $refresh = true
- end
- end
- class Game_Party
- #----------------------------------------------------------------------------
- # * 重命名方法
- #----------------------------------------------------------------------------
- alias ms_swap_order swap_order
- #----------------------------------------------------------------------------
- # * 交换顺序
- #----------------------------------------------------------------------------
- def swap_order(index1, index2)
- ms_swap_order(index1, index2)
- $refresh = true
- end
- end
复制代码 (因为时间关系,我就不详细说了,不过我相信根据注释,也不难看懂吧……)
这种用变量判断刷新的方法,不是最好的方法,却是最简单的方法。
测试一下,已经不卡了,看~我多厉害~(众:滚!!)
好吧,我们现在要开始介绍Window的属性了。
首先第一个,当然是最最重要的opacity啦~
opacity其实是用来控制窗口内除了描绘内容以外的的其它地方(背景+边框)的不透明度的,也就是说,想要窗口只显示内容,把opacity设为0就好了。
F1里是这样说的:
窗口的不透明度(0~255)。超出此范围的数值会自动修正。
一般l来说,初始化窗口的属性都是在initialize里初始化的,所以我们可以在initialize里加一句话:看看效果~
真的把背景给隐藏起来了呢!看吧,这比之前的简单多了~
但是呢,这个窗口这么大,好像出现了一些问题呢,比如说~
主角呢?主角去哪儿了?
很明显,他被埃里克的头像挡住了。
那我们要怎么办呢?对了!我们可以把内容调成半透明!
好啊,试试看吧:在initialize里加上下面这句话:- self.contents_opacity = 75
复制代码 看看效果吧:
啊,这下主角就看得很清楚了,所以你也知道contents_opacity的功能了吧,没错,就是修改窗口的内容的不透明度。
照例放上F1:
窗口内容的不透明度(0~255)。超出此范围的数值会自动修正。默认值为255。
但是这样子的话,不会导致窗口看不清楚吗?
所以,我们要使角色走上去才变成半透明,也就是说,又要开始写一大堆脚本了。
先把刚刚添上那句self.contents_opacity = 75删掉,然后再update里添上这样一段脚本:- if $game_player.screen_x >= 0 and $game_player.screen_x <= self.width and
- $game_player.screen_y >= 0 and $game_player.screen_y <= self.height
- self.contents_opacity = 75
- else self.contents_opacity = 255
- end
复制代码 我相信,通过之前的学习,这段脚本里唯一需要解释的就是$game_player.screen_x和$game_player.screen_y了吧。
顾名思义,这是用来获取玩家在画面上的x、y坐标的。
这个就是用来判断玩家是否走到了窗口的范围里,如果是,就半透明窗口,否则窗口恢复原状。
这样就人性化很多了吧!
说到这里,这节课就讲完了。现在,我们的窗口脚本就像以下这样了:- class Game_Actor < Game_Battler
- #----------------------------------------------------------------------------
- # * 重命名方法
- #----------------------------------------------------------------------------
- alias ms_refresh refresh
- alias ms_tp tp=
- alias ms_add_state add_state
- #--------------------------------------------------------------------------
- # * 刷新
- #--------------------------------------------------------------------------
- def refresh
- ms_refresh
- $refresh = true
- end
- #----------------------------------------------------------------------------
- # * 更改 TP
- #----------------------------------------------------------------------------
- def tp=(tp)
- ms_tp(tp)
- $refresh = true
- end
- #----------------------------------------------------------------------------
- # * 附加状态
- #----------------------------------------------------------------------------
- def add_state(state_id)
- ms_add_state(state_id)
- $refresh = true
- end
- end
- class Game_Party
- #----------------------------------------------------------------------------
- # * 重命名方法
- #----------------------------------------------------------------------------
- alias ms_swap_order swap_order
- #----------------------------------------------------------------------------
- # * 交换顺序
- #----------------------------------------------------------------------------
- def swap_order(index1, index2)
- ms_swap_order(index1, index2)
- $refresh = true
- end
- end
- #==============================================================================
- # ** Window_MapStatus
- #==============================================================================
- class Window_MapStatus < Window_Base
- #----------------------------------------------------------------------------
- # * 初始化
- #----------------------------------------------------------------------------
- def initialize
- super(0, 0, 273, 144)
- self.opacity = 0
- refresh
- end
- #----------------------------------------------------------------------------
- # * 刷新画面
- #----------------------------------------------------------------------------
- def update
- super
- refresh if $refresh
- $refresh = false
- if $game_player.screen_x >= 0 and $game_player.screen_x <= self.width and
- $game_player.screen_y >= 0 and $game_player.screen_y <= self.height
- self.contents_opacity = 75
- else self.contents_opacity = 255
- end
- end
- #----------------------------------------------------------------------------
- # * 更新内容
- #----------------------------------------------------------------------------
- def refresh
- self.contents.clear
- draw_actor_face($game_party.members[0], 0, 0)
- draw_actor_name($game_party.members[0], 0, 0)
- draw_actor_level($game_party.members[0], 101, 0)
- draw_actor_icons($game_party.members[0], 0, 72)
- draw_actor_hp($game_party.members[0], 101, 24, self.contents.width - 101)
- draw_actor_mp($game_party.members[0], 101, 48, self.contents.width - 101)
- draw_actor_tp($game_party.members[0], 101, 72, self.contents.width - 101)
- draw_actor_exp($game_party.members[0], 0, 96, self.contents.width)
- end
- #----------------------------------------------------------------------------
- # * 描绘EXP槽
- #----------------------------------------------------------------------------
- def draw_actor_exp(actor, x, y, width=124)
- rate = actor.exp.to_f / actor.next_level_exp.to_f
- draw_gauge(x, y, width, rate, Color.new(0, 255, 0), Color.new(100, 255, 100))
- self.contents.font.color = text_color(16)
- self.contents.draw_text(x, y, 56, 24, "EXP")
- self.contents.font.color = Color.new(255, 255, 255)
- en = "#{actor.exp}/#{actor.next_level_exp}"
- self.contents.draw_text(x, y, width, 24, en, 2)
- end
- #----------------------------------------------------------------------------
- # * 描绘值槽
- #----------------------------------------------------------------------------
- def draw_gauge(x, y, width, rate, color1, color2)
- fill_w = (width * rate).to_i
- self.contents.gradient_fill_rect(x, y+12, fill_w, 6, color1, color2, true)
- self.contents.gradient_fill_rect(x, y+18, fill_w, 6, color2, color1, true)
- self.contents.fill_rect(x, y+12, width, 2, Color.new(255, 255, 255))
- self.contents.fill_rect(x, y+22, width, 2, Color.new(255, 255, 255))
- self.contents.fill_rect(x, y+14, 2, 8, Color.new(255, 255, 255))
- self.contents.fill_rect(x+width-2, y+14, 2, 8, Color.new(255, 255, 255))
- end
- end
- class Scene_Map < Scene_Base
- #----------------------------------------------------------------------------
- # * 重命名方法
- #----------------------------------------------------------------------------
- alias ms_sta start
- #----------------------------------------------------------------------------
- # * 开始处理
- #----------------------------------------------------------------------------
- def start
- ms_sta
- @mapstatus_window = Window_MapStatus.new
- end
- 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。 | 关于窗口的三个主要方法,我们放到培优班再说。
窗口的new、update和dispose.
这三个方法是十分重要的,在VA里,对于写脚本的我们来说,update和dispose都是可以忽略的,因为根据Scene_Base的内容,所有的窗口都是会自动刷新和释放的,所以一般都是无视这两个家伙的。我在这里就说一说他们的功能吧!
window.new是最基础的,用于生成一个window的实例,没有它,后面的一切都没有用。而这个生成的实例,一般都会代入到某个变量中,方便后来对其修改。比如说,我们首次接触的就是:- $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天,想必这是我偷懒的结果吧……
当初的那一份热情似乎已经不见了呢,所以这一篇写得格外马虎。
有神马问题可以问我。
还有,这是最后一篇了…… |
|