ページ 11

ブロックと敵の衝突判定

Posted: 2013年6月30日(日) 20:46
by ヨシタケ
以前にも書き込みさせていただいた敵とブロックの衝突判定についてもう一度質問させていただきます。
以前は敵が1体だったので,妥協案ですませましたが,今回は複数配置を予定しています。
まず,敵が横に移動するものとして敵のブロックの当たる範囲(縦)を

コード:

					//敵がブロックにあたる範囲
					if(hitblocktop == -1 && ene[num].y -18>=block[k][i][j].hit.lt.y &&
						ene[num].y -18<=block[k][i][j].hit.rb.y){
						hitblocktop = i;
						break;
					}
					if(ene[num].y +15>=block[k][i][j].hit.lt.y &&
						ene[num].y +15<=block[k][i][j].hit.rb.y){
						hitblockbottom = i;
						break;
					}
というようにしました。
↓hitblocktop

□ ○←敵

↑hitblockbottom
というような感じです。
そして,ブロックと敵の衝突判定ですが,今敵のx座標がblock[k][j]の間にあるとき
左右(block[k][j-1],block[k][j+1])との衝突判定を行うように

コード:

					if(i>= hitblocktop && i<= hitblockbottom){
						if(block[k][i][j].flag == TRUE){
							if(ene[num].x>=block[k][i][j].hit.lt.x &&
								ene[num].x <=block[k][i][j].hit.rb.x){
								
								if((ene[num].spd <0 && 
									enehitblock.lt.x <= block[k][i-1][j].hit.rb.x)||
									(ene[num].spd > 0 &&
									enehitblock.rb.x >= block[k][j+1][j].hit.lt.x)){
											ene[num].spd *= -1;
												
								}
							}
						}
					}			
というようにしました。敵の速さがマイナスで敵のブロック用の当たり判定(四角)の左の辺が左のブロックの当たり判定の右の辺より小さい時,または,敵の速さがプラスで敵のブロック用の当たり判定(四角)の右の辺が右のブロックの当たり判定の左の辺より大きい時
速さがene[num].spd *= -1;となるようにしてあります。
しかし,敵がブロックに衝突しても移動方向を変えませんでした。
一応,ene[num].spd *= -1;のところにブレークポイントをおいてデバッグを行ったとき,止まったので
判定はされてるようです。

Re: ブロックと敵の衝突判定

Posted: 2013年7月01日(月) 11:16
by ヨシタケ
一応,下記のサイトにソースをアップしました。パスワードは「YT2013」です。

http://www1.axfc.net/uploader/so/2952367

敵の内容についてはenemy05.cppです。

Re: ブロックと敵の衝突判定

Posted: 2013年7月01日(月) 17:46
by ISLe
プロジェクトを見ていませんけど、複数のブロックに衝突したとき、-1*-1で変化しないのが原因だと思います。

後半のコードは、ブロックの判定が二重になっているだけで意味がないです。

ブロックに当たったらその場で方向を変えるのではなく、上下左右のどこに当たったかを記録しておいて、次に移動するとき変化する方向を決めるようにすれば良いかと思います。
この方法だとブロック個々に当たり判定するだけですから、範囲を調べる手間も不要です。

Re: ブロックと敵の衝突判定

Posted: 2013年7月01日(月) 22:44
by ヨシタケ
移動方向をenumを使い

コード:

typedef enum{
	up,
	down,
	left,
	right
}eMOVEDIRECTION;
というように追加し,
ブロックとの判定を

コード:

		for(int k=0;k<3;k++){
			for(int i=0;i<13;i++){
				for(int j=0;j<9;j++){
					//ブロックの各4辺(上,下,左,右)
					Line2D pt[4] = {{{block[k][i][j].hit.lt.x,block[k][i][j].hit.lt.y},{block[k][i][j].hit.rb.x,block[k][i][j].hit.lt.y}},
					{{block[k][i][j].hit.lt.x,block[k][i][j].hit.rb.y},{block[k][i][j].hit.rb.x,block[k][i][j].hit.rb.y}},
					{{block[k][i][j].hit.lt.x,block[k][i][j].hit.lt.y},{block[k][i][j].hit.lt.x,block[k][i][j].hit.rb.y}},
					{{block[k][i][j].hit.rb.x,block[k][i][j].hit.lt.y},{block[k][i][j].hit.rb.x,block[k][i][j].hit.rb.y}}};
					//敵のTOPとブロックの範囲
					if(hitblocktop == -1 && ene[num].y -18>=block[k][i][j].hit.lt.y &&
						ene[num].y -18<=block[k][i][j].hit.rb.y){
						hitblocktop = i;
						break;
					}
					if(ene[num].y +15>=block[k][i][j].hit.lt.y &&
						ene[num].y +15<=block[k][i][j].hit.rb.y){
						hitblockbottom = i;
						break;
					}
					if(i>= hitblocktop && i<= hitblockbottom){
						if(block[k][i][j].flag == TRUE){
							if(HitLineAndCircle(pt[3],enehitball) == TRUE)
								ene[num].movedir = right;
							if(HitLineAndCircle(pt[2],enehitball) == TRUE)
								ene[num].movedir = left;

						}
					}


				}
			}
		}
	}
というように変更しました。
hitblocktopからhitblockbottomの間(今回は9,10,11)で縦(i)の3つすべてのブロックがあるときは
移動方向を変えてくれるのですが,9または10のブロックがないときそのままブロックをすり抜けてしまいます。

以前は9だけ,9と10がある状態で11がないときfor文で9,10でTRUEでも11でFALSEになってしまというパターンが
あってそちらは質問させていただいて納得したのですが,今回の場合は原因がわかりません。
ちなみに敵の当たり判定の半径を大きくしてみたり,if(i>= hitblocktop && i<= hitblockbottom)をなくしてみたり
しましたがそれでもダメでした。

Re: ブロックと敵の衝突判定

Posted: 2013年7月02日(火) 00:58
by ISLe
提示されたコードはブロック1個毎に方向を変えているように見えますが。
奇数のブロックに当たったときOKで、偶数のブロックに当たったときNGだとすれば、先に説明したとおりだと思います。

現状は敵が左に移動していて、
ブロック10に当たっている→右に向かう
ブロック11に当たっている→左に向かう
というふうになっていると思います。

敵が左に移動していて、
ブロック10に当たっている→左に当たったと記録
ブロック11に当たっている→左に当たったと記録
左に当たって上下右に当たってないので右に向かう
というふうにすれば良いかと思います。

Re: ブロックと敵の衝突判定

Posted: 2013年7月02日(火) 10:37
by ヨシタケ
正確には
9 □
10□ ○←敵
11□
といった感じです。
9または10のブロックのフラグがFALSEのとき
ブロックをすり抜けるので奇数,偶数は関係ないとおもうのですが,
どうなのでしょうか。

Re: ブロックと敵の衝突判定

Posted: 2013年7月02日(火) 11:53
by ヨシタケ
追加です。
block[1][9][6](3つのうち一番上),block[1][10][6](真ん中)のブロックのフラグを常にFALSEの状態で
行ってみたところブロックをすり抜けてしまうのは真ん中のブロックが消えているときだけでした。

間違ったことを書いてしまい、すみませんでした。

Re: ブロックと敵の衝突判定

Posted: 2013年7月02日(火) 17:25
by ISLe
hitblocktopとhitblockbottomを求めたときbreakしたら当たり判定が行われません。
真ん中のブロックだけが影響するのはこれが原因だと思います。

hitblocktopとhitblockbottomが不定なまま、本来行われるはずのない当たり判定が行われる可能性もあります。
プロジェクトをダウンロードして動かしてみたところ頻繁に何もないところでボールが反射しますがおそらくこれが原因でしょう。

範囲を求めるループと、当たり判定を求めるループは分けなければいけません。
そもそも全ブロックに対してループを回しているので範囲を求める意味がありません。



比較時にいちいちメンバ同士で比較していてはRect2D等の構造体を定義している意味がありません。
構造体を引数に取って比較する関数を定義して使えばコードが見易くなります。

Re: ブロックと敵の衝突判定

Posted: 2013年7月02日(火) 21:16
by ヨシタケ
if(i>= hitblocktop && i<= hitblockbottom)を消してもすり抜けてしまうためたぶん関係ないと思います。

あと,何もないところでボールが反射するというのはステージのギミックとして真ん中上のほうにいる敵
にボールが引き寄せられる,または,反発するようにしてあるからだと思います。
その内容についてはstage04.cppにあります。

Re: ブロックと敵の衝突判定

Posted: 2013年7月03日(水) 01:02
by ISLe
ヨシタケ さんが書きました:if(i>= hitblocktop && i<= hitblockbottom)を消してもすり抜けてしまうためたぶん関係ないと思います。
breakするのはそこじゃない気がしますけど。
まあ自分で判断できるとおっしゃるのであればわたしから何も言うことはありません。
頑張ってください。
ヨシタケ さんが書きました:あと,何もないところでボールが反射するというのはステージのギミックとして真ん中上のほうにいる敵
にボールが引き寄せられる,または,反発するようにしてあるからだと思います。
その内容についてはstage04.cppにあります。
ボールが画面の下のほうにあっても反射する仕様なのですかね。
そういう仕様なら仕方ないですね。
stage04.cppを開いてそういうふうに動くコードが書かれているのを確認したとして、どうしろというのでしょうか。

Re: ブロックと敵の衝突判定

Posted: 2013年7月06日(土) 00:37
by ヨシタケ
すみません。色々試したのですが,ダメでした
とりあえず,少し変更して

コード:


void Enemy05UpData(int num,BLOCK block[3][13][9],BAR **bar,BALL **ball){
	//敵とボールの当たり判定
	//Ball2D enehitball = {ene[num].x-1,ene[num].y-1,17};
	Ball2D enehitball = {ene[num].x-1,ene[num].y-1,30};
	//敵とブロックの当たり判定
	Rect2D enehitblock ={ene[num].x -15,ene[num].y-18,ene[num].x +18,ene[num].y +15};
	
	switch(ene[num].movedir){
	case up:
		ene[num].y -= ene[num].spd;
		break;
	case down:
		ene[num].y += ene[num].spd;
		break;
	case left:
		ene[num].x -= ene[num].spd;
		break;
	case right:
		ene[num].x += ene[num].spd;
		break;
	}
	if(ene[num].movepattern == 0){
		if(ene[num].x<=40)
			ene[num].movedir = right;
		if(ene[num].x>=390)
			ene[num].movedir = left;

		for(int k=0;k<3;k++){
			for(int i=0;i<13;i++){
				for(int j=0;j<9;j++){
					//ブロックの各4辺(上,下,左,右)
					blockleft[k][i][j].startpos.x = block[k][i][j].hit.lt.x;
					blockleft[k][i][j].startpos.y = block[k][i][j].hit.lt.y;
					blockleft[k][i][j].endpos.x = block[k][i][j].hit.lt.x;
					blockleft[k][i][j].endpos.y = block[k][i][j].hit.rb.y;
					blockright[k][i][j].startpos.x = block[k][i][j].hit.rb.x;
					blockright[k][i][j].startpos.y = block[k][i][j].hit.lt.y;
					blockright[k][i][j].endpos.x = block[k][i][j].hit.rb.x;
					blockright[k][i][j].endpos.y = block[k][i][j].hit.rb.y;
					//Line2D pt[4] = {{{block[k][i][j].hit.lt.x,block[k][i][j].hit.lt.y},{block[k][i][j].hit.rb.x,block[k][i][j].hit.lt.y}},
					//{{block[k][i][j].hit.lt.x,block[k][i][j].hit.rb.y},{block[k][i][j].hit.rb.x,block[k][i][j].hit.rb.y}},
					//{{block[k][i][j].hit.lt.x,block[k][i][j].hit.lt.y},{block[k][i][j].hit.lt.x,block[k][i][j].hit.rb.y}},
					//{{block[k][i][j].hit.rb.x,block[k][i][j].hit.lt.y},{block[k][i][j].hit.rb.x,block[k][i][j].hit.rb.y}}};

					if(block[k][i][j].flag == TRUE){
						if(ene[num].movedir == left &&
							HitLineAndCircle(blockleft[k][i][j],enehitball) == TRUE)
							ene[num].movedir = right;
						if(ene[num].movedir == right &&
							HitLineAndCircle(blockright[k][i][j],enehitball) == TRUE)
							ene[num].movedir = left;
					}
				}
			}
		}
	}
	//敵とボールの当たり判定
	if(HitCircleAndCircle((*ball)->hit,enehitball)==TRUE){
		(*ball)->dy *=-1;
		PlaySESound(10);
	}
}
というように変更したのですが,やはりすり抜けてしまいます。
なにがいけないのか確認したところ
for文の中のk,i,jをそれぞれk=1,i=9or10or11,j=6に変更し,開始した場合iが9,11の場合すり抜けてしまったため
9,10のとき衝突判定が行われていないみたいです。実際,49行目にブレークポイントをおいてデバッグを行った場合
止まらずにそのままゲームが実行していました。
ただ,試しにenehitballの半径を大きくしても衝突判定が行われないので本当に原因がわかりません。

Re: ブロックと敵の衝突判定

Posted: 2013年7月06日(土) 16:56
by ISLe
enehitballとenehitblockに移動前の座標を使っているのは意図したものですか?
移動方向に対してブロックの奥側のラインと当たり判定しているのは意図したものですか?
ヨシタケ さんが書きました:for文の中のk,i,jをそれぞれk=1,i=9or10or11,j=6に変更し,開始した場合iが9,11の場合すり抜けてしまったため
9,10のとき衝突判定が行われていないみたいです。実際,49行目にブレークポイントをおいてデバッグを行った場合
止まらずにそのままゲームが実行していました。
止まらないのはどうしてかを調べるのがデバッグ作業ですよ。
トレースしてどこで分岐しているのか原因を見付けてください。

Re: ブロックと敵の衝突判定

Posted: 2013年7月07日(日) 15:37
by ヨシタケ
移動前の座標を使ってるというのはとくに意図していません。
一応,前回の書き込みを見てswitch(ene[num].movedir)のあとに
Ball2D enehitballを移したのですが,ブロックをすり抜けました。
ブロックの奥側のラインということですが,当たり判定を逆にしていました。すいません。

あれから,色々試してみました。
敵の位置を変えてみたところ,円の中心近くのx軸線に重なってるブロックにしか衝突判定が起こってないみたいです。かと言って半径を大きくしても変わりませんでした。
また,敵のブロックに対する当たり判定を線分に変更し,線分同士の当たり判定を行ってみたところ
初期位置で右移動→左移動→右移動の繰り返しでした。

for文の中に問題があるのかと思い,別に線分Lin2D hittest =(右側の縦3つのうち上か真ん中のブロックの左辺)
例 hittest = {{280,159},{280,175}}(右側の縦3つのうち上のブロックの左辺)
を使って,for文の外に「線分と円の当たり判定」or「線分と線分の当たり判定」を行いました。
線分の円の当たり判定の場合,以前と同じように真ん中のブロックには衝突したのですが,上のブロックの位置では
衝突判定は起きませんでした。
線分と線分の当たり判定の場合,どちらのブロックの位置に対しても衝突判定が起きませんでした。

正直,なにが原因なのかさっぱりわかりません。原因がわかりましたら,教えてください。どうかお願いします。

Re: ブロックと敵の衝突判定

Posted: 2013年7月07日(日) 15:49
by softya(ソフト屋)
横からすいません。進展が無さそうだったので。
デバッグというのは大事なテクニックなのですが、それが身に付いていないと見つけられるバグも見つけられなく無くなってしまします。
闇雲に調べるのではなくて、次にようにしたらどうでしょうか。
1.確実に再現できる最短状況を無操作で実現できるようにします。
2.1つ1つの衝突判定や、玉の挙動変化をログに記録したファイルを作ります。
3.問題が起きるフレーム数を経過したら、プログラムを自動終了します。
4.ログを調べます。
これをやれば、起こっている問題そのものは特定できるのでは無いかと思います。

Re: ブロックと敵の衝突判定

Posted: 2013年7月07日(日) 17:58
by ISLe
>ヨシタケさん
それだけ分かれば衝突の発生しない原因は明らかではないですか。
HitLineAndCircle関数ですよ。

HitLineAndCircle関数が使われていなかった当初と現在では、敵が方向を変えない理由はもはや別のものではないでしょうか。
進展がないのも仕方がないと思います。

Re: ブロックと敵の衝突判定

Posted: 2013年7月15日(月) 17:51
by ヨシタケ
返信遅れました。

円と線分の当たり判定については参考書に書いてあった内容をそのまま使っていたので
実のところ,関数の内容について完全には理解していないので調べておきます。

ただ,今まで失念していたのですが,円と四角の当たり判定を使用したらなんとかできるようになりました。
今までお手数おかけして申し訳ございませんでした。そして,ありがとうございました。

また,デバッグの仕方についてはスレッドの内容と異なるため別で質問させていただきます。