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

Project1

 找回密码
 注册会员
搜索
12
返回列表 发新帖
楼主: RyanBern
打印 上一主题 下一主题

[原创发布] 【14.7.5第二版更新】RGSS1脚本入门参考

[复制链接]

Lv4.逐梦者 (版主)

梦石
0
星屑
9497
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

11
 楼主| 发表于 2013-11-16 10:14:22 | 显示全部楼层
本帖最后由 RyanBern 于 2015-8-24 12:13 编辑

[box=RoyalBlue]
第7章节:尾声
[/box]

       呼~写了这么久,这个脚本教程贴总算要杀青了。不过打开脚本编辑器,我们还有一些部分没有说到,比如说Interpreter类的脚本,我们就没深入讨论。不过,这对于一般的需要来说,已经足够了。那么在最后一章,我们要说一些零碎的内容。说是零碎,其实是编程的死角,这也是一个脚本党的必备知识。
7.1  个人的几个体会
7.1.1 关于alias
       这个词我们在很久之前就已经提到了,但是一直没有说它的用法,现在就补上吧。alias的意思是“别名”,在这里是给函数取别名。具体的使用方法是:alias 新方法名 旧方法名,新方法名和旧方法名用空格隔开。那么这个功能有什么用呢?主要是利用在方法的重定义上。当我们要重新定义一个方法,又不想覆盖原来的方法,那么alias就派上用场了。请看下面的例子:
RUBY 代码复制
  1. class Person
  2.   attr_accessor :name
  3.   def initialize(name)
  4.     @name = name
  5.   end
  6.   def hello
  7.     print "我是" + @name
  8.   end
  9.   alias old_hello hello
  10.   def hello
  11.     print “Hello, I am ” + @name
  12.   end
  13. end
  14. # 测试一下
  15. ryan = Person.new("Ryan")
  16. ryan.hello
  17. ryan.old_hello

       如果按照上述定义,第一个语句会在屏幕上显示“Hello, I am Ryan”,第二个语句会在屏幕上显示“我是Ryan”,可见alias具有保留原有方法的功能。
       在这里,我们看到alias的威力还不算很大。这个语句一般用作整合脚本上,特别是给不会脚本的人写脚本时,我们要写出一个完整的脚本,让用户贴在Main前面即可,但是有时候并不是这样,假设我们要修改前面默认脚本的内容,如果不用alias,那么只能进行重定义。但是对于一些方法,我们可以这样:
假如你给Game_Temp增加一个名叫test_value的属性,并在initialize中将它初始化,我们可以用三种方法。一是直接在Game_Temp上进行修改,不过,如果写脚本给伸手党,那就不太好,二是把整个Game_Temp需要重定义的地方定义一遍,对于Game_Temp这样的脚本来说,重定义一遍无异于整体复制,脚本显得很不整洁,三就是利用alias,具体实现过程如下:
RUBY 代码复制
  1. class Game_Temp
  2.   attr_accessor :test_value
  3.   alias old_initialize initialize
  4.   def initialize
  5.     @test_value = 0
  6.     old_initialize
  7.   end
  8. end

       在这里,我们是先对initialize进行别名,然后重定义,在定义过程中,调用了原方法。因为这里的initialize做的工作就是赋值初始化,因此这样写是没有问题的。
       不过,需要注意的是,不能给同一个方法起两个相同的别名,这样说似乎比较别扭,我们来看下面的例子:
       假如上面的代码已经定义好,那么我现在继续往Game_Temp里面增加一个叫test_bool的属性(Game_Temp中已经有了我们刚刚增加的test_value,利用的也是alias),由于我们现在的initialize的功能已经能够初始化test_value,因此我们利用alias时,进行重定义的肯定是initialize方法而非old_initialize方法,但是我们不能写下面的:
RUBY 代码复制
  1. class Game_Temp
  2.   attr_accessor :test_bool
  3.   alias old_initialize initialize
  4.   def initialize
  5.     @test_bool = false
  6.     old_initialize
  7.   end
  8. end

       这样写的话,脚本肯定会出错,因为你又将initialize别名为old_initialize,而刚才那个名字已经有了对应的方法,这样就会出现一个符号表示两个方法的情况,引发内部冲突。因此这个时候就不能用old_initialize做别名了,应该换成别的。

7.1.2 关于类变量@@xxxx
       类变量我们在讲类的时候顺便也提了一句,这种变量我们一般不会用到,不过好歹也说一下吧。类变量和通常我们讲的类当中的实例变量不同,类变量作用于整个类的上面。作为一个类生成的实例,这个实例本身可以访问该类的类变量。这样说有些模糊,我们看下面的例子:
RUBY 代码复制
  1. class A
  2.   # 定义类变量 @@a
  3.   @@a = 1
  4.   def initialize
  5.     # 定义实例变量 @a
  6.     @a = 1
  7.   end
  8.   def a
  9.     return a
  10.   end
  11.   def a=(a)
  12.     @a = a
  13.   end
  14.   def ab
  15.     return @@a
  16.   end
  17.   def ab=(ab)
  18.     @@a = ab
  19.   end
  20. end
  21. a1 = A.new
  22. a2 = A.new
  23. a1.a = 2
  24. a2.a = 3
  25. a1.ab = 5
  26. print a1.a  # => 2
  27. print a2.a  # => 3
  28. print a1.ab  # => 5
  29. print a2.ab  # => 5

       在这里,@a表示我们通常用到的实例变量,@@a表示类变量,在这里我们看到,@a这个变量是每个实例私有的变量,而@@a这个变量是两个实例公用的变量。因此我们得到结论,只要是属于同一个类的同一个类变量,无论用这个类的哪个实例修改它,都会有同样的效果,无论用这个类的哪一个实例访问它,都会得到同样的值。
       值得注意的是,类本身,也可以对类变量进行修改,不过要来借助类方法来完成。类方法和模块方法比较类似,定义和使用的模式基本相同。
RUBY 代码复制
  1. class A
  2.   # 定义类变量 @@var
  3.   @@var = 0
  4.   # 定义类方法
  5.   def self.var
  6.     return @@var
  7.   end
  8.   def self.var=(var)
  9.     @@var = var
  10.   end
  11. end
  12. A.var = 5
  13. p A.var # => 5


7.1.3  相同和相等•clone•变量和指针
       这个也是我们经常说的一个问题,Ruby是以C语言为基础语言编写的,实际上是对C做的一个优化。我们都知道C语言中有指针这个东西,而Ruby中我们却看不到它。不是说Ruby中没有指针,而是Ruby已经采取某种方式将指针优化掉了。我们在编写程序的同时,就在使用大量的指针,只是我们从未发觉而已。为什么又说起这个事情来呢,这是源于本人最近的一道作业题,我嫌用C太复杂,于是就用Ruby了,但是有一个地方怎么也通不过,一时想破脑袋也没想明白。不过后来好在经过F1指点,终于明白了问题所在,接下来我们就看一下。
       我们在前面说了,赋值运算符“=”的作用是将右边的值赋给左边,传递过去的就是对象的引用。所以,当你把一个数组或者一个类的实例赋给一个变量,那么实际传递过去的就是变量的引用,如果你把这个值又赋给另外一个变量,那么依然是传递引用,对一个变量进行的操作必定会影响另一个。因此,有时候我们需要生成一模一样的一个对象,又不想让它们有任何关系,就要用到clone方法,这是Object类(最大的类)的方法,任何类的实例都可以调用,因此,写b = a.clone,就能把a和b区别开来,而且他们的内容也完全一样。我们知道利用比较运算符“==”可以判断两个对象是否相等,而这个运算符只能判断两个对象的值是否相等,例如,有b = a.clone,然后判断b == a,这个结果通常是true,不过,a和b并不相同,在Object类里面也有一个判断是否相同的方法equal?,如果执行b.equal?(a),我们得到的结果将会是false,因为equal?是判断二者是否相同的方法,在这里,a和b仅仅是内容相同,而它们实际上是两个“变量”(即内存的地址不同,这并不稀奇,就好比你和你的双生同胞不是同一个人一样)。
但是,即使是这样,也会遇到一些费解的问题。例如,有下面的定义:
RUBY 代码复制
  1. class A
  2.   attr_accessor :data
  3.   def initialize
  4.     @data = []
  5.   end
  6. end
  7. x1 = A.new
  8. x1.data[0] = 0
  9. x2 = x1.clone
  10. x2.data[0] = 1
  11. print x1.data[0]

       在这里,我们看到屏幕上显示的是1,这个最初看起来是非常奇怪的事情。我们明明对x1做了复制,按理说x1和x2的应该只是内容一样而已,为什么对x2的修改也影响到x1呢?这里我们注意的是,clone进行的只是浅层次的复制,它只能复制对象里面所有变量的内容,而不能复制变量引用的内容。我们知道,一个变量如果表示数组,那实际上就是指向数组的引用,在这里@data就是一个数组,表示的就是数组的引用,而clone做复制时,仅仅把这个引用的值复制了过去,因此它们表示的还是同一个东西。除非你将x2的data重新定向,否则在x2的data上面的改动还是会影响x1。
7.1.4  sprintf表达式
       说实话,学C语言的人在Ruby里面看到这个,应该感到无比亲切吧。这可以说是为数不多被保留下来的语句啊。sprintf这个名字蛮奇怪的,print是“打印、输出”的意思,那么后面的f,缩写的是format,表示“格式”,连在一起就表示“格式输出”,当然printf也是C的基本函数之一,前面的s,是表示输出的去向,s缩写的是string,表示这个函数将一定的内容输出到一个字符串内。在C语言中,sprintf的第一个参数是表示接受输入的字符串(字符数组指针),但是在Ruby里面,这个字符串直接作为sprintf的返回值。具体使用方法,如果学过C了,肯定都知道,如果不清楚就F1看看,其中“%”表示格式转换描述,例如写a = sprintf("%d %d", x1, x2),就是把x1和x2的值分别替换两个%d,然后做成字符串送到a中,我们注意%d是整数转换描述,如果x1表示的不是整数,那么就会出错的,因此,格式输出一定要严格控制,千万不能出现转换错误。

7.2  写在最后
       这个RGSS1教程帖就这样结束了,不知道能坚持看到最后的你们,能不能有所收获呢?我不敢期望这个教程的效果有多么强大,但是,只要它能为大家写游戏做出一丝一毫的贡献,我就知足了。
       每次写完一章,我都很期待大家的回帖,不过从第四章开始,这个帖子基本没有什么回帖的了,于是我就一直连帖下去,一直连帖,直到最后我发现大家似乎已经没有心情看下去了。我想这也是我个人方面的原因,第5章和第6章中间间隔将近一个月,或者说是我才疏学浅,但总之,我写这个东西的目的就是让大家能学会分拆脚本,根据默认脚本或者其他大神的作品的构造来提炼出自己的东西。
       很多人看到脚本教程,给出的评价,大多都是“变量计算、类那里还行,到后面就什么也看不懂了”、“看完教程后就学会了一个p函数,别的都没学会”,我其实还满希望我的教程能摆脱这个评价,但是现在想想,或许这个教程帖也难逃此厄运。毕竟,如果没有经历系统的学习,没有理解计算机工作的原理,只是走马观花地看教程,恐怕也没什么效果。这样的教程写出来,结果往往都是,会脚本的人更厉害了,不会脚本的人依然没学到什么……总之,虽然截稿了,但是很郁闷。

       6R站上已经有了很多RMXP的经典教程,而且侧重点各有不同。推荐大家在阅读教程帖子的时候,在多个教程之间比对,发现其中的不同,从而提出问题。毕竟所有的教程都会有疏漏和错误,写出一个完美的教程也实在是太过于困难。

       最后,建议想要学习脚本的同学,一定要多看,多提问,多练习,少伸手。学习的初期可能做不出自己想要的东西,这没有关系,学习脚本切忌急功近利,心急往往很容易冲淡学习脚本的热情。起初建议大家模仿默认脚本来修改和练习,慢慢磨合,今后使用脚本才能更加得心应手。

点评

↓依你之见还应该再加点什么呢?  发表于 2013-11-16 13:26
这就尾声了什么情况- -不过最后一章还是很赞- -很多教程都不说这一点的  发表于 2013-11-16 12:34
回复 支持 反对

使用道具 举报

Lv4.逐梦者 (版主)

梦石
0
星屑
9497
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

12
 楼主| 发表于 2013-11-16 20:19:52 | 显示全部楼层
芯☆淡茹水 发表于 2013-11-16 18:06
在一篇 Ruby 语言教学里看到的,觉得很经典。

  Ruby 的理念是:一切都是对象。包括:数值,字符串, ...

嗯,说得很形象,感谢你的帮忙哈!
回复 支持 反对

使用道具 举报

Lv4.逐梦者 (版主)

梦石
0
星屑
9497
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

13
 楼主| 发表于 2014-10-2 10:03:31 | 显示全部楼层
繁星千羽 发表于 2014-10-2 01:13
谢谢楼主……
最近才开始接触RMXP和脚本,因为之前有过一些很基础的编程基础,所以对编程的运算顺序和局部 ...

首先感谢你的回复呢。那我们就一条一条来说了。
首先第一点,这个教程帖我个人也是非常不满意。有些地方没有说清楚,对有一定经验的人来说太简单,对于新人来说太难。其实这是我一年前写这个东西的时候,面向的读者就不是一点基础都没有的新人。所以可能会吓跑一堆新手吧。对于attr_accessor :的理解,初学Ruby(RGSS1)的话这样理解完全可以。实际上就是可以在对象外面访问(写入和读取)对象本身的数据(成员变量)。还有要说明的是你要理解Taroxd大大的“挫折式言语”,正是因为不断受挫才会不断成长,我也是这么熬过来的。
第二点,第二个作业的要求只是提示你用脚本来完成独立开关的控制,核心就是“在一个事件中也可以控制另一个事件的独立开关”,仅此而已,没有必要把它想象得太复杂。完成这个任务是需要事件,事件脚本,地图结合起来的。并不是限制你做游戏的方式和方法,只是给了你一个提示。
说到这里,本人在XP提问区办的考场第二轮也即将开始,里面就有这个题目。如果你有兴趣可以拿去做做,其实这确实是一个很经典的题目了。
回复 支持 反对

使用道具 举报

Lv4.逐梦者 (版主)

梦石
0
星屑
9497
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

14
 楼主| 发表于 2015-7-29 23:09:30 | 显示全部楼层
舞小朵儿 发表于 2015-7-29 22:39
表示从前学过一点C++的我来说看到这个还是很无力。。。

首先,我得承认这个教程帖子写的不是很好,因为很多东西都没说清楚。后面的应用部分也是马马虎虎,感觉完全没有做一个视频来得实在。
然后,虽然都是面向对象编程语言,C++和Ruby有着极大不同,因此很多Ruby的现象让C++程序员都不能理解,再加上语言风格,关键字使用上的不同,让C/C++程序员很不适应。
所以,要真正弄懂还得去看专门的Ruby教程,推荐Ruby Programming
回复 支持 反对

使用道具 举报

Lv4.逐梦者 (版主)

梦石
0
星屑
9497
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

15
 楼主| 发表于 2015-8-19 08:55:46 | 显示全部楼层
bugmenot 发表于 2015-8-19 06:58
其实这个很讨厌的,太不一致了。其实 RM 完全可以从 0 开始的。或者为了照顾日常生活习惯,$data_xxx 和  ...

首先,非常感谢你的建议!提到的这些本来应该在第二版修正的(第一版的错误太多了),但是还是没有顾虑到。
不过我记得Ruby的一大特性就是“变量无需声明直接使用”,所以声明什么的,可以不必再提。
赋值那个地方其实讲得比较乱,完全可以用一句话代替:“赋值就是引用的重定向”。因为Ruby中并没有“值类型”和“引用类型”的说法,所以例如Fixnum类的对象,其实是即时值,赋值还是是改改引用而已。
回复 支持 反对

使用道具 举报

Lv4.逐梦者 (版主)

梦石
0
星屑
9497
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

16
 楼主| 发表于 2016-7-8 22:13:33 | 显示全部楼层
银羽凌云 发表于 2016-7-8 21:59
大神求教
class Cuboid
  def initialize(number)

001表示一个八进制数,因此不建议你这样给实变量赋值。

一个可行的办法是这样
[pre lang=Ruby]def count
  print sprintf("长方体%03d", @cuboid_number)
end[/pre]

然后调用cuboid_001 = Cuboid.new(1)
利用sprintf可以进行格式化输出。

至于第一个问题,我不会写。你可以考虑使用eval来计算表达式的值。
name='xiaoming'
eval name+'.name = "小红"'
回复 支持 反对

使用道具 举报

Lv4.逐梦者 (版主)

梦石
0
星屑
9497
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

17
 楼主| 发表于 2018-3-7 09:11:09 | 显示全部楼层
tsukishinu 发表于 2018-3-6 14:47
版主大大你好,想请教一个问题。我照着这个帖子写完了真实商店,虽然功能基本实现了,但是商店里的数据没法 ...

一个比较方便的做法是将真实商店变成 $game_system 对象里面的一个实变量。因为 $game_system 这个对象是可以自动存储的,所以以它为载体存储额外对象是个重要的技巧。

代码只需要添加:
RUBY 代码复制
  1. class Game_System
  2.   attr_accessor :visualshop
  3. end


而后在生成真实商店的时候使用 $game_system.visualshop = Game_VisualShop.new(args) 即可
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

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

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

GMT+8, 2024-5-16 00:10

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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