윈도우를 생성하는 WinMain 함수의 코드는 전부 중복이므로
WndProc 함수만 적는다.
작성자 본인이 공부 중 푼 문제로 모범답안이 아님을 밝힙니다.
5.
double LengthPts(int x1, int y1, int x2, int y2) // 점과 점 사이의 거리를 구하는 함수
{
return(sqrt((float)((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))));
}
BOOL InCircle(int x, int y, int mx, int my) // 점이 원 내부에 있는지 검사하는 함수
{
if (LengthPts(x, y, mx, my) < BSIZE) return TRUE;
else return FALSE;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static int x, y;
static BOOL Selection; // 선택 상태를 저장하는 값
int mx, my;
HBRUSH hBrush, oldBrush;
switch (iMsg)
{
case WM_CREATE:
x = 50; y = 50;
Selection = FALSE;
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
if (Selection) // 선택중이면 빨간색 원
{
hBrush = CreateSolidBrush(RGB(255, 0, 0));
oldBrush = (HBRUSH)SelectObject(hdc, hBrush);
Ellipse(hdc, x - BSIZE, y - BSIZE, x + BSIZE, y + BSIZE);
SelectObject(hdc, oldBrush);
DeleteObject(hBrush);
}
else // 아니면 그냥 원
{
Ellipse(hdc, x - BSIZE, y - BSIZE, x + BSIZE, y + BSIZE);
}
EndPaint(hwnd, &ps);
break;
case WM_LBUTTONDOWN:
mx = LOWORD(lParam);
my = HIWORD(lParam);
if (InCircle(x, y, mx, my)) Selection = !Selection; // 한번 더 누르면 선택이 해제됨
InvalidateRgn(hwnd, NULL, TRUE);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return(DefWindowProc(hwnd, iMsg, wParam, lParam));
}
6.
복잡한 길찾기 알고리즘은 모르기 때문에.. 단순히 쥐의 좌표를 따라가도록 구현했다.
void CatMove(POINT *cat, int mx, int my) // 고양이의 움직임을 구현하는 함수
{
if (cat->x > mx) // 쥐의 좌표와 비교해서 따라감
{
cat->x--;
}
if (cat->x < mx)
{
cat->x++;
}
if (cat->y > my)
{
cat->y--;
}
if (cat->y < my)
{
cat->y++;
}
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static int x, y;
static BOOL Selection; // 클릭되어있는지 체크하는 값
static POINT catPoint; // 고양이의 좌표를 저장하는 구조체
switch (iMsg)
{
case WM_CREATE:
x = 50; y = 50;
catPoint.x = 100; catPoint.y = 100;
Selection = FALSE;
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
if (Selection) // 클릭되어있으면 쥐 표시
{
TextOut(hdc, x, y, _T("쥐"), _tcslen(_T("쥐")));
}
TextOut(hdc, catPoint.x, catPoint.y, _T("고양이"), _tcslen(_T("고양이")));
EndPaint(hwnd, &ps);
break;
case WM_LBUTTONDOWN:
x = LOWORD(lParam);
y = HIWORD(lParam);
Selection = TRUE;
SetTimer(hwnd, 1, 1, NULL); // 클릭시 타이머 작동
InvalidateRgn(hwnd, NULL, TRUE);
break;
case WM_LBUTTONUP:
Selection = FALSE;
KillTimer(hwnd, 1);
InvalidateRgn(hwnd, NULL, TRUE);
break;
case WM_MOUSEMOVE:
x = LOWORD(lParam);
y = HIWORD(lParam);
InvalidateRgn(hwnd, NULL, TRUE);
break;
case WM_TIMER:
CatMove(&catPoint, x, y);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return(DefWindowProc(hwnd, iMsg, wParam, lParam));
}
8. 7번의 확장이 8번이므로 7번은 패스
double LengthPts(int x1, int y1, int x2, int y2)
{
return(sqrt((float)((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))));
}
BOOL InCircle(int x, int y, int mx, int my)
{
if (LengthPts(x, y, mx, my) < 20) return TRUE;
else return FALSE;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static POINT circle;
static BOOL clicked;
static int startX, startY, oldX, oldY;
static BOOL Drag;
static int endX, endY;
static int moving;
switch (iMsg)
{
case WM_CREATE:
Drag = FALSE;
circle.x = 20; circle.y = 20;
moving = 0;
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
if (clicked)
{
SelectObject(hdc, (HBRUSH)GetStockObject(BLACK_BRUSH));
Ellipse(hdc, circle.x - 20, circle.y - 20, circle.x + 20, circle.y + 20);
}
else
{
Ellipse(hdc, circle.x - 20, circle.y - 20, circle.x + 20, circle.y + 20);
}
EndPaint(hwnd, &ps);
break;
case WM_LBUTTONDOWN:
startX = oldX = 20;
startY = oldY = 20;
if (InCircle(circle.x, circle.y, startX, startY))
{ //원 안을 클릭했을때만 작동
Drag = TRUE;
clicked = TRUE;
}
InvalidateRgn(hwnd, NULL, TRUE);
break;
case WM_LBUTTONUP:
startX = oldX = 0;
startY = oldY = 0;
if (Drag)
{ //원 안을 클릭해서 직선을 그렸다면 작동
SetTimer(hwnd, 1, 70, NULL);
}
Drag = FALSE;
clicked = FALSE;
circle.x = 20; circle.y = 20; // 원 원위치
moving = 0;
InvalidateRgn(hwnd, NULL, TRUE);
break;
case WM_MOUSEMOVE:
hdc = GetDC(hwnd);
if (Drag)
{
SetROP2(hdc, R2_XORPEN);
SelectObject(hdc, (HPEN)GetStockObject(WHITE_PEN));
endX = LOWORD(lParam);
endY = HIWORD(lParam);
MoveToEx(hdc, startX, startY, NULL);
LineTo(hdc, oldX, oldY);
MoveToEx(hdc, startX, startY, NULL);
LineTo(hdc, endX, endY);
oldX = endX; oldY = endY;
}
ReleaseDC(hwnd, hdc);
break;
case WM_TIMER:
if (circle.x >= endX && circle.y >= endY) KillTimer(hwnd, 1);
moving +=10;
circle.x = moving + 20; // 일차함수 형식으로 경로를 계산
circle.y = ((double)(endY - 20) / (endX - 20)) * moving + 20;
InvalidateRgn(hwnd, NULL, TRUE);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return(DefWindowProc(hwnd, iMsg, wParam, lParam));
}
8번 문제는 완전히 능력부족이다..
일차함수를 만드는 과정에서 정수가 아닌 수가 생기다보니 오차가 생겨서
정확히 클릭을 끝낸 지점까지 가지 않는다.
또한 X값을 기준으로 두고 좌표를 증가시키다보니
가파른 직선일수록 움직이는 속도가 빨라지는 문제가 있다.
'핵심 API로 배우는 윈도우 프로그래밍' 카테고리의 다른 글
핵심 API로 배우는 윈도우 프로그래밍 연습문제 3장 10번(실패) (0) | 2022.10.01 |
---|---|
핵심 API로 배우는 윈도우 프로그래밍 연습문제 3장 9번 (0) | 2022.09.29 |
핵심 API로 배우는 윈도우 프로그래밍 연습문제 3장 1~4 (0) | 2022.09.26 |
[windowAPI] 마우스 클릭&드래그로 고무줄 직선 그리기 (2) | 2022.09.24 |
[windowAPI] 마우스 클릭이벤트 & 드래그 이벤트 (0) | 2022.09.23 |