楼主: taroxd

[版务] RGSS 3 入门教程大家写(第二弹)

[复制链接]

…あたしは天

梦石
0
星屑
2308
在线时间
4033 小时
注册时间
2010-10-4
回帖
10548

开拓者贵宾

 楼主| 发表于 2014-7-14 18:45:40 | 显示全部楼层
本帖最后由 taroxd 于 2014-7-14 18:50 编辑

[fold=如何在每次状态A消失后自动附加状态B?]

要做到这个效果,我们首先要知道 RGSS3 是如何做到解除状态的。
我们在脚本编辑器里全局搜索“状态”,找到了这一个结果。
搜狗截图_2014-07-14_17-48-38.png
[pre lang="ruby" line="1"]
def remove_state(state_id)
  if state?(state_id)
    revive if state_id == death_state_id
    erase_state(state_id)
    refresh
    @result.removed_states.push(state_id).uniq!
  end
end
[/pre]

让我们一行一行地来看:

if state?(state_id):我们查询脚本,可以知道 state? 是 Game_BattlerBase 里定义的,判断角色是否在某个状态的方法。
所以,这一行的意思是:如果角色当前有这一个状态的话,执行下面的内容。

revive if state_id == death_state_id:如果这个状态表示“死亡”,那么调用 revive 方法。
查询脚本,可以知道 revive 是把 HP 回复到 1,如果 HP 为 0 的话。

erase_state(state_id):彻底消除一个状态。

refresh:刷新。查询脚本可以知道,这是去除抵抗的状态,防止HP、MP超过最大值,并且判断死亡的方法。

@result.removed_states.push(state_id).uniq!:把清除的状态记录在战斗结果中,可以用于显示战斗信息等用途。

了解上述这些有什么用呢?他告诉我们,我们来对地方了。要改的地方就是这里。
在改之前,我们还需要了解如何增加一个新的状态。让我们使用全局搜索。

...
...

找到了吗?

...
...

就不告诉你,自己找去。

好的,让我们开始编写自己的代码。我们是要在每次状态A消失后添加状态B。为了表示状态A、状态B,并且便于修改。我们需要用到常量。
同时,为了更好的兼容性,也为了简化代码,这里用到了 alias 技巧。这个技巧在后面会提到。
[pre lang="ruby" line="1"]
class Game_Battler
  # 下面常量和方法别名的起名很随意、容易重名。
  # 请不要模仿这样随意的起名,而应该尽可能起独特的名字来防止重名。
  STATE_A = 26
  STATE_B = 27
  alias original_remove_state remove_state
  def remove_state(state_id)
    添加状态(STATE_B) if state_id == STATE_A && state?(STATE_A)
    original_remove_state(state_id)
  end
end
[/pre]

这就是最终的脚本。怎么样,是不是非常简单?
[/fold]

评分

参与人数 1梦石 +1 收起 理由
VIPArcher + 1 认可答案

查看全部评分

回复

使用道具 举报

梦石
0
星屑
122
在线时间
552 小时
注册时间
2012-8-18
回帖
1392
发表于 2014-7-15 01:13:09 | 显示全部楼层
本帖最后由 无脑之人 于 2014-7-15 01:16 编辑

以下内容不看也罢
[fold=并行赋值(Parallel Assignment)]
并行赋值,这是一个十分有趣的东西
我们平常赋值,一般就是a = 10这样,高端一点的可能会使用多重赋值:
  1. a=b=c=d=10
复制代码
但是ruby实际上支持一种非常高ji端lei的赋值方式,那就是并行赋值
1.首先是它最基础也是最经典的应用——交换
  1. a,b = b,a
复制代码
这体现了ruby在并行赋值中的求值顺序——先右后左
2.然后是正常的使用
  1. a,b,c = 1,2,3
复制代码
注意,如果右边的多了,那么多出来的部分会被舍弃,如果右边的少了,会用nil来填补
3.特殊情况——一对多,多对一
  1. a = 1,2,3,4,5,6
复制代码
这个时候,a被赋值为一个数组,元素不言而喻
  1. b,c,d,e,f,g = a
复制代码
由于a是一个数组,在多对一的情况下,这个数组被拆开了
4.混入展开式——显式要求数组,显式展开数组
  1. *a = 1,2,3,4,5,6
复制代码
这个时候是与一对多的情况一致,然而我们如果想要多对多的情况进行数组的包装
  1. a,*b = 1,2,3,4,5,6
复制代码
显然,a拿走了1,剩余的b都拿走了
对于Ruby 1.9以上的,我们允许展开式处于任意位置,不到1.9,很遗憾,只能放最后
【请不要试图用多个展开式233
其实我们可以看出赋值右侧实际上就是一个展开式,那么我们同样可以用*把数组展开在右侧
  1. a=1,2,3,4,5,6
  2. b,*c,d = *a
复制代码
这与
  1. b,*c,d = 1,2,3,4,5,6
复制代码
并无区别
右侧的展开式,自然是可以有多个
  1. a,b=[1,2,3,4,5],[7,8,9]
  2. *m = *a,6,*b
复制代码
5.括号限定范围
当等号右侧有数组时,我们可以使用括号将其拆开
  1. a = [1,2]
  2. (b,c),d = a,a
复制代码
效果怎样呢?当然是b,c分别获得了1,2,而d独享了a整个数组,如果不加这个括号,那么bc会分别获得数组a,而d只能是nil
对于括号内,相当于是子赋值,我们可以用递归的方式去理解,括号内的赋值:
  1. a = [[[1]],[2,3],[4,5,[6]]]
  2. (((b,c),*d),*e),f = a
复制代码
噢,这可真是复dan杂teng,我们一层一层的拆
这是多对一,a先被展开
  1. (((b,c),*d),*e),f = [[1]],[2,3],[4,5,[6]]
复制代码
f拿到了[2,3],心满意足的离去了,前面的括号得到了[[1]],后面的数组被舍弃了
由于多次多对一,数组外围不断被拆开
  1. ((b,c),*d),*e= 1
复制代码
好的,*e什么也没拿,变成空数组走了
  1. (b,c),*d= 1
复制代码
*d也只好离去了
  1. b,c= 1
复制代码
c默默的走了,只有b最后拿到了1
怎么样?理解了并行赋值的真谛了么?
实际上,对于yield,也就是块参数,同样满足以上规则,仅稍有出入:对于多对一可以,一对多就不行了——丢弃后面的多余参数
[/fold]

评分

参与人数 1梦石 +1 收起 理由
taroxd + 1 认可答案

查看全部评分

我要填坑!我要背单词!我要学日语!我要每天锻炼!
好吧呵呵= =
回复

使用道具 举报

梦石
0
星屑
122
在线时间
552 小时
注册时间
2012-8-18
回帖
1392
发表于 2014-7-15 15:05:06 | 显示全部楼层
本帖最后由 无脑之人 于 2014-7-15 16:03 编辑

public、protected、private方法是什么?它们有什么意义?
说真的,以下内容不看也罢
[fold=访问控制(Access Control)]
在OOP中,我们对类的设计需要考虑封装性,也就是类的访问控制。访问控制处理不当,往往导致数据泄露或者不当的操作。
首先我们要了解这样一个事实——在对象的外面无法直接取得对象的实例变量
【可能有人会说attr啊,或者元编程啊——他们也是方法,不是么?
因此我们的第一个访问控制就是基于这一限制——我们可以通过定义方法来允许自己希望被访问的实例变量被访问【元编程泥垢了】
那么偶尔我们可能会定义几个函数一样的方法,来帮助我们进行数据处理——我们并不希望它被外界调用
这个时候,就需要第二道访问控制——private
[pre lang="ruby" line="1"]class A
  def out_use
    #应该对外使用的
  end
  def in_use
    #不应对外使用的
  end
end[/pre]
这个时候这两个方法都是public,即允许外部调用
我们通过private方法,将其变为禁止外界访问的方法:
[pre lang="ruby" line="1"]class A
  def out_use
    #应该对外使用的
  end
  def in_use
    #不应对外使用的
  end
  private :in_use
end[/pre]
这个时候,A的实例调用in_use方法时便会无情的爆出NoMethodError,便好像自始至终就没有这样一个方法一样
然而,有时我们希望为A的功能进行扩充,又保留原来的类A
那么我们往往选择继承A,然而如果我们希望调用那个不对外使用的方法——很抱歉,它“不存在”:
[pre lang="ruby" line="1"]class B < A
  def derive_use
    self.in_use #NoMethodError
  end
end[/pre]
这个时候,我们可以将其定义为protected方法,这样既保留了对外禁止访问,又允许了派生类对其的访问
[pre lang="ruby" line="1"]class A
  protected :in_use
end
class B < A
  def derive_use
    self.in_use #√
  end
end[/pre]

当然,对于ruby来说,这样的功能简直毫无意义——他们在反射(reflection)甚至重定义的面前毫无还手之力,不过希望读者学会如何封装自己的类,使自己的类更加安全有效
[/fold]
[mode=yinzhan]对于Ruby来说,这个东西毫无意义[/mode]

评分

参与人数 1梦石 +1 收起 理由
taroxd + 1 不重要,但有意义

查看全部评分

我要填坑!我要背单词!我要学日语!我要每天锻炼!
好吧呵呵= =
回复

使用道具 举报

梦石
0
星屑
122
在线时间
552 小时
注册时间
2012-8-18
回帖
1392
发表于 2014-7-18 00:01:44 | 显示全部楼层
因为没东西写于是来这里扯扯淡

[fold=如何做一个能赚(bei)V(pen)的系统]
最近没什么教程可pian以jing写yan了,所以出一份用来赚bei钱biao的教程【噗
实际上就是教大家如何写一个很厉sha害bi的系统【23333
首先先说一下,层主多年没动过RM,默认脚本都忘光光了,所以这篇教程里面的系统只提供接口,将这个接口连入默认脚本就要求读者自己实现啦;另外数据的输入什么的请自己寻找方法咯,同样只是提供基本结构,请根据实际情况进行调整


以超级无敌噼里啪啦英俊潇洒风流倜傥万花丛中过片叶不沾身的神奇装备系统为例


第一步,将其分为两个部分——UI和逻辑
UI比较恶心我们一会儿再说,先说逻辑
我们假设我们要做像暗黑2一样的装备系统,也就是说有以下几点:
1.装备有品质,不同的品质有不同的特性
2.装备有基本的属性增幅,有等级限制职业限制属性限制,有孔
3.相同的基础装备产生不同的装备实例,效果和属性增幅都是在范围内随机的
4.能够镶嵌宝石和符文,并产生特殊的效果
这样我们需要做一个进行装备管理的类(EquipManager),一个基础装备类(BaseEquip),一个实际装备类(GameEquip),一个宝石类(Jewel),一个符文类(Rune),并从BaseEquip派生出具体的装备类(Helmet,Armor,Ring,Shoes等等),然后用GameEquip封装一个装备类实例
这是将整个类结构都分离出来,这个时候我们需要做的就是像苦力一样一个一个写好
当然在实际的编写过程中,我们将写出更多的辅助类
[pre lang="ruby" line="1"]class PicData #储存图像信息的辅助类
        def initialize(bmp = nil, rect = nil)
                @bmp = bmp
                @rect = rect
        end
        attr_accessor :bmp, :rect
end
#我们以这样的一个类储存了一个icon的图像信息

class ImageData #储存图像信息的辅助类
        def initialize(bmp = nil)
                @bmp = bmp
        end
        attr_accessor :bmp
        def rect ; nil ; end #我为什么要加这个方法呢?
end
#我们以这样的一个类储存了一个image的图像信息
#因此我们能看出类的一个作用——我们用它按照一定的结构储存信息

class Sprite
        def replace_data(data)
                self.bitmap.dispose if self.bitmap #使用RPG::Cache时需注意
                self.bitmap = data.bmp ? Bitmap.new(data.bmp) : nil #或使用RPG::Cache之类
                self.src_rect = self.bitmap ? data.rect || self.bitmap.rect : Rect.new(0,0,0,0)
                #Sprite在调用这个方法时,并没有检查对象的类型,也就是说,只要能提供一个代表图片地址的字符串(bmp方法)和一个矩形(rect方法)的对象,都能用在这个方法上
                #这个设计风格叫做“鸭子类型”(duck-typing),在这里,我们既可以使用PicData对象,又可以使用ImageData对象,这就是duck-typing给我们带来的益处
                #也是我为ImageData添加rect方法的原因
                #可能有人会说我完全可以把ImageData整合进PicData,你是对的,它在这里仅仅是举例,但是我们要理解这种只看接口不看类型的设计风格
        end
end

class BaseEffect #储存基本效果的辅助类
        def initialize(*args)
                @hp,@mp,@patk,@matk,@pdef,@mdef = *args #以及其他属性,这里使用了【并行赋值】
                instance_variables.each do |sym| #这里使用了元编程,是使输入更加方便,允许nil代替0
                        instance_variable_set(sym,0) if !instance_variable_get(sym)
                end
        end
        attr_accessor :hp,:mp,:patk,:matk,:pdef,:mdef #...
        def affect(actor)
                actor.hp += @hp
                actor.mp += @mp
                #......
                #这里提供了一个便捷的属性修改方式,当然在Actor类对此进行处理也是可以的
        end
        def self.rand_set(min, max)
                rand(max - min + 1) + min
        end
        def self.randomize(min, max) #通过给定区间提供一个随机化的数据
                cache = []
                min.instance_variables.each do |sym|
                        cache << rand_set(min.instance_variable_get(sym),max.instance_variable_get(sym))
                end
                BaseEffect.new(*cache)
        end
end
#这个类在这里也是用于储存信息,我甚至只需要一个数组就可以代替它,但我却使用了一个类,这是为什么?
#一方面是使输入更加方便,使各种运算更加便捷
#另一方面则是为了让它看起来像一个“效果”,而不是一些数字,这样不仅提高了可读性,还便于功能的拓展和修改——为了增加一个属性满世界改数组去?哦天哪

class SpecEffect #储存特殊效果的辅助类
        def initialize(id, *values)
                @id = id
                @values = values
        end
        attr_reader :id, :values
end
#这个类我写的很浅,因为它的功能与接口我还不确定,但是这样写,功能的拓展很方便

module EffectManager #对于装备的属性进行实现——这是一个接口,将用来与具体游戏连接
        module_function
        def affect(actor, object)
                case object
                when BaseEffect
                        object.affect(actor)
                when SpecEffect
                        special(actor, object.id, *object.values)
                end
        end
        def special(actor, id, *values)
                #... 具体实现
        end
end
#这是一个模块,我特意在模块名上加了一个“Manager”,这说明这个模块是用来管理的
#事实上它的功能就是具现化所有效果,基础属性委托给了BaseEffect自己,而各种特殊属性就在这里发挥作用或者添加标记
#还是,我不清楚他的实现,于是我仅仅写了一个接口,他将对外连接上Actor,Battle等等
#不过对于复杂的效果来说,我们可以选择把效果设计成一个类,甚至是多个类——只要他具有相同的接口

class BaseEquip
        MAP = {}
        @@ids = 0
        def initialize
                @id = @@ids
                @@ids += 1
                MAP[id] = self #这里被存入的,是派生类对象而非基类对象哦~事实上也没有基类对象出现
                @name = ""
                @icon = PicData.new
                @image = ImageData.new
                @description = ""
                @note = ""
                @price = 0
                @base_effect_min = BaseEffect.new
                @base_effect_max = BaseEffect.new
        end
        attr_reader :id, :name, :icon, :description, :note, :price, ;image
        def randomize
                BaseEffect::randomize(@base_effect_min, @base_effect_max)
        end
end
#这是基础装备的基类,他几乎表现了一个装备的所有基础内容,不过我们仍然可以很方便的拓展它
#我们可以不断生成他的派生类的实例来添加装备

class HoleHelper #对于装备的孔洞的辅助类
        def initialize(init = 0)
                @num = init
                @items = Array.new
        end
        attr_accessor :num
        attr_reader :items
        def full?
                @items.size == @num
        end
        def add(item)
                @items << item
        end
        def clear
                @items = Array.new
        end
end
#为什么镶嵌孔我也要写一个类?说实话最开始我本以为一个数字就可以代表镶嵌孔,但是后来发现我太肤浅了
#每个镶嵌孔是否安装宝石,是否满了,如何清空——这些问题如果我现在忽视了,可能以后的设计就会打脸打得啪啪响
#但是它不是模拟了孔,而是作为孔的一个管理者,我在这里表示为Helper,这个Helper要每个装备一个而不是像EffectManager一样只需要一个进行处理
#我也可以选择为孔单独成类——但我觉得那样过于麻烦,如果有必要可以尝试

class GameEquip
        @@ids = 0
        def initialize(id)
                @base = BaseEquip::MAP[id]
                @id = @@ids
                @@ids += 1
                @base_effect = @base.randomize
                @spec_effect = Array.new
                @Quality = :normal
                @holes = HoleHelper.new
        end
        attr_reader :id, :quality, :holes, :base_effect
        [:icon, :image, :description, :note].each do |sym| #这里采用元编程的方式将三个方法委托给了Base
                define_method(sym) do
                        @name.__send__(sym)
                end
        end
        def name
                EquipManager.make_name(self)
        end
        def price
                EquipManager.price_assess(self)
        end
        def affect(actor)
                EffectManager.affect(actor, @base_effect)
                @spec_effect.each do |effect|
                        EffectManager.affect(actor, effect)
                end
        end
end
#虽然从接口上来看用is-a更加方便一些,但是逻辑上他们是has-a的,也就是说,具体的装备类对基础的装备类选择包含,比继承更加符合语义一些,也更加安全一些
#这个具体装备类甚至不清楚基础类的类型——不知道自己是个绿帽子还是个绿帽子,但那不是他需要了解的,他只需要借助Manager,处理好他的效果
#当然还有他的名字和价钱233333

class Jewel
        def initialize(effect)
                @effect = effect
        end
        attr_reader :effect
end

class Rune
        def initialize(name, effect)
                @name = name
                @effect = effect
        end
        attr_reader :name,:effect
end
#宝石和符文短的简直令人难以置信,我甚至不知道effect是什么对象——等到我需要操心的时候再去操心好了

class Helmet < BaseEquip
        def initialize
                #... 实现
        end
        #其他方法...
end
#其他装备...
#这个就是你要具体写出帽子是怎样的嗯嗯,并借助它生成绿帽子的实例什么的

module EquipManager
        module_function
        def make_name(equip)
                #生成名字的接口
        end
        def price_assess(equip)
                #估价的接口
        end
        def create(type, quality)
                #生成随机装备的算法...
        end
end
#到这里基本上就是完全是接口了,这是管理所有装备的创建,名字,价格,掉落率等等等等对象的地方
#他需要按照具体的游戏内容进行设定,并连接在其他的系统上
[/pre]
请阅读上面的代码并理解其中的设计风格

紧接着是UI

虽然很想写UI部分的,但是我发现我没有VA……2333333
不过我想既然6R里面各种菜单啊什么的教程这么多,UI部分不写也可以的吧,反正我也不是很懂
不过我想要讲的其实也就是我们可以把无论是Window,还是Sprite,都封装成组件类,采用统一的图形刷新接口,并专门提供一个处理逻辑的方法

好了本节完.

[/fold]

以后恐怕真的没有淡可以扯了

评分

参与人数 1梦石 +1 收起 理由
taroxd + 1 认可答案

查看全部评分

我要填坑!我要背单词!我要学日语!我要每天锻炼!
好吧呵呵= =
回复

使用道具 举报

…あたしは天

梦石
0
星屑
2308
在线时间
4033 小时
注册时间
2010-10-4
回帖
10548

开拓者贵宾

 楼主| 发表于 2014-7-18 14:43:26 | 显示全部楼层
本帖最后由 taroxd 于 2014-7-18 14:45 编辑

[fold=区块中关键字的使用]

很多人会把区块理解为单纯的循环。next 就是进行下一次循环,break 就是跳出循环。
这种理解是非常自然的。按照这种理解,我们可以尝试解读一些默认脚本中的代码。

[pre lang="ruby" line="1"]
class Game_Troop < Game_Unit
  #--------------------------------------------------------------------------
  # ● 同名的敌人附加字母后缀
  #--------------------------------------------------------------------------
  def make_unique_names
    members.each do |enemy|            # 对敌群中的每个敌人 enemy 进行迭代
      next unless enemy.alive?         # 如果 enemy 已死,则跳过。后面的内容只有当 enemy 存活时才会执行
      next unless enemy.letter.empty?  # 如果名字后已经附加字母,则跳过。后面的内容只有当名字后面没有字母时才会执行。
      # 总之是给这个 enemy 加上字母后缀...
      n = @names_count[enemy.original_name] || 0
      enemy.letter = LETTER_TABLE[n % LETTER_TABLE.size]
      @names_count[enemy.original_name] = n + 1
    end
    # 设置复数出现的标志
    members.each do |enemy|
      n = @names_count[enemy.original_name] || 0
      enemy.plural = true if n >= 2
    end
  end
end
[/pre]

但是,next 在区块中出现的意义并不止于此。
next 在区块中,表示从区块中返回,返回值为 next 的参数。
如果把区块比作方法,那么 next 就相当于 return。

[pre lang="ruby" line="1"]

arr = (1..10).map do |n|
  next 2 if n % 2 == 0
  next 3 if n % 3 == 0
  next 5 if n % 5 == 0
  next 7 if n % 7 == 0
  1
end

p arr #=> [1, 2, 3, 2, 5, 2, 7, 2, 3, 2]
[/pre]

这是一个无聊的判断最小素因数的程序(不要在意 1,不要在意为什么用这么烂的方式去算)。
总之,在 map 这种需要用到区块返回值的时候,next 后面跟参数的意义才显示出来。

再想一想,如果我们来定义 each,大概会是这样吧。
[pre lang="ruby" line="1"]
class Array
  def each
    i = 0
    while i < size
      yield self
      i += 1
    end
    self  # 惯例,each 迭代器通常返回 self
  end
end
[/pre]

就以这个实现方式为例,我们再来看一看 next 在区块中的作用。

[pre lang="ruby" line="1"]
[1, 2, 3].each do |n|
  # p n if n.odd? 就可以,这里刻意使用了 next
  next if n.even?
  p n
end

# 输出 1 3
[/pre]

代回到 each 方法的定义,我们来看一看流程。

  1. i = 0
  2. i < 3 成立
  3.   yield 1 # 没有触发 next,输出 1
  4.   i = 1
  5. i < 3 成立
  6.   yield 2 # 触发了 next,p 2 没有执行就从区块返回了
  7.   i = 2
  8. i < 3 成立
  9.   yield 3 # 没有触发 next,输出 3
  10.   i = 3
  11. i < 3 不成立,跳出循环
  12. each 方法结束,返回 self
复制代码
因此,在一般情况下,把 next 解释为跳过这一次循环,是没有问题的。
但是把 next 理解为从区块中返回的话,才能对 next 更加运用自如。

break 则是从调用 block 的方法中返回,方法的返回值即为 break 的参数。
这个基本上简单的理解为终止循环就可以了,并不是很常用。

return 的用处,则是直接从当前的环境中返回。
比如,如果我们要找出队伍中那个名字叫做艾里克的角色。我们可以这样找。

[pre lang="ruby" line="1"]
def find_eric
  # 事实上,find 方法可以更好地完成这项任务。我们会在之后的数组中讲到。
  $game_party.members.each {|actor| return actor if actor.name == '艾里克' }
  nil  # 如果没有找到,返回 nil
end
[/pre]

也许你在没有看这一章之前,你也会写出这样的代码。
这就是 return 关键字的自然之处。你顺其自然地,就写出了这样的代码。

我们注意到,当 actor.name == '艾里克' 的条件满足时,调用了一次 return。
这一次 return 是直接从 find_eric 方法中返回了。

但是,return 有的时候并不是那么的好用。
我们讲过了方法的 block 参数,我们在这里使用一次。

[pre lang="ruby" line="1"]
def call_block(&block)
  block.call
end

result = call_block { return 1 } # unexpected return (LocalJumpError)
[/pre]

回忆一下,我们刚才讲过,return 是从当前环境中返回。
我们看到,这个 return 的位置是顶层。在顶层你 return 给谁呀 Σ( ° △ °|||)︴

还记得我们刚才说的吗? 是的,这种情况下我们就要用 next。

---------------------------------------------------------------------

根据上面的一些介绍,我们可以概括出:区块适合用于循环之类的流程控制。
但是,区块既然那么像方法,我们可不可以让它更像一些方法呢?
比如,传入参数时,检查参数的个数。
比如,return 的时候就从区块中返回,就像刚才的 next 一样。

可以!我们可以有两种方法来生成这样的 Proc 对象。我们通常把这样的对象叫做 lambda。
[pre lang="ruby" line="1"]
identity = lambda {|n| return n } # 一个永远返回自身的 lambda
# 或者
identity = ->(n) { return n } # -> 和 () 之间不要有空格

result = call_block(&identity) # wrong number of arguments (0 for 1) (ArgumentError)
[/pre]

哦对了,刚刚说了会检查参数。总之这样就更加像是一个方法了。

最后用一个例子作为尾声吧。

[pre lang="ruby" line="1"]

least_prime_factor_less_than_10 = lambda do |n|
  return 2 if n % 2 == 0
  return 3 if n % 3 == 0
  return 5 if n % 5 == 0
  return 7 if n % 7 == 0
  nil
end

no_prime_factor_less_than_10 =
  ->(n) { !least_prime_factor_less_than_10.call(n) }

p (2..10).map(&least_prime_factor_less_than_10) #=> [2, 3, 2, 5, 2, 7, 2, 3, 2]
p (11..20).select(&no_prime_factor_less_than_10) #=> [11, 13, 17, 19]
[/pre]

[/fold]

点评

λ演算滚粗-。-  发表于 2014-7-19 08:23
果然是因为抄的不全结果导致和λ演算关系不大了么= =|||那些规约和变换对这个貌似没有什么作用呢  发表于 2014-7-18 21:45

评分

参与人数 1梦石 +1 收起 理由
VIPArcher + 1 认可答案

查看全部评分

回复

使用道具 举报

…あたしは天

梦石
0
星屑
2308
在线时间
4033 小时
注册时间
2010-10-4
回帖
10548

开拓者贵宾

 楼主| 发表于 2014-7-21 14:17:51 | 显示全部楼层
本帖最后由 taroxd 于 2014-7-22 12:10 编辑

[fold=甜美的为啥我写的代码就是没法正常干活!]
  1. syntax error, unexpected end-of-input, expecting keyword_end
复制代码
看看你哪里少打了个 end
-----------------------------------------------
  1. syntax error, unexpected keyword_end, expecting end-of-input
复制代码
看看你哪里多打了个 end
----------------------------------------------
  1. syntax error, unexpected tIDENTIFIER, expecting '}'
复制代码
哈希或者数组哪儿少打了逗号吧。尤其是跨行的哈希和跨行的二维数组。

  1. undefined method `xxxxx' for nil:NilClass
复制代码
检查方法的接收者是否为 nil。
通常来说,接收者为 nil 有可能有这些原因:
  实例变量未初始化
  数组越界

另外,如果这条报错消息的结尾并不是 nil:NilClass,而且是正确的类名的话,一般来说是你方法名拼写错误了。
或者……这个方法真没定义……
----------------------------------------------
  1. no implicit conversion of String into Integer
  2. String can't be coerced into Fixnum
复制代码
你从哪儿的字符串读取了一个整数,然后忘了 to_i 就直接用了吧
----------------------------------------------
  1. divided by 0
复制代码
哪里用0作为除数了。尤其注意处理 Selectable 窗口选择项为 0 的情况。
----------------------------------------------
  1. 我想改角色的 hp,可是没有效果!
复制代码
比如要让 hp 变为 100,仅仅 hp = 100 是没有效果的。这只是将 100 赋值给了局部变量 hp。
你可以 @hp = 100,但并不推荐这样做,除非你知道你在做什么。
推荐的做法是 self.hp = 100,利用定义好的方法来完成赋值。
----------------------------------------------
  1. 我得不到我想要的计算结果!
复制代码
注意运算符的优先级。

[/fold]

评分

参与人数 2星屑 +1 梦石 +1 收起 理由
VIPArcher + 1 (ΦωΦ)
kuerlulu + 1 认可答案

查看全部评分

回复

使用道具 举报

菜鸟飞呀飞 该用户已被删除
发表于 2014-7-22 03:27:39 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

菜鸟飞呀飞 该用户已被删除
发表于 2014-7-22 06:50:22 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

百合控

梦石
0
星屑
6548
在线时间
1275 小时
注册时间
2013-8-21
回帖
3522

开拓者

发表于 2014-7-27 19:47:20 | 显示全部楼层
本帖最后由 余烬之中 于 2014-7-27 19:49 编辑

Stage Clear!

[fold=如何让编号为某一个变量的人暂时成为队列第一人?]
[pre lang="ruby" line="1"]
# 如何让编号为某一个变量的人暂时成为队列第一人?

# 首先 我们什么也不需要想 就可以新建一个模块 把变量ID定义为一个常量
# 以此作为用户设置的地方
#==============================================================================
# ** BH
#==============================================================================
module BH
  BianHaoID = 3
  # 变量ID
end

# 然后 我们需要检测变量的变化 并切换队长
# 我们知道 可以通过$game_variables来访问变量 而它是Game_Variables的一个实例
# 在Game_Variables中 可以找到:
#     def on_change
#       $game_map.need_refresh = true
#     end
# 也就是说 只要变量发生了改变 $game_map.need_refresh就会变为true
# 从字面上来看 就是“地图需要刷新”
# 我们只需要监听$game_map.need_refresh就可以了 至于它什么时候变回false……
# …………既然原装脚本就这么用了 我们就不用管了
# …………
# ……………………
# ………………………………
# 好吧 在这里 Game_Map的定义(也就是$game_map内部)
#     def refresh
#       @events.each_value {|event| event.refresh }
#       @common_events.each {|event| event.refresh }
#       refresh_tile_events
#       @need_refresh = false
#     end


# “监听谁”这个问题已经解决了 现在是……
# “谁来监听”
# 当然是让“被操作者”来监听啦 也就是我们的队长所在的地方:
# Game_Party($game_party)
# 让我们打开Game_Party…………
# ……………………
# 怎么会!它只有操纵队伍的方法 却不负责监听
# 让谁来监听呢?Scene?
# 麻烦死了 就让Game_Variables自己来吧(怎么又绕回来了……)

#==============================================================================
# ** Game_Variables
#==============================================================================
class Game_Variables
  # on_change就是我们要插入的地方
  # 当游戏变量被更改 on_change就会被调用
  alias :rang_bian_hao_wei_mou_bian_liang_zhe_zuo_dui_zhang_oc :on_change
  # 先起个别名 避免别人也改了这个方法 而我们抹去了人家的劳动成果
  def on_change
    rang_bian_hao_wei_mou_bian_liang_zhe_zuo_dui_zhang_oc
    # 先调用原方法
    # 然后……
    $game_party.让他当队长
  end
end
#==============================================================================
# ** Game_Party
#==============================================================================
class Game_Party
  # 哇咔咔
  def 让他当队长
    该当队长的人 = $game_variables[BH::BianHaoID] # 获取编号
    队员们 = @actors # 获取队列
    return unless 队员们.include?(该当队长的人)
    # 如果队伍里根本没这个人 我们就可以回家洗洗睡了
    return if 队员们[0] == 该当队长的人
    # 如果他本就是队长 我们也不需要做什么
    队员们.delete(该当队长的人)
    # 否则 就把他踢出队伍
    队员们.unshift(该当队长的人)
    # 再王者归来
    $game_player.refresh
    # 这句是复制Game_Party里面swap_order的
    # 该通知的还是要通知一下 这样才有利于同志们传达精神
    # 其实swap_order(一个人, 另一个人)可以把这两个人的位置调换
    # swap_order(0, 队员们.index(该当队长的人))
    # 但是原来的队长就会在现队长原来的地方 不过这也无关紧要了
  end
end

# 绕了一个弯路我们还是回来了
# 思维中常常出现这样那样的岔子 关键是要能绕得回来
# 现在我们想到了一个问题:
#   在我们把这个人改成了队长后 如果玩家进行了整队 把队长和别人调换…………
# 一定要阻止他!

# 整队在Scene_Menu里面负责 如果你挂载了专用整队脚本那就没用了…………
#==============================================================================
# ** Scene_Menu
#==============================================================================
class Scene_Menu
  # 整队中 按下确定键的处理
  alias :rang_bian_hao_wei_mou_bian_liang_zhe_zuo_dui_zhang_ofo :on_formation_ok
  # 先起别名
  def on_formation_ok
    if $game_variables[BH::BianHaoID] != 0 &&
    (@status_window.index == 0 || @status_window.pending_index == 0)
      # 如果当前是临时队长在位 并且调换的两个人中 有任意一个是队长
      # 就阻止他!
      Sound.play_buzzer # 顺便警告一下
      @status_window.activate
    else
      # 除此之外
      rang_bian_hao_wei_mou_bian_liang_zhe_zuo_dui_zhang_ofo
      # 就丢给原方法去管
    end
  end
end

# 但是这里又有一个小问题
# 假设一开始的队伍是
#  A B C D E F G
# 然后F临时当队长
#  F A B C D E G
# 然后C来当队长
#  C F A B D E G
# 这就不算是临时了 因为F还在A的前面
# 我们需要保存正常的队列状况
# 把上面的全部删掉 我们重来
# 算了……太麻烦了……
# 我们需要:
#   记忆原队列顺序 记忆原队长现在的位置
#   确保队伍正常变动时 我们的记忆也跟着变
#   万一原队长被踢出了退伍 我们还是要能了解他应该在哪里
#   等等等等
# 这就不是一个小问题了 所以我们(明明只有你一个人!)很不负责任的放弃了它
# 当然 如果不考虑这些问题 只考虑:
#   如果A是临时队长 B是原队长 C是另一人
#    1.当变量值为0时……
#     1.B不在队伍 则A继续当队长 且成为真正队长(而非临时)
#     2.B在队伍 则B与A调换位置
#    2.C被指定为临时队长
#     1.B不在队伍 则让A与C调换位置
#     2.B在队伍 则让A与B调换位置 然后B与C调换位置
#    总结:在变量改变的情况下
#     只要B在队伍 就一定要让A与B调换(原队长复辟)
#     然后如果变量为0 则什么都不需要再做
#         如果不为零 就把B和C调换(登基)
#   这样我们就只需要记忆原队长
#   下面是我的全部实现 不做说明了 有兴趣自己看也能看懂
# __END__ 以下的内容是不会被执行的 只有观赏意义

__END__
# 这段脚本的效果与上一段还是有很大不同的
# 虽然前期很像
#==============================================================================
# ** TemporaryCaptain
#==============================================================================
module TemporaryCaptain
  Var = 3
end
#==============================================================================
# ** Game_Variables
#==============================================================================
class Game_Variables
  alias :let_he_be_the_leader_2014_07_27_on_change :on_change
  def on_change
    let_he_be_the_leader_2014_07_27_on_change
    $game_party.let_he_be_the_leader
  end
end
#==============================================================================
# ** Game_Party
#==============================================================================
class Game_Party
  def let_he_be_the_leader
    swap_order(0, @actors.index(@last_captain_id_let_he_be_the_leader)) if
    @actors.include?(@last_captain_id_let_he_be_the_leader ||= @actors[0])
    if $game_variables[TemporaryCaptain::Var] == 0
      @last_captain_id_let_he_be_the_leader = @actors[0]
    else
      swap_order(0, @actors.index($game_variables[TemporaryCaptain::Var]))
    end
  end
end
#==============================================================================
# ** Scene_Menu
#==============================================================================
class Scene_Menu
  alias :let_he_be_the_leader_2014_07_27_on_formation_ok :on_formation_ok
  def on_formation_ok
    if $game_variables[TemporaryCaptain::Var] != 0 &&
    (@status_window.index == 0 || @status_window.pending_index == 0)
      Sound.play_buzzer
      @status_window.activate
    else
      let_he_be_the_leader_2014_07_27_on_formation_ok
    end
  end
end[/pre]
[/fold]

[fold=有没有办法让敌人hp越少越容易进入异常状态?]
[pre lang="ruby" line="1"]
# 有没有办法让敌人hp越少越容易进入异常状态?

# 没有

# ……
# …………
# …………………………

# 好吧 让我们想想 毕竟我对战斗这块不太熟
# 状态的添加和转移应该是由某个发送者(技能使用方)发出指令
#  然后由承受者(目标)响应
# 也就是 A攻击B 则 【A说: B.响应技能(我的技能)】
#  然后在B的内部【def 响应技能(某技能) ... end】
# 我们不用关心A是怎么让B开始响应的 只需要关注B对这个东西的响应和处理

# 既然涉及到战斗 自然要在战斗的基本单位:战斗者中来找
# Game_BattlerBase我已经找过了 "战斗者基础"定义了一些基础的东西 但是没有定义响应
# Game_Battler"战斗者"中倒是有我们需要的

# 但是 我们首先还是建立一个模块 进行一下相关设置
module HP2StateRate
  States = [3, 4, 5, 6, 7, 30]
  # 我们的这个规则需要对哪些状态生效? 在这里填写状态ID
  # 作为实验 先随便填几个
end

# 现在打开Game_Battler
#==============================================================================
# ** Game_Battler
#==============================================================================
class Game_Battler
  # 响应攻击的方法是item_apply 它会计算攻击的伤害值然后扣血 最后加上附加状态
  # 加上附加效果是通过item_effect_apply实现的 它有三个参数:使用者 物品 效果
  # 各种状态的附加是存在于效果中的 根据各种具体的效果 它会呼叫具体的方法
  # 我们只需要关注item_effect_add_state 至于buff我们就不管了
  #  其实知道了原理想改也很容易
  #   而且你还可以让他的异常状态更难消除 通过修改item_effect_remove_state
  
  # 打开item_effect_add_state 我们发现它会根据条件调用另外两个分支
  #  而它本身并不判断概率
  # 不需要管两个分支是什么意思了 打开吧
  # 首先是item_effect_add_state_attack
  # 默认是这样的
    # def item_effect_add_state_attack(user, item, effect)
    #   user.atk_states.each do |state_id|
    #     chance = effect.value1
    #     chance *= state_rate(state_id)
    #     chance *= user.atk_states_rate(state_id)
    #     chance *= luk_effect_rate(user)
    #     if rand < chance
    #       add_state(state_id)
    #       @result.success = true
    #     end
    #   end
    # end
  # 显然chance就是成功率
  # 我们想不出来什么方法可以*简单*明了*不再绕圈子*高度兼容*的办法来修改chance
  # 所以我们就用一种*简单*明了*不再绕圈子*但是兼容性一般般*的办法
  # 中间插一段 前后照抄
  def item_effect_add_state_attack(user, item, effect)
    user.atk_states.each do |state_id|
      chance = effect.value1
      chance *= state_rate(state_id)
      chance *= user.atk_states_rate(state_id)
      chance *= luk_effect_rate(user)
      
      if HP2StateRate::States.include?(state_id)  # 这是需要生效的状态
        chance *= 2 - hp_rate
        # 计算公式是 1 + 损失的HP比例, 也就是 1 + 1 - 剩余的HP比例
        # 这样 损失的血越多 概率越高 最高接近原概率的两倍
        # 因为这是个简易版本 所以公式就让我们来设置吧 玩家不需要了解
      end
      
      if rand < chance
        add_state(state_id)
        @result.success = true
      end
    end
  end
  # 好 现在是item_effect_add_state_normal 我们如法炮制
  def item_effect_add_state_normal(user, item, effect)
    chance = effect.value1
    chance *= state_rate(effect.data_id) if opposite?(user)
    chance *= luk_effect_rate(user)      if opposite?(user)
   
    if HP2StateRate::States.include?(effect.data_id) # 注意这里不是state_id
                                                   # 因为state_id不存在了
      chance *= 2 - hp_rate
    end
   
    if rand < chance
      add_state(effect.data_id)
      @result.success = true
    end
  end
end
# 成功了 可以打开战斗测试试一下 完美

# 写的专业点 装逼点 可以是这样:

__END__

#==============================================================================
# ** HP2StateRate
#==============================================================================
module HP2StateRate
  States = [3, 4, 5, 6, 7, 30]
end
#==============================================================================
# ** Game_Battler
#==============================================================================
class Game_Battler
  def item_effect_add_state_attack(user, item, effect)
    user.atk_states.each do |state_id|
      chance = effect.value1
      chance *= state_rate(state_id)
      chance *= user.atk_states_rate(state_id)
      chance *= luk_effect_rate(user)
      chance *= 2 - hp_rate if HP2StateRate::States.include?(state_id)
      if rand < chance
        add_state(state_id)
        @result.success = true
      end
    end
  end
  def item_effect_add_state_normal(user, item, effect)
    chance = effect.value1
    chance *= state_rate(effect.data_id) if opposite?(user)
    chance *= luk_effect_rate(user)      if opposite?(user)
    chance *= 2 - hp_rate if HP2StateRate::States.include?(effect.data_id)
    if rand < chance
      add_state(effect.data_id)
      @result.success = true
    end
  end
end[/pre]
[/fold]

[fold=如何显示一个显示指定文字的窗口?要求文字能够在游戏中修改。]
[pre lang="ruby" line="1"]
# 如何显示一个显示指定文字的窗口?要求文字能够在游戏中修改。

# 这个问题有点诡异啊:到底是在哪里显示呢?菜单?标题?存档界面?GameOver?……
# (再唧唧歪歪就把你送给楼主做女仆)
# 咳咳,我们假设这是要显示在地图上的 很显然 我们至少需要了解:
#  位置(x, y)
#  文本(text)
# 鉴于默认窗口太丑,我们需要一个作为补充的图片背景功能:
#  背景(background)
# 允许设定的项 除了文本外 还有窗口的不透明度(opacity)
# 窗口的大小就自适应文字吧 有背景图的话就固定为背景图的大小

# 我们的设想中 可以通过事件脚本来更改某窗口的文字
# 还可以新建窗口 用两个窗口来显示文字 甚至三个四个好多个

# 因为各项参数都用事件脚本 所以我们不需要用模块进行设置了好可惜

# 一般而言 事件脚本调用的环境是Game_Interpreter内部 不要问我环境是什么
# 反正保护环境 人人有责(我在说什么)
#==============================================================================
# ** Game_Interpreter
#==============================================================================
class Game_Interpreter
  def 新增文本窗口(文本, 横坐标 = 0, 纵坐标 = 0, 背景图片 = "", 不透明度 = 255)
    # 各种默认值就在上面设置完成 不需要玩家如何如何地设置
    # 乖乖调用【新增文本窗口(...)】就可以了
    SceneManager.scene.新增文本窗口(文本, 横坐标, 纵坐标, 背景图片, 不透明度)
    # SceneManager.scene获取当前场景 一般是地图场景
    # 后面这个方法 我们还没有在地图场景里面实现
    # 但是不要紧了 反正后面会实现的
  end
  def 更改窗口文本(窗口编号, 文本 = "")
    # 我怎么知道窗口编号?
    # 很简单 新建窗口的时候生成一个编号 然后返回给【新增文本窗口】
    # 让用户截取这个编号并保存 那不关我们的事
    SceneManager.scene.更改窗口文本(窗口编号, 文本)
  end
  def 更改窗口位置(窗口编号, 横坐标 = 0, 纵坐标 = 0)
    SceneManager.scene.更改窗口位置(窗口编号, 横坐标, 纵坐标)
  end
  def 更改窗口背景图片(窗口编号, 背景图片 = "")
    SceneManager.scene.更改窗口背景图片(窗口编号, 背景图片)
  end
  def 更改窗口不透明度(窗口编号, 不透明度 = 255)
    SceneManager.scene.更改窗口不透明度(窗口编号, 不透明度)
  end
  def 获取窗口信息(窗口编号)
    # 应该返回一个数组:[文本, 背景图片, 不透明度]
    SceneManager.scene.获取窗口信息(窗口编号)
  end
  def 删除窗口(窗口编号)
    SceneManager.scene.删除窗口(窗口编号)
  end
  def 暂时关闭窗口(窗口编号)
    SceneManager.scene.暂时关闭窗口(窗口编号)
  end
  def 暂时打开窗口(窗口编号)
    SceneManager.scene.暂时打开窗口(窗口编号)
  end
end

# 但是我们的窗口连影子都没有
# 开工了伙计们
class Window_ShowTextOnMap < Window_Base # 果然还是继承Base吧
  def initialize(text, x, y, back, opa)
    @text, @back, @opa = text, back, opa
    if @back == ""
      super(x, y, *get_width_and_height) #不使用背景图片 自适应文字
      self.opacity = @opa
    else
      pic = Cache.picture(@back) # Cache.picture访问的是Graphics/Picture文件夹
      super(x, y, pic.width, pic.height) # 使用背景图片 根据图片来
      self.back_opacity = 0
      self.contents_opacity = @opa
    end
    # get_width_and_height是一个不存在的方法 我们将要实现它
    # 使它返回文本合适的宽与高(以数组的形式)
    # 前面加一个*号 目的是将数组展开 因为super呼叫父类方法 在这里要四个参数
    refresh
    # 描绘文字
  end
  
  # 获取合适的宽与高 允许使用控制符 比如\I[3] \n \V[6]
  # 原理: 新建一个临时窗口 画一遍 观测绘制的范围 就知道合适的宽与高了
  def get_width_and_height
    tmp = Window_Base.new(Graphics.width, 0, Graphics.width, 1)
    # 新建临时窗口
    tmp.reset_font_settings
    # 重置字体设置
    width = 0
    # 记录宽度
    pos = {x: 0, y: 0, height: tmp.calc_line_height(@text)}
    # 当前描绘的位置
    @text.each_line do |s| # 逐行描绘
      # s.gsub!(/[\n]/){""} # 去除尾部的换行符 理论上可以用chomp!代替
      s.chomp! # 我想我们还是用更拉风的chomp!吧
      tmp.process_character(s.slice!(0, 1), s, pos) until s.empty? # 逐字描绘
      width = [pos[:x], width].max # 获取单行的宽度 记录最大值
      pos[:x] = 0 # 换行
      pos[:y] += pos[:height] # 换行
      pos[:height] = tmp.calc_line_height s #确定合适高度
      # 循环描绘下一行
    end
    # 没有手动对tmp进行dispose 因为它在窗口外 看不到 而且tmp作用域要消失了
    #  很快就会被GC弄死 这里不需要理解
    [width + standard_padding * 2, pos[:y] + standard_padding * 2] # 返回宽高
  end
  
  # 进行实际的描绘
  def refresh
    contents.clear
    pic = Cache.picture(@back)
    contents.blt(0, 0, pic, Rect.new(0, 0, pic.width, pic.height))
    draw_text_ex(0, 0, @text)
  end
  
  # 改变文字
  def set_text(text)
    @text = text
    refresh
  end
  
  # 位置
  def set_pos(x, y)
    self.x, self.y = x, y
  end
  
  # 背景图片
  def set_back(back)
    return if @back == back
    @back = back
    if @back == ""
      self.move(self.x, self.y, *get_width_and_height)
      self.opacity = @opa
    else
      pic = Cache.picture(@back)
      self.move(self.x, self.y, pic.width, pic.height)
      self.back_opacity = 0
      self.contents_opacity = @opa
    end
    refresh
  end
  
  # 不透明度
  def set_opa(opa)
    @opa = opa
    if @back == ""
      self.opacity = @opa
    else
      self.contents_opacity = @opa
    end
  end
  
  # 获取信息
  def get_info
    [@text, @back, @opa]
  end
end

# 好无聊 累死了 不想写了 就这样吧
# ………………
# 为了不做楼主女仆 我还是继续吧

# 我们已经完成了一个【入口】 可以接受事件脚本信息 但是还没有人来处理
# 我们已经完成了一个【窗口】 可以在地图上显示文本 但是还没有人来管理
# 所有的事实都指向一个结果 真相只有一个!

class Scene_Map
  # 首先 在开始的时候地图场景会建立一系列窗口
  # 我们把我们的窗口混进去一起建立…………不需要一次性建好 放个名单就行
  # 在方法create_all_windows中
  alias :我要往你里面塞一点东西哦_create_all_windows君 :create_all_windows
  def create_all_windows
    我要往你里面塞一点东西哦_create_all_windows君
    我要塞的东西之一
  end
  
  def 我要塞的东西之一
    @显示文本的窗口们 = []
  end
  
  def 新增文本窗口(text, x, y, back, opa)
    @显示文本的窗口们.push(Window_ShowTextOnMap.new(text, x, y, back, opa))
    @显示文本的窗口们.size - 1 # 这就是返回的窗口编号啦
  end
  
  def 更改窗口文本(id, text)
    @显示文本的窗口们[id].set_text(text)
  end
  
  def 更改窗口位置(id, x, y)
    @显示文本的窗口们[id].set_pos(x, y)
  end
  
  def 更改窗口背景图片(id, back)
    @显示文本的窗口们[id].set_back(back)
  end
  
  def 更改窗口不透明度(id, opa = 255)
    @显示文本的窗口们[id].set_opa(opa)
  end
  
  def 获取窗口信息(id)
    @显示文本的窗口们[id].get_info
  end
  
  def 删除窗口(id)
    @显示文本的窗口们[id].dispose
  end
  
  def 暂时关闭窗口(id)
    @显示文本的窗口们[id].close if @显示文本的窗口们[id].open?
  end
  
  def 暂时打开窗口(id)
    @显示文本的窗口们[id].open if @显示文本的窗口们[id].close?
  end
  
  # 很好 虽然这种重复冗余令人难以置信 但是完成了不是吗?元编程去死吧!
  
  # 等等 我们是不是忘了什么?
  
  # 更新!update!释放!dispose!
  alias :我也要往你里面塞一点东西哦_update_all_windows君 :update_all_windows
  def update_all_windows
    我也要往你里面塞一点东西哦_update_all_windows君
    我要塞的东西之二
  end
  
  def 我要塞的东西之二
    @显示文本的窗口们.each{|x| x.update unless x.disposed?}
  end
  
  alias :我还要往你里面塞一点东西哦_dispose_all_windows君 :dispose_all_windows
  def dispose_all_windows
    我还要往你里面塞一点东西哦_dispose_all_windows君
    我要塞的东西之三
  end
  
  def 我要塞的东西之三
    @显示文本的窗口们.each{|x| x.dispose unless x.disposed?}
  end
end
# 完美!

# 照例装逼化

__END__

#==============================================================================
# ** Game_Interpreter
#==============================================================================
class Game_Interpreter
  def new_text_window(text, x = 0, y = 0, back = "", opa = 255)
    SceneManager.scene.new_text_window(text, x, y, back, opa)
  end
  def delete_text_window(id)
    SceneManager.scene.delete_text_window(id)
  end
  def close_text_window(id)
    SceneManager.scene.close_text_window(id)
  end
  def open_text_window(id)
    SceneManager.scene.open_text_window(id)
  end
  def text_window_set_text(id, text = "")
    SceneManager.scene.text_window_set_text(id, text)
  end
  def text_window_set_pos(id, x = 0, y = 0)
    SceneManager.scene.text_window_set_pos(id, x, y)
  end
  def text_window_set_back(id, back = "")
    SceneManager.scene.text_window_set_back(id, back)
  end
  def text_window_set_opa(id, opa = 255)
    SceneManager.scene.text_window_set_opa(id, opa)
  end
  def text_window_get_info(id)
    SceneManager.scene.text_window_get_info(id)
  end
end
#==============================================================================
# ** Window_ShowTextOnMap
#==============================================================================
class Window_ShowTextOnMap < Window_Base
  def initialize(text, x, y, back, opa)
    @text, @back, @opa = text, back, opa
    if @back.empty?
      super(x, y, *get_width_and_height)
      self.opacity = @opa
    else
      pic = Cache.picture(@back)
      super(x, y, pic.width, pic.height)
      self.back_opacity = 0
      self.contents_opacity = @opa
    end
    refresh
  end
  
  def get_width_and_height
    tmp = Window_Base.new(Graphics.width, 0, Graphics.width, 1)
    tmp.reset_font_settings
    width = 0
    pos = {x: 0, y: 0, height: tmp.calc_line_height(@text)}
    @text.each_line do |s|
      s.chomp!
      tmp.process_character(s.slice!(0, 1), s, pos) until s.empty?
      width = [pos[:x], width].max
      pos[:x] = 0
      pos[:y] += pos[:height]
      pos[:height] = tmp.calc_line_height s
    end
    [width + standard_padding * 2, pos[:y] + standard_padding * 2]
  end
  
  def refresh
    contents.clear
    pic = Cache.picture(@back)
    contents.blt(0, 0, pic, Rect.new(0, 0, pic.width, pic.height))
    draw_text_ex(0, 0, @text)
  end
  
  def set_text(text)
    @text = text
    refresh
  end
  
  def set_pos(x, y)
    self.x, self.y = x, y
  end
  
  def set_back(back)
    return if @back == back
    @back = back
    if @back.empty?
      self.move(self.x, self.y, *get_width_and_height)
      self.opacity = @opa
    else
      pic = Cache.picture(@back)
      self.move(self.x, self.y, pic.width, pic.height)
      self.back_opacity = 0
      self.contents_opacity = @opa
    end
    refresh
  end
  
  def set_opa(opa)
    @opa = opa
    if @back == ""
      self.opacity = @opa
    else
      self.contents_opacity = @opa
    end
  end
  
  def get_info
    [@text, @back, @opa]
  end
end
#==============================================================================
# ** Scene_Map
#==============================================================================
class Scene_Map
  alias :text_window_create_all_windows :create_all_windows
  def create_all_windows
    text_window_create_all_windows
    create_text_windows
  end
  
  def create_text_windows
    @text_windows = []
  end
  
  alias :text_window_update_all_windows :update_all_windows
  def update_all_windows
    text_window_update_all_windows
    update_text_windows
  end
  
  def update_text_windows
    @text_windows.each{|x| x.update unless x.disposed?}
  end
  
  alias :text_window_dispose_all_windows :dispose_all_windows
  def dispose_all_windows
    text_window_dispose_all_windows
    dispose_text_windows
  end
  
  def dispose_text_windows
    @text_windows.each{|x| x.dispose unless x.disposed?}
  end
  
  def new_text_window(*args)
    @text_windows.push Window_ShowTextOnMap.new(*args)
    @text_windows.size - 1
  end
  
  def delete_text_window(id)
    @text_windows[id].dispose
  end
  
  def close_text_window(id)
    @text_windows[id].close if @text_windows[id].open?
  end
  
  def open_text_window(id)
    @text_windows[id].open if @text_windows[id].close?
  end
  
  def text_window_set_text(id, text)
    @text_windows[id].set_text(text)
  end
  
  def text_window_set_pos(id, x, y)
    @text_windows[id].set_pos(x, y)
  end
  
  def text_window_set_back(id, back)
    @text_windows[id].set_back(back)
  end
  
  def text_window_set_opa(id, opa = 255)
    @text_windows[id].set_opa(opa)
  end
  
  def text_window_get_info(id)
    @text_windows[id].get_info
  end
end[/pre]
[/fold]

评分

参与人数 1梦石 +7 收起 理由
taroxd + 7 补前几楼

查看全部评分

萌新瑟瑟发抖
看到我请叫我去干活
回复

使用道具 举报

百合控

梦石
0
星屑
6548
在线时间
1275 小时
注册时间
2013-8-21
回帖
3522

开拓者

发表于 2014-7-27 19:52:31 | 显示全部楼层
本帖最后由 余烬之中 于 2014-7-27 20:13 编辑

这个写的稍微欠感觉

[fold=默认脚本中的 rescue 是什么意思?我应该在什么情况下使用 rescue?]
[pre lang="ruby" line="1"]
# 默认脚本中的 rescue 是什么意思?我应该在什么情况下使用 rescue?

# 我想请你尝试一下这个脚本 相信我 它是可以运行的 会在控制台打印一些东西

#~ def some_of_the_ways_to_pretend_to_be_great only998
#~   believe / me % 'and' & you ^ will * "not" + regret!
#~   only998
#~ end

#~ some_of_the_ways_to_pretend_to_be_great 1000

# 好吧我只是开个玩笑 换一个例子

class Student
  attr_accessor :name
  def initialize(name)
    @name = name
  end
  
  def do_math(*x)
    puts "#{@name} OK!"
  end
  
  def do_chinese(*x)
    puts "#{@name} OK!"
    x
  end
end
# 这是一个学生的类 初始化时需要给他名字——你说性别?浮云浮云
# 这个学生可以做数学和语文

class BStudent < Student
  def do_english(*x)
    puts "#{@name} OK!"
    x
  end
end
# 一个B级的学生不仅会做数学和语文 还会英语

class AStudent < BStudent
  def do_physics(*x)
    puts "#{@name} OK!"
    x
  end
end
# 一个A级的学生不仅会做数学语文和英语 还会物理

class FStudent < Student
  def do_math(*x)
    做不来
  end
  def do_chinese(*x)
    做不来
  end
end
# 一个F级快退学的学生什么都不会 就一个名字

class SStudent < Student
  def method_missing *args
    puts "#{@name} OK!"
    args
  end
end
# 一个S级的学生什么都会(此话有歧义)

# 好吧 现在进行小组活动 两个学生一起 一个人做数学另一个人做物理
# 假设做物理的人需要做数学的人的某些结论
m = AStudent.new("小明")
g = BStudent.new("小刚")
result = g.do_math
m.do_physics(result)
# 一点问题也没有 A级的学生和B级的学生完美配合
# 下面你猜到了 让S级出马
l = SStudent.new("小灵")
h = FStudent.new("小华")
#~ result = h.do_math
#~ l.do_physics(result)
# 会报错的 所以我注释掉了
# 怎么办呢
result = h.do_math rescue l.do_math
l.do_physics(result)
# 如果小华做不出来 就让小灵做两件事吧

# 这就是用法一: 当某段语句存在出错的可能时使用,以便在出错后进行补救
# 用法二是写在方法定义中 假设小华那边是这样的:
class FStudent < Student
  def do_math(*x)
    做不来
  rescue
    puts "蒙一个答案"
    3
  end
  def do_chinese(*x)
    做不来
  rescue
    puts"蒙一个答案"
    "杜甫"
  end
end
# 那么我上边不写【rescue l.do_math】也不会出错
# 用法三是写在begin句中 检测某一段代码

# 这样还是有点不好说 直接看默认脚本吧

# 原装脚本中大部分rescue在DataManager中 所以我们先看看其他的用法
# Game_Interpreter中是这样的

->{
  #--------------------------------------------------------------------------
  # * Execute Variable Operation
  #--------------------------------------------------------------------------
  def operate_variable(variable_id, operation_type, value)
    begin
      case operation_type
      when 0  # Set
        $game_variables[variable_id] = value
      when 1  # Add
        $game_variables[variable_id] += value
      when 2  # Sub
        $game_variables[variable_id] -= value
      when 3  # Mul
        $game_variables[variable_id] *= value
      when 4  # Div
        $game_variables[variable_id] /= value
      when 5  # Mod
        $game_variables[variable_id] %= value
      end
    rescue
      $game_variables[variable_id] = 0
    end
  end
}

# 倒数第四行的rescue
# 有什么意义呢?
# 这一段是用来处理事件中对游戏变量的操作的 加减乘除取余数
# 如果把3除以0毫无疑问会出错 叫做Divided by 0
# 这个就是防止某些游戏制作者把一个变量除以0
# 如果不写的话会出错 如果写了的话……还是会出错 但是不会报错 它会进行一个补救措施
#   把变量设为0
# 流程是这样的:
#   如果 运算不出错
#     赋值 运算结果
#     结束
#   如果 出错了
#     赋值 0
#     结束
# 很简单对不对

# 来看另一个rescue
# Window_Base中

->{
  #--------------------------------------------------------------------------
  # * Destructively Get Control Code Argument
  #--------------------------------------------------------------------------
  def obtain_escape_param(text)
    text.slice!(/^\[\d+\]/)[/\d+/].to_i rescue 0
  end
}

# 这是什么?
# 当你【显示文章】的时候,可能会用到控制符比如【\I[9]】显示9号图标
# 上面的【text.slice!(/^\[\d+\]/)】会把文本中的这种东西【[9]】抠出来
# 然后再【[/\d+/]】就会把【9】抠出来
# 然后【to_i】,就把【"9"】变成了【9】
# 如果有一个逗比 他这样写:
# 【哈哈哈今天真高兴啊\I9】
# 那么上面当然不能把【[9]】抠出来 因为没有方括号 于是它返回nil
# 所以 此时的脚本就差不多是:
#  【nil[/\d+/].to_i rescue 0】
# 如果我们不写【rescue 0】,就是这样:【nil[/\d+/].to_i】
# 不要说【to_i】了 单单【nil[/\d+/]】就会报错你信不信?在nil里想抠点东西出来?
# 做梦吧你
# 所以 为了防止这种情况和类似的无法匹配的情况 加了【rescue 0】
# 这样 在出错的时候 不会给玩家弹个窗【啊哦】 而是返回0 也就是描绘0号图标
# 0号是没有图标的 所以它会当什么都木有发生 跳过去 继续说下面的话
# 如果你不是图标 而是变量 它就来描绘0号变量
# 0号是没有变量的 所以它会当什么都木有发生 跳过去 继续说下面的话


# 现在来看DataManager里面的种种

->{
  #--------------------------------------------------------------------------
  # * Execute Save
  #--------------------------------------------------------------------------
  def self.save_game(index)
    begin
      save_game_without_rescue(index)
    rescue
      delete_save_file(index)
      false
    end
  end
  #--------------------------------------------------------------------------
  # * Execute Load
  #--------------------------------------------------------------------------
  def self.load_game(index)
    load_game_without_rescue(index) rescue false
  end
  #--------------------------------------------------------------------------
  # * Load Save Header
  #--------------------------------------------------------------------------
  def self.load_header(index)
    load_header_without_rescue(index) rescue nil
  end
  #--------------------------------------------------------------------------
  # * Delete Save File
  #--------------------------------------------------------------------------
  def self.delete_save_file(index)
    File.delete(make_filename(index)) rescue nil
  end
}

# 老实说 这些都是与外部文件有关的
# 第一个 save_game中的 也就是存档的时候
#   它调用save_game_without_rescue方法 往index号存档文件里面写入信息
#   包括游戏时间啦 队伍物品啦 各种游戏对象啦……
#   与外部的交流永远是坎坷的 错误随时都可能会犯
#   万一出错了 save_game_without_rescue内部就会向上级报告:老大!出问题了!
#   然后如果老大save_game没有拯救的措施 那也只好再向上报告:头!这里有点麻烦!
#   一直上到顶,就弹个框,跟玩家说:不好意思,出了点意外,只好请你别玩了滚蛋吧
#   为了世界的和平,save_game毅然决定把问题揽下来
#     如果写存档出错了那么这个存档文件肯定是损坏的 要及时清理掉
#   于是它调用了delete_save_file
#   现在看到第四个rescue 也就是delete_save_file内部
#     如果写存档的出错,并非写着写着出错了,而是还没开始写就出错了
#     那么delete_save_file想要把它删掉 自然是删不掉的 只好报个错……
#     不行!太窝囊废了!没找到就没找到嘛!有什么大不了的!
#   于是它rescue nil 谁也不知道 事情结束了 真相已经湮灭于暗流汹涌之中
# 第二个和第三个resuce 都是从外界读取信息 也就是读档
#   我们假设,存档成功的完成了,但是读档文件有了损坏,就像食物变质一样
#   然后load_game_without_rescue毅然去吃了一口 上吐下泻 只好跟老大请假
#   老大load_game想,哎哟这可怎么办?要不要跟上级说?
#   思来想去:恩,不是多大事,不就是没读成功嘛!有补救的措施!于是rescue false
#     返回了一个值:恩,这次读档出了点问题,不是多大事,你换个档再读吧
#   load_header作为load_game的双胞胎弟弟 也是跟它哥一个作风
#   每次打前哨的时候出了问题 就rescue下来 谁也不说 这样大家根本不知道:
#    哇!这里还有一个存档!
#   因此这个损坏的存档也不会来影响大家心情了 load_header很自豪

# 什么?应该在什么时候使用rescue?感情我这一阵都白讲了?
# ……………………
# 一个字:悟
# 看懂了rescue的用法 自己也就会用了[/pre]
[/fold]

点评

…………神吐槽  发表于 2014-7-28 11:48
这东西说实话…………想滥用都有点难度 rescue 当我没说  发表于 2014-7-27 20:53
其实,我后半句想说的是不要滥用 rescue……  发表于 2014-7-27 20:38

评分

参与人数 1星屑 +150 梦石 +1 收起 理由
taroxd + 150 + 1 ~

查看全部评分

萌新瑟瑟发抖
看到我请叫我去干活
回复

使用道具 举报

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

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部