HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2020
0617
win傾斜の衝突判定13解決


win

リンク

2020/6/17(Wed) 20:34:26|NO.90799

みなさまはどうやってるのでしょう?
45度角だとy=xなどを利用するのでしょうか?
ぐぐってみると外積を使うやり方をよく目にします。



この記事に返信する


GENKI

リンク

2020/6/17(Wed) 21:33:19|NO.90800

やり方は色々あります。外積もひとつですが、ObaQだったりpgetだったり用途によって丁度いい方法は異なります。
どんな用途を想定していますか?

ちなみに私は最近自作したものをモジュールにまとめました。
https://mclab.uunyan.com/dl/dl50.htm



Slasher

リンク

2020/6/17(Wed) 23:57:38|NO.90801

初めまして。Slasherと申します。
当方は現在とあるゲーム制作中で、この手の問題に直面中です。

私の場合、大抵は双方を真円と看做した衝突検出を活用しています。
自:座(x1,y1)半径:r1
敵:座(x2,y2)半径:r2
dx = abs( x1 - x2 ) dy = abs( y1 - y2 )
a1 = int(sqrt( dx*dx + dy*dy ))
a2 = r1 + r2 -1

if a1 <= a2 ---> HIT

尚、横長や縦長な物体は、衝突検出範囲を複数用意し、直線状に並べ、ループで順次判定させています。

複雑な形状の場合は・・・そうですね。
様々なサイズの真円検出範囲を用意し、その形状内に埋め尽くす、でしょうか。
私は今まさにこれからそれを実践、検証しようとしている所です。

>GENKIさん
素晴らしいモジュールですね!
後程詳しく検分させて頂きます!



win

リンク

2020/6/18(Thu) 21:05:29|NO.90809

用途は定番の横スクロールアクションです。
意外とy=xの関係式を利用したレクチャーサイトってなくて内積や外積を利用したものばかりです。
内積を使う場合は逆余弦必須なんでしょうか?



Slasher

リンク

2020/6/18(Thu) 21:51:30|NO.90811

大変失礼致しました。
傾斜の意味を知らずに書き込んでしまいました。
どうか先の私の発言は無視して下さい・・・



あらや

リンク

2020/6/19(Fri) 00:13:41|NO.90813

>y=xの関係式を利用したレクチャーサイトってなくて
どういう形で傾斜と判定をしたいのかがわかりませんが(坂道を上るか下るかでしょうか?)
y=xは『直線』の式なので、
始点と終点が決まっている『線分』と衝突判定するのは
場合によっては逆に複雑になる可能性があるからではないでしょうか。

内積や外積は一見難しく思えますし、理屈も途中計算も少々難しいのですが
最終的な計算は意外と単純化されます。

簡単な例として、点が直線の左右どちらかにあるか判定するソースです。

#module // 点(x0, y0)と線分(始点(x1, y1) 終点(x2, y2))の外積を返す #defcfunc outerPointToLine double x0, double y0, double x1, double y1, double x2, double y2 drc = 0.0; drc = (y2 - y1)*(x2 - x0) - (x2 - x1)*(y2 - y0); // 外積の計算 if( absf(drc) < 0.0001 ): drc = 0.0; // 誤差レベルの数値はゼロにする return drc; #global // 以下サンプル(マウスが斜線の左右どちらにあるか判定) *main redraw 0; color 0, 0, 0: boxf; color 255, 255, 255: line 320, 20, 480, 240; pos 320, 0: mes "斜線の始点"; pos 400, 240: mes "斜線の終点"; op = outerPointToLine( mousex, mousey, 320, 20, 480, 240 ); // マウス座標と斜線の外積を取得 pos 0, 0: color 255, 255, 255; if( op > 0.0 ) { mes "外積がプラス(斜線の右側)"; } else:if( op == 0.0 ) { mes "外積がゼロ(斜線上にマウスがある)"; } else { mes "外積がマイナス(斜線の左側)"; } redraw 1; await 17; goto *main;
これは直線との判定なので、終点よりも下の方でも左右の判定をされてしまいますが
これを応用して、線分同士の交差判定をすることも出来ます。

#module // 点(x0, y0)と線分(始点(x1, y1) 終点(x2, y2))の外積を返す #defcfunc outerPointToLine double x0, double y0, double x1, double y1, double x2, double y2 drc = 0.0; drc = (y2 - y1)*(x2 - x0) - (x2 - x1)*(y2 - y0); // 外積の計算 if( absf(drc) < 0.0001 ): drc = 0.0; // 誤差レベルの数値はゼロにする return drc; // 線分1(始点(x0, y0) 終点(x1, y1))と線分2(始点(x2, y2) 終点(x3, y3))の交差チェック #defcfunc crossCheck double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3 drc1 = outerPointToLine( x0, y0, x2, y2, x3, y3 ); drc2 = outerPointToLine( x1, y1, x2, y2, x3, y3 ); // 線分1の始点と終点が両方線分2の片側にある場合は交差していない if( ((drc1 > 0.0) && (drc2 > 0.0)) || ((drc1 < 0.0) && (drc2 < 0.0)) ) { return 0; } else { drc1 = outerPointToLine( x2, y2, x0, y0, x1, y1 ); drc2 = outerPointToLine( x3, y3, x0, y0, x1, y1 ); // 線分2の始点と終点が両方線分1の片側にある場合は交差していない if( ((drc1 > 0.0) && (drc2 > 0.0)) || ((drc1 < 0.0) && (drc2 < 0.0)) ) { return 0; } } return 1; // 上記の判定に引っかからなかった場合は交差している #global // 以下サンプル(四角形と斜線の交差判定) *main redraw 0; color 0, 0, 0: boxf; color 255, 255, 255: line 320, 20, 480, 240; pos 320, 0: mes "斜線の始点"; pos 400, 240: mes "斜線の終点"; boxf mousex-10, mousey-10, mousex+10, mousey+10; // 自機(仮) // 自機の各辺と斜線の交差確認 cp1 = crossCheck( mousex-10, mousey-10, mousex+10, mousey-10, 320, 20, 480, 240 ); cp2 = crossCheck( mousex+10, mousey-10, mousex+10, mousey+10, 320, 20, 480, 240 ); cp3 = crossCheck( mousex+10, mousey+10, mousex-10, mousey+10, 320, 20, 480, 240 ); cp4 = crossCheck( mousex-10, mousey+10, mousex-10, mousey-10, 320, 20, 480, 240 ); pos 0, 0; // 全ての辺が交差していなければ、衝突していない if( (cp1 == 0) && (cp2 == 0) && (cp3 == 0) && (cp4 == 0) ) { color 255, 255, 255; mes "衝突していない"; } else { color 255, 0, 0; mes "衝突している"; } redraw 1; await 17; goto *main;
あきらかに解説不足な気がしますが、
このような手法はいかがでしょうか。



win

リンク

2020/6/19(Fri) 03:32:37|NO.90814

あらやさん、ありがとうございます。
点と線分の外積は点のほうもベクトル化するわけですか?
別名クロス積といわれる妙な法則ですよね。


GENKIさん、モジュールはありがたいのですが私は外積の原理が知りたいので・・



あらや

リンク

2020/6/19(Fri) 10:19:33|NO.90815

>点と線分の外積は点のほうもベクトル化するわけですか?
その通りです。

>別名クロス積といわれる妙な法則ですよね。
ほとんどの場合、外積と言えばクロス積ですね。

外積は基本的に3Dでよく使われる計算方法で
法線ベクトルを求めるのに便利だったりします。

法線ベクトルが求められると、
3Dの衝突判定や、いわゆる壁ずり移動の向きが求めやすくなるなど
ほかにも色々と利点があるんですが
ここではあまり関係が無いので省略させていただきます。



軽く前述のソースを解説させていただくために前提知識として
3次元上での2つのベクトルをそれぞれベクトルA、ベクトルBとした場合

ベクトルAの(X,Y,Z)成分を(Ax,Ay,Az)
同じくベクトルBの成分を(Bx,By,Bz)とします。

AとBの外積は
X成分 = Ay*Bz - By*Az
Y成分 = Az*Bx - Bz*Ax
Z成分 = Ax*By - Bx*Ay

という公式で求められます。

ここで2Dに戻って
線をベクトルA、点から線の終点までをベクトルBとした場合
Z成分はどちらも0なので、外積を求めると

X成分 = Ay*0 - By*0 = 0
Y成分 = 0*Bx - 0*Ax = 0

このようにXとY成分は0になり
残ったZ成分を求めるだけで済むことになります。

Z成分 = Ax*By - Bx*Ay

ソースないの変数を代入すると

Axは(x2 - x1)
Ayは(y2 - y1)
Bxは(x2 - x0)
Byは(y2 - y0)

なので

Z成分 = (x2 - x1)*(y2 - y0) - (x2 - x0)*(y2 - y1)

となります。
つまりZ成分がプラスかマイナスかで
点が線の左右どちらにあるのかがわかるという
まさに妙な法則になっているわけです。

ちなみにソースでは順番が違いますが、
単純に私が線の右側をプラス、左側をマイナスにしたかったから
入れ替えただけです。



GENKI

リンク

2020/6/19(Fri) 21:20:35|NO.90816

> GENKIさん、モジュールはありがたいのですが私は外積の原理が知りたいので・・

おっとそうでしたか。

外積の原理っていっても数学の教科書の話ではなく、衝突判定への応用の仕組みですよね。
1個のベクトルと1点を比較したとき、外積を使えば点がベクトルの右側にあるのか左側にあるのかがわかります。(…と、あらやさんも書いてますね。)
基本的にはこの性質を利用して判定します。

例:三角形(または四角形)と点の衝突判定(点が内側にあるかどうか調べる)
判定方法
1.辺をそれぞれ全てベクトルと考える
2.ベクトルは左回り方向に並んでいるとする
3.点が全てのベクトルで常に左側にあれば、点は三角形(または四角形)の内側にいる
それ以外なら点は外側にいる。

凸な多角形なら5角形以上でもこの手法が使えます。
↓このサイトが図入りでわかりやすいと思います。(昔見てたサイトが見つからない…)
https://ksta.skr.jp/topic/diaryb09.html



win

リンク

2020/6/19(Fri) 22:20:22|NO.90817

あらやさん、GENKIさんありがとうございます。
もうひとつ気になるのが内積のやり方なんですが逆余弦関数を使うのかどうか
わからないでしょうか?



あらや

リンク

2020/6/19(Fri) 22:54:07|NO.90818

>もうひとつ気になるのが内積のやり方なんですが逆余弦関数を使うのかどうか
座標やベクトルの成分が分かっている場合は不要です。

内積を計算するときはcos(余弦)を使うのが下記のように公式となっていますが

ベクトルA × ベクトルB × cosθ(θはベクトルABの間の角度)

角度がわからない場合は逆余弦で角度を求めてから
あらためて公式に当てはめて。。。という流れをイメージしているかもしれませんが、
座標や成分が分かっている場合はもっと簡略化されます。

座標で求める場合を例にさせていただくと

ベクトルAの始点を(Ax1,Ay1)、終点を(Ax2,Ay2)とした場合
ベクトルAの成分は終点マイナス始点で求められるので

AのX成分 = (Ax2-Ax1)
AのY成分 = (Ay2-Ay1)

同じくベクトルBの成分も

BのX成分 = (Bx2-Bx1)
BのY成分 = (By2-By1)

このように座標から成分を求められます。

そして成分から内積を求める公式として

ベクトルABの内積 = AのX成分*BのX成分 + AのY成分*BのY成分

というものがあります。
この公式は加法定理を使って求められるのですが、
これ以上長くなる話は置いておいて。

この公式に先程求めた成分を当てはめると

ベクトルABの内積 = (Ax2-Ax1)*(Bx2-Bx1) + (Ay2-Ay1)*(By2-By1)

このように座標の足し算、引き算、掛け算だけで内積を求めることが出来ます。

この内積の公式に関しては数学関係のサイトを調べると
いくつも出て来ると思うのでそちらを参考にしてください。



win

リンク

2020/6/20(Sat) 21:21:50|NO.90823

あらやさん、ありがとうございます。
私が考えているものは
cosθ = ( AとBの内積 ) / (Aの長さ * Bの長さ)でこの値をacosに渡して角度の比較をするものです。
でも、どうやら傾斜の判定は外積の利用が普通なようですね。



あらや

リンク

2020/6/20(Sat) 22:29:37|NO.90824

>cosθ = ( AとBの内積 ) / (Aの長さ * Bの長さ)でこの値をacosに渡して角度の比較をするものです。
なるほど、失礼いたしました。

角度の取得と比較だけならば内積、外積を使わずに
座標を使ってatanで取得した方が早い気もしますが、
衝突判定をするならばやはり外積を使った方が(理屈以外は)簡易かと思います。

横スクロールアクションという事なので
座標で、このからここまではθ°の傾斜がある、
という条件式を入れても良いかもしれませんが。。。
まあこれは汎用性が無い方法なので、
マップごとに設定する必要がありますね。



win

リンク

2020/6/21(Sun) 21:22:36|NO.90828

あらやさん、本当に回答ありがとうございました。
この手の手法はまたいろいろ試してみたいと思います。



ONION software Copyright 1997-2023(c) All rights reserved.