일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 알고리즘
- 연산자
- Javascript
- Kotlin
- 포인터
- CS
- 배열
- c
- tipssoft
- c#
- 백준
- Windows
- 프로그래밍
- Tips강좌
- Tips프로그래밍강좌
- Win32
- 함수
- 리뷰
- Desktop
- doit코틀린프로그래밍
- 티스토리
- 김성엽
- 이지스퍼블리싱
- c++
- 문법
- Direct2D
- Visual Studio
- 지식나눔강좌
- VS ERROR
- Programming
- Yesterday
- Today
- Total
F.R.I.D.A.Y.
물리엔진 - 중력 구현 본문
지구에서는 지구 중력의 영향으로 물체를 공중에 놓으면 바닥으로 떨어집니다. 이런 식으로 중력에 영향을 받는 듯한 코드를 작성해봅니다.
# Direct2D를 활용합니다.
기본 코드
기본 코드는 아래의 압축파일을 기준으로 합니다.
프로젝트 내 baseWin.h에 오류가 있습니다. 프로젝트 기준 baseWin.h > BaseWindow 클래스 > static WindowProc 함수에서 (LONG)을 (LONG_PTR)로 변경시 오류가 사라집니다.
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
DERIVED_TYPE* pThis = nullptr;
if (uMsg == WM_NCCREATE) {
CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
pThis = (DERIVED_TYPE*)pCreate->lpCreateParams;
// SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)pThis);
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);
pThis->hWnd = hWnd;
}
// .....
}
사각형 그리기
먼저 사각형을 그려봅니다. 이 코드에서는 사각형을 공중에 놓을 물체라고 생각하죠. 사각형을 그리는 방법은 두 가지입니다.
- 두 점을 기반으로 사각형 그리기
- 한 점과 사각형의 너비 및 높이
단순히 사각형을 그리는 것은 두가지 중 어느 것을 사용하던 상관 없겠지만, 지금은 단순 그리기가 아니라 물체의 위치를 연산하는 작업을 하므로 한 점과 사각형의 너비 및 높이를 이용한 그리기를 이용합니다.
변수 선언 및 초기화
받은 소스파일에서 mainWin.h 파일에 아래와 같이 rcCenter와 rcSize 변수를 생성해줍니다. 이 두 변수로 그리기도 하고 연산도 진행할 것입니다.
이제 초기화를 진행하겠습니다. OnCreate 메서드에서 아래와 같이 작업합니다.
사각형의 위치의 x좌표는 윈도우 영역의 중간[# 정확히는 윈도우 클라이언트 영역의 중간]이고, y좌표는 위에서 40만큼 위치한 곳입니다. 크기는 그 점을 중심으로 (40, 40)이죠.
사각형 그리기
위에서 설정한 코드를 기반으로 사각형을 그려보겠습니다. OnPaint 메서드로 이동합니다. 아무 처리도 하지 않았다면 아래처럼 코드가 구현되어 있을 것입니다.
LRESULT MainWindow::OnPaint()
{
PAINTSTRUCT ps;
pRT->BeginDraw();
BeginPaint(hWnd, &ps);
pRT->Clear(D2D1::ColorF(D2D1::ColorF::Black));
EndPaint(hWnd, &ps);
return pRT->EndDraw();
}
여기에 아래 코드를 추가해 우리가 설정한 위치에 사각형이 제대로 그려지는 테스트합니다.
pRT->DrawRectangle(D2D1::RectF(rcCenter.x - rcSize.width / 2, rcCenter.y - rcSize.height / 2,
rcCenter.x + rcSize.width / 2, rcCenter.y + rcSize.height / 2), pBrush);
# pBrush가 없는데요?
맞습니다. pBrush는 올려놓은 코드에는 존재하지 않습니다. 다만, 손쉽게 생성할 수 있습니다.
해당 문서의 CreateSolidColorBrush 항목을 찾아보세요. 이미 배경색은 Black으로 지정되어 있기 때문에 까만 색으로 브러시를 정해버리면 보이지 않습니다. 배경색, 혹은 pBrush 색을 다른 색으로 변경해야 보입니다.
저는 하얀 색으로 사각형을 그렸습니다. 잘 그려지네요.
사각형 떨어트리기
제공된 코드에는 이미 실시간으로 업데이트를 하도록 구성되어 있습니다. 특정 시점이 될 때마다 계속해서 윈도우를 새로 그리도록 하고 있죠.
그리기 전에 연산을 통해 사각형의 위치를 수정하겠습니다. 그러기 위해서는 계산을 위한 함수를 호출해야겠죠.
메서드 생성/호출
MainWindow 내부 메서드로 Calculate를 생성해줍니다. 외부에서 접근 가능해야하므로, 접근 제한자는 public으로 설정합니다.
void Calculate();
원형을 생성한 메서드는 이제 외부에서 호출이 가능해졌습니다. main.cpp의 아래 항목에 호출하도록 코드를 작성하겠습니다.
메서드 채우기
우리가 움직이려 하는 것은 사각형입니다. 이 프로젝트에서 사각형의 위치를 결정짓는 변수는 rcCenter입니다. 이 값의 y값을 계속 더해 윈도우에서 떨어지는 것처럼 만들어보겠습니다.
단 한줄의 코드로 떨어지는 사각형은 구현을 했지만 이대로라면 사각형은 계속해서 떨어져서 사용자 눈에서 보이지 않게 되네요. 아래에 코드 몇 줄을 추가해 윈도우 바깥으로 벗어나면 다시 초기 위치로 가져오도록 하겠습니다.
if (rcCenter.y + rcSize.height / 2 > (clientSize.bottom - clientSize.top)) {
rcCenter.y = 40;
}
중력 구현하기
여기까지만 해도 물체를 떨어트리는데는 이상이 없지만, 아쉽습니다. 우리가 생각한 이미지는 이게 아닌데 말이죠.
이게 우리가 바라는거죠. 낙하 속도가 점점 커지는 것.
이전 코드에서 우리는 사각형을 떨어트릴 때 상수 값을 더해 사각형 y 위치에 변형을 주었습니다. 변수 하나를 생성해 값을 더해주면 되겠네요.
void MainWindow::Calculate()
{
static float gravity = 3.f;
static float dropSpeed = 0.f;
dropSpeed += gravity;
rcCenter.y += dropSpeed;
if (rcCenter.y + rcSize.height / 2 > (clientSize.bottom - clientSize.top)) {
rcCenter.y = 40;
dropSpeed = 0.f;
}
}
dropSpeed 변수가 사각형의 실제 하락 속도입니다. 함수가 호출 될 때마다 dropSpeed 값이 gravity 값만큼 더해지는 것을 알 수 있습니다. 만일 늦게 떨어트리고 싶다거나 빠르게 떨어트리고 싶다면 gravity 값을 조정하면 됩니다.
초기 위치로 돌려놓을 때는 하락 속도를 초기화 해야합니다. 그래야 처음 떨어질 때와 같은 모습을 보일 수 있을테니까요. dropSpeed 값을 초기화를 하지 않으면 나중엔 분명 계산상으론 떨어지는데 이미지는 정지한 것과 같은 모습을 보일겁니다.[# 이동한 값이 클라이언트 영역보다 크니까요..]
Extra.
이 포스트를 따라했다면 중력과 유사한 효과를 만들 수 있습니다. 그런데 이 코드를 그대로 따라하면 약간 이상한 모습이 보입니다. 바닥에 닿지 않았는데 초기 위치로 돌아가버리는 거죠.
사각형의 하락 속도가 너무 커서 바닥을 찍었을 때 아래의 초기 위치로 되돌리는 명령이 실행되어 바닥을 찍은 모습을 보여주지 않고 그대로 다시 올려버리는거죠. 이 문제는 스스로 한 번 해결해보세요! 다음 포스트에서 해결 방법을 공개합니다.
# index
'DEV > Direct2D' 카테고리의 다른 글
물리엔진 - 벽 충돌 part1. 바닥 구현 (0) | 2021.05.11 |
---|---|
물리엔진 - 중력 구현 안정화 (0) | 2021.05.10 |
Direct2D - SetTransform (0) | 2021.05.05 |
Direct2D - WIC IWICBitmapFlipRotator (0) | 2021.05.04 |
Direct2D - WIC IWICBitmapClipper (0) | 2021.05.01 |