DirectX11 봄버맨 모작 프로젝트 개발일지 (2)
오늘은 저번 포스팅에 이어 콜라이더를 구현하고, 이를 활용하여 오브젝트간의 충돌을 체크하여 상호작용을 하는 것까지 만들어보도록 하겠습니다.
콜라이더를 구현하기 위해서 대략적인 계획을 만들어 보았습니다.
1. Collider 제작
2. Collider를 관리할 Manager 생성
3. Collider를 오브젝트에 추가
4. 충돌을 체크할 오브젝트 그룹을 추가
5. 각 오브젝트에 충돌 시의 상호작용 구현
순서에 따라서 조금씩 알아가보도록 합시다!
콜라이더부터 살펴보도록 합시다.
#pragma once
#include "pch.h"
class ModelClass;
class EffectClass;
class Collider
{
private:
static UINT g_iNextID; //
ModelClass* m_pOwnerModel; // collider를 소유하고 있는 오브젝트
EffectClass* m_pOwnerEffect; // collider를 소유하고 있는 이펙트
Pos m_vOffsetPos; // 오브젝트로부터 상대적인 위치
Pos m_vFinalPos; // finalupdate에서 매 프레임마다 계산
Pos m_vScale; // 충돌체의 크기
UINT m_iID; // 충돌체 고유한 ID값
UINT m_iCol;
public:
void SetOffsetPos(Pos _vPos) { m_vOffsetPos = _vPos; }
void SetScale(Pos _vScale) { m_vScale = _vScale; }
Pos GetOffsetPos() { return m_vOffsetPos; }
Pos GetScale() { return m_vScale; }
Pos GetFinalPos() { return m_vFinalPos; }
UINT GetID() { return m_iID; }
ModelClass* GetModel() { return m_pOwnerModel; }
EffectClass* GetEffect() { return m_pOwnerEffect; }
public:
void finalUpdate();
void render();
public:
// 충돌 시점 함수
void OnCollision(Collider* _pOther); // 충돌 중인 경우 호출되는 함수
void OnCollisionEnter(Collider* _pOther);
void OnCollisionExit(Collider* _pOther);
// 콜라이더 간의 대입을 방지한다.
Collider& operator= (Collider& _origin) = delete;
public:
Collider();
Collider(const Collider& _origin);
~Collider();
friend class ModelClass;
friend class EffectClass;
};
콜라이더는 오브젝트가 가질수도, 가지지 않을 수도 있는 '기능'입니다. 그렇기 때문에 존재하는 경우에 무조건 오브젝트의 하나의 부품으로써 존재하게 됩니다. 그렇기 때문에 해당 콜라이더를 가지는 오브젝트를 가리키는 포인터를 두고, 오브젝트와의 상대적 위치, 크기 등을 설정합니다. 또한 콜라이더를 가지는 오브젝트들 간의 구분을 위해서 ID 값을 지정하게 됩니다.
콜라이더를 대략적으로 알아보았습니다. 그렇다면 이를 관리하는 매니저 클래스도 알아봅시다.
#pragma once
#include "pch.h"
class Collider;
union COLLIDER_ID
{
struct {
UINT Left_id;
UINT Right_id;
};
ULONGLONG ID;
};
class CollisionMgr
{
SINGLE(CollisionMgr)
private:
map<ULONGLONG, bool> m_mapColInfo; // 충돌체 간의 이전 프레임 충돌 정보
UINT m_arrCheck[(UINT)GROUP_TYPE::END]; // 그룹간의 충돌 체크 매트릭스
public:
void init();
void update();
void CheckGroup(GROUP_TYPE _eLeft, GROUP_TYPE _eRight);
void Reset();
private:
void CollisionGroupUpdate(GROUP_TYPE _eLeft, GROUP_TYPE _eRight);
void CollisionGroupUpdate(GROUP_TYPE _eLeft, EFFECT_TYPE _eRight);
bool isCollision(Collider* _pLeftCol, Collider* _pRightCol);
};
콜리전 매니저를 두어 콜라이더들간의 충돌을 관리할 수 있게끔 싱글턴 패턴을 이용하여 하나의 인스턴스만을 두어 관리하고, 두 오브젝트가 부딪힐 때 각각의 ID를 이용하여 콜라이더간의 충돌하는 ID를 만들어서 관리합니다. 또한 충돌체크를 하고자 하는 오브젝트 그룹들을 설정하여 해당 그룹들만 처리를 진행하며, 충돌 체크를 진행합니다.
충돌 체크의 경우에는 부딪히는 콜라이더의 위치에 따라서 관리를 하게 됩니다.
bool CollisionMgr::isCollision(Collider* _pLeftCol, Collider* _pRightCol)
{
Pos vLeftPos = _pLeftCol->GetFinalPos();
Pos vLeftScale = _pLeftCol->GetScale();
Pos vRightPos = _pRightCol->GetFinalPos();
Pos vRightScale = _pRightCol->GetScale();
if (abs(vRightPos.x - vLeftPos.x) < (vLeftScale.x + vRightScale.x) / 2.f
&& abs(vRightPos.z - vLeftPos.z) < (vLeftScale.z + vRightScale.z) / 2.f)
{
return true;
}
return false;
}
이런 식으로 처리를 하게 됩니다. (저는 y축에 대한 계산은 불필요하여 뺏지만, 필요하다면 추가하면 됩니다.)
콜라이더를 관리할 매니저까지 만들었으니, 매니저 클래스에 있는 Check Group 기능을 이용하여 충돌을 체크하고자 하는 씬에 그룹들을 추가시킵니다.
(ex. CollisionMgr::GetInst()->CheckGroup(GROUP_TYPE::PLAYER, GROUP_TYPE::ENEMY);)
추가를 했다면, 충돌했을 때의 기능을 추가해야겠죠?
많은 기능을 추가할 수 있겟지만 저는 단순하게 Debug를 출력하는 기능을 만들어 보았습니다.
void Player::OnCollisionEnter(Collider* _pOther)
{
if(_pOther->GetModel() != nullptr && _pOther->GetModel()->GetName() == L"Enemy")
OutputDebugStringA("OnCollision Enter \n");
}
부딪힌 오브젝트가 이펙트가 아니고, GetName이 Enemy인 경우에 OnCollision Enter라는 Debug 문구를 출력하도록 했습니다.
핵심적인 내용들만 적어봤는데요, 생략되었지만 자잘한 수정사항들이 있었습니다. (Effect에 대한 콜라이더 처리기능 등) 전체 프로젝트 실행파일 및 코드는 해당 프로젝트가 모두 마무리되는 시점에 업로드 해보도록 하겠습니다..! (살짝 민망..) 모두 열심히 하셔서 좋은 결과 얻으면 좋겠습니다! 포바~