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

Project1

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

[讨论] Ruby/RGSS Tips 每日一更 [技术区的版聊帖?]

  [复制链接]

Lv3.寻梦者

梦石
0
星屑
1055
在线时间
1564 小时
注册时间
2008-7-30
帖子
4418

贵宾

跳转到指定楼层
1
发表于 2010-8-26 10:30:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

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

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

x


这个是一个偶然的想法,需要一定的试点。是这样的,这个帖子每天将会更新一些Ruby 或者 RGSS 的小技巧,这些技巧一般很简短,易于掌握。

细则如下:
  • 每天只能有一个新回复,其他请使用“点评”功能,补充请使用“编辑”功能。否则版主有权删贴。
  • 和水区版聊帖一样,先抢先得。
  • 每个tips不宜超过200字
  • 每月根据情况施予不同的表彰
  • 精华内容将被搜集、整理。
  • 不要重复。或者过于简略而含糊不清。
  • 转载或引用请注明原文或引用链接(有些会员可能无法发送链接)。



注意!
  • 本帖采用的是[倒序看帖],新的帖子在最上方。
  • 其他的问题将在以后补充。





See FScript Here:https://github.com/DeathKing/fscript
潜心编写URG3中。
所有对URG3的疑问和勘误或者建议,请移步至发布页面。
欢迎萌妹纸催更

Lv3.寻梦者

梦石
0
星屑
1055
在线时间
1564 小时
注册时间
2008-7-30
帖子
4418

贵宾

2
 楼主| 发表于 2010-8-26 10:31:15 | 只看该作者

Sample - $game_switches和$game_variables

本帖最后由 DeathKing 于 2010-8-26 11:14 编辑

2010-08-26

$game_switches和$game_variables分别掌管游戏开关和游戏变量,他们都是数组(Array),访问使用的是[]方法,修改使用的是[]=方法。

对于$game_switches来说有效值为true(真,游戏中为开),false(假,游戏中为关);
对于$game_variables来说,理论有效值是Object(可以理解为所谓Ruby可识别的对象),但因为编辑器的限制,只能是数字(Numeric)或者字符串(String)。

将1号开关打开:$game_switches[1] = true
将5号变量归零:$game_variables[5] = 0


内幕:
事实上,$game_switches和$game_variables并不是一个Array,其实变量@data才是一个数组。
Game_Switch和Game_Variable类定义了[]和[]=两个方法来从外部访问@data而已。


补充:
紫苏:可以具象化——这两个东西实际上就是开关数组和变量数组的外壳,通过接口与外部通信
小幽的马甲:顺便,这俩的访问和修改不受数据库里上限影响——并且本来会返回nil时会返回0或false

点评

精灵看到这篇时候震精了:我一直都把他们当成数组来着(因为在Game_variables和Game_switches)里面已经初始化了所有的开关变量的说……  发表于 2010-11-29 13:56
@trentswd:确实可以当成 Ruby 的运算符重载,只须知 Ruby 的“运算符”本质上还是方法,[]、= 之类的允许出现在方法名字元中的特殊字符只是一种语法糖(即本质上还是 .[]、.= 的调用形式)   发表于 2010-8-27 07:52
moy
经常用for循环批量初始化...算是批量操作的小技巧吧,数组相对于普通hash的便利性体现之一~~  发表于 2010-8-27 07:23
我一直把这个当重载运算符来看……  发表于 2010-8-27 03:20
..... 有点高端....  发表于 2010-8-26 12:46

See FScript Here:https://github.com/DeathKing/fscript
潜心编写URG3中。
所有对URG3的疑问和勘误或者建议,请移步至发布页面。
欢迎萌妹纸催更
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
61
在线时间
24 小时
注册时间
2008-8-5
帖子
1924
3
发表于 2010-8-26 10:55:10 | 只看该作者
有人会问:Ruby 没有析构方法?乍一看似乎这个真没有,其实这个可以有——
define_finalizer  ObjectSpace.define_finalizer( anObject, aProc=proc() )  

Adds aProc as a finalizer, to be called when anObject is about to be destroyed.  

ObjectSpace.define_finalizer 可以为某个对象添加一个类似 C++ 析构函数的最终化处理器,如果在 initialize (类似构造函数)中调用这个方法,就能为每个实例添加一个固定的析构方法
例:

  1. class MySprite < Sprite
  2.     def initialize(viewport = nil)
  3.         super(viewport)
  4.         ObjectSpace.define_finalizer(self, proc { self. dispose })
  5.     end
  6. end
复制代码
这样一来,当 MySprite 对象被回收时,精灵资源会自动释放

点评

moy
上的就是信息技术专业...准备朝编程方向发展,主要是蛮感兴趣的说~不过糟糕的是我数学不太好于是在起跑线上就被拉后腿了T_T  发表于 2010-8-28 01:20
@moy:呵呵,慢慢来~其实我觉得如果不想主走成程序的路没必要钻研太深,还是找朋友合作比较好,就像我不可能从头学美术一样……  发表于 2010-8-27 09:16
补充:Proc 还不是 Ruby 真正的闭包,lambda 才是,详见:[url]http://bbs.66rpg.com/forum.php?mod=viewthread&tid=153979[/url]  发表于 2010-8-27 09:15
moy
不管是内容还是点评一概都雾水了@_@,我还有很长的路要走啊.....好多概念都空白呢  发表于 2010-8-27 07:25
没错,实际上就是闭包的概念  发表于 2010-8-27 01:19
回复 支持 反对

使用道具 举报

Lv2.观梦者 (管理员)

八云紫的式神

梦石
0
星屑
554
在线时间
1243 小时
注册时间
2008-1-1
帖子
4282

烫烫烫

4
发表于 2010-8-27 08:39:48 | 只看该作者

2010-08-27 简略写法

p不是关键字,但是可以执行p 1正常输出1而不出错,为什么?
Ruby里调用方法时,如果不会产生歧义,则可以省略括号,使代码变得整洁美观
比如要输出一个跟RM里的用语【等级】同名的文件,可以简写成这样
  1. print IO.read Vocab.level
复制代码
这比完整写法
  1. print(IO.read(Vocab.level()))
复制代码
好看的多
但是一定要注意使用时的原则是不引起歧义,例如
  1. open File.expand_path "test.txt" , "w"
复制代码
就会出错,原因是参数"w"可能是expand_path的参数也可以是open的参数
所以必须加一层括号
  1. open File.expand_path("test.txt") , "w"
复制代码
Ruby中类似的简写除了括号之外,还有其他的,例如Hash
  1. p 1 => 2
复制代码
乍一看似乎是会Syntax,但是这一句是能执行的,输出{1 => 2}
这一特性在ruby的应用(窗口编程/网页)中使用得十分广泛

点评

只推荐用于单参数  发表于 2010-8-27 10:55
这样可能会一定程度降低可读性,使用时确保自己熟悉每个方法的参数  发表于 2010-8-27 09:08
点了回复的时候没看到嘛 >_< 结果就撞上了,不过今天入账2枚,收获颇丰啊。  发表于 2010-8-27 08:57
rm for linux(wine)制作中,期待夏娜SAMA能实现到webrm上
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1055
在线时间
1564 小时
注册时间
2008-7-30
帖子
4418

贵宾

5
 楼主| 发表于 2010-8-27 08:43:26 | 只看该作者

有关方法名的一些俗成约定

本帖最后由 DeathKing 于 2010-8-29 07:19 编辑

2010-08-28

昨天进行过一次讨论:http://rpg.blue/thread-154899-1-1.html
既然抢到了今天的帖子,那么就借花献佛。

Ruby中的方法名有一定的俗成的约定,下面列出了这些约定,不过,这不是强制性必须遵守的!

以 = 号结尾的方法通常是setter,会为同名实变量设定值;
以 ? 号结尾的方法返回的是一个所谓的布林值,也就是true或者false;
以 ! 号结尾的方法表示该方法具有破坏性,所以要小心操作。

一些例子:
  • 由元编程方法 attr_writer :methodattr_accessor :method 建立的 method= 方法就会为 @method 实变量赋值;
  • Object 类提供的 is_a? 方法返回 true 或者false ,来判断对象是否是一个类的实例,如: 1.is_a? Fixnum #=> true
  • String 类提供的gsub! 方法比较常见(Window_Message 大多用这个方法处理),它就具有破坏性,直接在源对象上操作;

关于破坏性与非破坏性的比较:

  1. ary = [1,3,5,7,9,2,4,6,8,10]

  2. ary.sort #=> [1,2,3,4,5,6,7,8,9,10]
  3. p ary    #=> [1,3,5,7,9,2,4,6,8,10]

  4. ary.sort! #=> [1,2,3,4,5,6,7,8,9,10]
  5. p ary     #=> [1,2,3,4,5,6,7,8,9,10]
复制代码

See FScript Here:https://github.com/DeathKing/fscript
潜心编写URG3中。
所有对URG3的疑问和勘误或者建议,请移步至发布页面。
欢迎萌妹纸催更
回复 支持 反对

使用道具 举报

Lv3.寻梦者

孤独守望

梦石
0
星屑
3126
在线时间
1535 小时
注册时间
2006-10-16
帖子
4321

开拓者贵宾

6
发表于 2010-8-28 18:26:52 | 只看该作者

2010-8-29

本帖最后由 IamI 于 2010-8-29 12:59 编辑

Class、Module两个类是抽象的抽象。在Class中定义的实例方法是Class类的对象的方法,也就是普通的类的类方法。比如说:
  1. class Class
  2.   def hi
  3.     p "HI!"
  4.   end
  5. end

  6. class A
  7.   hi
  8. end
  9. A.new.hi
复制代码
不言自明。

Class和Moudle的类方法只能被显式的调用,诸如Class.new

另外,事实上,假设A是一个类,当你调用A.new方法的时候,操作如下所示:
A.new调用A.allocate => 生成实例
调用实例的initialize方法 => 根据伪多态完成初始化操作。

Object是一切的起源。它是超脱一切的存在(囧)。Object的include-in Kernel(你没看错,它是一个Mix-in)可以在任何位置被调用。也许你会问。既然Kernel是一个嵌入模块,那么为什么在没有类没有实例的方法也可以调用?因为直接p self可以(VX)看到顶级被调——Main :Object。是的,你逃不出Object的掌控。

如果你要给所有类定义一个方法,想在Class类eval?错了,instance_eval。具体请参考一开始的那段话。

OK,给下面两楼两个话题。Binding、$SAFE
菩提本非树,明镜本非台。回头自望路漫漫。不求姻缘,但求再见。
本来无一物,何处惹尘埃。风打浪吹雨不来。荒庭遍野,扶摇难接。
不知道多久更新一次的博客
回复 支持 反对

使用道具 举报

Lv2.观梦者 (管理员)

八云紫的式神

梦石
0
星屑
554
在线时间
1243 小时
注册时间
2008-1-1
帖子
4282

烫烫烫

7
发表于 2010-8-30 08:18:07 | 只看该作者

2010-8-30

重名陷阱

由于Ruby在语法上很人性化很自由,这也就带来了一些问题

例如
1.在方法调用中省略括号所引起的误会  注:标引用的部分引自Ruby手册
因为表示Range对象(或范围表达式)的.., ...的结合度较低(请参考操作符表达式),所以会引发下列错误
1..3.to_a
=> -:1: bad value for range (ArgumentError)
上面的代码会被解释成下面这个样子。
1..(3.to_a)
下面的代码不会得到预期的结果
p (1..3).to_a
因为它被解释成下面的代码。
(p (1..3)).to_a
p (true && true)    #=> true
p (true and true)   #=> parse error
p ((true and true)) #=> true
因为true and false被看作是语句,所以必须使用括号将其变为表达式的等价形式。同时,将它传给p的参数时还需要再加上一层括号才行。
p {1=>2}    #=> parse error (大括号被当作块)
p ({1=>2})  #=> {1=>2}
p (1=>2)    #=> {1=>2} (参数被当作哈希表)
p (1=>2, 3) #=> parse error    (只能把省略大括号的哈希表放在参数列表的最后)
p (0,1=>2)  #=> 0
                1=>2

2.运算符和方法的重名
a=1;
b = a+2;   # a 和 2 的和
b = a +2;  # 被解释成 a(+2)
b = a + 2; # a 和 2 的和

a = b = c = true
a?b:c       # 被解释成 a?(b(:c))
a ? b : c   # 条件操作符

3.变量和方法的重名
以小写字母开头的方法,可能与变量重名
  1. def a
  2.   1
  3. end
  4. p a #=>1
  5. a = 2
  6. p a #=> 2
  7. p a() #=> 1
复制代码
如果没有a这个变量,那么只p a就可以输出1
但是大写字母则不同,无论有没有同名常量,都必须加()
  1. def A
  2.   1
  3. end
  4. p A #=>出错
  5. A = 2
  6. p A #=>2
  7. p A() #=>1
复制代码
带等号方法
  1. def a=(val)
  2.   @a = val
  3. end
  4. a = 1
  5. p @a #=> nil
  6. self.a = 1
  7. p @a #=> 1
复制代码
rm for linux(wine)制作中,期待夏娜SAMA能实现到webrm上
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
1055
在线时间
1564 小时
注册时间
2008-7-30
帖子
4418

贵宾

8
 楼主| 发表于 2010-8-31 00:02:57 | 只看该作者

2010-08-31

本帖最后由 DeathKing 于 2010-8-31 00:37 编辑

三元表达式、三元运算符(Ternary Operator

  平常接触的if控制结构都是这样的:
  1. if condition
  2.   exp1
  3. else
  4.   exp2
  5. end
复制代码
不过当exp只有一句的时候,这样看起来会十分的占地方,所以就有了下面这种简写为一排的方式:
  1. if condition then exp1 else exp2 end
复制代码
不过这样看起来也有很大一堆,还有没有更简单、优雅的写法呢?当然是有的,Ruby继承了C的三元运算符(Ternary Operator),上面的表达式会被替换成这样:
  1. condition ? exp1 : exp2
复制代码
实质上,首先会计算condition的值,为真的话就执行exp1,否则就就只exp2。不过要注意的是,三元运算符的优先级比=(赋值运算符)高,所以下面的做法是完全可行的:
  1. foo = true ? 1 : 0
  2. p foo #=> 1
复制代码
如果说你是Visual Basic程序员,你会发现,三元运算符就和IIf函数类似。

See FScript Here:https://github.com/DeathKing/fscript
潜心编写URG3中。
所有对URG3的疑问和勘误或者建议,请移步至发布页面。
欢迎萌妹纸催更
回复 支持 反对

使用道具 举报

Lv1.梦旅人

万物创造者

梦石
0
星屑
54
在线时间
352 小时
注册时间
2008-2-15
帖子
2432
9
发表于 2010-9-1 08:49:17 | 只看该作者
本帖最后由 小幽的马甲 于 2010-9-1 08:50 编辑

2010-9-1

垃圾回收(Garbage Collection)

GC是个很有意思的东西。不管是用C的malloc和free还是Pascal的new和dispose管理内存都需要有一个释放的过程,有的时候会很麻烦,GC就是把这个过程智能化了,可以把不用的对象(垃圾)自动释放掉。
RM里的GC模块只有三个方法:GC.enable(打开GC)、GC.disable(关闭GC)、GC.start(初始化GC),很好理解。
为了测试GC的效果,我们可以在事件里调用
  1. a = Window_Help.new
  2. a = 1
复制代码
执行后可以看到,地图上仍会留一个窗口,但是约一分钟后就会自动消失。
如果后面加句GC.start则会立刻消失。
当然,平时写脚本是绝对不要依赖GC,该释放的对象还是要释放。
默认脚本中只有在Cache.clear里用到了GC,因为那时候缓存的哈希表被清空,但对象并没有被释放,所以需要调用GC。
From mortal hope immortal power springs.
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
61
在线时间
24 小时
注册时间
2008-8-5
帖子
1924
10
发表于 2010-9-2 10:06:13 | 只看该作者
2010-09-02 Proc.new 和 lambda
Proc 是 procedure 的简称,意味着一个过程,或者例程。我们基本上可以把 Ruby 的 Proc 对象看作是 Ruby 的匿名函数,但在 Ruby 1.8 中,通过不同方法获取的 Proc 对象有微妙的区别:
  1. def foo
  2.   local = 'This is a local variable'
  3.   $proc = Proc.new { return }
  4.   $proc.call # OK
  5.   p '这里永远不会执行'
  6. end

  7. foo
  8. $proc.call # error
复制代码
在 foo 方法内部,$proc 执行后,直接结束了函数的运行,而在方法外部调用 $proc 则会产生非局部跳转的异常,这里的意思是告诉你不能在顶层 return。从这个现象可以得出结论:Proc.new 会绑定创建时的上下文,而在这个 Proc 对象内 return 则是与该上下文绑定的。比如,上面的代码中,$proc 创建时的上下文是 foo 方法的局部上下文,在方法内部调用 $proc 时 foo 的局部上下文还存在(方法还没有返回),所以没有问题;在方法外部调用 $proc 时 foo 的局部上下文已不复存在(方法已经返回),所以发生了异常
我们再来看看闭包的定义:
在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

然而 Proc.new 产生的 Proc 对象并没有真正的自由,它与创建时的上下文绑定在了一起,并不是一个独立的匿名函数个体(因为不能自由地 return,且成功 return 后会让外部的函数返回),所以它并不算是真正意义上的闭包
可喜的是,刁钻古怪的 Ruby 还是用一种隐晦的方式提供给了我们真实的闭包。把上面的代码中的 Proc.new 替换为 lambda 后,就能发现没有错误了。lambda 是 Kernel 里的方法,这个名称来源是 λ-calculus 中的 λ 符号,意味着一种匿名函数演算法,由 Scheme 语言最早支持,后来被各种语言继承。lambda 产生的 Proc 对象,其内部 return 是从当前的 Proc 对象,即当前的闭包返回,所以 lambda 产生的 Proc 对象才是 Ruby 真正的闭包
这里还有最后一个问题,就是 Ruby 1.8 对 proc 和 lambda 的定义产生了混淆。proc 也是 Kernel 里的一个方法,其文档中表示 Kernel#proc 等价于 Proc.new,但当我们实际把上面代码中的 Proc.new 替换为 proc 时,会发现没有异常。实际上在 Ruby 1.8 中,Kernel#proc 是等价于 Kernel#lambda 的,也就是说 Kernel#proc 也是真实的闭包。然而从命名上来看,proc 和 Proc.new 不同而合 lambda 相同,是一个很明显的设计失误,所以在 1.9 中,Ruby 巧妙地让 Proc.new 等价于了 Kernel#proc
回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

GMT+8, 2024-5-18 09:24

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

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