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 |
댓글