F.R.I.D.A.Y.

물리엔진 - 중력 구현 본문

DEV/Direct2D

물리엔진 - 중력 구현

F.R.I.D.A.Y. 2021. 5. 10. 00:55
반응형

 지구에서는 지구 중력의 영향으로 물체를 공중에 놓으면 바닥으로 떨어집니다. 이런 식으로 중력에 영향을 받는 듯한 코드를 작성해봅니다.

 

# Direct2D를 활용합니다.


기본 코드

 기본 코드는 아래의 압축파일을 기준으로 합니다.

PhysicsEngine.zip
0.01MB

 

프로젝트 내 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는 올려놓은 코드에는 존재하지 않습니다. 다만, 손쉽게 생성할 수 있습니다.

 

Direct2D - ID2D1SolidColorBrush

 단일 색상 브러시를 구현할 때 필요한 인터페이스이다. ID2D1SolidColorBrush  ID2D1HwndRenderTarget에서 생성할 수 있는 브러시에 대한 정보를 담는 객체의 인터페이스다. 사각형 등의 도형을 그릴 때 선

pang2h.tistory.com

 해당 문서의 CreateSolidColorBrush 항목을 찾아보세요. 이미 배경색은 Black으로 지정되어 있기 때문에 까만 색으로 브러시를 정해버리면 보이지 않습니다. 배경색, 혹은 pBrush 색을 다른 색으로 변경해야 보입니다.

 저는 하얀 색으로 사각형을 그렸습니다. 잘 그려지네요.

 

사각형 떨어트리기

 제공된 코드에는 이미 실시간으로 업데이트를 하도록 구성되어 있습니다. 특정 시점이 될 때마다 계속해서 윈도우를 새로 그리도록 하고 있죠.

main.cpp

 그리기 전에 연산을 통해 사각형의 위치를 수정하겠습니다. 그러기 위해서는 계산을 위한 함수를 호출해야겠죠.

 

메서드 생성/호출

 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

728x90
반응형

'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
Comments