Fiberを使いやすくする仕掛け

RubyのFiberはコルーチンというかマイクロスレッドというか、ユーザが中断ポイントを指定して任意に切り替えられるスレッドなので、これを使うとパターンで行動するキャラの制御ロジックが書きやすくなる。
Fiberは生成時にコードが必要で、たとえばSpriteなどに適用しようとするとインスタンスごとにFiber.newする必要があって、initializeにコードを書かないといけなくなる。これではちょっと扱いづらいし読みにくい。
そこでちょこっと細工してみた。

require 'dxruby'

class FiberSprite < Sprite
  def initialize(x=0,y=0,image=nil)
    super
    @fiber = Fiber.new do
      self.fiber_proc
    end
  end

  def update
    @fiber.resume
  end

  def wait(t=1)
    t.times {Fiber.yield}
  end

  def add_x(x, t=1)
    t.times {self.x += x;Fiber.yield}
  end

  def add_y(y, t=1)
    t.times {self.y += y;Fiber.yield}
  end

end

class Foo < FiberSprite
  def fiber_proc
    loop do
      add_x 1, 10
      add_y 1, 10
      wait 10
    end
  end
end

s = []
s << Foo.new(100,100,Image.new(100,100,C_WHITE))
s << Foo.new(300,100,Image.new(100,100,C_WHITE))

Window.loop do
  Sprite.update(s)
  Sprite.draw(s)
end

FiberSpriteクラスはFiberオブジェクトを作って保持し、updateメソッドでFiberのresumeをする。Fiberオブジェクトのコードはfiber_procメソッドの呼び出しで、この中身はここでは定義されていないので、FiberSpriteを継承するクラスのほうで定義する。
ユーザはFiberSpriteを継承してfiber_procメソッドを定義する。fiber_procメソッドはupdate時にFiberオブジェクトの中から呼ばれるので、Fiber.yieldを使うことができる。ていうか使わなければならない。Fiber.yieldを山ほど書くのも面倒なので、FiberSprite側によく使いそうな機能を定義しておけばfiber_procはDSLのような感じになる。