ページ 11

オブジェクト同士の当たり判定 とあるケースの場合

Posted: 2013年6月05日(水) 12:46
by 土門
質問させて下さい。
単純なシューティングのオブジェクト同士の当たり判定においては
お互いの座標位置から判定if( (ax1<bx2) && (bx1<ax2) && (ay1<by2) && (by1<ay2) )し、
trueなら重なってるとみなし、消滅させるなどの衝突処理を書けば済む、じゃないですか。

でも、もしあれを単純な衝突処理では無く、
ただ「合わさることが出来ないオブジェクト」ってだけ場合は
とたんに四面分の処理を書くめんどうな判定処理をを書くことになりますか?

というのも、その移動しているオブジェクトに対して
プレイヤーが下から当たった場合はプレイヤーを下側に戻す処理を施して描画、
プレイヤーが右から当たった場合はプレイヤーを左に戻す処理を施して描画、になりますよね?
ということは、単純に画像同士がぶつかればひとつの処理を施す、では済まなくて、
上下左右からの衝突のケースを書いて処理する必要出てくるはずです。

そういうケースの判定プログラム(お互いが重なれないケース)については
自分はマップの当たり判定の情報が入っている二次元配列に対して
プレイヤーが重なることが出来ないように処理するプログラムはすでに書いています。
単純では無く、四面分の処理を書いているので結構長いプログラムです。
しかし、XY座標が可変であるオブジェクトに対してもそれを流用する形になりそうですが
相手の座標と画像幅、そして自分の座標と画像幅だけで
「合わさることが出来ないだけのオブジェクト判定」のプログラムって書けませんか?

Re: オブジェクト同士の当たり判定 とあるケースの場合

Posted: 2013年6月05日(水) 13:07
by h2so5
衝突前の座標を記録しておけば上下左右で分けなくても元に戻せると思います。

もっと言うと、移動して衝突してしまったらもとに戻すのではなくて、
移動前に移動先の座標で衝突するかどうか判定するのがスマートだと思います。

Re: オブジェクト同士の当たり判定 とあるケースの場合

Posted: 2013年6月05日(水) 13:17
by 土門
>もっと言うと、移動して衝突してしまったらもとに戻すのではなくて、
>移動前に移動先の座標で衝突するかどうか判定するのがスマートだと思います。[/quote]

回答ありがとうございます。
すみません、自分はまだ経験の浅い初心者であるので
移動前を記憶しておくとか、移動前に移動先の座標で判定、といった
処理は想像だにしませんでした。なるほどです。
ただ、たぶんそういうややこしい処理はまだ自分には無理なんで
こちらで質問させて頂きました。

もっと単純なプログラムでは無理でしょうか?

Re: オブジェクト同士の当たり判定 とあるケースの場合

Posted: 2013年6月05日(水) 13:28
by softya(ソフト屋)
どれが一番単純に成るかと言うと、当たり判定をして衝突したら移動を取り消すのが最終的にシンプルになります。
それ以外の方法で書くと返って無駄に難しいプログラムになると思います。
 → つまりバグを取りづらいプログラムが出来上がります。

Re: オブジェクト同士の当たり判定 とあるケースの場合

Posted: 2013年6月05日(水) 13:44
by 土門
お世話になっております。

>当たり判定をして衝突したら移動を取り消すのが最終的にシンプルになります。

確かにシンプルそうです。
つまり、自分の質問に書いたSTGにおいての衝突判定の定石
座標を用いた矩形衝突判定をしておいて、
重なった時の処理が、「移動を取り消す」にするってことですよね?
移動を取り消す、というのは「進んだ分だけ引く」ということでしょうか?
この場合は、あくまでプレイヤーをもとの位置に戻すわけですから
四面の各面に対する処理は書く必要がない、
逆にいうと単純になるが「下から接触した場合はこの処理」
などといったことは出来ない、そういうの度外視の簡潔なプログラム
ってことですよね?

Re: オブジェクト同士の当たり判定 とあるケースの場合

Posted: 2013年6月05日(水) 13:52
by softya(ソフト屋)
そういえば、反射するんでしたっけ? そうなると話は取り消し法では問題が出るかもしれません。 取り消し法は h2so5 さんの書かれた方法です。

>単純では無く、四面分の処理を書いているので結構長いプログラムです。
>しかし、XY座標が可変であるオブジェクトに対してもそれを流用する形になりそうですが相手の座標と画像幅、そして自分の座標と画像幅だけで

これに関しては、構造体やら関数化やらを徹底すれば素晴らしくコンパクトなコードにすることが出来ます。
つまり、コードの共通化が不徹底な状態なのだと思います。

Re: オブジェクト同士の当たり判定 とあるケースの場合

Posted: 2013年6月05日(水) 13:57
by usao
・斜めに動く際に,X座標とY座標について独立に扱いたい
とか
・一定距離進もうとしたとき,進行方向に障害物がある場合は障害物に密着する場所までは移動させたい
とか
・鏡面反射したように動かしたい
とか…
「衝突する(した)」となったときに具体的にどうしたいのか? によってそこらへんは変わってくると思います.

・衝突の方向や深さ(重なり具合,とでもいうか)によらず
単純に移動そのものをキャンセル(なかったことにする=移動前の座標に戻す)
ということをしたいだけなのであれば
>移動前に移動先の座標で衝突するかどうか判定する
のが最もややこしいことが起きない単純な方法だと思います.
要するにこれ↓だけなので.

コード:

仮移動先座標=現在座標+移動量;
if( !仮移動先座標が他の物と衝突する )
{
    現在座標=仮移動先座標;
}
else
{
    //現在座標を更新しない.
    //どっち方向からどう衝突したか とかは全く考慮しない
}

Re: オブジェクト同士の当たり判定 とあるケースの場合

Posted: 2013年6月05日(水) 15:50
by 土門
やりたいことは単純で、移動中のプレイヤーに対して
そのオブジェクトは障害物として存在させたいだけです。
今は「ぶつかった反対側にプレイヤーを戻す」ということしか出来ておりません。

ただ、皆さんの回答をもとに、今しがた

>衝突前の座標を記録しておけば

を実装してみたところ、
なんとも簡単に、やりたいことが実装出来ました。

posx,posyとは別に毎度それぞれの値を移動する前に格納する変数(仮にQposx,Qposyとする)を作っておき、
相手オブジェクトとの接触判定が真だとなれば、
プレイヤーの移動フラグをストップ、posx,posyへQposx,QposYの値を代入。
そうしただけです。
すごく簡単でした。
こんな感じで問題無いですか?

このプログラムの弊害があるとするならば、
やはり、対象のオブジェクトの下側からの接触の場合にはこの処理、
などといったオブジェクトの四面に関した詳細な処理には向いてない、ということでよろしいでしょうか?

Re: オブジェクト同士の当たり判定 とあるケースの場合

Posted: 2013年6月05日(水) 16:25
by usao
要は,
「プレイヤーが障害物の方向に移動しようとしてもできない
 =結果として,プレイヤーの位置が変わらない」
が達成されればよいのだ,という話なのであれば,それで問題ないのではないでしょうか.

で,そのようなプレイヤー移動処理仕様 なのであれば,
>下側からの接触の場合の処理
とかいう処理(の内容)は,プレイヤの移動処理方法とは全く関わりの無い内容なハズなので,
「障害物の衝突判定処理の方法」というか「衝突判定処理がどれだけ詳細な情報を返してくるか?」という側の話かと思います.
多分,多くの場合で,
「障害物があって動けなかった」ということだけがわかっていれば,
(例えば,プレイヤの移動処理を行う関数の戻り値でこの情報を返すとかすれば)
あとは,プレイヤーが動こうとした方向がそのまま接触方向として使えると思います.
「プレイヤキャラクタが側面を障害物にこするように接触」 とかいう場合だとそうもいかないでしょうけど.

Re: オブジェクト同士の当たり判定 とあるケースの場合

Posted: 2013年6月05日(水) 16:44
by 土門
>プレイヤーが動こうとした方向がそのまま接触方向

なるほど!対象の当った面を割り出さずとも、
プレイヤーの移動方向、ないしは状態(落ちている状態とか)で
接触方向を判断することが可能ですね!
なんか成長出来ました、
皆様、どうもありがとうございます。