加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员  
 
x
 
 本帖最后由 Cichol 于 2015-10-3 18:16 编辑  
 
刚接触RGSS,近日在啃RM的自带脚本,对Fiber还是比较困惑的,好像论坛里搜不到Fiber的文章,就写(shui)一些我对Fiber的理解 
 
我比较关注的是Window_Message这个类,这个类的本体就是在update里不断监听$game_message的改动,然后新建Fiber以及执行@fiber,不过暂时不管它,先用个简单点的模型去观察Fiber。 
 
RM的体系里每帧会调用一次update,在update里做一些数据的读取和更新,重新绘图之类的事情。如果整个update只做一件事,例如: 
def update   recalculate_x end 
 
 def update  
  recalculate_x  
end  
 
  
每次update时重新计算x值,这是每次update都需要考虑的,可以认为是一种单一的状态,直接写在update里也十分自然。 
 
那么非单一状态是什么样的呢?假如我们需要等待用户的输入,获取到输入的时候重绘,但是update一秒钟会调用60次,它怎么知道这次调用应该做什么呢?是应该等待输入,还是用户已经输入了,应该处理重绘? 
这时候我们可以用一个状态机去处理: 
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 
 
 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  
 
  
等待input的时候,不改变状态,直到监听到input,把状态改为redraw,然后下一次update进行redraw。 
在draw_process完成之后,把状态改回wait_input,继续监听input。 
这本质上是一个input-redraw流程的循环,这个流程有wait_input和redraw两个状态。 
 
那么看看Fiber可以如何简化这些状态,使用Fiber的等价代码: 
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 
 
 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  
 
  
除了第一次调用到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)。 |