CommandとExecuter
DXRubyFramework0.0.2ではSpriteクラスはコマンド列を処理する機能を持っているが、コマンド列は配列であるので、それをもうちょっと簡単に簡易DSLで記述するためのCommandクラスを用意した。
用意したというほどのものでもない。
class Command attr_reader :command def initialize @command = [] end def method_missing(m, *arg) @command.push([m] + arg) end def self.generate(&block) c = Command.new c.instance_eval(&block) if block c.command end end
これをrequireしておいて、Command.generateでコマンドを並べれば配列が返ってくる。
前に作ったものを大幅に簡素化しただけだ。シンプルなものが好みなのでこうなった。
0.0.1のSpriteクラスのクラスメソッド(updateなど)はSpriteオブジェクトしか扱えなかったが、今回はSpriteオブジェクト以外の場合にupdateやdrawメソッドがあった時にのみそれを呼び出すようにしてみた。
Spriteじゃなくてもそのメソッドがあれば、配列に突っ込んで1フレーム1回呼び出すことができる。Sprite.cleanはdelete_flagメソッドの戻りを見て配列から削除してくれる。いまのところ衝突判定までは対応しておらず、Sprite以外は無視される。
この機能を応用するとSpriteクラスを使わない自作の描画プリミティブや、そもそも描画と関係無い処理まで統一して扱えるようになる、かもしれない。別にすばらしいアイデアというわけではなく、タスクでシステム全てを管理しようというのはよくある話である。そのようにやろうと思えばできるし、やらなくてもよい。
で、これを使って汎用のコマンド処理を提供するためのExecuterクラスも用意した。
用意したというほどのものでもない。
class Executer attr_accessor :wait, :delete_flag, :command def initialize(command) @pc = 0 @wait = 0 @command = command @delete_flag = false end def update while(@wait == 0) c = @command[@pc] if c.size == 2 self.__send__ c[0], c[1] else self.__send__ c[0], *c[1..-1] end @pc += 1 if @pc == @command.size @pc = 0 end end @wait -= 1 end def wait(count) @wait = count end def vanish @delete_flag = true end end
これも前のやつを大幅に簡素化したもので、waitとvanishだけをコマンドとして実装してある。描画プリミティブではないのでdrawは無い。
ただし、これを使うとアリガチなupdateメソッドを作れなくなるので、その辺がちょっと困った感じだ。
Cで書いてもよかったのだが、Spriteと違って大量に処理するようなものに使うこともないだろうし、Cで書いてもほとんど速度は変わらない(どうせメソッド呼び出ししかしない)ので、中身が見えるようにRubyで。
特性としては、ノンプリエンプティブなマルチタスク、ようするにコルーチンモドキのような振る舞いをする。
これで何ができるかというと、アイデア次第で何でも、ということになるわけだが、例えばSTGで敵の出現パターンをこれで作ることができる。
実際に出現させるコードはコマンドとしてメソッドに書いて、それを指定のフレームで呼び出すようにコマンド列を作る感じだ。
その他、弾幕生成器を作ったり、Sprite.updateから呼び出す使い方から離れれば、フレーム数指定で動くもの以外の、なんでも。モノがシンプルだしパブリックドメインのコードにするから、好きなように改造して拡張して自由に使ってもらえるとよい。