ブロック崩しでの角と面の当たり判定

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
chalaza

ブロック崩しでの角と面の当たり判定

#1

投稿記事 by chalaza » 14年前

いろんなサイトを参考にしてブロック崩しを作っていて、ブロックとボールの判定を作ったところなのですが、
ボールが角と面に当る判定を分けて一通りできたのですが、ブロックが2つならんでいるところの真ん中にボールがぶつかったときに
たまにブロックを突き抜けて進んでしまいます。
ボールのXとYの速度が0以上か0以下かで向きを判定して、
角判定はボールの右下がブロックの左上縦横2ドット分にぶつかったら角に当ったと判定してXとY速度を反転して作って
それを4方向分作って、
面の判定は下に進んでいるときにボールの下がブロックの範囲に入っていて、ボールの右端がブロックの左端以上、左側がブロックの右端以下なら
Y座標を反転として、それを4方向作りました。
たぶん反転させる判定以外の通り道ができてしまってるんだと思うのですが、どこがおかしいでしょうか…
ゲームのコードすべては長いのでボールの衝突関数の部分だけ貼らせていただきます。

コード:

void ballhit()
{
	//ボールと壁の衝突
	if(ballX < 20)
		ballVX *= -1;
	if(ballX+10 > 220)
		ballVX *= -1;
	if(ballY+10 > 460)
		ballVY *= -1;
	if(ballY < 20)	//テスト用壁
		ballVY *= -1;
	//ボールとバーの衝突
	if(ballY <= barY+8 && ballY >= barY)
		if(ballX <= barX+60 && ballX+10 >=barX)
			ballVY *= -1;

	int i, j; //forループ制御用変数

	for(i = 0; i<24; i++) {
		for(j = 0; j<12; j++) {
		if((MAP[i][j]>=1)&&(MAP[i][j]!=8)){	//ブロックの種類が1以上で8以外のとき

			//角に衝突
			 //右下に動いてるときにブロックの左上にぶつかったら移動を反転
			if( ballY+10>=i*20 && ballY+10<=i*20+2 && ballX+10>=i*20 && ballX+10<=i*20+2 && ballVX>=0 && ballVY>=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			ballVY *= -1; 
			} //左下にうごいているときにブロックの右上にぶつかったら移動を反転
			if( ballY+10>=i*20 && ballY+10<=i*20+2 && ballX>=i*20+18 && ballX<=i*20+20 && ballVX<=0 && ballVY>=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			ballVY *= -1; 
			} //右上にうごいているときにブロックの左下にぶつかったら移動を反転
			if( ballY>=i*20+18 && ballY<=i*20+20 && ballX+10>=i*20 && ballX+10<=i*20+2 && ballVX>=0 && ballVY<=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			ballVY *= -1; 
			} //左上にうごいているときにブロックの右下にぶつかったら移動を反転
			if( ballY>=i*20+18 && ballY<=i*20+20 && ballX>=i*20+18 && ballX<=i*20+20 && ballVX<=0 && ballVY<=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			ballVY *= -1; 
			}
			//面に衝突
			//下に動いているときにブロックの上にぶつかったらY速度を反転
			if( ballY+10>=i*20 && ballY+10<=i*20+20 && ballX+10>=j*20 && ballX<=j*20+20 && ballY>=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVY *= -1; 
			} 
			//上に動いているときにブロックの下にぶつかったらY速度を反転
			if( ballY>=i*20 && ballY<=i*20+20 && ballX+10>=j*20 && ballX<=j*20+20 && ballY<=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVY *= -1; 
			} 
			//右に動いているときにブロックの左にぶつかったらX速度を反転
			if( ballY+10>=i*20 && ballY<=i*20+20 && ballX+10>=j*20 && ballX+10<=j*20 && ballVX>=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			} 
			//左に動いているときにブロックの右にぶつかったらX速度を反転
			if( ballY+10>=i*20 && ballY<=i*20+20 && ballX>=j*20 && ballX<=j*20+20 && ballVX>=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			}
		}
		}
	}

}

アバター
GRAM
記事: 164
登録日時: 14年前
住所: 大阪

Re: ブロック崩しでの角と面の当たり判定

#2

投稿記事 by GRAM » 14年前

取りあえずぱっと見で気になったのは

コード:

            //下に動いているときにブロックの上にぶつかったらY速度を反転
            if( ballY+10>=i*20 && ballY+10<=i*20+20 && ballX+10>=j*20 && ballX<=j*20+20 && ballY>=0 ){ 
            MAP[i][j]=0; 
            field[i][j] = MAP[i][j];
            ballVY *= -1; 
            } 
            //上に動いているときにブロックの下にぶつかったらY速度を反転
            if( ballY>=i*20 && ballY<=i*20+20 && ballX+10>=j*20 && ballX<=j*20+20 && ballY<=0 ){ 
            MAP[i][j]=0; 
            field[i][j] = MAP[i][j];
            ballVY *= -1; 
            }
これ、ballY <= 0とかでいいのですかね? ballVYでは?

あと、同じブロックと複数回判定しているようですが、より上位の部分であたり判定が終わればcontinueで次のループへ行ってはいかがでしょうか?

chalaza

Re: ブロック崩しでの角と面の当たり判定

#3

投稿記事 by chalaza » 14年前

まずballY <= 0の部分をballVYに直してcontinueも入れてみましたが、これはたぶん
たとえばボールが右に動いていてブロックに当ったとき、ボールの右下や右上がボールの右と下と上の判定を併用してしまっているので
ブロックの左に当ったのを上や下とぶつかったと勘違いしているのだと思うのですが、
とりあえずボールの側面の判定をボールの角まででなく、ボールの角より1ドット内側までで判定するようにしてみたのですが、
やっぱり貫通してしまいます。ボールの速度が2なのが原因かとおもったのですが、上下と左右の判定を間違えさせないようにするには
どうすればいいでしょうか…

コード:

void ballhit()
{
	//ボールと壁の衝突
	if(ballX < 20)
		ballVX *= -1;
	if(ballX+10 > 220)
		ballVX *= -1;
	if(ballY+10 > 460)
		ballVY *= -1;
	if(ballY < 20)	//テスト用壁
		ballVY *= -1;
	//ボールとバーの衝突
	if(ballY <= barY+8 && ballY >= barY)
		if(ballX <= barX+60 && ballX+10 >=barX)
			ballVY *= -1;

	int i, j; //forループ制御用変数

	for(i = 0; i<24; i++) {
		for(j = 0; j<12; j++) {
		if((MAP[i][j]>=1)&&(MAP[i][j]!=8)){	//ブロックの種類が1以上で8以外のとき

			//角に衝突
			 //右下に動いてるときにブロックの左上にぶつかったら移動を反転
			if( ballY+10>=i*20 && ballY+10<=i*20+2 && ballX+10>=i*20 && ballX+10<=i*20+2 && ballVX>=0 && ballVY>=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			ballVY *= -1; 
			continue;	
			} //左下にうごいているときにブロックの右上にぶつかったら移動を反転
			if( ballY+10>=i*20 && ballY+10<=i*20+2 && ballX>=i*20+18 && ballX<=i*20+20 && ballVX<=0 && ballVY>=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			ballVY *= -1; 
			continue;	
			} //右上にうごいているときにブロックの左下にぶつかったら移動を反転
			if( ballY>=i*20+18 && ballY<=i*20+20 && ballX+10>=i*20 && ballX+10<=i*20+2 && ballVX>=0 && ballVY<=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			ballVY *= -1; 
			continue;	
			} //左上にうごいているときにブロックの右下にぶつかったら移動を反転
			if( ballY>=i*20+18 && ballY<=i*20+20 && ballX>=i*20+18 && ballX<=i*20+20 && ballVX<=0 && ballVY<=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			ballVY *= -1; 
			continue;	
			}
			//面に衝突
			//下に動いているときにブロックの上にぶつかったらY速度を反転
			if( ballY+10>=i*20 && ballY+10<=i*20+20 && ballX+10>=j*20 && ballX<=j*20+20 && ballVY>=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVY *= -1; 
			continue;	
			} 
			//上に動いているときにブロックの下にぶつかったらY速度を反転
			if( ballY>=i*20 && ballY<=i*20+20 && ballX+10>=j*20 && ballX<=j*20+20 && ballVY<=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVY *= -1; 
			continue;	
			} 
			//右に動いているときにブロックの左にぶつかったらX速度を反転
			if( ballY+10>=i*20 && ballY<=i*20+20 && ballX+10>=j*20 && ballX+10<=j*20+20 && ballVX>=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			continue;	
			} 
			//左に動いているときにブロックの右にぶつかったらX速度を反転
			if( ballY+10>=i*20 && ballY<=i*20+20 && ballX>=j*20 && ballX<=j*20+20 && ballVX>=0 ){ 
			MAP[i][j]=0; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			continue;	
			}
		}
		}
	}

}

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: ブロック崩しでの角と面の当たり判定

#4

投稿記事 by ISLe » 14年前

ボールがブロックに近付いているときだけ判定するというのはどうでしょう。

コード:

// ボール中心からブロック中心への差
int fvx = (j*20+20/2)-(ballX+10/2);
int fvy = (i*20+20/2)-(ballY+10/2);
if ((fvx < 0 && ballVX < 0) || (fvx > 0 && ballVX > 0)) {
  if ((fvy < 0 && ballVY < 0) || (fvy > 0 && ballVY > 0)) {
    // ボールはブロックへ近付くように移動している
  }
}

chalaza

Re: ブロック崩しでの角と面の当たり判定

#5

投稿記事 by chalaza » 14年前

すみません。ブロックに右からボールがぶつかったときの条件がballVX<=0と逆になっていただけでした…
ボールの速さとか関係なかったみたいです。すいませんでした。解決しました。

コード:

void ballhit()
{
	//ボールと壁の衝突
	if(ballX < 20)
		ballVX *= -1;
	if(ballX+10 > 220)
		ballVX *= -1;
	if(ballY+10 > 460)
		ballVY *= -1;
	if(ballY < 20)	//テスト用壁
		ballVY *= -1;
	//ボールとバーの衝突
	if(ballY <= barY+8 && ballY >= barY)
		if(ballX <= barX+60 && ballX+10 >=barX)
			ballVY *= -1;

	int i, j; //forループ制御用変数

	for(i = 0; i<24; i++) {
		for(j = 0; j<12; j++) {
		if((MAP[i][j]>=1)&&(MAP[i][j]!=8)){	//ブロックの種類が1以上で8以外のとき

			//角に衝突
			 //右下に動いてるときにブロックの左上にぶつかったら移動を反転
			if( ballY+10==i*20 && ballX+10==i*20 && ballVX>=0 && ballVY>=0 ){ 
			MAP[i][j]--; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			ballVY *= -1; 
			continue;	
			} //左下にうごいているときにブロックの右上にぶつかったら移動を反転
			if( ballY+10==i*20 && ballX==i*20+20 && ballVX<=0 && ballVY>=0 ){ 
			MAP[i][j]--; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			ballVY *= -1; 
			continue;	
			} //右上にうごいているときにブロックの左下にぶつかったら移動を反転
			if( ballY==i*20+20 && ballX+10==i*20 && ballVX>=0 && ballVY<=0 ){ 
			MAP[i][j]--; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			ballVY *= -1; 
			continue;	
			} //左上にうごいているときにブロックの右下にぶつかったら移動を反転
			if( ballY==i*20+20 && ballX==i*20+20 && ballVX<=0 && ballVY<=0 ){ 
			MAP[i][j]--; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			ballVY *= -1; 
			continue;	
			}
			//面に衝突
			//下に動いているときにブロックの上にぶつかったらY速度を反転
			if( ballY+10==i*20 && ballX+10>=j*20 && ballX<=j*20+20 && ballVY>=0 ){ 
			MAP[i][j]--; 
			field[i][j] = MAP[i][j];
			ballVY *= -1; 
			continue;	
			} 
			//上に動いているときにブロックの下にぶつかったらY速度を反転
			if( ballY==i*20+20 && ballX+10>=j*20 && ballX<=j*20+20 && ballVY<=0 ){ 
			MAP[i][j]--; 
			field[i][j] = MAP[i][j];
			ballVY *= -1; 
			continue;	
			} 
			//右に動いているときにブロックの左にぶつかったらX速度を反転
			if( ballY+10>=i*20 && ballY<=i*20+20 && ballX+10==j*20 && ballVX>=0 ){ 
			MAP[i][j]--; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			continue;	
			} 
			//左に動いているときにブロックの右にぶつかったらX速度を反転
			if( ballY+10>=i*20 && ballY<=i*20+20 && ballX==j*20+20 && ballVX<=0 ){ 
			MAP[i][j]--; 
			field[i][j] = MAP[i][j];
			ballVX *= -1; 
			continue;	
			}
		}
		}
	}

}

閉鎖

“C言語何でも質問掲示板” へ戻る