テレワークならECナビ Yahoo 楽天 LINEがデータ消費ゼロで月額500円〜!
無料ホームページ 無料のクレジットカード 海外格安航空券 海外旅行保険が無料! 海外ホテル


log

2010.09.21 C++:とってもやさしい壁沿い移動の解説?


ひさしぶりの投稿ですじゃ。

最近めっきりと日記を書く機会が減っておりましたが、ここ1ヶ月くらいは
プログラムの方を進めてました。え?そんな変わってないって?苦笑

具体的には壁沿い移動、パーティ歩き、それと新しくキャラクターの
位置にスプライトを表示できるようにしてみました!
実質的には壁沿い移動にほとんど時間がかかってしまいましたね…。
ようやく壁抜けしない壁沿い移動を実装できて、色々と反省するべき点が
多かったので以下に少しまとめてみたいと思います。

まず壁沿い移動の実装を考えてみたときに、大抵の方が
真っ先に思い浮かぶのが、
0.壁との内外判定で衝突判定テスト
1.衝突予定の壁と移動線分を順番に衝突判定
2.1で衝突した壁で壁沿い移動
3.壁の範囲を超えていたら補正
だと思うのですが。ここでこのまま思いついた通りにプログラムを組んで、
for(衝突予定リストを順番に) {
if(衝突している) {壁沿い移動;break;}
}
としてしまった場合、なんと。壁抜けが発生してしまうんですねえ;

ここで問題になるのが2の線分と線分の衝突判定での精度の
問題でして。この衝突判定、ちょうど線分の頂点で衝突していた
場合、衝突していないとして返される可能性が高いのです。
つまり、壁の辺の間でぐりぐりと移動していると衝突していると
判断されるべきが衝突してないよウフフ、として判定されるために
壁抜けしてしまいます。

じゃあどうすればいいかと色々と考えてみましたが。このままだと
どうしようも無いので第3者の情報を借りてきてそれと比較することで
解決することにしました。具体的には、現在壁の実装方法は
地面のポリゴンが存在していない部分については壁という風に
実装しているのですが。。この地面の情報を元に、自身の
真下の地面のポリゴンの3辺とまず一度内外判定を行い、
2辺以上外に判定された辺が存在する、且つ1辺が壁の場合は
強制的に2辺で共有する頂点位置に設定することで無事
解決できるようになりました。(他にも色々と条件分岐が複雑
なのですが、ここでは面倒臭いので抜きにします苦笑)

それにしても、これにたどり着くまでに大分試行錯誤してしまいました。
途中「floatからdoubleにすると精度上がって直るかな?」なんて
考えたりもしましたが、現在既にほとんどの関数でfloatによる実装を
してしまっていて変更がとんでもなく大変な上に根本的な解決に
ならないと思うので。とりあえずやる前に解決できてよかったのでした笑。

comment

たけなか 2010.09.21-23:15 Edit

最近、プログラムと平行して息抜き程度にアセンブリの勉強をしてますが。
VC2008の最適化オプションをちゃんと設定するとcos,sqrtや
キャストといった処理は自前で最適化するより2~10倍程度早いですね。。

ただ、なぜかD3DX算術関数と自作の計算簡略化関数で
速度比較を行っていて、自作の方はなぜか速度0になるなあと
思ってたら。どうやらループ内で同じ代入を行った場合は自作の方は
ループが省かれるぽいです(逆アセしたことないからなんとも
いえませんが)。で、代入ではなく加算処理にしてみると
やはりD3DX算術関数の方が2~5倍程度早かったです。
D3DX算術関数だけなぜ等価の代入ループの省略をしなかったのか
については少し疑問でしたが、おそらくDLLからの外部クラスに
ついては既に処理が決まっているのでそれ以上最適化しようが
ないということなんだと思います。

結果としてなんだか自前で最適化する必要が無いというより、
自前で最適化する余地が無い感じの結果でした苦笑。VC優秀だなあ。