晴兰的反向Ruby教程-2 RMVA小程序
上一节我们学习了Ruby的消息,如何定义消息(方法,我们在这里不需要区分消息与方法,可以认为是一样的),现在当你去看F1手册时,看到的都是模块、类和方法名。下面试试来做更多的事情。
 RMVA的手册在写本文时大约没有完整的中文版,但就像XP、VX、VA各版本的手册的”RGSS参考>标准库>预置函数”一节开宗明义都会说到的,像system这种函数,事实上是Kernel模块的一个方法,以消息编程来看,不指定对象,我们发消息的对象是Kernel。也可以指定对象,用”对象.方法”来调用。因此事实上是这个样子的:
| 1 2 3 4 5 | def 运行 程序    Kernel.system 程序 end 运行 "notepad" | 
下面来看看更多的例子
手册的”RGSS参考>游戏库>Audio” “RGSS リファレンス>ゲームライブラリ>Audio”
这个页面,可以看到一堆模块方法。
例如bgm_play: Audio.bgm_play(filename[, volume[, pitch[, pos]]])
要注意的是,Audio就是要发消息的对象,消息名是bgm_play,后面的消息参数分别是文件名、音量、音调、位置。加了方括号的表示可以省略。例如:
| 1 | Audio.bgm_play "Audio/BGM/Theme1.ogg" | 
但这样,会播放了不到1秒就游戏结束了,因为没有让他停留在那里播放,我只是对音频模块说,播放这个BGM,然后游戏的主要脚本也就结束了。为了让他停在那里播放,可以用rgss_stop:
| 1 2 | Audio.bgm_play "Audio/BGM/Theme1.ogg" rgss_stop | 
现在为止我们只能手动点击关闭按钮关掉。
当然也可以像上一节一样弄的好看点
| 1 2 3 4 5 6 7 8 9 10 | alias 无限刷新画面 rgss_stop 音频模块 = Audio class << 音频模块   alias 播放BGM bgm_play end 某音乐 = "Audio/BGM/Theme1.ogg" #----------------------------以上是各种设置和别名--------------------------- #----------------------------以下是要做的事情------------------------------ 音频模块.播放BGM 某音乐 无限刷新画面 | 
说是半残播放器,是因为只能播放一首曲子,不过更改下面的设置可以播放其他的曲子。从网络上取得的脚本,通常也会有些设置。
一个游戏至少要和用户有所交互,就说刚才简单的播放BGM,可以说是音乐欣赏,但是我为了控制它的播放情况,可以读取用户的按键:
- 上键: 增大音量
- 下键: 减小音量
- 右键: 提高音调
- 左键: 降低音调
- 回车, C: 暂停、恢复暂停
- ESC, X: 退出游戏
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | class << Audio   alias 播放BGM bgm_play   alias BGM位置 bgm_pos end class << Input   alias 按了一下? trigger? #repeat? 并不是一按下就起作用,就按一下   alias 一直按着? repeat?  #repeat? 并不是一按下就起作用,重复按下   alias 按着?     press?   #press?  是按下就会起作用 end @图形模块      = Graphics @音频模块      = Audio @键盘模块      = Input @上键          = :UP @下键          = :DOWN @左键          = :LEFT @右键          = :RIGHT @回车          = :C @ESC           = :B #--------------------------↑别名------------------------------- @某音乐      = "Audio/BGM/Theme1.ogg" @音量        = 100 @音调        = 100 @暂停位置    = 0 @设置是暂停  = false @改变了设置  = false @退出游戏    = false @暂停        = false #--------------------------↑数据------------------------------- def 初始化   @音频模块.播放BGM @某音乐 end def 按了一下? 某键        #按了一下?   @键盘模块.按了一下? 某键   #问键盘模块,按了一下某键吗?Ruby的方法名最后的问号多是要返回真假,表示测试或者疑问 end def 判断按键修改设置   case     when 按了一下?(@上键)       @音量 += 5       @改变了设置 = true     when 按了一下?(@下键)       @音量 -= 5       @改变了设置 = true     when 按了一下?(@左键)       @音调 -= 5       @改变了设置 = true     when 按了一下?(@右键)       @音调 += 5       @改变了设置 = true     when 按了一下?(@回车)       @暂停 = ! @暂停 #切换暂停/不暂停       @改变了设置 = true       @设置是暂停 = true     when 按了一下?(@ESC)       @退出游戏 = true   end end def 更新设置   exit if @退出游戏 #当退出游戏为真时退出   if @改变了设置   #如果改变了设置     unless @设置是暂停      #除非改变的设置是暂停 相当于if not 设置是暂停       @当前位置 = @音频模块.BGM位置       #当前位置 = Audio.bgm_pos       @音频模块.播放BGM @某音乐, @音量, @音调, @当前位置     else       if @暂停         @暂停位置 = Audio.bgm_pos         Audio.bgm_stop       else         @音频模块.播放BGM @某音乐, @音量, @音调, @暂停位置       end     end   end   #复位设置   @改变了设置 = false   @设置是暂停 = false end #--------------------------↓运行------------------------------- 初始化 loop do   Graphics.update   Input.update   #↑这两句就不用别名了,是整个RGSS系列都很重要的用法   判断按键修改设置   更新设置 end | 
对比一下下面的数据设置,不过下面这种用法不需要太追究:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | class << Audio   alias 播放BGM bgm_play   alias BGM位置 bgm_pos end class << Input   alias 按了一下? trigger? #repeat? 并不是一按下就起作用,就按一下   alias 一直按着? repeat?  #repeat? 并不是一按下就起作用,重复按下   alias 按着?     press?   #press?  是按下就会起作用 end @图形模块      = Graphics @音频模块      = Audio @键盘模块      = Input @上键          = :UP @下键          = :DOWN @左键          = :LEFT @右键          = :RIGHT @回车          = :C @ESC           = :B #--------------------------↑别名------------------------------- @某音乐      = "Audio/BGM/Theme1.ogg" @音量        = 100 @音调        = 100 @暂停位置    = 0 @设置是暂停  = false @改变了设置  = false @退出游戏    = false @暂停        = false @按键设置 = {    @上键  =>      ->{@音量 += 5} ,#这里有逗号    @下键  =>      ->{@音量 -= 5} ,    @左键  =>      ->{@音调 += 5} ,    @右键  =>      ->{@音调 -= 5} ,    @回车 =>       ->{       @暂停 = ! @暂停 #切换暂停/不暂停       @设置是暂停 = true    },#可以写几行    @ESC => ->{@退出游戏 = true},  } #--------------------------↑数据------------------------------- def 初始化   @音频模块.播放BGM @某音乐 end def 判断按键修改设置   if @按键设置.any?{|键, 要做的事情|   #对于按键设置表而言,有任何为真的情况:     if @键盘模块.按了一下? 某键        #↓       要做的事情.call                        true #按下了某键                     else                                    false     end   }                                  #↓      @改变了设置 = true               #有任何为真的情况,改变了设置   end end def 更新设置   exit if @退出游戏 #当退出游戏为真时退出   if @改变了设置   #如果改变了设置     unless @设置是暂停      #除非改变的设置是暂停 相当于if not 设置是暂停       @当前位置 = @音频模块.BGM位置       @音频模块.播放BGM @某音乐, @音量, @音调, @当前位置     else       if @暂停         @暂停位置 = Audio.bgm_pos         Audio.bgm_stop       else         @音频模块.播放BGM @某音乐, @音量, @音调, @暂停位置       end     end   end   #复位设置   @改变了设置 = false   @设置是暂停 = false end #--------------------------↓运行------------------------------- 初始化 loop do   Graphics.update   Input.update   判断按键修改设置   更新设置 end | 
| 1 2 3 4 5 6 7 8 9 10 11 12 | 平面 = Plane 图片 = Bitmap class Plane   alias 图片 bitmap   alias 图片= bitmap= end @壁纸 = 平面.new #新建一个平面 @壁纸.图片 = 图片.new "Graphics/Titles1/Night" #新建(事实上是载入图片) rgss_stop #还记得吗 无限刷新画面 | 
  
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 平面         = Plane 图片         = Bitmap class Plane   alias 图片  bitmap   alias 图片= bitmap= end class Bitmap   {     "dispose"              => "释放",     "disposed?"            => "释放了吗?",     "width"                => "宽度",     "height"               => "高度",     "rect"                 => "矩形区域", # =>相当于 Rect.new(0, 0, width, height)     "blt"                  => "描绘"   ,     "stretch_blt"          => "缩放描绘",     "fill_rect"            => "填充矩形",     "gradient_fill_rect"   => "渐变填充",     "clear"                => "清除",     "clear_rect"           => "清除矩形",     "get_pixel"            => "取点",     "set_pixel"            => "画像素",     "hue_change"           => "改变色相",     "blur"                 => "模糊化",     "radial_blur"          => "径向模糊",     "draw_text"            => "描绘文字",     "text_size"            => "文字大小",     "font"                 => "字体",     "font="                => "字体=",   }.each{|英文名, 中文名| alias_method 中文名, 英文名} end @壁纸        = 平面.new #新建一个平面 @壁纸.图片   = 图片.new "Graphics/Titles1/Night" #新建(事实上是载入图片) @壁纸.图片.径向模糊 6, 20#角度,份数 rgss_stop #还记得吗 无限刷新画面 | 
也可以使用系统API,就像其他程序那样:
| 1 2 3 4 5 | =begin C声明,注意对比 int __stdcall MessageBox(HWND, LPSTR, LPSTR, INT); =end MessageBox = Win32API.new "user32", "MessageBox", "ippi", "i" MessageBox.call  0, "Hello", "Title", 16 | 
Win32API.new的参数: DLL名, 函数名, 参数类型表, 返回值类型
但是通常情况下,类型可以自动推断出来,返回值也可以忽略,或者通常是整数兼容的类型。
这里用method_missing来匹配MessageBox这个不存在的方法,并生成”ippi”这样的参数表:
| 1 2 3 4 5 6 7 8 9 10 11 | class API   def initialize(dll)     @dll = dll   end   def method_missing sym, *a     Win32API.new(@dll, sym.to_s, a.map{|x|x.is_a?(Integer) ? ?i: ?p}, ?i).(*a)   end end user32 = API.new "user32" user32.MessageBox 0, "Hello", "Title", 16 |