コマンドDSLの定義
RubyはDSL(DomainSpecificLanguege)に向いた言語だと言われる。
DSLってのは特定用途に特化した仕様のミニ言語で、何かを定義する専用にちょっとした宣言・定義文を作ってそれで書けば確かにやりやすい。
そういうミニ言語をRubyのプログラム内に埋め込もうというのが言語内DSLで、Rubyはメソッドコールの構文、ブロックの存在のおかげでそういったものが作りやすい。
具体的にはこのようなコードになる。
ライブラリ側はアレコレいじり中なので今んとこ非公開だが、前の弾幕生成のんと似たようなものが動くと思ってもらえればよい。
2次元配列を並べるのと比較すると随分読みやすく書きやすい感じになっているのではなかろうか。
require 'dxruby' require 'dxrubyex' require 'bulletgenerator' require 'sprite' # コマンドDSL拡張ここから class Command attr_reader :command def initialize @command = [] end def method_missing(m, *arg) if m == :wait @command.push([:wait=, arg[0]]) else @command.push([m] + arg) end end end class Sprite def self.define_command(&block) c = Command.new c.instance_eval(&block) if block c.command end end class BulletGenerator def self.define_command(&block) c = Command.new c.instance_eval(&block) if block c.command end end # コマンドDSL拡張ここまで class Shot < Sprite @@image = Image.load("image/enemyshot1.png") @@command = define_command { # ←コマンドDSL wait -1 } def initialize(x, y, angle, speed) super(x-@@image.width/2, y-@@image.height/2, angle, speed, @@command) self.collision = CollisionBox.new(self, 0, 0, 7, 7) self.collision_enable = true self.image = @@image end end class BL_8way < BulletGenerator action1 = define_command { # ←コマンドDSL fire_relative Shot, 0, 5 rotation 45 } @@command = define_command { # ←コマンドDSL call_command action1, 8 wait 2 rotation 12 } def initialize(parent, x, y) super(Objects, parent, x, y, 0, @@command) end end class Enemy2 < Sprite @@anime_image = Image.loadToArray("image/enemy2.png", 4, 1) @@anime_pattern = [15, [0,1,2,3]] @@command = define_command { # ←コマンドDSL right 100, 1 left 100, 1 } def initialize(x, y) super(x, y, 0, 0, @@command) Objects.push(BL_8way.new(self, 16, 48)) Objects.push(BL_8way.new(self, 112, 48)) self.angle = 90 self.anime_image = @@anime_image self.start_animation(@@anime_pattern) end end Objects = [] Objects.push(Enemy2.new(200,100)) font = Font.new(32) Window.loop do Sprite.update(Objects) Sprite.clean(Objects) Sprite.draw(Objects) Window.drawFont(0, 0, Window.getLoad.to_i.to_s + " %", font, :z => 100.0) Window.drawFont(0, 32, Objects.size.to_s + " objects", font, :z => 100.0) end