当たり判定の高速処理を考える

DXRubyの他との決定的な違いは、Windows専用でDirectXを使っていることであって、その点で差が出るのは実行環境の限定と実行速度のみである。
言い換えれば、ライブラリの扱いやすさや機能などは純粋に仕様・考え方の相違であって、DirectXを使うかSDLを使うかの話とは関係がない。
DXRubyは簡単であることをアピールポイントとしているが、DirectXを使いつつ高機能なものに微妙にマイナーだけどLuna/Rubyとその後継のSelene/Rubyというものがある。
C/C++用のゲームライブラリLuna/Seleneのラッパライブラリなのだが、これがフルにRubyから使えるとしたらマジで驚異的だ。
http://www.twin-tail.jp/selene/
余談だがLuna時代には色々と参考にさせてもらった。
この人にはあらゆる面でかなわないと思っているから、DXRubyはこれとはかぶらないようなところを狙っている。
正直、ほんの少したりとも競合したくない。


DXRubyは機能を限定して扱いやすくし、それに特化することで最適化ができる。
その意味では、アクションゲームでよく使うアルゴリズムをCで書いて提供することも、ギリギリのラインではあるが視界に入ってこないでもない。
たとえば当たり判定をCで高速化することはできるのだろうか。


サンプルシューティングの当たり判定を例に考えてみよう。
当たり判定処理のイメージは、配列を2つ(攻撃側、防御側)渡して、矩形で全判定するような感じだ。
判定のための座標は配列内のオブジェクトのx1、y1、x2、y2メソッドで取得できるようになっていて、当たっていたら攻撃側のshotメソッドと防御側のhitメソッドを、それぞれ相手のオブジェクトを引数にして呼ぶ。
判定する2つのオブジェクトを引数にしてtrue/falseを返すようなCのメソッドを作ると、確かに少しは速くなるだろうが、結局x1などのメソッド呼び出しは発生するから、あまり変わらないことが想像できる。
shotとhitを呼ぶところまで、とか、配列のぶんだけループするところまで、とかしても、結局のところRubyの文法部分のParse処理が無くなるだけで、Ruby1.9.1を使えば効果は薄れる。
俺がDXRubyをシンプルにしているのは、枠にはめられたコードを書くぐらいなら自分で処理を書いたほうが気楽だからであって、わざわざ人を枠にはめる仕組みを作るなら、使う側が気楽さを失っても納得できるだけの性能を提供できなければ、俺的には意味が無いのだ。
性能だけを強調するものをDXRubyに含める気はないから、やっぱり別の形にするのがいいのだろう。


根本的に処理の仕組みを変えてみよう。
なんらかの形でRubyからアクセスできて、Cのほうからもメソッド呼び出しではなく直接参照できるような座標データがあれば、高速処理ができるようになるはずだ。
たとえばオブジェクト配列じゃなくて、[x1, y1, x2, y2, self]という感じのデータを突っ込んだ配列を渡すようにする。
当たり判定時にメソッド呼び出しがなくなって速くなる。
Rubyレベルで同じことをしても配列の参照にメソッド呼び出しが発生するが、Cでは配列の参照はマクロでやってしまえばかなりの処理が省ける。
ライブラリ側での高速判定の仕組みを提供しても、たとえばRuby側で毎回座標配列を生成していては速度的に厳しい。
どうせやるなら、[nil, nil, nil, nil, nil]という配列をnewの時に生成してインスタンス変数に入れておいて、その中身を書き換えるだけにするのがよいが、Ruby側が速いか遅いかは使うほうの責任なのでそうする義務は無い。
そういうことを考えなくていいようにするために、CollisionBoxクラスを提供しといて、Newしたら勝手に当たり判定グループ配列に追加されて、CollinsionBox#setで座標をセットするとかにすれば、つまり、使う側の枠を増やしてやれば速くはなる。


ところで、世の中にはRubyを使っていながら当たり判定機能を提供してほしい人もいるのは事実で、そういう人にはなるべく簡単に使えるようなのが望ましい。
異常に使いにくいが異常に速いというのは、尖った仕様であり、需要は極端に少ないのである。
最終的には現実的な落とし所を探るのがいいのだろう。