Programming Language/Windows API
지렁이게임
1. 뱀 그리기
- 먼저 게임을 만들기 위해 규칙이 여러가지 필요하지만 게임에 대한 깊이가 낮아 핸디캡이나 죽는 것이 없다.
[1] 화면 영역 내에서 뱀이 자유롭게 움직일 수 있다.
[2] 화면 영역 내에 뱀의 먹이가 파란색으로 표시된다.
[3] 뱀의 먹이는 일정 시간이 흐른 후에 없어지며, 다른 곳에 새로 먹이가 생성된다.
[4] 뱀은 먹이를 먹으면 꼬리가 1씩 증가한다.
[5] 뱀의 머리는 빨간색이다.
[6] 뱀의 몸은 녹색이다.
----------------미 추가사항------------------
[7] 머리가 자신의 몸에 닿으면 죽는다.
[8] 화면 영역 밖으로 나가도 죽는다.
[9] 30초에 한 번은 먹이를 먹어야 한다. (안 그럴 경우 가만히 있으면 죽지 않기 때문이다.)
2. 소스
1) 사용자 정의함수
#include<time.h> void Init(HWND hWnd, int size) { srand(time(NULL)); SetTimer(hWnd, 1, 5000, NULL); //5초마다 1번 타이머가 WM_TIMER 발생 } void Outline(HWND hWnd, HDC hdc, RECT rect, int size) { //맵 표시 int x = 10; int y = 30; TCHAR str[80]; _stprintf_s(str, _T("범위좌표 : (%d, %d) / (%d, %d)"), 20, 40, rect.right - rect.right % 20, rect.bottom - rect.bottom % 20); TextOut(hdc, 500, 0, str, _tcslen(str)); for (x = 10; x < rect.right; x += 20) { Rectangle(hdc, x - size, y - size, x + size, y + size); } x = 10; for (y = 30; y < rect.bottom; y += 20) { Rectangle(hdc, x - size, y - size, x + size, y + size); } y -= 20; for (x = 10; x < rect.right; x += 20) { Rectangle(hdc, x - size, y - size, x + size, y + size); } x -= 20; for (y = 30; y < rect.bottom; y += 20) { Rectangle(hdc, x - size, y - size, x + size, y + size); } } void Snake(HDC hdc, int *x, int *y, int length) { for (int i = 0; i <= length; i++) { if (i == 0) { SelectObject(hdc, CreateSolidBrush(RGB(255, 0, 0))); //처음 그리는 머리는 빨간색 } else { SelectObject(hdc, CreateSolidBrush(RGB(0, 255, 0))); //이후 그리는 몸은 녹색 } Ellipse(hdc, x[i] - 10, y[i] - 10, x[i] + 10, y[i] + 10); } /*SelectObject(hdc, CreateSolidBrush(RGB(255, 0, 0))); Ellipse(hdc, x1 - 10, y1 - 10, x1 + 10, y1 + 10); SelectObject(hdc, CreateSolidBrush(RGB(0, 0, 255))); Ellipse(hdc, x2 - 10, y2 - 10, x2 + 10, y2 + 10);*/ } void Food_Place(HWND hWnd, RECT rect, int *fx, int *fy) { int tmp; do { *fx = (rand() % rect.right); tmp = *fx % 10; *fx -= tmp; } while (*fx % 20 != 10); //먹이의 x좌표 do { *fy = (rand() % rect.bottom); tmp = *fy % 10; *fy -= tmp; } while (*fy % 20 != 10); //먹이의 y좌표 //영역 내 먹이를 표시해야 한다. 뱀의 좌표와 일치하기 위해서는 항상 20의 간격을 유지해야 한다. InvalidateRgn(hWnd, NULL, TRUE); } void Food_Draw(HDC hdc, int *fx, int *fy) { TCHAR tmp[20]; _stprintf_s(tmp, _T("먹이좌표 : [%d, %d]"), *fx, *fy); TextOut(hdc, 20, 0, tmp, _tcslen(tmp)); SelectObject(hdc, CreateSolidBrush(RGB(0, 0, 255))); //먹이를 먹었을 경우 파란색으로 다시 그린다. Rectangle(hdc, *fx - 10, *fy - 10, *fx + 10, *fy + 10); }
2) 윈도우 메세지처리함수
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; static int width[100] = { 50, 70, 90, 110, 130 }; static int height[100] = { 50, 50, 50, 50, 50 }; //뱀의 시작위치 static int length = 4; //뱀의 길이 static int fx; static int fy; //먹이의 위치 static RECT rect; //맵의 영역 static int size; //맵테두리 사각형길이의 반 switch (message) { case WM_CREATE: size = 10; GetClientRect(hWnd, &rect); Init(hWnd, size); break; case WM_TIMER: { hdc = GetDC(hWnd); Food_Place(hWnd, rect, &fx, &fy); //먹이 좌표 재생성 ReleaseDC(hWnd, hdc); } break; case WM_KEYDOWN: { if (wParam == VK_UP) { for (int i = 0; i < length; i++) { width[length - i] = width[length - i - 1]; height[length - i] = height[length - i - 1]; } height[0] -= 20; //뱀의 머리는 위로 한 칸 이동, 몸은 한 칸씩 땡기기 } else if (wParam == VK_DOWN) { for (int i = 0; i < length; i++) { width[length - i] = width[length - i - 1]; height[length - i] = height[length - i - 1]; } height[0] += 20; //뱀의 머리는 아래로 한 칸 이동, 몸은 한 칸씩 땡기기 } else if (wParam == VK_LEFT) { for (int i = 0; i < length; i++) { width[length - i] = width[length - i - 1]; height[length - i] = height[length - i - 1]; } width[0] -= 20; //뱀의 머리는 왼쪽으로 한 칸 이동, 몸은 한 칸씩 땡기기 } else if (wParam == VK_RIGHT) { for (int i = 0; i < length; i++) { width[length - i] = width[length - i - 1]; height[length - i] = height[length - i - 1]; } width[0] += 20; //뱀의 머리는 오른쪽으로 한 칸 이동, 몸은 한 칸씩 땡기기 } if (width[0] == fx && height[0] == fy) { //뱀의 머리위치와 먹이의 위치가 같으면? width[length + 1] = width[length]; height[length + 1] = height[length]; length++; //뱀의 꼬리가 하나 증가 Food_Place(hWnd, rect, &fx, &fy); //먹이 위치 재배치 KillTimer(hWnd, 1); SetTimer(hWnd, 1, 5000, NULL); //타이머 처음부터 다시발동 InvalidateRgn(hWnd, NULL, TRUE); TCHAR msg[40]; TCHAR show[40]; _stprintf_s(msg, _T("먹이를 먹어 꼬리가 +1 증가하였습니다.")); _stprintf_s(show, _T("현재 꼬리의 길이는 %d칸 입니다."), length+1); MessageBox(hWnd, msg, show, MB_OK); //먹이를 먹었다는 메세지 표시 } InvalidateRgn(hWnd, NULL, TRUE); } break; 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: { hdc = BeginPaint(hWnd, &ps); Outline(hWnd, hdc, rect, size); //맵 영역그리기 Snake(hdc, width, height, length); //뱀 그리기 Food_Draw(hdc, &fx, &fy); //타이머에서 새로 만든 먹이좌표를 그리기 EndPaint(hWnd, &ps); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
3. 시연
- 먹이를 먹으면 메세지박스가 출력되고, 먹이의 좌표는 변경되고, 뱀의 꼬리는 증가한다.
'Programming Language > Windows API' 카테고리의 다른 글
리소스파일 (0) | 2018.12.09 |
---|---|
메뉴 및 공용대화상자 (0) | 2018.10.09 |
두더지잡기 게임 (0) | 2018.09.30 |
입력된 방향키 확인 (0) | 2018.09.30 |
사각형 그리기 (0) | 2018.09.30 |
댓글