Windows API 바라보는 방향으로 움직이기
사각형을 회전시켰다.
회전시키기 전까지 움직이기는 껌인줄 알았다.
그러나 여태 내가 만든 프로그램들은 엔진이 대신해줘서 쉬웠던거지
쌩 코드로 만드는 움직임은 쉽지 않았다.
1. 뭐가 어려운가.
일단 회전을 시켰으면 바라보는 방향으로 움직이기를 할껀데
단순히 화면기준 위아래양옆으로 움직이는 것이 아니기에
이것조차 삼각함수를 써야한다!
뭔가 머릿속에는 이렇게 하면 된다 싶어
A4용지에 끄적여보는데
멍청한 머리로는 답이 안나와 일단 해봤다.
2. 코드
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static float x = 0, y =0;
static float ang = 0;
HDC hdc;
static float r = 0;
static float mP[] = { 500,250 };
static float fP[] = { 500, 240 };
static const float fPAng = atan2f(mP[1] - fP[1], mP[0] - fP[0]) * RAD2DEG;
static const float pA[] = { 300,150, atan2f(mP[1] - pA[1], mP[0] - pA[0]) * RAD2DEG }, pB[] = { 700,150, atan2f(mP[1] - pB[1], mP[0] - pB[0]) * RAD2DEG }, pC[] = { 300, 350, atan2f(mP[1] - pC[1], mP[0] - pC[0]) * RAD2DEG }, pD[] = { 700, 350, atan2f(mP[1] - pD[1], mP[0] - pD[0]) * RAD2DEG };
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 메뉴 선택을 구문 분석합니다.
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
TCHAR greeting1[] = _T("Hello world");
TCHAR greeting2[] = _T("man!");
// TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다.
r = sqrt(pow((pC[1] - pA[1]), 2) + pow((pD[0] - pC[0]), 2))/2;
TCHAR IpOut[1024];
MoveToEx(hdc, mP[0] - r*cos(DEG2RAD*(pA[2] + ang)), mP[1] - r*sin(DEG2RAD*(pA[2] + ang)), NULL);
TextOut(hdc, mP[0] - r*cos(DEG2RAD*(pA[2] + ang)), mP[1] - r*sin(DEG2RAD*(pA[2] + ang)), TEXT("A"), 1);
LineTo(hdc, mP[0] - r*cos(DEG2RAD*(pB[2] + ang)), mP[1] - r*sin(DEG2RAD*(pB[2] + ang)));
TextOut(hdc, mP[0] - r*cos(DEG2RAD*(pB[2] + ang)), mP[1] - r*sin(DEG2RAD*(pB[2] + ang)), TEXT("B"), 1);
LineTo(hdc, mP[0] - r*cos(DEG2RAD*(pD[2] + ang)), mP[1] - r*sin(DEG2RAD*(pD[2] + ang)));
TextOut(hdc, mP[0] - r*cos(DEG2RAD*(pD[2] + ang)), mP[1] - r*sin(DEG2RAD*(pD[2] + ang)), TEXT("D"), 1);
LineTo(hdc, mP[0] - r*cos(DEG2RAD*(pC[2] + ang)), mP[1] - r*sin(DEG2RAD*(pC[2] + ang)));
TextOut(hdc, mP[0] - r*cos(DEG2RAD*(pC[2] + ang)), mP[1] - r*sin(DEG2RAD*(pC[2] + ang)), TEXT("C"), 1);
LineTo(hdc, mP[0] - r*cos(DEG2RAD*(pA[2] + ang)), mP[1] - r*sin(DEG2RAD*(pA[2] + ang)));
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
switch (wParam) {
case VK_LEFT:
ang--;
break;
case VK_RIGHT:
ang++;
break;
case VK_UP:
mP[0] = fP[0];
mP[1] = fP[1];
fP[0] -= 10 * cos(DEG2RAD*(fPAng + ang));
fP[1] -= 10 * sin(DEG2RAD*(fPAng + ang));
break;
case VK_DOWN:
fP[0] = mP[0];
fP[1] = mP[1];
mP[0] += 10 * cos(DEG2RAD *(fPAng + ang));
mP[1] += 10 * sin(DEG2RAD *(fPAng + ang));
}
InvalidateRect(hWnd, NULL, TRUE);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
무려 86줄이나 되는 쌩코드를 올렸다.
일단 지난번 코드에서 몇가지를 바꿨다.
지난번 코드로 출력시킨 사각형은
사실 비대칭이었다..
그래서 좀 더 정확한 사각형을 위해
각 점의 위치와 각도를 저장한 pA~pD, mP의 타입을 int에서 float로 바꾸고
앞을 가리킬 점 fP와 각도 fPAng 을 추가했다.
fP는 mP에서 약간 위에 위치해 있다.
fP는 앞을 가리키는 용도 외에 움직이는 속도까지 담당한다.
그리고 사각형 각 꼭짓점들이 회전할때 앞을 가리키는 fP또한 눈에는 안보이지만 같이 회전한다.
위 방향키를 누르면 mP가 fP의 위치로 이동해 움직이는 듯한 효과를 보여준다.
fP는 다시 새 좌표를 잡고 이렇게 저렇게 해서 만들었다.
그리고 각 점의 각도들은 const를 해서 변경되는 일이 없게 해야한다.
그렇지 않으면

이런 3D스러운 움직임을 볼 수 있다.
저런 처리까지 이래저래 다 완벽한듯이 하면

어디 아픈 사각형의 움직임을 볼 수 있다.
4. 끝
사실 아직 많이 부족하고
fP는 필요 없다.
없어도 만들 수 있다.
근데 있는게 나는 좋다.
태클은 언제나 환영