DirectX/DirectX 2D_(구)

DX_Collider [2 / 3] AABB 충돌

컴맹학자 2021. 1. 20. 17:31
728x90

AABB(Axis Aligned Bounding Box) 충돌 관련해서 간단하게 애기하면 박스와 박스 끼리 충돌 하는 방법중 하나인데

간단하게 축과 축끼리 부딫치면 충돌 한다는 판정이다. 그림으로 간단하게 보면

 

B1, B2 박스가 각각의 위치에서 해당 위치에서 각각의 X, Y좌표가 동시에 겹쳤을때 충돌 하는 방법이다

 

물론 장점과 단점이 존재한다.

장점 . 간단한 계산방식으로 인한 충돌처리

단점 . 회전축 사용시 박스 관련 계산이 없으므로 박스 크기가 커질수도 작을수도 있다.

 

즉 간단한 충돌 처리할땐 요 방법이 좋지만 회전이 들어가면 박스가 오브젝트에 맞지않게 커질수 있어 문제가

생길수가 있다.


Collider.cpp, h 수정

더보기

헤더파일

#pragma once

class Collider
{
public:
	Collider();
	~Collider();

	void Update(D3DXMATRIX& V, D3DXMATRIX& P);
	void Render();

	void World(D3DXMATRIX& world) { this->world = world; }
	D3DXMATRIX World() { return world; }

	static bool Aabb(D3DXMATRIX& world, D3DXVECTOR2& position);
	static bool Aabb(D3DXMATRIX& world1, D3DXMATRIX& world2);
	//충돌 확인용
	void DrawColliderColor(bool val) { bDrawColliderColor = val; }
	 
private:
	void CreateBuffer();

private:
	struct Vertex
	{
		D3DXVECTOR3 Positon;
	};

private:
	Shader* shader;
	ID3D11Buffer* vertexBuffer;
	
	D3DXMATRIX world;

	D3DXCOLOR initLineColor; // 기본색
	D3DXCOLOR collidedColor; // 충돌식 변경색
	bool bDrawColliderColor; // 충돌판정

	ID3DX11EffectMatrixVariable* sWorld;
	ID3DX11EffectMatrixVariable* sView;
	ID3DX11EffectMatrixVariable* sProjection;
	ID3DX11EffectVectorVariable* sColor;
};

cpp 파일

#include "stdafx.h"
#include "collider.h"

Collider::Collider()
	: bDrawColliderColor(false)
{
	shader = new Shader(L"Bounding.fx");
	CreateBuffer();
	
	D3DXMatrixIdentity(&world);
	sWorld = shader->AsMatrix("World");
	sView = shader->AsMatrix("View");
	sProjection = shader->AsMatrix("Projection");
	sColor = shader->AsVector("LineColor");

	initLineColor = D3DXCOLOR(0, 1, 0, 1); //기본색
	collidedColor = D3DXCOLOR(1, 0, 0, 1); //충돌색
}

void Collider::CreateBuffer()
{
	Vertex vertices[5];
	vertices[0].Positon = D3DXVECTOR3(-0.5f, -0.5f, 0.0f);
	vertices[1].Positon = D3DXVECTOR3(-0.5f, +0.5f, 0.0f);
	vertices[2].Positon = D3DXVECTOR3(+0.5f, +0.5f, 0.0f);
	vertices[3].Positon = D3DXVECTOR3(+0.5f, -0.5f, 0.0f);
	vertices[4].Positon = D3DXVECTOR3(-0.5f, -0.5f, 0.0f);

	//Create VertexBuffer
	{
		D3D11_BUFFER_DESC desc;
		ZeroMemory(&desc, sizeof(D3D11_BUFFER_DESC));
		desc.ByteWidth = sizeof(Vertex) * 5;
		desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;

		D3D11_SUBRESOURCE_DATA data;
		ZeroMemory(&data, sizeof(D3D11_SUBRESOURCE_DATA));
		data.pSysMem = vertices;

		HRESULT hr = Device->CreateBuffer(&desc, &data, &vertexBuffer);
		assert(SUCCEEDED(hr));
	}
}

void Collider::Update(D3DXMATRIX & V, D3DXMATRIX & P)
{
	sWorld->SetMatrix(world);
	sView->SetMatrix(V);
	sProjection->SetMatrix(P);
}

void Collider::Render()
{
	UINT stride = sizeof(Vertex);
	UINT offset = 0;

	DeviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
	DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP);
	sColor->SetFloatVector(bDrawColliderColor ? collidedColor : initLineColor);
	shader->Draw(0, 0, 5);
}

Collider::~Collider()
{
	SAFE_RELEASE(vertexBuffer);
	SAFE_DELETE(shader);
}

// 지역 충돌
bool Collider::Aabb(D3DXMATRIX & world, D3DXVECTOR2 & position)
{
	D3DXVECTOR2 position1 = D3DXVECTOR2(world._41, world._42); //X. Y 위치값
	D3DXVECTOR2 position2 = position;

	D3DXVECTOR2 distance;
	distance.x = fabsf(position1.x - position2.x);
	distance.y = fabsf(position1.y - position2.y);

	D3DXVECTOR2 halfSize;
	halfSize = D3DXVECTOR2(fabsf(world._11), fabsf(world._22)) * 0.5f; //X, Y 크기값

	
	if (distance.x > halfSize.x) return false;
	if (distance.y > halfSize.y) return false;
	
	return true;
}

// 오브젝트와 오브젝트
bool Collider::Aabb(D3DXMATRIX & world1, D3DXMATRIX & world2)
{
	D3DXVECTOR2 position1 = D3DXVECTOR2(world1._41, world1._42);
	D3DXVECTOR2 position2 = D3DXVECTOR2(world2._41, world2._42);

	D3DXVECTOR2 distance;
	distance.x = fabsf(position1.x - position2.x);
	distance.y = fabsf(position1.y - position2.y);

	D3DXVECTOR2 halfSize1, halfSize2;
	halfSize1 = D3DXVECTOR2(fabsf(world1._11), fabsf(world1._22)) * 0.5f;
	halfSize2 = D3DXVECTOR2(fabsf(world2._11), fabsf(world2._22)) * 0.5f;

	if (distance.x > halfSize1.x + halfSize2.x) return false;
	if (distance.y > halfSize1.y + halfSize2.y) return false;

	//x,y가 겹쳐질때
	return true;
}



S01_Collider.cpp h 수정

더보기

헤더파일

#pragma once
#include "Scene.h"

class S01_Collider : public Scene {
public:
	S01_Collider(SceneValues* values);
	~S01_Collider();

	// Scene을(를) 통해 상속됨
	void Update() override;
	void Render() override;


private:
	class Background * background;
	class Prinny * Ply;
	class Obstacle* obj;

	Collider* col[2];
	bool colliderColor = false;
};

cpp파일

#include "stdafx.h"
#include "S01_Collider.h"
#include "Viewer/Following.h"

//배경
#include "Object/Background.h"

//캐릭터
#include "Object/Move.h"

//오브젝트
#include "Object/Obstacle.h"

S01_Collider::S01_Collider(SceneValues * values) : Scene(values)
{
	//파일경로
	wstring shaderFile = L"Effect.fx";
	background = new Background(shaderFile);
	Ply = new Move(Vector2(0.0f, 0.0f), Vector2(2.0f, 2.0f));
	obj = new Obstacle(Vector2(30.0f , 0.0f) , Vector2 (2.0f ,2.0f));

	col[0] = new Collider();
	col[1] = new Collider();

	//카메라 제설정
	SAFE_DELETE(values->MainCamera);
	values->MainCamera = new Following(Ply);
}

S01_Collider::~S01_Collider()
{
	SAFE_DELETE(obj);
	SAFE_DELETE(col[0]);
	SAFE_DELETE(col[1]);
	SAFE_DELETE(Ply);
	SAFE_DELETE(background);
}

void S01_Collider::Update()
{
	D3DXMATRIX V = values->MainCamera->View();
	D3DXMATRIX P = values->Projection;	

	//박스에 월드값을 넣기
	{
		col[0]->World(Ply->GetSprite()->World());
		col[0]->Update(V, P);
		col[1]->World(obj->GetWorld());
		col[1]->Update(V, P);
	}

	//충돌판정
	if (colliderColor = Collider::Aabb(Ply->GetSprite()->World(), obj->GetWorld()))
		col[0]->DrawColliderColor(colliderColor);
	else
		col[0]->DrawColliderColor(colliderColor);

	background->Update(V, P);
	Ply->Update(V, P);
	obj->Update(V, P);
}

void S01_Collider::Render()
{	
	background->Render();
	Ply->Render();
	obj->Render();
	col[0]->Render();
	col[1]->Render();
}


오브젝트

더보기

헤더파일

#pragma once

class Obstacle
{
public :
	Obstacle(Vector2 position, Vector2 scale = Vector2(1.0f, 1.0f));
	~Obstacle();

	void Update(Matrix& V, Matrix& P);
	void Render();

	void Position(float x, float y);
	void Position(Vector2& vec);
	Vector2 Position() { return position; }

	void Scale(float x, float y);
	void Scale(Vector2& vec);
	Vector2 Scale() { return scale; }

	D3DXMATRIX GetWorld() { return brick->World(); }
private:
	Sprite * brick;
	Vector2 scakedtextureSize;

	Vector2 position;
	Vector2 scale;
};

cpp파일

#include "stdafx.h"
#include "Obstacle.h"

Obstacle::Obstacle(Vector2 position, Vector2 scale)
	:position (position), scale(scale)
{
	brick = new Sprite(L"./Prinny/Object.png", L"Effect.fx", 4 , 10 , 51 ,47);

	float width = brick->TextureSize().x * scale.x ;
	float height = brick->TextureSize().y * scale.y ;

	brick->Scale(scale);
}

Obstacle::~Obstacle()
{
	SAFE_DELETE(brick);
}

void Obstacle::Update(Matrix & V, Matrix & P)
{
	brick->Position(position);
	brick->Update(V, P);

}

void Obstacle::Render()
{
	brick->Render();
}

void Obstacle::Position(float x, float y)
{
	Position(Vector2(x, y));
}

void Obstacle::Position(Vector2 & vec)
{
	position = vec;
}

void Obstacle::Scale(float x, float y)
{
	Scale(Vector2(x, y));
}

void Obstacle::Scale(Vector2 & vec)
{
	scale = vec;
}

실행

 

 

어찌보면 그냥 사용해도 될꺼같은데?

생각 하지만 팽귄 캐릭터를 x, y축 회전을 하면 박스 크기가 더 커지거나 작아 질수가 있다.

간단한 고정형 오브젝트끼리 충돌 할 때는 계산이 빠른게 더 좋은 방법인거 같다.

'DirectX > DirectX 2D_(구)' 카테고리의 다른 글

DX_Collider [3 / 3] OBB 충돌  (0) 2021.01.26
DX_Collider [1 / 3]  (0) 2021.01.18
DX_카메라 시점변환  (0) 2021.01.05
DX_Move  (0) 2020.12.23
DX_Keyboard  (0) 2020.12.21