본문 바로가기

Win32 api

Win32 api 강의 27 - 28화.

- Collision Manager 설계.

// CCollisionMgr.h
#pragma once
class CCollisionMgr
{
    SINGLETON(CCollisionMgr);

private:
    UINT m_arrCheck[(UINT)GROUP_TYPE::END];

private:
    void CollisionGroupUpdate(GROUP_TYPE eType1, GROUP_TYPE eType2);
public:
    void init();
    void late_update();

public:
    void CheckGroup(GROUP_TYPE eType1, GROUP_TYPE eType2);
    inline void Reset() { memset(m_arrCheck, 0, sizeof(UINT) * (UINT)GROUP_TYPE::END); }
};

 

m_arrCheck 는 충돌 매트릭스임. UINT 값(4바이트)

 

 

충돌 매트릭스는 이렇게 row 값이 col 값 이하인 부분만 씀.

그래서 그림으로 나타냈을 때 이차원 배열이지만(column 은 비트 값 역순으로 나열), 배열의 절반은 안써야 함.

// CCollisionMgr.cpp
void CCollisionMgr::CheckGroup(GROUP_TYPE eType1, GROUP_TYPE eType2)
{
    // 더 작은 그룹 번호가 eType1이 되도록 보장.
    if (eType1 > eType2)
        std::swap(eType1, eType2);

    m_arrCheck[(UINT)eType1] ^= (1 << (UINT)eType2);
}

 

CheckGroup 함수에서 입력된 두 그룹의 충돌 유무를 on / off 한다. XOR 연산자로 기존의 값을 반전시킬 수 있음.

 

// CCollisionMgr.cpp
void CCollisionMgr::late_update()
{
    for(UINT i = 0; i < (UINT)GROUP_TYPE::END; ++i)
    {
        for(UINT j = i; j < (UINT)GROUP_TYPE::END; ++j)
        {
            if(m_arrCheck[i] & (1 << j))
            {
                CollisionGroupUpdate((GROUP_TYPE)i, (GROUP_TYPE)j);
            }
        }
    }
}

 

매 프레임마다 두 그룹 간 충돌 체크를 한다. late_update 로 해줬는데,

이는 충돌체 위치의 최종 계산이 오브젝트에서 update 로 로직 계산이 끝난 이후

late_update 에서 이루어지기 때문.

 

// CCore.cpp
void CCore::progress()
{
    update();

    late_update();

    render();
}
void CCore::update()
{
    // Manager Update
    CTimeMgr::GetInstance()->update();
    CKeyMgr::GetInstance()->update();
    CSceneMgr::GetInstance()->update();
}
void CCore::late_update()
{
    // Scene late_update -> Object late_update
    CSceneMgr::GetInstance()->late_update();
    CCollisionMgr::GetInstance()->late_update();
}

 

Core 에서 호출 순서도 조금 손봤다. 

 

// CCollisionMgr.cpp
void CCollisionMgr::CollisionGroupUpdate(GROUP_TYPE eType1, GROUP_TYPE eType2)
{
    CScene* pCurScene = CSceneMgr::GetInstance()->GetCurScene();
    if (pCurScene == nullptr)
        return;

    const vector<CObject*>& arrObj1 = pCurScene->GetObjByGroup(eType1);
    const vector<CObject*>& arrObj2 = pCurScene->GetObjByGroup(eType2);

    for(CObject* pObj1 : arrObj1)
    {
        if (pObj1 == nullptr || pObj1->GetCollider() == nullptr)
            continue;
        for(CObject* pObj2 : arrObj2)
        {
            if (pObj2 == nullptr || pObj2->GetCollider() == nullptr)
                continue;
            // 같은 오브젝트끼리 충돌 검사하지 않도록.
            if (pObj1 == pObj2)
                continue;
            // 충돌 검사.
            if (pObj1->GetCollider()->Collision(pObj2->GetCollider()))
            {
                // 충돌 처리 로직 구현.
                // 예: 이벤트 발생, 상태 변경 등.
                int a = 0;
            }
        }
    }
}

 

코드는 길지만 단순히 2중 for 문을 돌면서 두 그룹 간 충돌한 Collider 를 찾아내는 과정임. Collider::Collision 함수는

// CCollider.cpp
bool CCollider::Collision(CCollider* pOther)
{
    if (pOther == nullptr)
        return false;
    // AABB 충돌 검사
    float leftA = m_vFinalPos.x - m_vSize.x * 0.5f;
    float rightA = m_vFinalPos.x + m_vSize.x * 0.5f;
    float topA = m_vFinalPos.y - m_vSize.y * 0.5f;
    float bottomA = m_vFinalPos.y + m_vSize.y * 0.5f;

    float leftB = pOther->m_vFinalPos.x - pOther->m_vSize.x * 0.5f;
    float rightB = pOther->m_vFinalPos.x + pOther->m_vSize.x * 0.5f;
    float topB = pOther->m_vFinalPos.y - pOther->m_vSize.y * 0.5f;
    float bottomB = pOther->m_vFinalPos.y + pOther->m_vSize.y * 0.5f;

    // 사각형 A와 B가 겹치는지 확인
    if (leftA >= rightB || rightA <= leftB ||
        topA >= bottomB || bottomA <= topB)
    {
        // 겹치지 않음
        return false;
    }
    return true;
}

 

일단 사각형 충돌만 구현해둠. 

'Win32 api' 카테고리의 다른 글

Win32 api 강의 31 - 33화.  (0) 2025.09.19
Win32 api 강의 29 - 30화.  (0) 2025.09.18
Win32 api 강의 25 - 26화.  (0) 2025.09.17
Win32 api 강의 24화.  (0) 2025.09.17
Win32 api 강의 23화.  (0) 2025.09.16