衝突判定と拡張ライブラリ

2Dのシンプルなアクションゲームを作る場合、衝突判定は円と円、もしくは矩形と矩形で判定することになる。
そのような簡単な判定でも、すべてのオブジェクト同士が衝突する可能性があるものを総当りで検出していると、たかだか50個ぐらいのオブジェクトを動かしただけでもRubyで書いていては全くお話にならない処理時間になってしまう。
そうじゃなくても、例えば敵35匹と自分の弾35個でほぼ同じ計算量になる。判定する対象が1つならずっと余裕になって、敵の弾1200個と自分だけの判定でだいたい同じぐらいだ。
DXRubyには高速衝突判定ライブラリとしてDXRubyExtensionを添付してあるが、これは単純に総当りの判定をCで真面目に書いただけだ。コツコツと。
2Dの簡単なゲームを作る程度ならこれでも十分な速度が出ていると思うが、今後、3D用の判定やもっと複雑な形状の判定などを追加していこうと思うと、もっと効率のよい衝突判定を考えなくてはならない。


複雑な形状の衝突判定は、基本形状を組み合わせて行う。基本形状を10個組み合わせていたら、10倍の処理時間がかかるということだ。
だから、その全体を覆うような基本形状を用意して、まずはそれとの判定を行って、当たっていたら「衝突の可能性あり」として詳細な判定をする。
オブジェクトの形状が複雑であればあるほど、数が多くなればなるほど、それから回転したりするようになると詳細判定負荷が増えるから、この基本形状をコンパクトにまとめることが重要になる。
基本形状を回転させた矩形にしたり、円にしたりするのもありだ。このあたりはどのようなオブジェクトの判定をするのか、どのぐらい動かすのか、などによって最適解が変わってくるから、結局は作るものにあわせて自分でコードを書くのが望ましい。が、Rubyで書いたら遅いからCで、となると妙に敷居が高くなる。
拡張ライブラリとして提供するにも限界はあるので、Rubyで書くよりは速いけど最適解にはならない、みたいなものに落ち着くことになる。


大量のオブジェクトの衝突判定を行う場合、総当りの判定をする前に、絶対に当たらない判定を除外する、という処理をしておくのも効果がある。
例えば敵100匹、自分の弾100個の判定をすると、総当りで10000回の比較を行うことになるが、事前に画面の左右にわけてどっちに含まれるかを調べておくことで、判定負荷を50*50*2+α=5000+α(αは調べる負荷)で半分ちょいまで減らせる可能性がある。
全部のオブジェクトが右半分に集中していると単純にαが増えるだけになってしまうし、真ん中のラインをまたがるオブジェクトは両方で判定しないといけないから、うまいこと画面全体に分散している必要はある。
この分割処理については昔から色々と考えられていて、効率のよい分割手法があるので、そういうのを勉強したほうがよい。
また、自分1機に対して敵の弾との判定をする場合は分割する処理そのものが無駄だから、色んなパターンを考えておく必要もある。


と、あれこれ考えてみたが、現状Rubyで作るゲームでそこまで高度な衝突判定が必要かというと、そんなことも無いんかな、と思う部分もある。
大量のオブジェクトを動かそうとするとRubyの動作速度そのものがネックになるし、複雑な形状で判定しようと思うとそれを加工するツールが必要になり、そういうものを作るレベルのゲームであればRubyで個人がちょっと作る、とかではないだろうから。
なので、高度な判定処理を実際に作るかと聞かれると、まだ考えるだけでほんとに作ったりはしないんじゃないかとおもう。