두더지잡기 게임
1. 두더지잡기 게임을 모티브로 한 원 잡기.
[1] 게임을 진행할 영역을 얻어와야 한다.
[2] 마우스 좌표가 원의 영역내에 있다면 점수가 증가한다.
[3] 1000점이 초과되면 스테이지가 증가한다.
[4] 10스테이지가 되면 메세지가 출력된다.
[5] 원은 1초에 한번씩 좌표가 변경된다.
[6] 스테이지가 올라갈 수록 원의 크기는 줄어든다.
2. 소스
1) 사용자 정의함수
#include<time.h>
#include<math.h>
void Init(HWND hWnd, LPRECT rect, int *x, int *y, int *r, int *score, int *stage) {
srand(time(NULL));
GetClientRect(hWnd, rect);
//창 생성 시 화면의 좌표영역을 얻어온다.
*x = rand() % rect->right;
*y = rand() % rect->bottom;
*r = 185;
//원의 반지름
*score = 0;
*stage = 1;
SetTimer(hWnd, 1, 1000, NULL);
//1번타이머 = 1초에 한 번씩 WM_TIMER메세지 발생
}
void Draw(HDC hdc, LPRECT rect, int *x, int *y, int r, int score, int stage) {
TCHAR str[80];
_stprintf_s(str, _T("스테이지 : %d 점수 : %d 좌표 : (%d, %d) 반지름 : %d"), stage, score, *x, *y, r);
TextOut(hdc, 400, 5, str, _tcslen(str));
//현재 정보 출력
Rectangle(hdc, 5, 25, rect->right - 5, rect->bottom - 5);
// 전체 맵 그리기
SelectObject(hdc, CreateSolidBrush(RGB(255, 0, 0)));
// 창의 브러시속성에 빨간색을 부여
Ellipse(hdc, *x - r, *y - r, *x + r, *y + r);
//빨간색 원 그리기
}
void Timer(HWND hWnd, LPRECT rect, int *x, int *y) {
*x = rand() % rect->right;
*y = rand() % rect->bottom;
//영역 내 원의 좌표 얻어오기
InvalidateRgn(hWnd, NULL, TRUE);
}
double Length(int x1, int y1, int x2, int y2) {
return sqrt((x2 - x1)*(x2 - x1) + (y2 - y1) * (y2 - y1));
//클릭한 마우스의 범위를 구하기 위해 사용하며 원으로부터 거리 반환
}
void Mouse(HWND hWnd, LPARAM lParam, LPRECT rect, int *x, int *y, int *r, int *score, int *stage) {
int mx = LOWORD(lParam);
int my = HIWORD(lParam);
//마우스의 좌표 얻어오기
//if (*x - *r < mx && mx < *x + *r && *y - *r < my && my < *y + *r) {
if (Length(*x, *y, mx, my) < *r) {
//마우스의 좌표가 원의 내부에 있다면?
*score += 100;
//스코어 증가
*x = rand() % rect->right;
*y = rand() % rect->bottom;
//새로그리기 위한 원의 좌표 확보
if (1000 < *score) {
//점수가 1000점을 초과했다면?
(*stage)++;
//다음스테이지로
*score = 0;
//스코어는 초기화
*r -= 20;
//난이도 조절을 위해 원의 반지름은 감소
}
if (10 < *stage) {
MessageBox(hWnd, _T("WOW!!!"), _T("you are great!!"), MB_OK);
// 10스테이지가 넘어가면 메세지 출력
}
KillTimer(hWnd, 1);
//1번타이머 죽이기
SetTimer(hWnd, 1, 1000, NULL);
//1번 타이머 생성
//죽이고 다시 생성하는 이유는 클릭했을 때 기존 원의 위치에서 대기하지 않도록하기위함.
InvalidateRgn(hWnd, NULL, TRUE);
}
}
2) 윈도우 메세지처리함수
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
static RECT space;
//게임영역
static int x;
static int y;
//원의 좌표
static int r;
//반지름
static int stage;
//스테이지
static int score;
//점수
switch (message)
{
case WM_CREATE:
Init(hWnd, &space, &x, &y, &r, &score, &stage);
break;
case WM_TIMER:
Timer(hWnd, &space, &x, &y);
break;
case WM_LBUTTONDOWN:
Mouse(hWnd, lParam, &space, &x, &y, &r, &score, &stage);
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);
Draw(hdc, &space, &x, &y, r, score, stage);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
3. 시연[1]
- 마우스 클릭 시 점수가 올라가고 1000점 초과 시 스테이지가 올라가고 반지름은 줄어드는 것을 확인할 수 있다.
- 그러나 이렇게 할 경우 9스테이지에서는 원이 거의 보이지 않는다.
4. 시연[2]
1) 치트엔진을 사용하여 10스테이지를 달성하고 메세지의 내용을 확인하려 한다.
- 치트엔진을 실행 후 현재 실행중인 두더지게임을 올린다.
- 현재 점수가 200이므로 메모리 상에 200이라는 값이 있는 주소를 검색한다.
- first scan 시 5개의 메모리주소에 200이라는 값이 들어있다.
- 그러나 이 중 어떤 것이 점수인지 모르므로 점수 점수를 올린다.
- 원을 클릭해서 점수를 300으로 올리고 300을 next scan 한다.
- 점수가 들어있는 주소를 확인하고 이 주소의 값을 1111로 변경하였다.
- 스테이지가 6으로 오른 것을 확인할 수 있다.
- 이렇게 할 경우 여러번 해야해서 번거로우므로 반지름의 사이즈를 변경해보려고 한다.
- 현재 반지름인 85를 first scan한다.
- 스테이지를 올린 후 반지름의 크기에 변화를 주어 65로 next scan한다.
- 반지름이 저장되어 있는 주소를 찾았으므로 1000정도로 변경한다.
- 이 경우 원의 반지름이 커져서 영역 대부분을 차지하므로 수월하게 스테이지를 올릴 수 있다.
- 11스테이지까지 올린 후 출력되는 메세지를 확인할 수 있다.
[1] 변경 불가능하도록 하는 방법
- 출력되는 값을 기준값 + 알파 식으로 부여한다.
ex) 점수의 메모리에 있는 값을 50이라고 잡으면 출력시에는 항상 score - 50을 출력한다.
※ 치트엔진은 휴리스틱을 이용하여 찾는방법을 이용한다.
한 마디로 값만 알면 찾을 수 있기에 실제 값이랑 보여지는 값이랑 다르게 하면 된다.
그러나 리버싱으로 변경하는 것은 단순히 값을 다르게 하는 것만으로는 불가능하며 복잡도와 난독화를 이용해야 한다.
'Programming Language > Windows API' 카테고리의 다른 글
| 메뉴 및 공용대화상자 (0) | 2018.10.09 |
|---|---|
| 지렁이게임 (0) | 2018.09.30 |
| 입력된 방향키 확인 (0) | 2018.09.30 |
| 사각형 그리기 (0) | 2018.09.30 |
| 도형 자동이동 (0) | 2018.09.30 |
댓글