反則ワザ

たとえば、Rubyで大量のループをする。

objects.each do |obj|
  obj.draw
end

みたいなことをする場合、drawメソッドの呼び出しが大量に発生するわけだ。
もちろんこれを省くことはできないのだが、Rubyではブロック付きイテレータは遅いのだ。
いや、Ruby内では速い。
イテレータ以外の手段で同じことをするより、イテレータを使ったほうがずっと速い。
しかし大量のオブジェクトを動かす場合、どうしてもここで処理時間が食われる。
どのぐらいか計ってみると、からっぽのdrawを10000呼び出しで10ms。
移動、描画、削除で300回ずつループすれば1ms弱となり、これだけで6%ほどの負荷だ。
ターゲットにしているローエンドPCではループと呼び出しだけで10%を超えてくる計算となり、結構でかい。
定型処理なんだから、Cでどうにかならないだろうか。
で、考えてみた。

objects.hs_each(:draw)

Arrayクラスにhs_eachを追加する。hsはハイスピードの略。
こいつは引数で渡されたシンボルor文字列のメソッドを全部順番に呼ぶ。
実装して試してみると、10000呼び出しで3.5msほどになった。1/3だ。
ついでにhs_delete_ifも実装して、サンプルシューティングで使ってみたところ、ボスの弾でも30%いかなくなった。
微妙だが確実に効果はあるようだ。
DXRubyExtensionに追加しておこう。
こんなん使って喜ぶ人などいないと思うが、もともとDXRubyExtensionは複雑な当たり判定をこなすのが目的なのではなく、ただ単純にゲームを高速実行するのが目的なのだから、これでよい。


Rubyゲームで実行速度をたたき出そうとする試みというのは、例えるならダンプカーでサーキットをいかに速く走るかみたいな、激しく手段と目的が狂っている行為である。
正直なところ意味はないし、1.9系がしっかりしてこれば更に意味が薄れる。
でもまあ、他にそんなことやってる人もいないみたいだし、なにより趣味でやっていることだ。
生産性とか意味とか考えてもしょうがない。
Just for Fun、ってことで。