sdl2rでゲームライブラリを作る(7)

昨日の記事で「オススメできない」と書いたばっかりだが、せっかくボタン用定数にオブジェクトが入っているのだから、これを利用して何か面白いことができないかを考えてみた。

条件の論理合成

module DXRuby
  module Input
    class ButtonChecker
      attr_reader :prc

      def initialize(prc)
        @prc = prc
      end

      def check
        @prc.call
      end

      def &(v)
        ButtonChecker.new(Proc.new{@prc.call and v.prc.call})
      end

      def |(v)
        ButtonChecker.new(Proc.new{@prc.call or v.prc.call})
      end

      def !
        ButtonChecker.new(Proc.new{!@prc.call})
      end
    end

    module UseButtonChecker
      def down
        ButtonChecker.new(Proc.new{self.down?})
      end

      def push
        ButtonChecker.new(Proc.new{self.push?})
      end

      def release
        ButtonChecker.new(Proc.new{self.release?})
      end
    end
  end
end

Inputモジュールの下にButtonCheckerクラスを作ってみた。これはボタンの状態チェックをするProcオブジェクトを受け取って、論理演算で合成することができるクラスである。UseButtonCheckerモジュールをMouseButtonクラスとKeyboardクラスにincludeしておくと、down/push/releaseの3つのメソッドが追加されて、これを呼ぶことでそれぞれのチェックを行うProcを持つButtonCheckerオブジェクトが返ってくる。ButtonCheckerオブジェクトはcheckメソッドで条件が成立しているかをチェックすることができる。もうちょっといい名前ありそうなのだが英語よくわかんないし。
具体的な使い方は以下のような感じ。

B_SHIFT_Z = K_LSHIFT.down & K_Z.push
Window.loop do
  if B_SHIFT_Z.check
    break
  end
end

左シフトが押された状態で、新たにZが押された場合にのみ終了する。&はメソッドとして定義してあり、selfと引数をandで繋いだ条件式を生成する。|と!もあるのでそれなりに思い通りの条件を作ることができる。

複数ボタンをまとめる

module DXRuby
  module Input
    class Buttons
      include UseButtonChecker

      def initialize(*ary)
        @ary = ary
      end

      def push?
        @ary.any?{|b|b.push?}
      end

      def down?
        @ary.any?{|b|b.down?}
      end

      def release?
        @ary.any?{|b|b.release?}
      end
    end
  end
end

さっきのんは条件自体(pushとかreleaseとか)ごと合成する機能だったが、ボタンだけをまとめたい、ということがある。例えばK_LSHIFTとK_RSHIFTをまとめてK_SHIFTにしたい、などである。これを実現する方法として、Buttonsクラスを作ってみた。単純に受け取った引数を全て配列として保持して、any?でチェックするだけである。
以下のように使う。

  K_LSHIFT  = Input::Keyboard.new(SDL::SCANCODE_LSHIFT)
  K_RSHIFT  = Input::Keyboard.new(SDL::SCANCODE_RSHIFT)
  K_SHIFT   = Input::Buttons.new(K_LSHIFT, K_RSHIFT)

これで普通にK_SHIFTを扱うことができるようになる。

おしまい

キー定数に独自のオブジェクトを入れるようにすると、基本の使い方は同じままでも、発想次第でいろんなことができるようになるみたいである。
ただし、この状態でdxsdl2rに突っ込むかというと怪しい。もうちょいうまいこと作れるんじゃないかとか思うし、もうちょい機能追加できるんじゃないかとも思うし、とりあえず思いついたから作ってみただけなので、まあ、まだ練り込みが足りない。