查看: 2724|回复: 0

[讨论] 【RGSS相关】Fiber的意义和使用

[复制链接]
梦石
0
星屑
1539
在线时间
12 小时
注册时间
2014-11-24
回帖
1
发表于 2015-10-3 18:01:11 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 Cichol 于 2015-10-3 18:16 编辑

刚接触RGSS,近日在啃RM的自带脚本,对Fiber还是比较困惑的,好像论坛里搜不到Fiber的文章,就写(shui)一些我对Fiber的理解

我比较关注的是Window_Message这个类,这个类的本体就是在update里不断监听$game_message的改动,然后新建Fiber以及执行@fiber,不过暂时不管它,先用个简单点的模型去观察Fiber。

RM的体系里每帧会调用一次update,在update里做一些数据的读取和更新,重新绘图之类的事情。如果整个update只做一件事,例如:
[pre lang="ruby"]
def update
  recalculate_x
end
[/pre]
每次update时重新计算x值,这是每次update都需要考虑的,可以认为是一种单一的状态,直接写在update里也十分自然。

那么非单一状态是什么样的呢?假如我们需要等待用户的输入,获取到输入的时候重绘,但是update一秒钟会调用60次,它怎么知道这次调用应该做什么呢?是应该等待输入,还是用户已经输入了,应该处理重绘?
这时候我们可以用一个状态机去处理:
[pre lang="ruby"]
def update
  case @current_state
  when :wait_input
    wait_input
  when :redraw
    redraw
  end
end

def wait_input
  if have_input?
    @current_state = :redraw
  end
end

def redraw
  draw_process
  @current_state = :wait_input
end
[/pre]
等待input的时候,不改变状态,直到监听到input,把状态改为redraw,然后下一次update进行redraw。
在draw_process完成之后,把状态改回wait_input,继续监听input。
这本质上是一个input-redraw流程的循环,这个流程有wait_input和redraw两个状态。

那么看看Fiber可以如何简化这些状态,使用Fiber的等价代码:
[pre lang="ruby"]
def update
  if @fiber
    @fiber.resume
  else
    @fiber = Fiber.new {fiber_main}
  end
end

def fiber_main
  loop do
    Fiber.yield until have_input?
    draw_process
  end
end
[/pre]
除了第一次调用到update会生成一个@fiber,之后的每次调用都是简单地唤醒@fiber。
而@fiber的代码,fiber_main,描述的就是我们的input-redraw流程。等待input然后直接redraw,由于原来的程序是一个循环,这里就直接塞在loop{}里。
如果have_input?为false,Fiber的控制权会移交到外部,等待下一次resume。而下一次update的@fiber.resume又会让执行的步骤回到until have_input?这一行,再次判断有无输入。

Fiber(Coroutine)这种风格可以简化代码的逻辑,让异步的代码写起来像同步的一样,在fiber_main里代码逻辑和直观的操作流程是一样的,可以连续地写出来,不需要我们去考虑每次调用update的时候是什么状态。

理解了这些之后,再去看Window_Message的代码应该就不会迷糊了,而且也更能感受到Fiber是如何使代码简化的(参考Window_Message的fiber_main)。

评分

参与人数 2星屑 +145 收起 理由
中野梓 + 85 精品文章
kuerlulu + 60 精品文章

查看全部评分

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

本版积分规则

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

在本版发帖返回顶部