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のような感じになる。