ブロック崩しにおけるあたり判定について

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

ブロック崩しにおけるあたり判定について

#1

投稿記事 by つきたてほやほや » 14年前

こんにちわ。つきたてほやほやです。
私のプログラム経験は龍神録を少しいじる程度でしたが、今回初めての一からのゲーム制作をすることになりました。

作ることになったゲームは「ブロック崩し」です。

その前に今回、ゲームの開発環境がC♯ + XNAなのですが、このサイトでC♯に関する質問は可能でしょうか? 
もし可能なら、今後、オブジェクト指向に関する質問や複数人でのゲーム開発をどのようにしたら効率よくで出来るかなどの質問をしたいと思っています。

それはさておき、今回の質問は「ブロック崩しにおけるあたり判定について」です。
ブロック崩しでは、バー・ボール・ブロックが出てきますよね。

その中で、ブロックとボール。バーとボールのあたり判定の実装を行いたいのですが、効率的な実装方法が思いつきません。

サイトで調べた限りでは、どれもボールを四角形(短形?)として扱い、短形同士でのあたりを判定しています。

私は円のあたり判定をそのまま円として扱いたいのですが、
私が思いつく限りでは、
・ボールの右とバーの左側面が当たったら
・ボールの左とバーの右側面が当たったら
・もしバーの角に当たったら
   ・
   ・  
   ・

というよう風にいちいち場合分けをする形になりあまり賢い書き方ではありません。

この場合どのように判定をすればすっきりした形でプログラムを書くことが出来るでしょうか?

若干漠然とした質問であるかもしれないですけど回答お願いします。

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

Re: ブロック崩しにおけるあたり判定について

#2

投稿記事 by GRAM » 14年前

えっと、・・・コードで語ることにしましょう。
C言語でなおかつDxLibを使っていますが、大丈夫でしょうか?
もしコードがCで書かれているゆえわからないところがございましたらまた聞いてください
じぶんならこんな感じの実装にするでしょう。(簡単にするため余計なことはしていません)

コード:

#include "DxLib.h"

typedef double Point[2];

//長方形の構造体
struct AABB{
	Point lt;	//左上	
	Point rb;	//右下
};

//円
struct Circle{
	Point	center;	//中心
	double	r;	//半径
};


//長方形と点との距離の平方を求める
double SqDistPointToAABB(const AABB& b, const Point p){
	double dist = 0.0;
	for(int i = 0; i<2; ++i){
		if(p[i] < b.lt[i]) dist += (b.lt[i]-p[i])*(b.lt[i]-p[i]);
		if(p[i] > b.rb[i]) dist += (b.rb[i]-p[i])*(b.rb[i]-p[i]);
	}
	printfDx("%f",dist);
	return dist;
};

//長方形と円との判定を行う
bool AABBtoCircle(const AABB& b, const Circle& c){
	double sqDist = SqDistPointToAABB(b,c.center);
	return sqDist < c.r*c.r;
}


int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
        ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定
		Circle c;
		c.r = 10.0;
		c.center[0] = c.center[1] = 0.0;
		
		AABB b;
		b.lt[0] = 300.0; b.lt[1] = 200.0;
		b.rb[0] = 350.0; b.rb[1] = 220.0;

		int XBuf,YBuf;
        // while( 裏画面を表画面に反映, メッセージ処理, 画面クリア )
        while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 ){
			clsDx();
			GetMousePoint( &XBuf, &YBuf );
			c.center[0] = XBuf; c.center[1] = YBuf;

			int color = 0xff0000;
			if(AABBtoCircle(b,c)) color = 0x0000ff;
			DrawBox( b.lt[0], b.lt[1] , b.rb[0], b.rb[1] , color,true) ;
			DrawCircle( c.center[0], c.center[1], c.r, 0x00ff00) ;
        }
        
        DxLib_End(); // DXライブラリ終了処理
        return 0;
}
長方形との距離の平方を求め、円の半径の2乗より小さいかを判定しています

アバター
うしお
記事: 56
登録日時: 14年前

Re: ブロック崩しにおけるあたり判定について

#3

投稿記事 by うしお » 14年前

GUAMさん、細かいところで申し訳ないのですが、
参照や変数の宣言位置などからC言語というよりはC++ではないでしょうか?

ちょっと広い視点で考えてみます。
「コードをどう纏めていくか?」
「どう見やすく書くか?」
といった問題ですよね。

GUAMさんが挙げてくださっている、構造体に纏める、関数に纏める、
とても良い方法だと思います。

言語にもよりますが、プログラミング言語には先人達が知恵を絞って考えた、
便利な機能、構文が沢山沢山あります。
C#ではクラス、プロパティ、インターフェース、継承、・・・
等など数え切れないほどです。
どの機能も、どうすれば効率よく、再利用しやすく、読みやすくコードが書けるのか?
といった観点から生まれたものです。 そういった類の機能に触れてみるのも良いのではないでしょうか?
少々だらだらと書いてしまってすみません。

つきたてほやほや

Re: ブロック崩しにおけるあたり判定について

#4

投稿記事 by つきたてほやほや » 14年前

こんばんわ、回答ありがとうございます。
一週間前に投稿したはずだったのになぜか更新されてなくて焦りました;;

>>うしおさん
そうですね、私が困っているのはまさに「コードをどうまとめていくか」というところですね。
具体的には、一つのクラスのどの変数とどの変数を一緒にしてあげればよいか、どのクラスを継承させてあげればよいのか、
といった非常に初歩的な部分です。
また、プロパティや抽象メソッド、仮想メソッドなどは、その利便性をつかみ切れていない状態です。
やはり、これらの解決法は、サンプルコードを参照したり、自分でコードをたくさん書いていくほかありませんね。

>>GRAMさん
貴重なサンプルプログラムをありがとうございます。
まだ、じっくりとは見ていないのですが、他のどのサイトのものよりもわかりやすいと思います。
このコードから、どのバーの面、または角に当たったかの場合分けをしてボールの反射を決めていきたいですね。
もしかしたら、場合分けでも分からなくなることがあるかもしれないので、その時は再度質問させていただくかもしれません。

閉鎖

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