🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
DXライブラリ

DXライブラリとは、DirectXを使ったWindowsソフトの開発に必ず付いて回るDirectXやWindows関連のプログラムを使い易くまとめた形で利用できるようにしたC++言語用のゲームライブラリです。

Q&A

解決済

2回答

1150閲覧

ベクトルの外積を使ったすり抜け補正のコードのプログラム上でのコーディング法が知りたい。

退会済みユーザー

退会済みユーザー

総合スコア0

DXライブラリ

DXライブラリとは、DirectXを使ったWindowsソフトの開発に必ず付いて回るDirectXやWindows関連のプログラムを使い易くまとめた形で利用できるようにしたC++言語用のゲームライブラリです。

0グッド

1クリップ

投稿2019/12/09 10:07

編集2019/12/10 15:49

四角で縦横64,64px同士の当たり判定で100動いた時にすり抜けしまうバグを修正するためにベクトルの外積を使って回避するコードを組みたいです。困っているのは
1、ブロック(64,64)の座標をどうやって手に入れるか?

2、参考サイトの真ん中より下の方のスライドの[4っの端点に対して、線分のどちら側にあるのかを判定すればいい]スライド部の
ベクトル外積を計算して掛け算していますがこれを "プログラム上"でどうすればいいかわかりません。
(AB×AC)*(AB× AD) <= 0.0 &&
(CD×CA)*(CD× CB) <= 0.0

3、止まっている物体とプレイヤーの場合止まっている物体のベクトルの向きはどの向きにすればいいのか?
この場合はc Dの点線分ベクトルがブロックの場合は?

4、提示コードは調べて出てきたものなのですがこれはスライドの計算をプログラム上で計算していると思われるのですがなぜ真ん中で足し算しているのでしょうか?外積のクロス式を見ると - していますが(スライド上部)

追記 提示コードのネットから拾った版と自作版とで少し処理の書き方違うのですがこれはなぜでしょうか?
また自分が作った自作版の処理は正しいのでしょうか?

参考サイト: http://www.zengeren.com/content/data/05/05_2DCollision.pdf

イメージ説明

using System; namespace ConsoleApp3 { class Program { class Position { public float x; public float y; public Position(float xx = 0.0f,float yy = 0.0f) { x = xx; y = yy; } } //ネットから拾った。 static bool vec_test(float ax,float ay,float bx,float by,float cx,float cy,float dx,float dy) { var ta = (cx - dx) * (ay - cy) + (cy - dy) * (cx - ax); var tb = (cx - dx) * (by - cy) + (cy - dy) * (cx - bx); var tc = (ax - bx) * (cy - ay) + (ay - by) * (ax - cx); var td = (ax - bx) * (dy - ay) + (ay - by) * (ax - dx); Console.WriteLine("a: " + tc * td); Console.WriteLine("b: " + ta * tb); if(tc * td <= 0.0f && ta * tb <= 0.0f) { return true; } else { return false; } } /*自作版*/ /*高速の当たり判定に対応した版*/ static bool cross_col(Position A,Position B,Position C,Position D) { Position AB,AC,AD,CA,CD,CB; AB = new Position(); AC = new Position(); AD = new Position(); CA = new Position(); CD = new Position(); CB = new Position(); /*線分を作る*/ AB.x = B.x - A.x; AB.y = B.y - A.y; AC.x = C.x - A.x; AC.y = C.y - A.y; AD.x = D.x - A.x; AD.y = D.y - A.y; CA.x = A.x - C.x; CA.y = A.y - C.y; CD.x = D.x - C.x; CD.y = D.y - C.y; CB.x = B.x - C.x; CB.y = B.y - C.y; /*ベクトル外積の公式 (A x B) = x0 * y1 - x1 * y0 */ float AB_AC = (AB.x * AC.y) - (AC.x * AB.y); float AB_AD = (AB.x * AD.y) - (AD.x * AB.y); float CD_CA = (CD.x * CA.y) - (CA.x * CD.y); float CD_CB = (CD.x * CB.y) - (CB.x * CD.y); float a = AB_AC * AB_AD; float b = CD_CA * CD_CB; Console.WriteLine("a: " + a); Console.WriteLine("b: " + b); if(a <= 0.0 != b <= 0.0) { return true; }else{ return false; } } static void Main(string[] args) { Position a = new Position(); Position b = new Position(); Position c = new Position(); Position d = new Position(); Console.Write("a.x: "); a.x = int.Parse(Console.ReadLine()); Console.Write("a.y: "); a.y = int.Parse(Console.ReadLine()); Console.WriteLine(); Console.Write("b.x: "); b.x = int.Parse(Console.ReadLine()); Console.Write("b.y: "); b.y = int.Parse(Console.ReadLine()); Console.WriteLine(); Console.Write("c.x: "); c.x = int.Parse(Console.ReadLine()); Console.Write("c.y: "); c.y = int.Parse(Console.ReadLine()); Console.WriteLine(); Console.Write("d.x: "); d.x = int.Parse(Console.ReadLine()); Console.Write("d.y: "); d.y = int.Parse(Console.ReadLine()); Console.WriteLine(); if(cross_col(a,b,c,d) == true) { Console.WriteLine("交差します。!"); }else{ Console.WriteLine("交差していません"); } Console.WriteLine(); Console.WriteLine(); Console.WriteLine("以下ネットのコピペ版"); if(vec_test(a.x,a.y,b.x,b.y,c.x,c.y,d.x,d.y) == true) { Console.WriteLine("交差しています。"); } else { Console.WriteLine("交差しています。"); } } } }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2019/12/10 02:48

参考先はページ数が多いですが…そのうちのどこを参考にするのでしょうか. あなたが今どんな判定をしようとしていて,それに対して何と何の外積をどう使えばよいと考えているのか,という内容を質問に明記してはどうでしょうか.(必要ならば図を用いて説明する等しないと伝わらないように思います)
退会済みユーザー

退会済みユーザー

2019/12/10 03:26

文章を編集しました。
guest

回答2

0

ベストアンサー

1、ブロック(64,64)の座標をどうやって手に入れるか?

配列インデックスに64を乗算しましょう。

//map[x][y]の場合 int x1 = x * 64; int y1 = y * 64; int w = x1 + 64; int h = y1 + 64;

2、参考サイトの真ん中より下の方のスライドの[4っの端点に対して、線分のどちら側にあるのかを判定すればいい]スライド部の

ベクトル外積を計算して掛け算していますがこれを "プログラム上"でどうすればいいかわかりません。
(AB×AC)*(AB× AD) <= 0.0 &&
(CD×CA)*(CD× CB) <= 0.0

線分同士の交差判定は最低でも 高校で習うベクトルをきちんとと理解することが最低条件になります。参考サイトでは重要な部分はすべて省いていますね。
この説明では、いくら読んでも私でも分からない。

3、止まっている物体とプレイヤーの場合止まっている物体のベクトルの向きはどの向きにすればいいのか?

この場合はc Dの点線分ベクトルがブロックの場合は?

そもそも、停止している物体にベクトルはありません。
線分があるとすれば、物体の各四方の位置からの線分になります。

4、提示コードは調べて出てきたものなのですがこれはスライドの計算をプログラム上で計算していると思われるのですがなぜ真ん中で足し算しているのでしょうか?外積のクロス式を見ると - していますが(スライド上部)

これに関しては私も分かりません。そもそもABCDの関係性も曖昧でコメントもないので一切分からない。

追記 提示コードのネットから拾った版と自作版とで少し処理の書き方違うのですがこれはなぜでしょうか?

また自分が作った自作版の処理は正しいのでしょうか?

それはデバックしてみましょう。
きっと正解の方が壁に衝突した時にTrueが返ってきます。
私の予想ではどちらもFalseが返ってきます。

投稿2019/12/11 00:04

stdio

総合スコア3307

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/12/11 00:40

いえtrueが両方返ってきたのですがどっちを使えば良いのでしょうか?
stdio

2019/12/11 05:40

問題が発生した時に修正しやすい観点からみると、自作のを残すべきかな?
退会済みユーザー

退会済みユーザー

2019/12/11 05:58 編集

これって自作版の方がいいのでしょうか?ネットから拾ってきたコードでは少し式を変えてあるようにみえるのですが?
stdio

2019/12/11 05:52 編集

「少し」どころではありません。減算の左辺と右辺が違う、加算と減算が違うのは答えが全く違います。 まず、その式がなぜ動いているのか証明が出来ません。 確かに動けばいいという世界ではありますが、今は都合よく動いているだけの可能性が最も高いので、そのようなコードは残すべきではないです。 記念として残しておきたいなら、ブランチを切りましょう。
退会済みユーザー

退会済みユーザー

2019/12/11 07:09 編集

質問ですがA(10,20),B(20,40),C(3,15),D(5,40)の衝突計算をすると自作版はfalseでネットからコピペ版はもfalseが返ってきます。これはどちらが正しいのでしょうか?紙の上で座標系を書いて交差している座標を自分で書いたのですが..
stdio

2019/12/11 06:11 編集

エクセルで図ってみましたがfalseですね。 自分で図るなら、方眼紙かエクセルが良いよ。 線分の交差判定は逆ベクトルの可能性も考慮しないといけないので、想像以上に難しいですよ。 私でもカプセルの衝突判定に線分の交差判定が必要でしたが、余裕で200行超えた記憶があります。
退会済みユーザー

退会済みユーザー

2019/12/11 10:04 編集

ゲーム場合だと点と点を線分とする計算と始点とベクトルどっちなのでしょうか?
stdio

2019/12/17 01:28

点と点を線分とする計算..... それなら円形の衝突判定でいいような気がします。 それにゲーム画面を見ていると、2DのAABB同士の衝突判定だけで出来たはずです。 私も作成経験があるので分かりますが、線分の交差判定なんて使わなくても出来ます。 私の場合、線分の交差判定を使用したのは3Dになってからですね... それにファミコン版の初代マリオもそこまで衝突判定をそこまでしっかり作りこんでいる訳ではないです。実際にステージ1-2にて壁にめり込むバグが報告されています。
guest

0

1回の移動量が大きい場合にも通用する判定方法として
線分同士の交差判定を使用することを考えているわけですね.
で,

3、

とは,
「線分」とは,実際は何と何なのか? ということでしょうか.

これはあなたがキャラクタの当たり判定というのをどのように扱っているのか次第だけども……
ここでは「判定の形状は四角形で,しかも,当たり判定の処理としてはその四角形の4つ角だけ考えれば何とかなる世界」を考えてみます.

キャラクタ(の当たり判定形状たる四角形)の4つ角に関して,それぞれ,
移動前の位置 と 移動先の位置 を結ぶ線分
を考えることができます.
これが「何と」交差する場合に,そのまま移動先にキャラクタを移動させてはまずいのだろうか?
…ということを考えれば,それは「ブロックの辺」でしょう.

キャラクタの移動方向が右下方向であれば,ブロックの上辺と左辺という2本の線分と,前記した角の移動量を表す線分とが交差しないかどうかをチェックする必要がありそうです.
もし交差するなら,その角の移動先はその交点位置までに制限してやる必要があるわけですが,角は4つあるので,それらの「衝突時刻(移動前の位置から交点までの距離かな)」を考えて,その中で最も(時間的に)早く衝突するやつに基づいて移動先を修正することになるでしょう.

投稿2019/12/10 04:57

編集2019/12/10 04:59
fana

総合スコア11985

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/12/11 08:07 編集

画像のようにとりえず右に200くらい動くとします。その場合ブロックはc,d点との線分を算出して計算すればいいのでしょうか?もちろんプレイヤーのa,b点なので線分にしますが? また逆ベクトルの場合は処理が異なるとありますがこれはなんの場合でしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問