晴兰的反向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 |