-
[Direct2D] 충돌 및 지형 구현C++/미분류 2024. 5. 31. 17:35
지난 글에서 등속, 등가속 운동을 적용하여 중력을 구현했습니다.
[Direct2D] 등속 운동, 등가속 운동, 중력 구현
위 글에 따라 중력이 적용된 객체는 바닥이 없어 계속 추락하는 상태가 지속되었습니다.
이번 글에서는 간단한 지형과 충돌을 구현하여 이미지가 착지할 수 있도록 해보겠습니다.
이번 글은 지난 글에서 코드가 이어집니다.
1. 충돌 판정
더보기이번 글에서 사용될 "충돌"은 두 기하(이미지)가 겹치는 경우를 의미합니다.
우선 D2D에서 사용되는 사각형은 D2D1_RECT_F 자료형을 사용하며, 형태는 다음과 같습니다.
사각형의 상, 하, 좌, 우 모서리의 좌표를 사용합니다.
사각형 A와 B가 있다고 가정할 때, 두 사각형의 충돌 여부는 다음과 같이 판정할 수 있습니다.
A의 오른쪽 모서리가 B의 왼쪽 모서리보다 오른쪽에 있는가? ( = 큰가?)
A의 왼쪽 모서리가 B의 오른쪽 모서리보다 왼쪽에 있는가? ( = 작은가?)
A의 하단이 B의 상단보다 낮게 있는가? ( = 큰가?)
A의 상단이 B의 하단보다 높게 있는가? ( = 작은가?)괄호 내부의 대, 소 여부는 Direct2D의 좌표계 (오른쪽이 +X, 아래쪽이 +Y)를 따르는 표현입니다.
두 사각형이 충돌하는 것과 위 4가지 조건은 서로 동일합니다.
몇 가지 예시를 살펴보도록 하겠습니다.
이 경우는 사각형의 Y축은 겹쳤지만, X축은 겹치지 않은 경우입니다.
각각의 조건문은 다음과 같이 성립합니다.
A의 오른쪽 모서리가 B의 왼쪽 모서리보다 오른쪽에 있는가? ( = 큰가?) (X)
A의 왼쪽 모서리가 B의 오른쪽 모서리보다 왼쪽에 있는가? ( = 작은가?) (X)
A의 하단이 B의 상단보다 낮게 있는가? ( = 큰가?) (O)
A의 상단이 B의 하단보다 높게 있는가? ( = 작은가?) (O)반대의 경우입니다.
이 경우는 X축은 겹치게 되었지만 Y축은 그렇지 않은 경우입니다.
A의 오른쪽 모서리가 B의 왼쪽 모서리보다 오른쪽에 있는가? ( = 큰가?) (O)
A의 왼쪽 모서리가 B의 오른쪽 모서리보다 왼쪽에 있는가? ( = 작은가?) (O)
A의 하단이 B의 상단보다 낮게 있는가? ( = 큰가?) (X)
A의 상단이 B의 하단보다 높게 있는가? ( = 작은가?) (X)다음과 같이 두 사각형이 완전히 겹쳤을 경우에만 모든 조건이 참이 됩니다.
A의 오른쪽 모서리가 B의 왼쪽 모서리보다 오른쪽에 있는가? ( = 큰가?) (O)
A의 왼쪽 모서리가 B의 오른쪽 모서리보다 왼쪽에 있는가? ( = 작은가?) (O)
A의 하단이 B의 상단보다 낮게 있는가? ( = 큰가?) (O)
A의 상단이 B의 하단보다 높게 있는가? ( = 작은가?) (O)위 조건을 코드로 구현할 경우 다음과 같이 함수를 작성할 수 있습니다.
bool IsCollision(D2D1_RECT_F a, D2D1_RECT_F b) { if (a.right >= b.left && a.left <= b.right && a.bottom >= b.top && a.top <= b.bottom) return true; return false; }
위 함수는 충돌 시 물리량에 대해서는 고려하고 있지 않습니다.
두 물체의 충돌에 의해 일어나는 물리현상은 다른 글에서 다룰 수 있도록 하겠습니다.
2. 지형 구현
더보기게임에서 지형이라는 용어는 여러가지 의미로 사용됩니다.
이번 글에서 지형은 게임 내 오브젝트가 딛을 수 있는 바닥, 플랫폼을 의미합니다.
이전 문단에서 구현한 충돌 판정을 사용하기 위해, 지형도 D2D1_RECT_F자료형을 사용하겠습니다.
이번 글에서는 다음과 같이 플랫폼 2개를 만들었습니다.
class MyApp { ... private: ... std::vector<D2D1_RECT_F> ground = { D2D1::RectF(0.0f, 400.f, 640.f, 480.f), D2D1::RectF(200.0f, 350.f, 440.f, 410.f) }; };
위 클래스 변수를 렌더링 함수에서 렌더링합니다.
HRESULT MyApp::OnRender() { ... for (auto& i : ground) { myDirect2dContext->FillRectangle(&i, myCornflowerBlueBrush.Get()); } ... }
프로그램을 실행하면 다음과 같이 파란색 플랫폼 2개를 확인할 수 있습니다.
하지만 아직 충돌 관련 코드가 적용되지 않았기 때문에, 떨어지는 플레이어 캐릭터는 플랫폼을 딛지 못하는 것을 볼 수 있습니다.
3. MyBitmap 수정
더보기충돌 판정을 하는 함수는 두 개의 D2D1_RECT_F를 받습니다.
하지만 이번 글에서 충돌 판정을 할 객체 중 플레이어 캐릭터는 Bitmap객체입니다.
따라서, Bitmap객체의 Rect를 구하는 함수를 추가로 작성해야 합니다.
우선, 헤더에 현재 프레임의 Rect를 구하는 함수를 추가합니다.
class MyBitmap { public: D2D1_RECT_F GetBitmapRect(); ... };
그리고, Bitmap의 프레임별 Rect를 저장하는 변수를 추가합니다.
class MyBitmap { private: std::vector<D2D1_RECT_F> bitmapRect; ... }
Initialize함수에 BitmapRect를 초기화하는 코드를 추가합니다.
void MyBitmap::Initialize(...) { ... for (auto& i : bitmap) { ... auto tmp = i->GetSize(); bitmapRect.push_back(D2D1::RectF(0, 0, tmp.width, tmp.height)); } ... }
GetBitmapRect함수는 초기화된 Rect의 크기와 현재 위치를 이용해서 이미지의 Rect를 반환합니다.
D2D1_RECT_F MyBitmap::GetBitmapRect() { if (bitmapRect.size() > currentFrame && bitmap.size() > currentFrame) { auto rect = bitmapRect[currentFrame]; auto size = bitmap[currentFrame]->GetPixelSize(); rect.left += currentPosition.x - size.width / 2; rect.right += currentPosition.x - size.width / 2; rect.top += currentPosition.y - size.height; rect.bottom += currentPosition.y - size.height; return rect; } else { return D2D1::RectF(); } }
이것으로, MyBitmap의 GetBitmapRect함수를 호출하면 현재 이미지의 Rect를 알 수 있게 되었습니다.
4. Update함수 수정
더보기Update함수는 현재 틱 (프레임)과 관련된 연산을 수행합니다.
기존 코드는 각 이미지의 Tick함수 호출 및 플레이어 캐릭터에 중력을 적용하는 코드가 있었습니다.
이제 플레이어 캐릭터가 지형과 충돌하면 멈출 수 있는 코드를 추가하도록 하겠습니다.
void MyApp::Update() { ... D2D1_RECT_F t = myCharacterBitmap->GetBitmapRect(); for (auto& i : ground) { if (IsCollision(t, i)) { downSpeed = 0; deltaDown = 0; } } ... }
Bitmap의 Rect를 가져온 후, 각각의 지형에 대해 충돌 연산을 수행하는 코드입니다.
충돌했다고 판정될 경우, 해당 프레임에서의 낙하 속도 및 변위를 0으로 만들어줍니다.
이전 글에서 중력을 적용할 때, 바닥을 만들어주지 않아 캐릭터가 계속 추락했었습니다.
이번 글에서는 간단한 충돌을 구현하고, 바닥을 만들어 캐릭터를 착지할 수 있게 만들었습니다.
이번 글에서 사용된 코드의 전문은 아래 Github에서 확인하실 수 있습니다.
GitHub - ruru14/WinapiStudy: WinAPI및 DirectX를 공부하며, 간단한 운동 법칙을 적용해봅니다.
WinAPI및 DirectX를 공부하며, 간단한 운동 법칙을 적용해봅니다. Contribute to ruru14/WinapiStudy development by creating an account on GitHub.
github.com
이번 글이 도움이 되셨길 바랍니다.
감사합니다.
'C++ > 미분류' 카테고리의 다른 글
[WinAPI] Alt키 제어하기 (WM_SYSCOMMAND) (0) 2024.06.18 [Direct2D] 점프 구현 (1) 2024.06.13 [Direct2D] 등속 운동, 등가속 운동, 중력 구현 (0) 2024.05.17 [Direct2D] ID2D1Effect : Chroma key (1) 2024.04.22 [Direct2D] ID2D1Effect : Edge detection (0) 2024.04.17