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

Macを買ったらDXRubyが動かないので、いや、Wineで動くらしいんだけど、それをいうと話が終わってしまうので、とりあえず動かないことにしておいて(すみません)、RubyからSDL2を使うバインダsdl2rで遊んでみようという企画。
sdl2rはSDL2を使ってみたかったという素朴な理由で開発されたRuby用ライブラリで、Cで書かれていて、シンプルにSDL2の関数群をほぼそのままRubyから呼べるようにしたものだ。ただし、Rubyのような言語で使い方に問題があったとしても、ライブラリがコケるのは問題外という認識から、コケないように気を使って作られている。sdl2rを使っていれば、segvなどにお目にかかることは(バグってなければ)ないはずだ。
SDL2とsdl2rに関する基本的な話は約1年前の記事、SDL2の使い方から連続で3日間書いているので、知らない人はそっちを参照するとよいかもしれない。

また、RubyでSDL2を使う方法として、Ruby/SDL2もあるのでっていうかそっちのほうがいいかもしれないので、そのあたりは適当に。

作るものを考える

何を作るかって新しいAPIのネタも無いことだし、とりあえずDXRubyに近い何かを作ってみよう。SDL2の使い方、sdl2rの使い方、それから、DXRubyの動きをRubyで記述することによって、内部動作を理解することができる。かもしれない。ちなみにRubyで書かれたDXRubyはすでにdxruby_sdlが存在するので、そっちを見るのも勉強になるだろう。dxruby_sdlRuby/SDLを使って作られている。あー、Ruby/SDL2を使ってdxruby_sdlを作り直したほうが早いんでないの、って?俺もそう思うんだけども、そのへんはそっちの人たちにお任せしておいて、俺は俺で独自路線を行こうかな、なんて。ほら、多様性は善って言うし。知らんけど。

超基本部分を作ってみる

とりあえず作ってみた。
そういえば開発環境について何も書いてなかったけども、MacではhomebrewでSDL2をインストールして、gitでsdl2rをcloneして、extconf.rbを動かして、makeして、make installすれば使えるようになる。Windowsではちょっと厄介なんだけども、簡単に準備する方法があったりするのかしらん。そこいらへんはまたいずれ。
今回の超基本部分はFPS制御にdxruby_sdlのfpstimer.rbを使っている。単純にそのまま持ってきただけ。モジュール名がDXRubySDLってなってたのでそこだけDXRubyに変えた、かな?たぶん。
これらを適当なディレクトリにおいて、

require_relative 'dxsdl2r'

Window.loop do
  Window.caption = "#{Input.mouse_x}, #{Input.mouse_y}"
end

こんなコードを実行すると、ウィンドウが開いてマウスの座標がタイトルバーに表示される。
おお、それっぽい・・・?

解説

このコードは見てもらえるとわかると思うが、require時にSDLの初期化をして、ENDブロックで終了処理を行う。また、DXRubyモジュールをincludeする。
更に、Windowモジュール内でSDLのウィンドウを非表示状態で生成する。DXRubyの大きな特徴に、Windowクラスなどが用意されていないのに勝手にウィンドウを生成して状態を保持・更新するというところがある。ウィンドウは通常1つしか作らないんだからわざわざクラス化しなくてもいいし、制御はライブラリに任せてしまえばよいじゃない、というのが俺の考えで、オブジェクト指向的には美しくないかもしれないが、オブジェクト指向的に美しくしたからと言って扱いやすくなるわけでもなかろう、という話だ。
ところで、最初にウィンドウを生成してしまう理由として、DirectXOpenGLが初期化時にウィンドウを要求する、というところがある。なぜウィンドウが必要なのかは知らないが、なんしかこれを渡す必要がある。Window.loopでウィンドウを表示する前にImageやRenderTargetを作ったりしたいので、とりあえず非表示で生成するようにしてある。これはSDL2でも同じで、Rendererを作るにはWindowが必要だし、Textureを作るにはRendererが必要である。従って、Window.loop前にTextureを作りたいなら非表示でウィンドウを用意しておくことになる。
Window.loop内ではとりあえずRendererを使って画面をクリアしているが、現状描画機能が無いのであまり意味は無い。色は黒固定にしていて、ここは今後bgcolorでクリアするようにする必要があるだろう。
SDLのイベントはInputモジュール側で処理している。これは、キーやマウスの入力がイベントで飛んでくるからで、それらで取得した値はInputモジュール内でコソコソと保持して各種入力を処理する必要があるからである。DXRubyでもWindowsのメッセージやDirectInputの入力の処理はInputモジュール内でやっていて、Windowモジュールにこれらの処理は無い。

おしまい

と、まあ、簡単に基本部分を作ってはみたが、実はDXRuby互換ライブラリ的なものはプロトタイプがある程度すでに動いていて、んでも、ちょっと強引に作りすぎた感があるので、再実装すんべ、ということでそのついでに記事にすることにした。逆に言えばsdl2rはとりあえずそのへんまで動くレベルぐらいには実装できている。未実装の関数はまだまだ多いけど。
いまのところはImageも描画もキー入力も何も無いので、今後こつこつと作っていくことになるだろう。Imageのdraw系メソッドやSpriteの衝突判定などは非常にめんどくさいのでたぶん最後になるだろうし、めんどくさいので作らずに終わるかもしれない。
あー、あと、DXRuby作者が作っているからと言って、これが公式のSDL2版DXRubyである、みたいなことはまったく無いので勘違いなさらぬよう。sdl2rも実績ないし。あくまでも実験ね、実験。同じものが作れるわけがないし、SDL2ではできないこともあるだろうし、逆にSDL2の機能を使えばもっといいものにできる部分もあるだろうし、てな感じで、そう、これはsdl2rでRuby用ゲームライブラリを作る公開実験、なのである。ということにしておこう。