2次元での回転有りの長方形同士の当たり判定
つまり、2D有向境界ボックス(OBB)同士の当たり判定をやってみたいと思います
長方形同士の当たり判定はかなり使い道が多いので覚えておいて損はないと思います

前回やった文字表示で当たったかどうかの状態を表示します
DirectXTextクラスをfont.cppとfont.hにプログラムを別ファイルに分割しました
こちらは特に説明することがないのでそのまま使ってください

今回使うファイルは次のようになってます。どぞー(-ω-)つ旦
・&ref(direct3d.h);
・&ref(direct3d.cpp);
・&ref(texture.h);
・&ref(texture.cpp);
・&ref(sprite.h);
・&ref(sprite.cpp);
・&ref(font.h);
・&ref(font.cpp);
・&ref(hittest.cpp);(WinMain関数があるアプリケーション本体)
今回使う画像はこちら
・&ref(car.bmp);

zipでほしい人はこちら
・&ref(hittest.zip);


今回焦点を当てたい当たり判定関数はsprite.hとsprite.cppに実装してあります

 #pragma once
 
 // Direct3Dの各種ヘッダーのインクルードが必要なため
 // すでにまとめてあるヘッダーをインクルードする
 #include "direct3d.h"
 
 struct AnimationNum{
	unsigned int numU;
	unsigned int numV;
 };
 
 // スプライトクラス(2D板ポリゴン)
 class Sprite
 {
  public:
	// 板ポリゴン頂点情報
	struct Vertex{
		float x,y,z;// 3次元座標
		float rhw;	// 2D変換済みフラグ
		float u,v;	// UV座標
	};
	// FVF(柔軟な頂点構造体宣言)フラグ
	static const DWORD SPRITE_FVF = D3DFVF_XYZRHW | D3DFVF_TEX1;
 	
	// スプライト位置
	D3DXVECTOR2 pos;
	// スプライトサイズ
	int width;
	int height;
	// UVの分割数
	unsigned int divU;
	unsigned int divV;
	// UVの番号
	unsigned int numU;
	unsigned int numV;
	// 回転値(ラジアン)
	float rotate;
 
	// コンストラクタ
	Sprite();
	// デストラクタ
	~Sprite();
 
	void SetPos(float x,float y);
	void SetWidth(int Width,int Height);
	void SetRotate(float Rotate);
 
 ///////////////////////////////////////////////////////////////////////
	void UpdatePos(float x,float y);
	void UpdateRotate(float Rotate);
 ///////////////////////////////////////////////////////////////////////
 
	void SetDivide(unsigned int DivU,unsigned int DivV);
	void SetUVNum(unsigned int NumU,unsigned int NumV);
	void Draw(IDirect3DDevice9* pDevice3D,IDirect3DTexture9* pTexture,bool isTurn = false);
 };
 
 ///////////////////////////////////////////////////////////////////////
 
 // スプライトの当たり判定(2次元のOBB vs OBB)
 bool IsHitTest(const Sprite& sprite1,const Sprite& sprite2);
 


sprite.cppは次のようになります

 #include "sprite.h"
 
 // 20回と同じなので略
 
 ////////////////////////////////////////////////////////////////////////////////////////////
 
 void Sprite::UpdatePos(float x,float y)
 {
	pos.x += x;
	pos.y += y;
 }
 void Sprite::UpdateRotate(float Rotate)
 {
	rotate += Rotate;
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////
 
 // 20回と同じなので略
 
 ////////////////////////////////////////////////////////////////////////////////////////////
 
 // 有向境界ボックス(2次元)
 struct OBB 
 {
   D3DXVECTOR2	Pos;        // 位置
   D3DXVECTOR2	Dir[2];		// XY各座標軸の傾きを表す方向ベクトル
   float		Length[2];  // 各軸方向の長さの半分
 };
 
 // OBB作成
 void CreateOBB(OBB* pOutOBB,const D3DXVECTOR2& Pos,const D3DXMATRIX& RotateMtx,const D3DXVECTOR2& Length)
 {
	pOutOBB->Pos = Pos;
	pOutOBB->Length[0] = Length.x;
	pOutOBB->Length[1] = Length.y;
	pOutOBB->Dir[0] = D3DXVECTOR2(RotateMtx._11,RotateMtx._12);
	pOutOBB->Dir[1] = D3DXVECTOR2(RotateMtx._21,RotateMtx._22);
 }
 
 // 分離軸に投影された軸成分から投影線分長を算出
 float LenSegOnSeparateAxis( D3DXVECTOR2 *Sep, D3DXVECTOR2 *e1, D3DXVECTOR2 *e2 )
 {
	// 3つの内積の絶対値の和で投影線分長を計算
	// 分離軸Sepは標準化されていること
	float r1 = fabs(D3DXVec2Dot( Sep, e1 ));
	float r2 = fabs(D3DXVec2Dot( Sep, e2 ));
	return r1 + r2;
 }
 
 // OBB vs OBB
 bool TestOBBOBB(const OBB &obb1,const OBB &obb2)
 {
	// 各方向ベクトルの確保
	// (N***:標準化方向ベクトル)
	D3DXVECTOR2 NAe1 = obb1.Dir[0], Ae1 = NAe1 * obb1.Length[0];
	D3DXVECTOR2 NAe2 = obb1.Dir[1], Ae2 = NAe2 * obb1.Length[1];
	D3DXVECTOR2 NBe1 = obb2.Dir[0], Be1 = NBe1 * obb2.Length[0];
	D3DXVECTOR2 NBe2 = obb2.Dir[1], Be2 = NBe2 * obb2.Length[1];
	D3DXVECTOR2 Interval = obb1.Pos - obb2.Pos;
 
	// 分離軸 : Ae1
	float rA = D3DXVec2Length( &Ae1 );
	float rB = LenSegOnSeparateAxis( &NAe1, &Be1, &Be2 );
	float L = fabs(D3DXVec2Dot( &Interval, &NAe1 ));
	if( L > rA + rB )
		return false; // 衝突していない
 
	// 分離軸 : Ae2
	rA = D3DXVec2Length( &Ae2 );
	rB = LenSegOnSeparateAxis( &NAe2, &Be1, &Be2);
	L = fabs(D3DXVec2Dot( &Interval, &NAe2 ));
	if( L > rA + rB )
		return false;
 
	// 分離軸 : Be1
	rA = LenSegOnSeparateAxis( &NBe1, &Ae1, &Ae2);
	rB = D3DXVec2Length( &Be1 );
	L = fabs(D3DXVec2Dot( &Interval, &NBe1 ));
	if( L > rA + rB )
		return false;
 
	// 分離軸 : Be2
	rA = LenSegOnSeparateAxis( &NBe2, &Ae1, &Ae2);
	rB = D3DXVec2Length( &Be2 );
	L = fabs(D3DXVec2Dot( &Interval, &NBe2 ));
	if( L > rA + rB )
		return false;
 
	// 分離平面が存在しないので「衝突している」
	return true;
 }
 
 // スプライトの当たり判定(2次元のOBB vs OBB)
 bool IsHitTest(const Sprite& sprite1,const Sprite& sprite2)
 {
	OBB obb1;
	OBB obb2;
	D3DXMATRIX rotMtx1;
	D3DXMATRIX rotMtx2;
 
	D3DXMatrixRotationZ(&rotMtx1,sprite1.rotate);
	D3DXMatrixRotationZ(&rotMtx2,sprite2.rotate);
	CreateOBB(&obb1,sprite1.pos,rotMtx1,D3DXVECTOR2(sprite1.width/2.0f,sprite1.height/2.0f));
	CreateOBB(&obb2,sprite2.pos,rotMtx2,D3DXVECTOR2(sprite2.width/2.0f,sprite2.height/2.0f));
	return TestOBBOBB(obb1,obb2);
 }

実行結果は次のようになります
色々動かして遊んでみてください
&ref(hittest.jpg);

前:DirectX講座21回
次:DirectX講座23回

#vote( どやぁ・・・[4],あぁ・・・今回もダメだったよ[5],神は言っている、まだここで死ぬ命運ではないと[16]);
| どやぁ・・・|4|
|あぁ・・・今回もダメだったよ|5|
|神は言っている、まだここで死ぬ命運ではないと[|16|



トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS