본문 바로가기

WinAPI

[WinAPI] 게임 프레임워크 - 7. Collision

Collision은 Scene 내 Collider을 가진 Object 들의 충돌처리를 한다.

 

void CCollisionManager::Collision(float fDeltaTime)
{
	if (m_CollisionList.size() < 2)
	{
		m_CollisionList.clear();
		return;
	}

	list<CObj*>::iterator iter;
	list<CObj*>::iterator iterEnd = m_CollisionList.end();
	--iterEnd;

	for (iter = m_CollisionList.begin(); iter != iterEnd; ++iter)
	{		
		list<CObj*>::iterator iter1 = iter;
		++iter1;
		list<CObj*>::iterator iter1End = m_CollisionList.end();
		for (; iter1 != iter1End; ++iter1)
		{
			Collision(*iter, *iter1, fDeltaTime);
		}
	}
	m_CollisionList.clear();
}

 

Scene 내 Object들의 ColliderList는 매 업데이트 틱마다 새로 추가되고 collision 함수가 종료하면 list를 비우는 것을 반복해 실시간으로 Collider을 가지고 있는 객체 목록을 최신화한다. 모든 객체 간 충돌 처리를 하기 위해 이중 루프를 만든다. 그래서 첫번째 요소와 이후 요소를 모두 충돌 처리하고 두번째 요소와 이후 요소를 모두 충돌처리한다. 이것을 반복하면 모든 객체간의 충돌 처리가 이루어진다. 그렇다면 충돌 처리가 일어나는 과정에 대해 알아보자. 

 

bool CCollisionManager::Collision(CObj* pSrc, CObj* pDest, float fDeltaTime)
{
	const list<CCollider* > * pSrcList = pSrc->GetColliderList();
	const list<CCollider* >* pDestList = pDest->GetColliderList();

	list<CCollider*>::const_iterator iterSrc;
	list<CCollider*>::const_iterator iterSrcEnd = pSrcList->end();

	list<CCollider*>::const_iterator iterDest;
	list<CCollider*>::const_iterator iterDestEnd = pDestList->end();

	bool bCollision = false;

	for (iterSrc = pSrcList->begin(); iterSrc != iterSrcEnd; ++iterSrc)
	{
		for (iterDest = pDestList->begin(); iterDest != iterDestEnd; ++iterDest)
		{
			if ((*iterSrc)->Collision(*iterDest))

 

먼저 충돌처리 할 두 객체의 충돌체 (Collider) 리스트를 pSrcList, pDestList에 얻어온다. 그리고 이중 루프를 통해서 모든 충돌체 간 충돌 처리를 한다. 처리는 충돌체의 종류에 따라서 달라진다. 충돌체의 종류는 RECT, SPHERE, PIXEL, POINT가 있다. 사각형끼리 충돌 처리는 서로의 left, top, bottom, right만 비교하면 되서 간단히 가능하지만, 사각형과 원의 충돌 처리는 상하좌우에서는 사각형에 원의 반지름 만큼 더한 만큼의 사각형과 원의 중점을 비교해서 충돌 처리하고 대각선에서는 사각형의 꼭지점과 원의 중점 간 거리를 비교한다. 그 외에 픽셀 충돌 처리 등 다른 계산 방법은 생략한다.

 

	bCollision = true;

	(*iterDest)->SetHitPoint((*iterSrc)->GetHitPoint());

	//목록에 충돌된적없으면 처음 충돌된거
	if (!(*iterSrc)->CheckCollisionList(*iterDest))
	{
		(*iterSrc)->AddCollider(*iterDest);
		(*iterDest)->AddCollider(*iterSrc);

		(*iterSrc)->CallFunction(CS_ENTER, *iterDest, fDeltaTime);
		(*iterDest)->CallFunction(CS_ENTER, *iterSrc, fDeltaTime);
	}
	//기존 충돌된적 있으면 계속 충돌 상태인거
	else
	{
		(*iterSrc)->CallFunction(CS_STAY, *iterDest, fDeltaTime);
		(*iterDest)->CallFunction(CS_STAY, *iterSrc, fDeltaTime);
	}
    //충돌이 되고있었다면 이제 충돌상태가 아닌거
	else if((*iterSrc)->CheckCollisionList(*iterDest))
	{
	//서로 지워줌
		(*iterSrc)->EraseCollisionList(*iterDest);
		(*iterDest)->EraseCollisionList(*iterSrc);

		(*iterSrc)->CallFunction(CS_LEAVE, *iterDest, fDeltaTime);
		(*iterDest)->CallFunction(CS_LEAVE, *iterSrc, fDeltaTime);
	}

 

위 코드는 이어지는 코드로 두 Collider이 충돌했을 때 실행된다. Collider는 자신과 충돌한 Collider들의  List를 가지고 있다. 두 Collider이 충돌한적 없으면 서로의 CollisionList에 서로를 추가한다. 그리고 충돌되었을 때 명령을 실행하기 위해 CallFunction으로 함수를 호출한다. 

 

void CallFunction(COLLISION_STATE eState,
		CCollider* pDest, float fDeltaTime)
	{
		list<function<void(CCollider*, CCollider*, float)>>::iterator iter;
		list<function<void(CCollider*, CCollider*, float)>>::iterator iterEnd = m_FuncList[eState].end();

		for (iter = m_FuncList[eState].begin(); iter != iterEnd; ++iter)
		{
			(*iter)(this, pDest, fDeltaTime);
		}
	}

 

CallFunction은 Collider이 가지고 있는 함수List를 실행한다. 함수List의 종류는 처음 충돌했을 때 CS_ENTER, 충돌 상태를 유지할 때 CS_STAY, 충돌상태에서 벗어났을 때 CS_LEAVE, 세가지가 있다. Collider가 가지고 있는 함수List는 Collider을 생성할 때 AddCollisionFunction으로 추가한다.

 

	template <typename T>
	void AddCollisionFunction(COLLISION_STATE eState,T* pObj,
		void(T::*pFunc)(CCollider*, CCollider*, float))
	{
		function<void(CCollider*, CCollider*, float) > func;
		func = bind(pFunc,pObj, placeholders::_1, placeholders::_2,
			placeholders::_3);

		m_FuncList[eState].push_back(func);
	}

 

m_funList는 함수를 저장하기 위해 만든 함수 객체 리스트이다. 함수 객체는 function<인수>의 형식을 가진다. m_funcList는 서로 충돌하는 Collider 객체 2개와 실수 하나를 인수로 가지는 함수들을 저장한다. 

 

	pRC->AddCollisionFunction(CS_ENTER, this, &CPlayer::Hit);
	pRC->AddCollisionFunction(CS_STAY, this, &CPlayer::HitStay);

 

마지막으로 실제 Collider에 충돌했을 때와 충돌 유지중일 때 함수를 추가한다. Hit과 HitStay 함수는 모두 Collider 2개와 실수를 인수로 가지는 함수이다.