设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 2573|回复: 1
打印 上一主题 下一主题

RGSS2的教程

[复制链接]

梦石
0
星屑
239
在线时间
2399 小时
注册时间
2008-4-11
帖子
12326

贵宾第6届短篇游戏比赛季军

跳转到指定楼层
1
发表于 2011-3-19 16:49:52 | 只看该作者 回帖奖励 |正序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
由于这篇脚本太长了= =所以特意单独整合。
从0开始学RGSS2  八云紫
初级篇(RGSS2 基础):
01. 写在前面
02. RGSS2 与 Ruby
03. 第一个脚本
04. 变量 常量
05. 运算
06. 复合运算
07. 字符串(String)
08. 函数(方法)
09. 条件分歧(判断)
10. 数组(Array)
11. 哈希(Hash)
12. 类(class) by 7姐
13. 补充

中级篇(RGSS2 内部类解读):
01. Viewport 显示端口
02. Bitmap 位图 by david50407
03. Sprite 精灵 和 Plane 平面
04. Window 窗口
05. Color 色彩 和 Tone 色调
06. Tilemap 元件地图 和 图块
07. Rect 矩形
08. Font 字型 和 Table 表格
09. RGSSError RGSS错误 by ZH99998
中级篇(RPG VX解读):
01. RPG 模块
02. Game 类集
03. Window 类集
04. Sprite 和 Spriteset 类集
05. Scene 类集
06. Main
07. 外带脚本

高级篇:
01. 正则表达式
02. pack and unpack
03. API

附录:
01. 关键字解析

实战篇:
01. 修改存档位置
02. Game 类应用<< 技能书脚本>







































写在前面


致新人们:
? ?? ? 脚本的难易度其实是看你们的努力,??兴趣,??耐心等方面来决定的.??当然, 如果之前有学过其他的编程语言的话,??事半功倍也是常有的事情.
? ?? ? 本教程面向零基础新人, 咱会一点点的来慢慢解说 RGSS2 的. 如果您使用的是 RGSS(也就是 XP)的话, 也可以来看看, 它们在基本的语法啦什么的, 基本上都是一样的. 不一样的是默认脚本以及一些方法.
? ?? ? 所以, 有耐心的话, 请慢慢往下看吧.

致脚本大大们:
? ?? ? 咱知道咱在这里是有点班门弄斧了. 请你们嘴下留情. 如果有什么错误或者建议什么的,??请指正.

致大家:
? ?? ?你们的支持就是咱的动力. 不要介意咱的某些语病或者表达问题, 咱语文不是很在行, 不过尽量使用最通俗的语言来表达意思.

最后:
? ?? ?这个算是全文字或者有图片的教程了吧. 求视频教程的, 请出门右拐, 谢谢~~~

最后的最后:
? ?? ?不定期更新~~~~ (其实是自己有一个游戏坑要填埋, 所以, 见谅).
? ?? ?这个是无聊啦, 没劲啦什么的教程
















RGSS2 与 Ruby

? ?? ?
? ???说到 RGSS2, 应该要先说说 Ruby.
? ???Ruby 的具体信息, 请查看 百度百科 (偷懒~). 一句话概括的话, 就是: Ruby 是一个面向对象的脚本语言. 就这么简单.
? ???知道 Ruby 后,就可以来说说 RGSS2 了. RGSS2 其实是在 Ruby 语言的基础上衍生来的一个脚本库. 所以, 语法上有共通的地方.
第一个脚本


? ?? ? 好吧,??以上基本上都是一些废话. 正文从这里开始.
? ?? ? 想要学写脚本, 当然是从基础的语句开始啦. 那么就国际惯例, 从 Hello World 开始吧.
1. p "Hello World"
复制代码
恩, 就这么简单.
? ?? ? 具体的解释一下吧, 首先来看第一个单词 "p" . p 方法(也有叫做 函数) 的用法就是输出后面的信息. "Hello World" 呢, 就是需要输出的字符串. 在 RGSS2 或者说是 Ruby 里 , 使用 " " (双引号) 包含的内容都是字符串.
? ?? ? 那么, 怎么使用以上脚本呢? 要么, 就需要准备 RPG VX 一只, 新建一个新工程(具体流程就偷懒了~~), 按 F11 打开脚本编辑器. 然后把这边的滚动条向下拉, 就会看到一个 Main 脚本, 就是这个:

2010-11-2 19:30 上传
下载附件 (25.51 KB)

? ?? ? 然后再 Main 之前点右键->插入(Ins) 一个新的空白脚本, 将以上的脚本写进去, 就是这样子:

2010-11-2 19:30 上传
下载附件 (41.03 KB)

? ?? ? 请注意一下那个 "Hello World" 的颜色了, 如果不是红色的话, 请检查一下有没有写错.
? ?? ? 最后是应用->确定->F12 就可以看到结果了. 如果不出错的话, 应该是这样:

2010-11-2 19:30 上传
下载附件 (6.53 KB)

? ?? ?点确定后就来到熟悉的标题界面了.




























变量 常量

? ?? ? 啰嗦一下, 如果大家想直接测试脚本, 比如之前的 Hello World , 点确定后不进入标题的话, 可以在脚本后添加一句:
1. exit
复制代码
即可.
? ?? ?进入正题吧.

? ?? ?变量是在脚本里使用最多的东东了. 从字面上说变量就是会变的量. 你可以往里面放任何东东(在 Ruby 里是这样的). 可以这样比喻吧: 变量就是一个抽屉, 你可以放书, 也可以放铅笔, 都放也是可以的. 你可以在需要的地方从这个抽屉里拿出里面的东东.
? ?? ?知道了这个 "抽屉" 的功能, 那么怎么去识别它呢? 你不能对着 RGSS2 说:" 那个那个抽屉里放书." 所以需要一个明确的标示符, 也可以叫名字(变量名) 来区分它们, 就像大家都有一个名字一样.

? ?? ?变量名的命名规则
? ?? ?知道了需要用一个名字来区分它们, 那么这个名字也需要遵守一定的规则. 想我们的名字一样, 先姓氏, 然后名字.??脚本里的变量名命名规则要遵守这三个规则:
? ???
1. 第一个字符必须以小写英文字母或 _(下划线)开头。
? ?? ?2. 第二个字符开始可以使用英文字母、数字或 _(下划线)。
? ?? ?3. 不能使用保留字作变量的名称。
? ?? ?保留字是作为 Ruby 中具有特殊意义的词而被系统所「保留」,所以变量名称不能使用。以下就是系统的保留字。
? ???alias? ? def? ?? ?false? ? nil? ?? ?return? ?unless
? ???and? ?? ?do? ?? ? for? ?? ?not? ?? ?self? ???until
? ???begin? ? else? ???if? ?? ? or? ?? ? super? ? when
? ???break? ? elsif? ? in? ?? ? redo? ???then? ???while
? ???case? ???end? ?? ?module? ?rescue? ?true? ???yield
? ???class? ? ensure? ?next? ???retry? ? undef

? ???以上抄至 F1 帮助.
? ???其实在 RGSS2 里可以使用中文来命名变量. 不过个人感觉不要这么做为好.
? ???于是举几个例子吧:
? ???这些都是正确的: a , aa, aaa( = =a ), _times_ , __rgss2 ....
? ???这些都是错误的: 2rgss(不能数字开头), class (保留字).
? ???
? ???变量的使用
? ???知道如何标识一个变量后, 就可以大张旗鼓的使用它们了. 之前就说过了, 我们可以往里面放书, 也可以从里面拿书(前提是里面有). RGSS2 里对于 "放书" 这个动作叫做赋值. 于是, 我们就可以这样往一个变量的抽屉里放一本书:
1. text = "<66RPG 使用指南>"
text 就是之前所说的变量名字, 这个变量叫做 text , 以后想叫它的话, 直接叫 text 就好. "<66RPG 使用指南>" 书名(内容请无视). 一整句的意思就是 将 "<66RPG 使用指南>" 这个书 放进变量名是 text 的变量里去. 或者 将变量 text 赋值, 内容是 "<66RPG 使用指南>" (好吧, 很绕口).

? ???懂的放书后, 取书就易如反掌了. 还记得 "Hello World" 例子里的那个 p 方法么? 它的用作是输出内容. 那么, 我们就可以这样做:
1. text = "<66RPG 使用指南>"
2. p text
3. exit
变量的类型
? ???其实抽屉也是有分类的. 有私人的抽屉, 放日记的.(是谁都不希望日记和其他人共享吧.); 还有就是类似图书馆的书架, 谁都可以从上面拿书. 于是, 变量就可以这样分类了:
? ???1. 全局变量(就是 图书馆的书架), 在任何地方都可以使用的变量,??$ 加上变量名 作为新名字.
? ???2. 类变量(你家的抽屉, 你和你的家人都可以使用), 在 类 里可以使用, @ 加上变量名 作为新名字.
? ???3. 局部变量(你房间里放日记的抽屉), 只有在一个特定的地方才可以使用它, 前面什么都不加, 直接 变量名.

? ???如果你一时间记不住这些的话也没啥关系, 以后会慢慢的说明的.

? ?? ? 常量 就是不会改变的变量. 常量的名字全部都是由大写字母组成, 比如 WHL 等, 这些例子在一些脚本的设定部分尤为常见. 请不要试图去改变一个常量的值, 虽然这个在 RGSS2 里是可以做到的.
? ?? ? 另外, 常量默认在任何地方都可以使用的. 例如 π (小光) , 我们谁都可以使用它来计算圆面积.



运算


? ?? ?在说运算之前, 先聊聊数值. RGSS2 里的数值分为两种, 整数(或者 整型) 和 浮点数(带小数的数值). 整数 就是不带小数的数值, 比如 1, 10, 65535 等. 浮点数说直接点就是带有 小数点 的数值, 所以??1.0 , 3.141592 等都属于浮点数. 最后要说的是, 整数在计算上要比浮点数来的快捷, so 能用整数的尽量使用整数吧.

? ?? ?运算 算是脚本的核心吧. 所有的一切都离不开运算, 图片的移动, 变量的增减都是需要计算. 加减乘除四则运算都没啥必要说明了吧. 举个例子:
1. p 1 + 1? ?? ?? ?? ? # 加法
2. p 10 - 3? ?? ?? ?? ?# 减法
3. p 7 * 5? ?? ?? ?? ? # 乘法
4. p 25 / 4? ?? ?? ?? ?# 除法
5. p 7.0 * 5? ?? ?? ?? ? # 乘法
6. p 25.0 / 4? ?? ?? ?? ?# 除法
复制代码
是 不是有个疑问? 为什么 25 / 4 的结果是 6 而不是 6.25 ? 这里需要说明下, RGSS2 在运算的时候会保留数值类型, 只要参与运算的两个数值中, 至少有一个是浮点数的话, 那么结果就会是浮点类型. 由于 25/4 是 整数/整数, 呢吗结果就是整数, 但是整数是没有小数位的, so 就是 6 了. 最后要注意的是, RGSS2 可不会四舍五入, 它的做法是都去掉.
? ?? ?问题 : 如果执意要四舍五入呢? 怎么办?
? ?? ?最后的最后, 加减乘除符合数学上的运算优先级, 即 先乘除后加减, 如果需要的话, 请使用 "( )",如: 10.0 * (1 \ (10.0 - 5)

? ?? ?除了加减乘除外, RGSS2 还有其他的基础运算, 比如 模(也就是 求余), 符号是 "%", 例如:
1. p 25 % 4
2. p 25.0 % 4
复制代码
还有一个就是 乘方, 符号是 "**" , 两个乘号. 想计算 3 的 3 乘方的话, 就是
1. p 3 ** 3
复制代码
结果是 ⑨ 哦. 其实是 27 .

? ???赋值 的使用也是很普遍的, 这个之前说明过了. 也就没说好重复了.
复合运算


? ???如果把这些运算组合在一起就是复合运算. 常用的有 "+=" "-=" "*=" "/=" "%=" . 例如:
1. a = 10
2. a += 1
3. p a
复制代码
先把 10 赋值进 变量 a 里面进, 然后 a += 1 , 就是 a 自己加上 1 , 这句等价于??a = a + 1 . 其他的 "-=" "*=" "/=" "%=" 类似就偷懒一下吧.


























字符串


? ?? ?好早好早之前就使用了这么一个例子??p "Hello World" 其中的 "Hello World" 指的就是字符串.
? ?? ?字符串就是由零个或多个字符组成的有限序列. 字符是什么就不需要解释了吧.
? ?? ?在 RGSS2 里, 使用 "" (双引号) 来表示里面的是一个字符串, 例如 "Hello World" 什么的.

? ?? ?字符串其实也可以参与计算的, 不过只限于 加 和 乘. 字符串的加法就是两个字符串连接, 例如:
1. p "Hello World" + " Reisen"
复制代码
输出就是 "Hello World Reisen" .
? ?? ?乘法在数学上就是连续的加, 所以 乘法可以将字符串复制几次. 例如:
1. p "Hello" * 5
复制代码
这样就出现了5个 Hello 了.

? ???"\" 这个符号在 字符串里有一个特殊的作用, 那就是转意. 常用的有 "\n" (换行) "\t"(制表符, 也就是键盘上的那个 Tab键) "\s" (空格) 和 "\0" (空, 什么也不放, 可是一个字符串的结束标志, 和句子的结束标志句号一样) "\\" 就是 "\"
举个例子:
1. print "Hello World \n" * 2
2. print 'Hello World \n' * 2
3. p "Hello World \n" * 2
4. print "Hello\sWorld"
5. print "Hello\\World"
6. print "Hello\tWorld"
7. print "Hello\0World"
复制代码
注意1: 这里使用了一个新的方法 print . 使用它来输出字符串. 如果使用 p 来输出的话, 那些转意字符就会被原样输出.
? ?? ? 注意2: 看到第二个语句了么? 这里使用了 ' '(单引号) 而不是双引号来声明字符串. 使用 单引号的作用在于它使得里面的转意字符会被当做原样处理, 就是说, 什么也不做.
? ?? ? 注意3: 最后一个字符串不要理所当然的以为输出的是 "Hello World", "\0" 不是空格的说. 另外, 每个字符串都是以 \0 结束的.只是没有显示出来. 所以, 这里只输出了 "Hello" 后面的内容都被忽略了.

? ?? ? 内嵌表达式 也是字符串的一个特性. 有的时候我们需要动态的生成一个字符串, 而不是在写脚本的时候去直接指定它们. 比如 VX 里的数值输入. 因为我们不可预见玩家会输入什么数值. 所以需要使用内嵌表达式. 惯例, 一个例子:
1. game = "VX"
2. print "RPG #{game}"? ?? ?
3. game = "XP"
4. print "RPG #{game}"
复制代码
这样就可以取得一个动态的字符串了.
? ?? ? 里面的 #{ } 用来将一个 变量 或者语句的结果 直接嵌入到字符串中. 同样的, 如果声明的字符串使用 ' ' 单引号的话, 内嵌表达式 也是无效的.
另一篇教程 : http://rpg.blue/forum.php?m ... &fromuid=107872










函数(方法)

? ?? ?
? ?? ?先来说说函数(或者叫方法)吧. 可以这么说吧, 函数就是一些具有特定功能的语句的组合.??通俗的认为, 函数就类似一个加工厂一样, 我们提供给它原料, 那么它在不出错的前提下就会完成某种功能, 然后可能返回一个成品给我们.

? ?? ?RGSS2 中, 这样定义一个函数:
1. def 函数名[(参数列表)]
2. ? ?函数体
3. ? ?[return ...]
4. end
复制代码
def 属于关键字, 表示定义函数的开始. 函数名遵守于变量名一样的规则. 后面的 参数列表 表示这个函数工厂需要什么原料. 特别的, 当函数不需要这个参数列表的时候, 可以连着 "( )" 一起不写. 函数体里写这个函数的实现过程, 例如工厂是怎么依次处理原料的. return 是 这个函数的返回关键字, 表示这个函数返回一个什么成果给我们, 也就是 返回值 了. end 与 def 对应, 不能少.

? ???举个例子吧,
1. def add(x, y)
2. ? ?return x + y
3. end
复制代码
这个叫做 add 的函数需要两个原料, 分别是 x, y . 函数的功能是将两个原料相加, 返回相加后的结果. 值得注意的是 参数列表使用 "," 逗号来分隔每个需要的参数.

? ???定义完函数后, 就可以使用它们了. 使用方法非常简单, 直接 函数名(需要的参数) 即可. 如果函数有返回值的话, RGSS2 执行好这个函数后, 就会返回那个返回值. 依旧是上一个例子:
1. a = add(1, 2)
2. p a
复制代码
不过要注意的是, 函数后的参数列表的个数一定要和定义的时候的个数一样. 否则就会出现错误.

? ???什么情况下可以使用函数? 这个估计会多人都会问到. 一口气把函数里的内容全部都柔和在一起不是更好?
? ???函数的使用可以减少一些不必要的麻烦. 比如 某个功能 需要在多个地方执行多次, 但是实现的脚本都是一样的话, 使用函数是最好的办法. 这样如果需要修改的话, 不需要一个地方一个地方的去找, 然后修改. 这样写脚本的效率就会提高很多. 虽然使用函数会照成额外的脚本开销.

? ???那么, 我们继续吧. 来说说参数. 其实参数可以在定义的时候直接指定一个默认值, 这样的调用上就可以忽略这个参数了. 例如
1. def add(x, y = 1)
2. ? ?return x + y
3. end
4. p add(1, 1)
5. p add(1)
6. p add(1, 2)
复制代码
可以看到两个函数的返回值都是一样的. 所以, 在使用函数的时候, 如果忽略某一个默认参数, 那么脚本就会带入设定好的值, 比如这个例子的 y.
? ?? ?不过主要注意的话, 默认参数只能定义在最后. 也就是说, 默认参数的后面只能是默认参数. add(x , y = 1, z) 这么定义是错误的.

? ? 函数是可以重定义. 这个是外带脚本的编写原理. 两个同名(相同的函数名)的函数在相同的定义环境下, 后定义的函数会取代前一个函数, 多个的情况也是类似.
1. def add(x, y)
2. ? ?return x + y
3. end
4. p add(1, 1)
5.
6. def add(x, y)
7. ??return x - y
8. end
9. p add(1, 1)
复制代码
可以看到第一个定义的 add 被覆盖掉了.

? ?? ?在写外带脚本的时候, 需要保留前一个, 也就是默认的脚本的功能的话, 可以使用 alias .用法如下 :
1. alias 新函数名 旧函数名
复制代码
这里含义是, 给旧函数名取一个别名, 小名什么的. 在后面就可以使用这个别名来表示这个函数. 例如:
1. def show
2. ? ?p 1
3. end
4. show
5. #
6. alias old_show show
7. def show
8. ? ?old_show
9. ? ?p 2
10. end
11. show
复制代码
第6句就是给第一个函数show取别名, 这样在后面重定义这个函数的时候, 就不会直接影响到原来的函数了.
写外带的脚本的时候, 使用 alias 是一个好习惯.


















条件分歧(判断)


? ?? ? 条件分歧其实就是通常说的判断, 在需要的时候可以做到走岔路的效果. 和事件里的条件分歧一样的效果. 在这之前先说说判断条件.
? ?
? ?? ?常用的判断条件有这么几个: == (相等) > (大于) < (小于) >= (大于等于) <= (小于等于) != (不等于) 这些运算符的含义和数学上的一样. 不过要注意的是 等于 "==" 和 赋值 "=" 不要混淆了. 前者用于判断, 后者是赋值.

? ?? ? 常用的判断语法有这么几个:
? ?? ? 1. if ... elsif ... else ... end
1. a = 10
2. if a > 9
3. ? ?p 1
4. end
复制代码
if 后面跟着条件, 然后另起一行写如果这个条件满足后的语句. 多的话, 可以使用 elsif 和 else .
1. a = 10
2. if a >= 10
3. ? ?p 1
4. elsif a >= 9
5. ? ?p 2
6. else
7. ??p 3
8. end
复制代码
这 个例子可以看出脚本的运行方式. 先判断 if a >= 10 是否满足要求, 然后执行 p 1 . 紧接着是跳转到 end 语句后. 说明 if 和 elsif 至多只执行一个. 如果前面的 if 或者 elsif 都没有满足条件 以及 存在 else 的时候, 脚本就会使用 else 后的语句.

? ? 2. unless ... end
? ? 和 if 相反, unless 是条件不满足的时候才执行的. 并且没有 unless ... elsif ... end 什么的使用方法.
1. a = 10
2. unless a < 10 # 如果 a 大于等于10 的话
3. ??p 1
4. end
复制代码
注意, 条件是相反的.

? ?3. case ... when ... else ... end
? ?case 更像是条件分歧.
1. a = 10
2. case a # case 的后面写上需要判断的变量
3. when 5 # 判断 a 是否等于 5
4. ? ?p 2
5. when 10
6. ? ?p 3
7. else??# 前面的 when 都不满足要求的话
8. ??p 4
9. end
复制代码
其中 else 不是必须的. when 的个数可以任意添加. 以上例子可以等同于
1. a = 10
2. if a ==??5 # 判断 a 是否等于 5
3. ? ?p 2
4. elsif a == 10
5. ? ?p 3
6. else??#
7. ??p 4
8. end
复制代码
逻辑值
? ? 逻辑数字上有表示真假的 1 0 , 在 RGSS2 里也有. true 表示真, false 表示假. 当然, 我们可以使用任何不是 false 和 nil(空) 的语句变量来表示真, 只有 false 和 nil 表示假. 这和 C 不太一样. C 中只有 false 和 0 才是假. NULL 其实就是 0.

? ? 对应逻辑值就有逻辑运算符. and &&(与), or ||(或), not !(非). 使用它们可以多个条件一起判断.
F1 里的例子:
1. p (100 > 77 and 1 + 1 == 2)? ?? ?? ?# => true
2. p (100 > 77 && 1 + 1 == 2)? ?? ?? ? # => true
复制代码
后缀表达式
? ? if 和 unless 可以后缀使用. 这个写法更方便.
比如第一个例子可以简写成:
1. a = 10
2. p 1 if a > 9
3. ? ?
复制代码



































数组


? ???数组可以看成是可以重复元素的集合. 在处理多个类似的元素的时候, 数组可以发挥很大的作用.

? ???常用的数组初始化方式有三种:
? ???1. 带有初始值的数组
1. a = [ 65, 66, 67]
复制代码
2. 声明一个空的数组, 没有任何元素
1. a = []
复制代码
3. 带有默认初始值的数组
1. a = Array.new(5, 66)
复制代码
第三种后面后说明道. 先知道一下吧.

? ? 数组初始化好后就可以使用了. 就可以使用一些常用的方法来操作这个数组了. 例如:
? ? 1. 读取元素的值
? ? 读取数组,需要使用 "[ ]" ,中括号里面跟着一个数字, 表示需要读取那个序号的元素. 比如:
1. a = [ 65, 66, 67]
2. p a[1]
复制代码
要注意的是, 数组的序号是从 0 开始算的, 而不是 从 1 开始. 所以, 需要读取第 N 个元素的话, 写到脚本里的序号应该是 N - 1. 如果需要读取的序号超过了这个数组的大小的话, 就会返回一个 nil . 例如:
1. a = [ 65, 66, 67]
2. p a[3]
复制代码
其实, 数组的序号可以是负值. 表示从后面开始算起. 比如:
1. a = [ 65, 66, 67]
2. p a[-1]
复制代码
可以认为 符号 是表示倒数.
? ? 2. 重新赋值
? ? 当某个元素需要赋值的时候, 可以用类似读取的方法.
1. a = [ 65, 66, 67]
2. a[1] = 1
3. a[-1] = 2
4. p a #=> 67
复制代码
其实也可以怎么认为, a 是一个数组, 那么 数组里的 元素认为是变量. 所以, a[n] 就可以看做一个变量.
? ?进阶请看 http://rpg.blue/forum.php?m ... &fromuid=107872




























哈希(Hash)


? ?? ?Hash表的核心在于 key(键) 和 value(值) 的对应关系. 这个和数组有点相像. 数组的 Key 就是在读取的时候所需要使用的序号值. 从 0 开始. 值就是这个序号所对应的值. 一一对应. 而且不能存在两个相同的 key . 所以, Hash 也有这个规定. key 是不能重复的. 粗略的可以理解成 数组 是 Hash 的一个特例, key 是连续数字的特例.

? ???那么怎么定义一个 Hash 呢? 先来看看语法:
1. 变量 = {key1 => value1, key2 => value2 , ...}
复制代码
其中的 key 可以是任意类型, 数字也好, 字符串也好, 只是不能重复. 这样就定义好了一个hash. 举个例子吧:
1. a = { 1 => "1", "Hash" => 1, "Array" => [1, 2]}
复制代码
可以使用类似数组的办法来使用 Hash , 例如读取:
1. a = { 1 => "1", "Hash" => 1, "Array" => [1, 2]}
2. p a[1]
3. p a["Hash"]
4. p a["Array"]
5. p a["Array"][0]
复制代码
这 个时候呢, 那个序号就是定义 Hash 的时候定义的 Key 来代替了. 最后一个语句可以这么理解 (a["Array"])[0] , 也就是先读取 a 这个 Hash 表, 然后 返回的是数组, 后面的 [0] 其实就是读取数组的第一个元素了. 所以返回的是 1.

还有重赋值:
1. a = { 1 => "1", "Hash" => 1, "Array" => [1, 2]}
2. a[1] = 2
3. p a[1]
4. a["Array"] = "A"
5. p a["Array"]
复制代码
【酱油括号】
嘛,关于类的部分由愚者来写了
以前有人问,67你是RGSS党还是2党?你用的VX一定是2吧?
好吧,愚者绝对不是2,愚者其实是Ruby党,所以诸君看这篇教程的时候一定要小心
普通字色部分是初级【如果你是想学点RGSS2基础】
红色部分为高危Ruby部分【适合已经有基础的同学们】
【酱油完毕】
类:一个抽象的概念,举个例子,张三是人【类】,李四是人【类】,但是人这个【类】,在这个世界上是找不到一个对象来表达的

在Ruby中,定义一个类用class,如下:
1. class Person
2. end
复制代码
然后就可以创建张三和李四了~
1. z3 = Person.new
2. l4 = Person.new
复制代码
咦,为啥张三李四啥都没有…那咱们开始添加姓名和年龄这些属性吧
1. class Person
2. attr_accessor :name, :age
3. def initialize(name,age)
4. @name = name
5. @age = age
6. end
7. end
复制代码
解说:
首先attr_accessor :name这行,attr_accessor是类方法,参数为一个或多个符号,加了这句就可以通过z3.name读取@name变量,用z3.name = xxx来设置@name变量了
其次def initialize(name,age)这行,initialize是Person.new时调用,里面放置一些对象的基础设置【initialize被称作钩子方法,类似的还有inherited方法在类被继承时调用】
第三点@name = name这行,@name是实例变量(为什么叫实例变量?因为是实例所拥有的,亦即z3和l4各自有一个@name而且不冲突),而name是通过参数传递进来的局部变量。

咱们重新创建张三和李四【这俩货一直在投胎么…大雾】
1. z3 = Person.new('张三',20)
2. l4 = Person.new('李四',18)
复制代码
喵,创建完毕~来试一试~
1. p “那年#{l4.name}#{l4.age}岁,#{z3.name}#{z3.age}岁,他们相爱了”
复制代码
如果没出意外的话,会出来一段很狗血的剧情:【白字慎重】
那年李四18岁,张三20岁,他们相爱了
什么!你看不懂#{}???往回翻前面的教程吧……XD自重

咦,张三和李四怎么光有名字和年龄啊,你们俩还会干点别的么?
于是咱们得给Person类定义方法
1. class Person
2. def do_sth
3. p '干!'
4. end
5. end
6. z3.do_sth? ?#'干!'
复制代码
好吧这回张三会骂街了…大家以后可以创建一打的张三李四帮你去骂人哟~【大雾……】
当然你也可以培育他们去做很多的事情内个。。。【说多了】


以下开始大规模红字部分,大家慎重…
首先说变量:
实例变量:以@开头,由实例对象所拥有
类变量:以@@开头,【愚者以为叫做共享变量会更可靠一点】意指由一个类产生的所有实例所共享的变量,举个例子,地球上的所有生物都拥有同一个地球~而地球却只有一个,大家都要爱护呀~
全局变量:以$开头,这个在RGSS2里遍地都是,比如$game_party啊$game_variables啊等等等

类也是对象:在Ruby中一切皆为对象,所以类也是对象,是Class类的对象,比如A = Class.new,然后使用A.new就可以产生A的对象了~【请使用常量命名类或者模块】
那么类既然是对象,有没有方法和实例变量?答案是有的:
1. class A
2. def self.output
3. p '我是小A不是小三'
4. @a = 1 if @a == nil
5. p (@a+=1)
6. end
7. end
8. A.output
复制代码
这里用def self.output定义的就是类方法【也可以使用def A.output,如果这样写的话注意不要写错类名】
类方法与类变量不同,并不是共享的,而是类作为对象时的方法。
而在类方法内的@xxx变量即是类作为对象的实例变量

然后说继承
在RGSS2脚本中大量的使用了类的继承
比如Window_Command是继承Window_Selectable,而Window_Selectable则是继承Window_Base
继承链为Window_Command < Window_Selectable < Window_Base【这里不是RGSS2代码,请勿在编辑器里这样写…后果自负】
这样的好处是,如果几个类同时要用同样的一个方法【代码相同】,那么只要在它们的父类里定义即可~【子类在找不到方法时,会从继承链上回溯查找方法定义】

关于super:
在方法里写上super会调用继承链上一级的同名方法【如果没有继续回溯直到找到第一个为止】
而super有两种写法:
super【不带括号】:会将参数传递给父类的同名方法
super()【带括号】:则参数必须手动传递

关于Module的混入改变继承链:
1. class Class_B
2. def initiazlie
3. p 'B'
4. end
5. end
6. class Class_A < Class_B
7. def initialize
8. super
9. p 'A'
10. end
11. end
复制代码
这时候继承链为Class_A < Class_B,输入Class_A.new会依次输出'B','A'
1. module A
2. def initialize
3. super
4. p 'module A'
5. end
6. end
7. module B
8. def initialize
9. super
10. p 'module B'
11. end
12. end
13. class Class_A
14. include A
15. include B
16. end
复制代码
这时的继承链为Class_A < B < A < Class_B【混入的Module会插入继承链,并且后混入的Module更靠近子类】
这时输入Class_A.new会依次输出'A','module A','module B','B'【很神奇不是么~】















Viewport 显示区域

? ? Viewport 这个东东其实理解起来不难. 比如 显示器的可以显示的区域相对于 Windows 桌面来说就是一个 Viewport . 在 VX 里,??大部分的图片是不需要也不可能需要显示整张图的内容的, 例如 行走图. 这样的情况下就需要使用到 Viewport 了, 截取 行走图 里的一部分来显示, 其他的部分不显示.
? ? Viewport 的意思通俗点来说就是 需要显示的区域. 图片, 精灵, 窗口什么的都可以设定这样的一个显示区域来显示我们需要显示的内容.
? ? 下面的代码可以来帮助我们来理解这个显示区域的含义.
? ? 1. 创建一个空的 Scene 场景.
1. class Scene_Viewport < Scene_Base
2. ??def start
3. ? ? @sprite = Sprite.new
4. ? ? @sprite.bitmap = Bitmap.new("Graphics/Pictures/143555.jpg")
5. ? ? @sprite.y = -200
6. ??end
7. ??def update
8. ??end
9. ??def terminate
10. ? ? @sprite.bitmap.dispose
11. ? ? @sprite.dispose
12. ??end
13. end
复制代码
结果是这样的,

2011-1-24 22:53 上传
下载附件 (79.48 KB)
1

? ? 毫无疑问的, 我们知道 Sprite 将这个图片全部都显示到 VX 的窗口上了. 不过这里其实也可以看到整个 VX 窗口也是一个 Viewport.
? ? 2. 使用 Viewport 来显示我们需要的部分.
? ? 将上面的那个脚本段修改一下:
1. ??def start
2. ? ? @viewport = Viewport.new(0, 0, 400, 400)
3. ? ? @sprite = Sprite.new(@viewport)
4. ? ? @sprite.bitmap = Bitmap.new("Graphics/Pictures/143555.jpg")
5. ? ? @sprite.y = -150
6. ??end
复制代码
测试结果为:
? ?
2011-1-24 23:00 上传
下载附件 (55.12 KB)
2

? ? 看出区别了么? 由于添加了 Viewport 的限制, 显示图片的时候, 只能显示 400 * 400 大小的区域. 不过这里需要注意一点:添加 Viewport 的限制后, 原来的 Sprite 的坐标是相对于 Viewport 来定义的, 并不是相对于 窗口. 这就意味着, 从 Sprite 的角度来看, Viewport 的指标才是指标原点.


? ?? ?Viewport 的方法, 属性什么的, 看看 F1 就可以了. 不过需要说明一下 这两个属性 ox, oy .
? ?? ?ox, oy 这两个坐标可以理解成上面的那个例子里, Sprite 的坐标. 修改 ox oy 的值, 其实就是修改 Sprite 的 x y 的值. 只是 Viewport 的内部不一定是 Sprite .

(补充 by剑兰)
这里不知是补充还是说明了,
Viewport在控制游戏的整个Sprite(活动块)里扮演了一个不少的地位,
就像在"Spriteset_Battle"和"Spriteset_Map"里面,里面的几个Viewport,(有@viewport1、@viewport2.....)
他们控制了整个各自不用的活动块所看的范围(比如计时器、地图、人物......),
一旦我们用了
Graphics.resize_screen(640, 480)
来加大画面,
在地图和战斗里整个视窗就会留有黑边,这是因为首先战斗场景和地图场景再调用Spriteset_(Battle/Map)
然后@viewport1、@viewport2.....都是没有超过640和480,所以地图元件无法显示在544和416之外。
只要这是把所有viewport类都变为640,480这样就没有黑边,
不过战斗和对话窗口窗口位置会不配合位置而很怪(这是当然的~哈哈哈~)。




































Bitmap 位图

  这次换我来给各位解说了 恩。
  位图,简单来说就是图像,在画面上显示位图,必须使用精灵(Sprite 精灵类)之类的对象。
  当然我们的图像是要能够有多种变化的,所以Bitmap类提供了两种生成的方式:
1. # 由文件载入并生成
2. b = Bitmap.new(filename)
3. # 生成新的位图
4. b2 = Bitmap.new(width, height)
复制代码
喔,对了,生成位图之后是会保留在内存的,如果不需要的话要记得释放唷~
1. # 释放位图
2. b.dispose
3. # 侦测已释放位图与否 当位图已释放则返回 true
4. b.disposed?
复制代码


  说位图 MS 不大容易明白,把他想成是绘图板吧,所谓绘图板就是画画的地方,一个美好的园地(你扯过头了 喂!)
  做为一个绘图板,就要具备绘图的功能(这不是废话吗?)。在这里,RGSS2 已经准备好了一些绘图的方法了:
1)绘制矩形 fill_rect
1. # 绘制矩形 将区域 (x, y, width, height) 填满指定颜色 color(Color 色彩类)
2. b.fill_rect(x, y, width, height, color)
3. # fill_rect 能吃 rect (Rect 矩形类) 的唷~
4. b.fill_rect(rect, color)
复制代码
2)绘制渐层矩形 gradient_fill_rect
1. # 绘制渐层 将区域 (x, y, width, height) 填满从颜色 color1(Color 色彩类)至 color2(Color 色彩类)的渐层色彩
2. b.gradient_fill_rect(x, y, width, height, color1, color2)
3. # 能加上 vertical 来设置是否为纵向渐层 (true 为纵向)
4. b.gradient_fill_rect(x, y, width, height, color1, color2, vertical)
5. # 当然也吃 rect (Rect 矩形类) 噜~
6. b.gradient_fill_rect(rect, color1, color2)
7. b.gradient_fill_rect(rect, color1, color2, vertical)
复制代码
3)绘制文字来了~~ draw_text (此处理需要花费时间,因此不建议每画格重绘一次文字。)
1. # 绘制文字 在位图区域 (x, y, width, height) 或矩形 rect??(Rect 矩形类) 中描绘字符串 str 。
2. b.draw_text(x, y, width, height, str)
3. # 能加上 align (0:靠左对齐,1:居中对齐,2:靠右对齐) 来指定对齐方式
4. b.draw_text(x, y, width, height, str, align)
5. # 惯例... 吃 rect (Rect 矩形类)
6. draw_text(rect, str)
7. draw_text(rect, str, align)
复制代码
text_size 则能获取绘制文字时所需的矩形大小(不包含斜体倾斜的文字部分)
1. # text_size 获取绘制文字 str (String 字符串) 所需矩形
2. rect = b.text_size(str)
3. # 合起来用就是
4. b.draw_text(b.text_size(str), str)
5. # 是不是方便多了呢?
复制代码
4)啊咧 涂错了怎办? clear 和 clear_rect 来帮你解决这个问题
1. # clear 清除整个位图
2. b.clear
3.
4. # clear_rect 清除位图区域 (x, y, width, height) 或矩形rect (Rect 矩形类)
5. b.clear_rect(x, y, width, height)
6. b.claer_rect(rect)
复制代码


  接下来是一些进阶应用:
1)绘制像素点 set_pixel
1. # 绘制像素点 设定指定像素点 (x, y) 的色彩 color(Color 色彩类)。
2. b.set_pixel(x, y, color)
复制代码
2)有繪製當然有獲取像素點的顏色 get_pixel
1. # 获取指定像素点 (x, y) 的色彩(Color 色彩类)。
2. b.get_pixel(x, y)
复制代码
3)不知道各位写报告的时候是不是也像我一样善用"拷贝 黏贴"呢?
  拷贝位图 blt
1. # 拷贝位图 拷贝位图 src_bitmap 的矩形 src_rect 部分到指定的座标 (x, y)
2. b.blt(x, y, src_bitmap, src_rect)
3. # 能指定 opacity 透明度 (范围 0~255)
4. b.blt(x, y, src_bitmap, src_rect, opacity)
复制代码
变形的拷贝 stretch_blt
1. # 变形的拷贝 拷贝位图 src_bitmap 的矩形 src_rect 部分到指定的矩形中 dest_rect (可能导致变形)
2. b.stretch_blt(dest_rect, src_bitmap, src_rect)
3. b.stretch_blt(dest_rect, src_bitmap, src_rect, opacity)
复制代码
4)模糊 blur
1. # 模糊 对位图执行模糊效果 此处理需要花费时间
2. b.blur
复制代码
放射型模糊 radial_blur
1. # 放射型模糊
2. # angle 指定 0~360 的角度,角度愈大,效果愈圆润
3. # division 指定 2~100 的分界数,分界数愈大,效果愈平滑 此处理需要花费大量时间
4. b.radial_blur(angle, division)
复制代码
5)色相变换 hue_change 此处理需要花费时间,另外色彩转换的误差,反复转换可能会导致色彩损失。
1. # 色相变换 在 360 度内变换位图的色相。
2. b.hue_change(hue)
复制代码


  再来又是些基本的东西了...
1. b.width #获取位图宽度
2. b.height #获取位图高度
3. b.rect # 获取位图矩形(Rect 矩形类)
4. b.font # 指定或取得draw_text方法描绘字符串时所使用的字体。(Font 字型类)。
复制代码
虽然 Bitmap 看起来很复杂,却又是整个游戏中不可或缺的元素之一啊。
但是只要精熟这恼人的东西之后,就天不怕地不怕了唷~
(PS: 刚刚被 DZ 脑残到... 重新写 呜呜呜~~)



























Window 窗口

? ? 其实这个教程想了好久, 不知道该怎么写. 于是就照搬 F1 了, 只是更加进一步说明一下. 或者给点例子什么的.

? ? Window 窗口类
? ? 游戏窗口的类。在内部由多重的精灵所组成。

? ? 类方法
? ?? ???Window.new([viewport])
? ?? ???生成一个窗口物件。必要时指定一个显示端口(Viewport 显示端口类)。

? ?? ? 方法
? ?? ? ★ dispose
? ?? ? 释放窗口。若窗口已释放则什么都不做。

? ?? ? ★ disposed?
? ?? ? 当窗口已释放则返回 true。

? ?? ? ★ update
? ?? ? 刷新光标的闪烁和暂停标记的动画。原则上每一画格调用一次。
? ?? ? 除非有使用光标或者是暂停标记, 其他的情况下, 没有必要调用这个方法. 起不到任何作用.

? ?? ? 属性
? ?? ? ★ windowskin
? ?? ? 引用作为窗口外观的位图(Bitmap 位图类)。
? ?? ? 只能够使用 VX 的窗口外观。(RGSS2)
? ?? ? VX 所使用的窗口素材与 XP 相比有很大的不同, 这个看素材就知道了.(其实是没有安装 XP , 也不好细说, 以后增加吧. 或者去看看有没有人写过这个~)
? ???
? ?? ? ★ contents
? ?? ? 引用作为窗口内容的位图(Bitmap点阵图类)
? ?? ? 默认的 contents??的初始值其实是这个的:
1. contents = Bitmap.new(0, 0, 1, 1)
复制代码
这个值分别在 Window_Base 和 Window_Selectable 的 create_contents 方法里被重新赋值.


? ?? ? ★ viewport (RGSS2)
? ?? ? 引用与窗口关联的显示端口(Viewport显示端口类)。
? ?? ? 这里要非常的注意一个问题, Window 类里使用的viewport 其实就是在初始化的时候指定的那个. 如果之前的那个 viewport 被修改的话, 这里也会被修改.
1. v = Viewport.new(0, 0, 100, 100)
2. w = Window.new(v)
3. p w.viewport.rect
4. v.rect.x = 10
5. p w.viewport.rect
复制代码


? ?? ? ★ cursor_rect
? ?? ? 游标的矩形(Rect矩形类)以相对坐标 (-16, -16) 设置窗口的左上角。
? ?? ? 这里注意一下, 真实的测试效果和 F1 的说明不一致, 不知道是不是我的测试出问题了.
1. w = Window.new()
2. p w.cursor_rect
复制代码
得到的结果是 (0, 0, 0, 0) . 不是F1 里的 -16, -16.


? ?? ? ★ active
? ?? ? 光标闪烁的状态。true 表示闪烁。

? ?? ? ★ visible
? ?? ? 窗口可见的状态。true 表示可见。

? ?? ? ★ pause
? ?? ? 暂停标记可见的状态。true 表示可见。

? ?? ? ★ x
? ?? ? 窗口的 X 坐标。
? ?? ?
? ?? ? ★ y? ?? ???
? ?? ? 窗口的 Y 坐标。

? ?? ? ★ width
? ?? ? 窗口的宽度。

? ?? ? ★ height
? ?? ? 窗口的高度。

? ?? ? ★ z
? ?? ? 窗口的 Z 坐标。数值愈大的平面愈靠近玩家。Z 坐标相同的,最后生成的对象则会最靠近玩家。
? ?? ? 窗口背景和内容的 Z 坐标在 RGSS2 中不能使用不同的 Z 坐标。(RGSS2)

? ?? ? ★ ox
? ?? ? 窗口内容的 X 坐标。滚动窗口时修改此数值。

? ?? ? ★ oy
? ?? ? 窗口内容的 Y 坐标。滚动窗口时修改此数值。
? ?? ? 以上两个属性和 Sprite 的同名属性作用一样. 在不移动窗口位置的情况下, 仅仅是移动窗口的内容. 这个可以理解成 当角色在地图上行走的时候, 地图需要适应性的滚动, 但是 RM 的窗口的位置依旧不变一样.

? ?? ? ★ opacity
? ?? ? 窗口的不透明度(0~255)。超出此范围的数值会自动修正。
? ?? ? opacity 针对的是整个Window

? ?? ? ★ back_opacity
? ?? ? 窗口背景的不透明度(0~255)。超出此范围的数值会自动修正。

? ?? ? ★ contents_opacity
? ?? ? 窗口内容的不透明度(0~255)。超出此范围的数值会自动修正。

? ?? ? ★ openness (RGSS2)
? ?? ? 窗口的开启程度(0~255)。超出此范围的数值会自动修正。
? ?? ? 将此数值从 0(完全关闭)至 255(完全开启)之间变换,可以产生窗口打开和关闭的动画效果。 openness 若低于 255,则不会显示其内容。默认值 255。
? ?? ? Window 的内容只有在 openness??等于 255 的时候才能显示出来.










Color 色彩 和 Tone 色调

? ?? ? Color 色彩
? ?? ? 说到颜色, 需要从我们的眼睛说起.
? ?? ? 人的视觉系统有3类与颜色相关的锥细胞. 我们就是使用这三类的锥细胞对颜色做出反应的. 这个就是三基色的理论基础. 这样就可以让计算机的颜色表示方法减少到3总颜色值. 于是, 两种颜色的三基色值相同的话, 他们在视觉上就是等价可互换的.
? ?? ? 另外一个颜色系统. 可以区分成两类, 加色法和减色法.
? ?? ? 加色法是指使用三基色相加来获取颜色. 我们 VX 里的颜色系统就是使用加色法的. 加色法中的三基色分别是: 红色, 绿色, 蓝色. 我们可以将这三个颜色值按照一定的比例投影到黑色的屏幕上获取颜色.
? ?? ? 减色法与加色法相反. 它是从白色的光中去除某些颜色来获取最终的颜色的. 减色法在 打印机, 绘图仪等工具上使用. 减色法里的三基色分别是: 青色, 品红色, 黄色.

? ?? ? 回到 VX . VX 的颜色使用的加色法. 于是得到三基色 RGB . 于是我们就可以用这个来取得我们需要的颜色, 比如品红:
1. magenta = Color.new(255, 0, 255)
复制代码
单 纯的使用 RGB 的话, 有的场合时不能达到要求的. 于是我们就引入 四色系统(RGBA) . 前三个 RGB 和前面说的一样. A 是指 α(alpha)通道. 也就是透明度(正确叫法是 不透明度, 透明度是咱习惯叫法). 例如我们需要一个半透明的品红:
1. magenta = Color.new(255, 0, 255, 128)
复制代码
Tone 色调
? ?? ???Tone 类和 Color 类很类似. 只是用的地方有点区别就是了. Tone 类里相对于 Color 的 alpha 的位置, 是灰度值, 也就是指纯白、纯黑以及两者中的一系列从黑到白的过渡色。
? ?? ???Tone 类用来指定精灵(Sprite) 和 Viewport 的整体颜色倾向.
? ???





Tilemap 类

? ???Tilemap 元件地图类, 用于处理地图的描绘以及管理地图的类. 其属性说明如下:
1. 方法
? ? Tilemap 类方法不多, 仅有4个:
? ?? ? ● new([Viewport]).
? ?? ?? ?? ?用于生成类实例. Viewport 为显示端口.
? ?? ? ● dispose . dispose? . update
? ?? ?? ?? ?释放, 判断是否释放. 更新.
2. 属性
? ? ● bitmaps
? ???长度为 8 的数组. 用于存放地图图块素材的属性. 其对应关系如下:
? ???
序号
对应图块
序号
对应图块
序号
对应图块
0
TileA1
1
TileA2
2
TileA3
3
TileA4
4
TileA5
5
TileAB
6
TileC
7
TileD
8
TileE

? ? ● map_data
? ? 地图数据. Table 表格类. 通常是从 MapXXXX.rvdata 里获取的. 读取的方法简写为:
1. load_data(sprintf("Data/Map%03d.rvdata", map_id)).data
复制代码
其大小规定为: 地图长 * 地图宽 * 3 . 这里的 3 层说明如下:
? ? 0.??A层. 存放 A类图块的 ID 号.
? ? 1.??辅助层: 如果某个 ID 具有草木茂盛属性的话, 这层的数据会和 0层的数据正好相差 48 . 是否有其他功能有待研究
? ? 2. BCDE 层: 用于存放 BCDE 层的 ID 数据.
? ? ● flash_data??
? ? F1 的说明是 "引用仿真游戏等中显示可以移动的范围时所用的闪烁信息" , 默认脚本没有使用这个功能. 该功能多数是在 SLG 脚本中使用到(感觉 紫苏酱 补充。) 数组,对于地图上的 x y 坐标。??
? ? ● passages??
? ? 数组. 地图图块ID对应的通行度数组. 目前的发现是: 用于显示标记有 "☆" 图块的ID的时候, 将会显示在最上层.
? ? ● 剩下的属性??
? ? 不多说了. 看 F1 一目了然.
注意: F1 里有提到
组成元件地图的每个精灵之 Z 坐标都是固定的。
??1. 显示在角色之下的元件,其 Z 坐标为 0。
??2. 显示在角色之上的元件,其 Z 坐标为 200. (RGSS2)


图块

? ? VX 的图块粗略的可以分成两大类, 包含自动原件的 A图块和普通的 B C D E 四个图块. 每个图块都有它自己的ID, 利用 ID 来决定地图的某个坐标需要描绘什么图块, 以及判断该点的属性(柜台属性, 草木茂盛属性什么的).
? ? 对于图块ID, 胃君 给出了一个表格, 这里我来引用下:
Tile_ID编号规则
0-1024? ?? ? B/C/D/E,每张256个元件
1536-1664? ? A5,共128个元件
2048-2816? ? A1,共16个元件,每个元件占48个编号,不同编号含义见样式一,样式三
2816-4352? ? A2,共32个元件,每个元件占48个编号,不同编号含义见样式一
4352-5888? ? A3,共32个元件,每个元件占48个编号,不同编号含义见样式二
5888-? ?? ???A4,共16个元件,每个元件占48个编号,不同编号含义见样式一,样式二
更加具体的说明, 请参照帖子末尾的参考资料3

? ? 接下来是判断属性.
? ? 通行度判断: 利用 Game_Map 里的 @passages 来获取对应图块ID的通行度. 不要这里需要注意一下, 由于每个坐标上都有3层, 所以在判断的时候需要遍历这 3 层, 次序是由大到小依次判断.
? ?? ? 这里列举出四个重要的通行度判断数据:
用途
数据
人物
0x01
小型船
0x02
大型船
0x04
飞船降落点
0x08

? ???回到通行度判断, 设定我们需要判断的数据是 flag (其实就是 0X01 等). 在依次取得地图 ID 所对应的通行度数据的时候, 可以这么判断:
? ???1. 如果其值等于 0x10 的时候, 也就是我们设定的 "☆" , 直接跳过.
? ???2. 如果其值与 flag 做与运算的话, 等于 0x00 (其实就是0)的话, 就是 "o" , 可以通行.
? ???3. 如果其值与 flag 做与运算的话, 等于 flag (flag 自己本身)的话, 就是 "x" , 不可通行.

? ? 从这里可以看到图块的优先级问题:
? ? 1. 标记有 "☆" 默认显示在最上面, 并且不参与通行判断.
? ? 2. B C D E 四个图块最先参与判断, 只有在 B C D E 图块不存在的场合("☆" 参照第一条), 在调用 1层和 0层来判断.

? ?柜台属性和草木繁茂属性判断:
? ?柜台属性 引用的数据时来自于第1层的., 对比数据为 0x40, 与运算之后等于 0x40 的话, 就是说明有柜台属性.
? ?草木繁茂属性: 和 柜台属性 类似, 不过引用的是第 0 层数据, 对比数据为 0x80



参考资料:
1. Kiss姐姐的 TileMap脚本
2. 柳大的 还原Tilemap类脚本
3. 胃君 的主动元件解说
























Rect 矩形

? ???好吧, 这个其实很不知道怎么组合的, 就单独写一个吧.
? ?
? ???RGSS2(Ruby)矩形的矩形使用一个四元组来表示: ( 矩形左上角的 X 坐标, 矩形左上角的 Y 坐标, 宽度, 高度 ) 来表示.
? ???我们可以创建这么一个矩形: 左上角坐标为( 10, 10) , 宽 20, 高 30 的矩形:
1. a = Rect.new(10, 10, 20, 30)
复制代码
这里需要注意一个问题: RGSS2 里的 Rect 每个元素都是整数, 也就是说, 就算是使用小数, 也会被取整. 比如:
1. a = Rect.new(10.0, 10.0, 20.0, 30.0)
2. p a
复制代码
至于 Ruby 就不知道了. 不过 Ruby 默认有 Rect 类么???

? ???


? ???提高:
? ???Window 里也有 Rect 结构, 定义是:
1. typedef struct tagRECT
2. {
3. ? ? LONG? ? left;
4. ? ? LONG? ? top;
5. ? ? LONG? ? right;
6. ? ? LONG? ? bottom;
7. } RECT, *PRECT, NEAR *NPRECT, FAR *LPRECT;
复制代码
Window 的 Rect 四元组应该是(矩形左上角的 X 坐标, 矩形左上角的 Y 坐标, 矩形右下角的 X 坐标, 矩形右下角的 Y 坐标)

? ???如果需要在 RGSS2 里的矩形切换到 Window 的矩形的话, 应该这样:
1. rgss2_rect = Rect.new(0, 0, 10, 10)
2.
3. window_rect = [rgss2_rect.x, rgss2_rect.y, rgss2_rect.x + rgss2_rect.width, rgss2_rect.y + rgss2_rect.height].pack("l*")
复制代码




















RGSSError RGSS错误

在试图访问一个无效(释放掉了或者尚未生成)的Sprite/Window/Plane/Tilemap时会抛出此异常

sp = Sprite.new
sp.dispose
sp.x = 1 #=>RGSSError

另一个比较常见的情况时尚未生成
例如

class Window_Test < Window_Base
??def initialize
? ? self.z = 100
? ? super(0,0,544,416)
??end
end
Window_Test.new #RGSSError
由于调用Window_Test.new,系统执行Window_Test的initialize
然后执行了self.z=,这时这个Window尚未生成(在Window顶层类的initialize里生成,需要用super调用上去),所以产生了错误
正确的写法应该是
class Window_Test < Window_Base
??def initialize
? ? super(0,0,544,416)
? ? self.z = 100
??end
end















RPG 模块

? ?? ?RPG 模块 只在 *.rvdata 这些数据库文件里使用过. 具体的每个子模块的属性什么的, 都可以查看 F1 帮助电子档. 这里就不细说了.
? ?? ?这里具体先说说一个主意事项. 就是在 VX 里 , RPG 模块的所有 initialize 初始化方法都是无效的. 为什么? 看脚本的 Scene_Title 就知道了. 脚本里事先读取了 *.rvdata 文件. 所以, 脚本里使用的 $data_XXX 变量都是事先声明好的. so , 脚本里是不会调用 initialize 方法的. 那么? 怎么有效的添加一个属性呢?? 其实可以在那个属性的读取方法上的做文章. 比如
1. def cp
2. ? ?@cp = 10??if @cp == nil
3. ? ?return @cp
4. end
复制代码
这样就可以防止出现 NoMethodError .

各个文件对应的资料:


文件名? ?? ?? ?? ?? ?? ?? ?? ?? ?数据类型 对应的 RPG 模块? ?? ?? ?? ?? ?? ? 变量类型? ?? ?? ?? ?? ?? ?? ?对应脚本里的变量


Actors.rvdata? ?? ?? ?? ?? ???角色数据??RPG::Actor .? ?? ?? ?? ?? ?? ?? ?? ? 数组? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?$data_actors


Classes.rvdata? ?? ?? ?? ?? ? 职业数据??RPG::Class .? ?? ?? ?? ?? ?? ?? ?? ???数组? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?$data_classes


Skills.rvdata? ?? ?? ?? ?? ?? ???技能数据??RPG::Skill .? ?? ?? ?? ?? ?? ?? ?? ?? ? 数组? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?$data_skills


Items.rvdata? ?? ?? ?? ?? ?? ? 物品数据??RPG::Item .? ?? ?? ?? ?? ?? ?? ?? ???数组? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?$data_items


Weapons.rvdata? ?? ?? ?? ? 武器数据??RPG::Weapon .? ?? ?? ?? ?? ?? ???数组? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???$data_weapons


Armors.rvdata? ?? ?? ?? ?? ? 防具数据??RPG::Armor .? ?? ?? ?? ?? ?? ?? ?? ?数组? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???$data_armors


Enemies.rvdata? ?? ?? ?? ?? ?敌人数据??RPG::Enemy.? ?? ?? ?? ?? ?? ?? ???数组? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???$data_enemies


Troops.rvdata? ?? ?? ?? ?? ???敌人队伍数据? ?RPG::Troop.? ?? ?? ?? ?? ???数组? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? $data_troops


States.rvdata? ?? ?? ?? ?? ?? ?状态数据? ?RPG::State.? ?? ?? ?? ?? ?? ?? ?? ? 数组? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???$data_states


Animations.rvdata? ?? ?? ???动画数据? ?RPG::Animation.? ?? ?? ?? ?? ?? ?数组? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???$data_animations


CommonEvents.rvdata? ?公共事件数据? ?RPG::CommonEvent.? ?数组? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???$data_common_events


System.rvdata? ?? ?? ?? ?? ? 系统数据? ?RPG::System.? ?? ?? ?? ?? ?? ?? ? 单个类实例? ?? ?? ?? ?? ?? ?? ? $data_system


Areas.rvdata? ?? ?? ?? ?? ?? ? 区域数据? ?RPG::Area.? ?? ?? ?? ?? ?? ?? ?? ?? ?Hash? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???$data_areas


MapXXX.rvdata? ?? ?? ?? ?? ?地图数据 RPG::Map.? ?? ?? ?? ?? ?? ?? ?? ?? ???单个类实例? ?? ?? ?? ?? ?? ?? ???$game_map.map


MapInfos.rvdata? ?? ?? ?? ? 地图信息数据,??RPG::MapInfo.? ?? ?? ?? ?Hash? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?需手动加载


Scripts.rvdata? ?? ?? ?? ?? ???脚本文件 数组 对应三个值 [可能是ID, 脚本名字, 脚本内容]? ?? ?? ? $RGSS_SCRIPTS































Game 类集

? ?? ?VX 里处理所有游戏数据的类集合. 本身 Game 类的写法没什么具体要求.
? ?? ?注意的是, Game 类都不处理图像数据.


01. Game_Temp($game_temp)
? ?? ?和名字的意思一样, 处理缓存的. 在每次游戏开始的时候, 都会重新生成. 不会写如存档.


02. Game_System($game_system)
? ?? ?处理系统数据的类. 处理诸如 计时器, 版本ID, 遇敌标志等. 会写入存档.??


03. Game_Message($game_message)
? ?? ?处理信息的类. 包括 对话设定, 头像, 对话内容, 选项等属性. 会写入存档.


04. Game_Switches($game_switches)
? ?? ?处理开关的类. 其实开关就是一个数组 @data . 对这个数组的读取写入就是对开关的操作.??
? ?? ?比如打开第 10 号开关: $game_switches[10] = true .
? ?? ?不过需要注意的是, 默认脚本限制开关ID在 5000 之内. 脚本 31 行有说明


05. Game_Variables($game_variables)
? ?? ?处理变量. 与 Game_Switches 写法相同.


06. Game_SelfSwitches($game_self_switches)
? ?? ?处理独立开关的类. 本质上是一个 Hash . 其 Key 结构是这样的一个数组:
1. [地图ID, 事件ID, 开关ID]
复制代码
其中的 开关ID 就是 "A" "B" "C" "D" 这四个. 想扩展的话, 可以修改这里.


07. Game_Screen($game_map.screen(地图), $game_troop.screen(战斗))
? ?? ?可以看成是处理画面效果数据的类. 画面震动, 画面亮度, 显示事件图片, 淡入淡出等等效果都是这个类处理的.


08. Game_Picture($game_map.screen.pictures(地图), $game_troop.screen(战斗).pictures)
? ???处理图片数据的类. 需要注意的是, 无论是在地图或者是战斗, 图片的 ID 都是在 1 到 20 之间. 一共 40 张图片. 这个和 XP 不同.(VX)


09. Game_Battler
? ???所有战斗者的父类(超类). 处理 HP MP , 不死身标志等数据.


10. Game_BattleAction
? ???处理行动的类. 包括战斗者使用的技能 ID , 物品 ID, 速度等数据. 在??Game_Battler 内部使用.


11. Game_Actor
? ???处理单个我方角色的类. 一切我方的数据都包含在这个类里. 默认是 Game_Actors 外壳的数据.


12. Game_Actors($game_actors)
? ???处理角色的外壳类. 和 Game_Switches 类似写法. 真正使用的是 Game_Actor 数据.


13. Game_Enemy
? ???处理敌人数据的类。在 Game_Troop 的 内部使用.


14. Game_Unit
? ???处理单位数据的类. 是 Game_Troop 和 Game_Party 的超类.


15. Game_Party($game_party)
? ???处理队伍数据的类. 一些比较常见的用法:
1. $game_party.gain_gold # 获得金钱
2. $game_party.steps # 步数
3. $game_party.gain_item# 获得物品
复制代码


16. Game_Troop($game_troop)
? ???处理敌人队伍数据的类. 具体的看脚本注释就可以了.


17. Game_Map($game_map)
? ???处理地图数据的类. 几乎所有的地图数据都包含在这里, 比如事件, 远景图, 公共事件等. 比较常见的有:
1. $game_map.need_refresh # 刷新地图
2. $game_map.map??# 地图数据
复制代码
等.


18. Game_CommonEvent
? ???处理公共事件的类. 可以看成是 公共事件数据 的外壳类, 真正的数据在 $data_common_events 里.


19. Game_Character
? ???处理地图上角色数据的类. 和 Game_Actor 不同的是, Game_Character 处理的是地图上行走图的数据. 是 Game_Player??Game_Event 和 Game_Vehicle 的超类.


20. Game_Event
? ???事件类. 所有事件的处理都是在这个类中. 包括事件页切换, 事件 ID, 事件启动判断等.


21. Game_Vehicle
? ???交通工具类. 需要注意的是, 每张地图都是有交通工具的, 只是在没有设定的情况下, 交通工具的坐标是 (-1, -1)


22. Game_Player($game_player)
? ???处理地图上的角色的类. 我们控制的角色其实就是这个类在管理.


23. Game_Interpreter
? ???事件命令解析类. 一切事件的核心类. 处理事件的解析和执行. 所有的事件在这里都可以找到.




存档结构
VX 的存档数据结构如下:
01. 我方角色的数组, 结构是 [ 行走图文件名,??行走图序号]
02. 刷新次数的计数值, 其实可以认为是游戏时间(这个值除以 FPS 值就是游戏时间)
03. 正在播放的 BGM
04. 正在播放的 BGS
05. $game_system
06. $game_message
07. $game_switches
08. $game_variables
09. $game_self_switches
10. $game_actors
11. $game_party
12. $game_troop
13. $game_map
14. $game_player


















Scene 类集

基础语法:
1. class Scene_XXX < Scene_Base
2. ? ?def initialize([...])
3. ? ?? ?...
4. ? ?end
5. ? ?def start
6. ? ???super
7. ? ???...
8. ? ?end
9. ? ?def update
10. ? ???super
11. ? ???...
12. ? ?end
13. ? ?def terminate
14. ? ???super
15. ? ???...
16. ? ?end
17. end
复制代码
.
★ initialize
? ? 初始化方法, 不是必须要的, 不过需要外部的某个值的时候, 可以使用该方法来传值.
★ start
? ? 开始, 处理从进入这个场景开始, 到第一个刷新(update) 之间的部分. 常用来初始化窗口, 或者变量什么的. 作用和 initialize 类似.
★ update
? ? 刷新. 每帧调用一次. 一般用于窗口的刷新, 或者必要的时候变量的刷新.
★ terminate
? ? 释放. 用处类似 dispose .只是最好不要手动去调用. 常用于释放窗口什么的.

? ? 其中的 start update terminate 都是必须需要的. 不写的话, 会默认调用父类 Scene_Base 的同名方法, 然后就是 Scene_Base 的同名方法都是空的, 仅仅只是预留下一个名字.
? ? 其他的 Scene 脚本的用法都是这样的. 只是用途不一样. 这个看默认脚本说明就可以了.


? ?
Scene 类运行原理

? ? 说到 Scene 的运行原理, 需要从 main 脚本的某一段说起. 脚本段如下:
1. $scene = Scene_Title.new
2. $scene.main while $scene != nil
复制代码
$scene 全局变量表示的是当前的场景, 也就是说我们在窗口里显示的那个场景. 在初始化好 $scene 后, 只要 $scene 不等于 nil, 那么将会无限的调用 $scene 的 main 方法. 也就是说, 一直循环调用 Scene 类的 main 方法.
? ? 那么, main 方法在哪里呢? 之前说明基本语法的时候, 也没有提到过 main 方法的说?
? ? 其实 main 方法是写在 Scene_Base 里的. 那么, 我们来看看内容:
1. #--------------------------------------------------------------------------
2. ??# ● 主处理
3. ??#--------------------------------------------------------------------------
4. ??def main
5. ? ? start? ?? ?? ?? ?? ?? ?? ?? ? # 开始处理
6. ? ? perform_transition? ?? ?? ?? ?# 执行渐变
7. ? ? post_start? ?? ?? ?? ?? ?? ???# 开始后处理
8. ? ? Input.update? ?? ?? ?? ?? ?? ?# 更新输入讯息
9. ? ? loop do
10. ? ?? ?Graphics.update? ?? ?? ?? ? # 更新游戏画面
11. ? ?? ?Input.update? ?? ?? ?? ?? ? # 更新输入讯息
12. ? ?? ?update? ?? ?? ?? ?? ?? ?? ? # 更新画面
13. ? ?? ?break if $scene != self? ???# 切换画面时中断循环
14. ? ? end
15. ? ? Graphics.update
16. ? ? pre_terminate? ?? ?? ?? ?? ???# 结束前处理
17. ? ? Graphics.freeze? ?? ?? ?? ?? ?# 准备渐变
18. ? ? terminate? ?? ?? ?? ?? ?? ?? ?# 结束处理
19. ??end
复制代码
具体的含义, 注释都说明了.
? ? 我们来看看大概的一个流程:
? ?
2010-12-20 21:36 上传
下载附件 (26.84 KB)


? ? main 方法里的核心部分就是 loop do ... end 的了. 这个可以理解成这个场景的主循环主循环. 它一共做了四件事情:
? ? 1. Graphics.update 负责图像部分的刷新, 其实也包含有窗口的消息循环刷新.
? ? 2. Input.update 输入模块刷新, 用于检测键盘的状态.
? ? 3. update Scene类的刷新方法. 自定义的.
? ? 4. break if $scene != self? ?如果当前场景 $scene 不是自己本身的话, 就跳出循环.


































Main

? ? Main 的含义和它的名字是一样的意思, "主要的". Main脚本在 VX 的脚本库, 乃至 XP 里都是一个很重要的脚本.
? ? 让我们先来看看 Main 的内容.
1. #==============================================================================
2. # ■ Main
3. #------------------------------------------------------------------------------
4. #  各定义结束后,从这里开始实际处理。
5. #==============================================================================
6.
7. # 一些常用的字体
8. Font.default_name = ["SimHei", "黑体", "DFKai-SB", "標楷體", "Verdana", "Arial Unicode MS"]
9. begin
10. ??Graphics.freeze
11. ??$scene = Scene_Title.new
12. ??$scene.main while $scene != nil
13. ??Graphics.transition(30)
14. rescue Errno::ENOENT
15. ??filename = $!.message.sub("无此文件或文件夹 - ", "")
16. ??print("无法找到文件 #{filename}.")
17. end
复制代码
重要的部分其实都已经说过了. 忘记的话, 就查查 F1 吧.
? ?? ? Main 脚本里一个重点在于 begin .. rescue.. end 结构. 它的用处是当??begin .. rescue 中级部分出现异常(或者说是错误)的时候, 可以被我们捕获到. 这里捕获的是 "文件找不到" 这个异常. 这就是问什么当我们的素材缺失的时候, RM 会提醒我们什么文件找不到的错误.??具体的部分, 请看 RGSS2异常 部分.


VX 脚本的运行顺序

? ?? ?Main 的位置标志着 RM 脚本的运行起点. 这里就简单的说说 RM 的脚本运行顺序吧. (其实我自己也不知道是不是这样, 不过八九不离十就是了 > <)
? ?? ?解说之前要说明一下几点:
? ?? ?1. 脚本的运行都是从脚本的第一个的第一行开始的.
? ?? ?2. 遇到 class(类) def(方法) module(模块) 都不会主动运行, 除非你去调用它.
? ?? ?3. 脚本都是按顺序执行的, 前提是满足执行条件.

? ?? ?知道这些之后就可以开始说明脚本运行顺序了.
? ???1. 从右边脚本列表的第一个脚本的第一行开始执行.(是的, 很拗口.)
? ???2. 如果遇到 class 的话, 那么 RM 就知道这里是定义类的, 于是它将这个类名保存起来.
? ???3. 如果这个类有父类, 那么 RM 就会去之前的纪录里去查看有没有这个类, 有的话, 就指定它们的继承关系, 没有的话, 就会提示找不到这个类.
? ???4. def 方法 和 module 模块也是类似的.
? ???5. 默认的脚本在 Main 脚本之前都是 类 或者 模块 定义的, 所以在执行到 Main 之前都仅仅是扫描.
? ???6. 到达 Main 脚本后, 真正的执行就是从这里开始了.
? ???7. 由 Main 脚本的调用关系可以延伸到之前所定义的所有类.
? ???8. 当我们选择游戏结束的时候(也就是使用脚本来结束, 这里不包含 exit 和 点击右上角的那个红叉), 才会继续从 Main 脚本里脱离出来继续执行后面的内容.

? ???其实顺序大致就是这样的. 这里呢, 我们就可以注意到一些细节:
? ???1. 在 类 里面的 方法定义是不限制顺序的, 也就是说, 我们可以先使用, 然后再去定义这个方法的内容. 但是早整个脚本库里, 只能是使用到这个类之前的所有资源. 因为它之后的类啦什么的, 都是没有扫描记录的. 所以, RM 并不知道的它之后的内容是什么.
? ???2. 由于 Main 里的内容既不是 class module 也不是 def 定义, 它仅仅是一段脚本, 于是满足调用条件, 所以, 真正的脚本开端就是 Main 脚本.
? ???3. 除非使用到 exit 或者那个红叉来关闭 RM , 否则 Main 后面的内容也是会执行的. 就算是有错误, RM 也是会提醒. 所以, 在某个脚本不需要的情况下, 最好还是批量注释掉.
? ???4. 没有了吧, 大概.










不常用关键字补充


相当简单的补充下常用的用法.

01. redo 和 retry
redo:??重新开始这次
retry: 重新开始整个循环体
例子:
1. for i in [1, 2, 3]
2. ??if 1 == i
3. ? ? p "redo"
4. ? ? i = 0
5. ? ? redo
6. ??elsif i == 3
7. ? ? p "retry"
8. ? ? i = -1
9. ? ? retry
10. ??end
11. ??p i
12. end
复制代码
02. undef? ?
语法:
1. undef 方法名
复制代码
作用: 释放一个方法. 注意的是, 在子类里调用 undef 的话, 父类的同名方法也被释放
例子:
1. class Animal
2. ??def eat
3. ? ? p "Animal eat"
4. ??end
5. end
6.
7. class Human < Animal
8. ??def eat
9. ? ? p "human eat"
10. ??end
11. end
12.
13. class Human < Animal
14. #~? ?remove_method??:eat
15. ??undef :eat
16. end
17.
18. Animal.new.eat? ? #=> "Animal eat"
19. Human.new.eat? ?#=> NoMethodError
20.
21. exit
复制代码
03. yield
作用: 类似占位符的功能, 可以保存上下文, 让随后的快来使用.
例子:
1. def call_back
2. ? ?p 1
3. ? ?a = "back"
4. ? ?yield(a)
5. end
6. call_back{|a|p a}
复制代码



















修改存档位置

? ?? ?目标: 修改存档位置, 做到自定义存档的保存位置.
? ?? ?修改过程:
01. 明确修改目的.
? ?? ?默认的存档文件是保存在根目录下的(也就是和 Game.exe 同一个目录), 现在的目标是保存在 Save 文件夹里. 然后再读取的时候也可以找到.
02. 当前已知
? ???存档的文件名是 SaveXXX.rvdata , 保存在根目录. 并且在进入标题的时候, 有存档的情况下, 光标会停留在 "继续游戏" 的选项上.
03. 开始修改
? ???先全局搜索 Save . 可以找到一些信息:

2010-11-8 20:59 上传
下载附件 (32.79 KB)

先关注 Scene_File(158) , 点进去后可以看到注释: 生成文件名称. 那么就是这里了, 修改成
1. return "Save/Save#{file_index + 1}.rvdata"
复制代码
之前的 Save 是文件夹的名称. 可任意.

? ???然后注意, Scene_Title(131), 可以看到这里是查找存档的,??那么就继续改:
1. @continue_enabled = (Dir.glob('Save/Save*.rvdata').size > 0)
复制代码
OK.
04. 测试.
? ? 测试开始. 进入存档, 保存. 然后就出现:
1. 无法找到文件 No such file or directory - Save/Save1.rvdata.
复制代码
好吧, 出问题了. 找不到文件.
? ? 其实不要被错误提示迷惑了. 找不到文件是因为我们没有创建 Save 这个文件夹. 新建后测试正常.
Game 类应用<< 技能书脚本>>
??★ 要实现的功能
??名字是 << 技能书脚本>> , 那么, 脚本的功能就是使用一个物品(技能书), 让被使用的角色可以学习到物品里指定的技能.

??★ 初期问题
??1. 既然是物品, 那么就存在一个方法来实现这个物品的使用.
??2. 既然是技能书, 那么就应该有一个对应关系, 就是 物品 => 技能 . 也就说什么物品可以学习到什么技能.
??3. 物品可以使用, 那么技能也应该需要学习.
??4. 需要知道这个物品时给谁使用.

??★ 初期运行步骤构思
??1. 使用物品
??2. 从使用的物品中取得某个资料
??3. 将这个资料通过某种方式转换成技能资料
??4. 获得被使用者的资料
??5. 让这个使用者学习到这个技能.

??★ 初期资料收集
??1. 找到能实现 使用物品 的方法.
? ?于是全局搜索 "使用物品". 找到一些满足条件的.

2010-12-23 21:17 上传
下载附件 (27.99 KB)

? ? 我们一个个来排除:
? ???● Sound: 这个一定不是了. 看名字就知道是处理声音的.
? ???● Game_Battler: 计算的方法, 也不是.
? ???● Scene_Item 和 Scene_Skill : 看起来好像就是这里, 点进去一看, 其实是场景跳转什么的.
? ???● Scene_Battle : 有两处. 我们想来看看第一个.
1. when 2??# 使用物品
2. ? ?? ?execute_action_item
复制代码
可能性很高. 于是继续查找 execute_action_item 这个方法.
1. #--------------------------------------------------------------------------
2. ??# ● 执行战斗行动:使用物品
3. ??#--------------------------------------------------------------------------
4. ??def execute_action_item
5. ? ? item = @active_battler.action.item
6. ? ? text = sprintf(Vocab::UseItem, @active_battler.name, item.name)
7. ? ? @message_window.add_instant_text(text)
8. ? ? targets = @active_battler.action.make_targets
9. ? ? display_animation(targets, item.animation_id)
10. ? ? $game_party.consume_item(item)
11. ? ? $game_temp.common_event_id = item.common_event_id
12. ? ? for target in targets
13. ? ?? ?target.item_effect(@active_battler, item)
14. ? ?? ?display_action_effects(target, item)
15. ? ? end
16. ??end
复制代码
于是就找到了. 就是那个 target.item_effect(@active_battler, item). item_effect就是实现使用物品的方法.

??使用同样的方法可以查找到学习技能的方法: learn_skill.
??
??★ 开始修改脚本
??1. 我们先从 item_effect 入手. 因为需要修改默认脚本的方法, 所以 alias 的作用很重要.
1. alias old_item_2_skill_item_effect item_effect
复制代码
2. 然后写一个 item_effect 方法.
1. def item_effect(user, item)
2. ? ? old_item_2_skill_item_effect(user, item)
3. ? ? item_id = item.id
4. ? ? skill_id = Item2Skill::Item_to_Skill[item_id]
5. ? ? return if skill_id == nil
6. ? ? skill_id.each do |id|
7. ? ?? ?user.learn_skill(id)
8. ? ? end
9. ??end
复制代码
这里可以将 old_item_2_skill_item_effect 理解成旧的 item_effect. 调用 old_item_2_skill_item_effect 也就是调用 旧的 item_effect. 所以参数是一样的.
? ? 3. 主要到??Item2Skill 这个模块了吗? 它的作用就是将 物品和技能联系在一样. 于是可以这么定义??Item2Skill 模块.
1. module Item2Skill
2. ??Item_to_Skill = {
3. ? ? 21 => [2],
4. ??}
5. end
复制代码
第一个 21 是物品的ID号, 后面的 2 是要学习的技能ID. 使用数组的理由是可以添加多个技能ID.

? ? ★ 测试
? ? 测试就不说了. 有错误改就是了.

























Window 类集

基本语法:
1. class Window_XXX < Window_Base
2. ??def initialize
3. ? ???super(x, y, w, h)
4. ? ???...
5. ??end
6. ??def refresh
7. ? ? ...
8. ??end
9. end
复制代码
1. 1. 父类
? ? 一般的窗口可以分成两大类. 一个是带有光标的窗口, 还有一个就是普通的窗口. 两者的父类是不一样的. 一般带有光标的窗口都是直接或者间接的继承于 Window_Selectable . 不带有光标的窗口继承于 Window_Base. 不过需要了解的一点是,所有的窗口的最终父类只能是 Window 类.. 但是 Window 的实现是在其 dll 里的, 所以无源码.
2. 2. 初始化
? ? 对于无光标的窗口: super 都是需要写的. 参数看父类就可以了.
? ? 对于有光标的窗口: 除了要使用 super 以外, 还需要注意这几个变量.
? ?? ???

? ?? ???
o @item_max: 选择项的总个数.
? ?? ???
o @column_max: 列数. 也就是说如果等于 2 的话, 会出现左右分开描绘选择项的效果. 具体的可以参照 Scene_Item.
? ?? ???
o @index: 当前选择项. 用于取得当前玩家选择的序号.(注意:不是选项内容, 而是序号)
? ?? ???
3. 3. 刷新
? ? refresh 方法不是必须的. 大多数的 Window 的 refresh 方法只是在 初始化或者需要刷新的时候才调用. 而不像 update 方法那样每帧调用. refresh 方法里常用的语句就是
1. self.contents.clear
复制代码
清除画布全部内容.只有这样,在接下来需要描绘的内容才不会重复的画在窗口上.
4. 4. 描绘
? ? 窗口类的描述都是在Window_Base 里创建的一个画布上进行的. 也就是 self.contents . 常用的描绘方法参考 Window_Base .需要注意的是, 窗口内容描绘是非常占用刷新时间的. 一般一个描绘内容没帧刷新的话, FPS 就惨不忍睹了.
5. 5. 常用属性
? ? 窗口类常用属性请查找 F1 帮助里的 Window 部分. 所有的 Window 类都可以使用里面的属性.














梦石
0
星屑
239
在线时间
2399 小时
注册时间
2008-4-11
帖子
12326

贵宾第6届短篇游戏比赛季军

2
 楼主| 发表于 2011-3-19 16:50:18 | 只看该作者
我承认我很无聊
回复 支持 反对

使用道具 举报

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-24 00:03

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表