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

Spriteクラスを作ろう。
DXRubyのクラス群の中では唯一、DirectXを直接叩かないのがSpriteである。描画に必要な情報をまとめ、DXRubyの描画機能を呼び出すことで間接的にDirectXにアクセスする。なので作ろうと思えば他のライブラリでも同様のものは作れるだろうし、依存するライブラリに関係する部分を切り離せば汎用的なSpriteを作ることもできるはずだ。ただし、DXRubyのSpriteは実行速度的な問題で汎用的にはなっていないので、コードをそのまま持ってきてもsdl2rで使えるようにはならない。
ということでRubyで書く。

Spriteクラスのコード

  class Sprite
    def self.update(sprites)
      sprites.flatten.each do |s|
        if !s.respond_to?(:vanished?) or !s.vanished?
          if s.respond_to?(:update)
            s.update
          end
        end
      end
      nil
    end

    def self.draw(sprites)
      sprites.flatten.each do |s|
        if !s.respond_to?(:vanished?) or !s.vanished?
          if s.respond_to?(:draw)
            s.draw
          end
        end
      end
      nil
    end

    def self.clean(sprites)
      sprites.size.times do |i|
        s = sprites[i]
        if s.kind_of?(Array)
          Sprite.clean(s)
        else
          if s.respond_to?(:vanished?)
            sprites[i] = nil if s.vanished?
          end
        end
      end
      sprites.compact!
      nil
    end

    def x;@_x;end
    def x=(v);@_x=v;end
    def y;@_y;end
    def y=(v);@_y=v;end
    def z;@_z;end
    def z=(v);@_z=v;end
    def image;@_image;end
    def image=(v);@_image=v;end
    def target;@_target;end
    def target=(v);@_target=v;end
    def collision;@_collision;end
    def collision=(v);@_collision=v;end
    def vanished?;@_vanished;end
    def vanish;@_vanished=true;end

    def initialize(x=0, y=0, image=nil)
      @_x, @_y, @_image = x, y, image
      @_z = 0
      @_vanished = false
    end

    def draw
      if @_target
        @_target.draw(@_x, @_y, @_image, @_z)
      else
        Window.draw(@_x, @_y, @_image, @_z)
      end
      self
    end
  end

めっちゃ基本的な機能だけである。せめて衝突判定でも作ってあればまだ使い道もあったかもしれないが、矩形の判定だけでも判定部分以外がややこしいことになるのでとりあえず無しで。

この連載はここまで

おおまかな基本機能がだいたい揃ったのでここまでとする。後は頑張って機能を追加していくだけだ。
そういえばSoundクラスが無いが、あれはSDL2では同じように作ることはできないので、何かしら違うものにしかならないだろう。むしろ同じように作るほうに価値が無い。SoundEffectはかなりめんどくさいができることはできると思う。どっちかというと需要のほうが怪しい。
DXRubyは長いことかけて力技で作った部分が多いので、同様な機能を揃えるのは骨が折れる。さすがにそこまでのモチベーションは無い。あと、やはりこの作り方では思ったほどのパフォーマンスが出ない。C実装のRubyメソッドから直接DirectXを叩くという極端なショートカットはパフォーマンス的には有利なようだ。とはいえ速度は実用的であればそれ以上は必要無く、需要があるとすればある程度機能が揃った扱いやすいAPI、ということになるのだろう。であるならば、この程度しか実装していないライブラリには存在価値は無いのかもしれない。

今後を考えてみる

ここまでのコードはこちらに置いておいた。近いうちにgithubリポジトリ作って置こうと思うが、完成する気はしない。機能追加してぷるりもらえると嬉しいし、この機能が欲しい、ってリクエストがあれば作るかもしれない。
なにはともあれ、sdl2rとその上に構築したRubyのコードでここまで動くということはわかったので、これは大きな収穫である。一連の実装経験から得られた知見は、言語の実行速度に依存するような力技の処理でなければ、そこそこの速度で動くマルチプラットフォーム対応のものが、Rubyで書ける、ということだ。
Cで書いているDXRubyそのものを修正して実験するのは大変だが、DXRubyの上にRubyのコードで書いても実のところあまり自由度は無い。SDL2を叩くレベルからRubyで書けるのであれば、dxsdl2rのRubyで書いてあるベースの処理からぶっ壊して作り直すような実験もやりやすい。クラスを再構成してChipmunkと融合する方法を考えたり、OpenGLで3Dを試したり、複数ウィンドウに対応するようなインターフェイスを考えたりしながら、それを直接実験できるのだから、これはなかなか面白い。
興味深いオモチャを手にいれたような気分である。っていうか実際そうなのだろう。