#include <Windows.h> #include "resource.h"
#define X_SIZE 48 /* 출력할 그림의 X 사이즈 */ #define Y_SIZE 48 /* 출력할 그림의 Y 사이즈 */ #define X_BLOCK 18 /* 행 의 갯수 */ #define Y_BLOCK 13 /* 열 의 갯수 */ #define X_LINE 6 /* 출력할 그림의 X 좌표 보정하기위한 크기 */ #define Y_MENU 32 /* 출력할 그림의 Y 좌표 보정하기위한 크기 */ #define TILE '#' /* 벽 */ #define TUTA '@' /* 캐릭 */ #define ROAD ' ' /* 길 */ #define BOX 'B' /* 박스 */ #define MAXSTAGE 2 /* 총 스테이지 */ #define GOAL 'X' /* 박스 도착 지점 */
typedef struct _MsgMap /* 함수 구성 */ { UINT iMessage; /* UINT 선언 : 어떤종류의 메시지인지 확인 가능 */ LRESULT (*fp)(HWND , WPARAM , LPARAM ); /* 함수 포인터 선언 : 메시지와 같은 기능의 함수 포인터 */ }MsgMap;
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); HINSTANCE g_hInst; /* 인스턴스 핸들 : 프로그램 자체를 말하는 고유값(프로그램 각각을 모두) */
LPCTSTR lpszClass = TEXT("KKIMSSI's Sokoban2"); // 창 제목
int iMap_X; /* 그림위치 X */ int iMap_Y; /* 그림위치 Y */ unsigned int uiKeyCount; /* 움직인 횟수 */ unsigned int uiStage; /* 스테이지 */ unsigned int uiMatch; /* 다음 스테이지로 넘어가기위한 변수 설정 */ unsigned int uiM_Cnt; /* 다음 스테이지로 넘어가기위한 변수 설정 : 박스와 골의 갯수가 같으면 클리어하게 변수 설정 */
static HBITMAP SELBitmap; /* Bitmap 파일의 속성을 선택하기위한 변수 */ static HBITMAP MapDown; /* MapDown ~ Goal 까지는 Bitmap 파일 */ static HBITMAP MapUp; static HBITMAP MapLeft; static HBITMAP MapRight; static HBITMAP Tile; static HBITMAP Road; static HBITMAP Box; static HBITMAP Goal;
void Init_Game(void);
/* WM_~ : Window Message , 메세지 발생 시 호출되는 함수선언 */ LRESULT My_Create(HWND , WPARAM , LPARAM ); LRESULT My_KeyDown(HWND , WPARAM , LPARAM ); LRESULT My_Paint(HWND , WPARAM , LPARAM ); LRESULT My_Destroy(HWND , WPARAM , LPARAM );
/* 함수 포인터를 이용해서 윈도우 메세지와 대응되는 함수는 호출 */ MsgMap MESSAGEMAP[] = { {WM_CREATE, My_Create}, {WM_KEYDOWN, My_KeyDown}, {WM_PAINT, My_Paint}, {WM_DESTROY, My_Destroy}, };
/* 바뀌는 위치정보를 저장하는 맵 */ unsigned char ucMap[Y_BLOCK][X_BLOCK+1];
/* 스테이지 전체를 항상 저장 */ unsigned char ucStageMap[MAXSTAGE][Y_BLOCK][X_BLOCK+1] = { { "##################", "##################", "##################", "##### ##########", "#####B ##########", "##### B##########", "### B B #########", "### # ## #########", "# # ## #### XX#", "# B B @ XX#", "##### ### # # XX#", "##### ########", "##################", }, { "##################", "##################", "##################", "##################", "##################", "##################", "## ##############", "# B######### @#", "# # ## #### #", "# B X#", "##### ### # # X#", "##### ########", "##################", } };
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) // WinMain , API Main 함수 { // nCmdShow 인자의 갯수가 온다 HWND hWnd; // Window Handler // LPSTR 는 char * 배열 C의 main 의 2번째 인자 MSG Message; WNDCLASS WndClass; /* 1. 윈도우 구조체 생성 ( Class ) */ g_hInst = hInstance;
/* 2.1 구조체에 값을 넣어 스타일을 변화시켜준다 */ WndClass.cbClsExtra = 0; WndClass.cbWndExtra = 0; WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 바탕색 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); // 마우스 모양 WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClass.hInstance = hInstance; WndClass.lpfnWndProc = WndProc; WndClass.lpszClassName = lpszClass; WndClass.lpszMenuName = NULL; WndClass.style = CS_HREDRAW|CS_VREDRAW; /* 2.2 앞에 모든 Class 값을 등록시켜주는 함수 */ RegisterClass(&WndClass);
/* 3. 창 만들기, 인자 dwStyle과 좌표값 초기화 */ hWnd=CreateWindow(lpszClass,lpszClass,WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT, X_SIZE*X_BLOCK+X_LINE , Y_SIZE*Y_BLOCK+Y_MENU , NULL , (HMENU)NULL , hInstance , NULL); /* 4. 창을 화면에 출력 하는 함수 */ ShowWindow(hWnd,nCmdShow);
/* 5. 창에서 일어나는 메세지 처리 (클릭, 닫기 등등..) */ while(GetMessage(&Message,NULL,0,0)) { TranslateMessage(&Message); DispatchMessage(&Message); } return (int)Message.wParam; }
/* 마우스나 키보드를 움직이면 OS 에서 자동으로 호출 */ /* 메세지 처리는 여기서 처리된다 */ LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { unsigned int uiCnt;
/* */ for(uiCnt = 0;uiCnt< (sizeof(MESSAGEMAP)/sizeof(MESSAGEMAP[0])) ; ++uiCnt) { if(iMessage == MESSAGEMAP[uiCnt].iMessage) {
return ( (MESSAGEMAP[uiCnt].fp)(hWnd,wParam,lParam) ); } }
return(DefWindowProc(hWnd,iMessage,wParam,lParam)); }
void Init_Game(void) { unsigned int ui_XCnt; unsigned int ui_YCnt;
uiKeyCount = 0;
uiMatch = 0; SELBitmap = MapDown; /* 캐릭 좌표 입력 */ for(ui_YCnt = 0 ; ui_YCnt < Y_BLOCK ; ui_YCnt++) { for(ui_XCnt = 0 ; ui_XCnt < X_BLOCK ; ui_XCnt++ ) { if( TUTA == ucStageMap[uiStage][ui_YCnt][ui_XCnt] ) { iMap_X = ui_XCnt; iMap_Y = ui_YCnt; } ucMap[ui_YCnt][ui_XCnt] = ucStageMap[uiStage][ui_YCnt][ui_XCnt]; if( GOAL == ucStageMap[uiStage][ui_YCnt][ui_XCnt] ) { ucMap[ui_YCnt][ui_XCnt] = ROAD; ++uiMatch; } } } return; }
LRESULT My_Create(HWND hWnd, WPARAM wParam, LPARAM lParam) { MapDown = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP1)); /* bitmap1 */ MapUp = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP2)); /* bitmap2 */ MapLeft = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP3)); /* bitmap3 */ MapRight = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP4)); /* bitmap4 */ Tile = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP5)); /* bitmap5 */ Road = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP6)); /* bitmap6 */ Box = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP7)); /* bitmap7 */ Goal = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP8)); /* bitmap8 */
/* 맵, 캐릭터 초기화 함수 */ Init_Game();
return 0; }
LRESULT My_KeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam) { RECT rc;
/* 무효화영역 지정, 현재위치의 사각형 */ rc.left = iMap_X*X_SIZE; rc.top = iMap_Y*Y_SIZE; rc.right = rc.left + X_SIZE; rc.bottom = rc.top + Y_SIZE;
switch(wParam) { /* 왼쪽 키 입력 */ case VK_LEFT: SELBitmap = MapLeft; if( TILE != ucMap[iMap_Y][iMap_X-1] ) { /* 선택영역만 다시 그리기 */ rc.left = rc.left - X_SIZE;
if( BOX == ucMap[iMap_Y][iMap_X-1] ) { if( ROAD == ucMap[iMap_Y][iMap_X-2] ) { /* 선택영역만 다시 그리기 */ rc.left = rc.left - X_SIZE;
ucMap[iMap_Y][iMap_X-2] = BOX; } else { break; } }
ucMap[iMap_Y][iMap_X] = ROAD; --iMap_X; ucMap[iMap_Y][iMap_X] = TUTA; //iMan_X = iMan_X-X_SIZE; ++uiKeyCount; }
break; case VK_RIGHT: SELBitmap = MapRight; if( TILE != ucMap[iMap_Y][iMap_X+1] ) { rc.right = rc.right + X_SIZE;
if( BOX == ucMap[iMap_Y][iMap_X+1] ) { if( ROAD == ucMap[iMap_Y][iMap_X+2] ) { rc.right = rc.right + X_SIZE;
ucMap[iMap_Y][iMap_X+2] = BOX; } else { break; } }
ucMap[iMap_Y][iMap_X] = ROAD; ++iMap_X; ucMap[iMap_Y][iMap_X] = TUTA; //iMan_X = iMan_X-X_SIZE; ++uiKeyCount; }
break; case VK_UP: SELBitmap = MapUp; if( TILE != ucMap[iMap_Y-1][iMap_X] ) { rc.top = rc.top - Y_SIZE;
if( BOX == ucMap[iMap_Y-1][iMap_X] ) { if( ROAD == ucMap[iMap_Y-2][iMap_X] ) { rc.top = rc.top - Y_SIZE;
ucMap[iMap_Y-2][iMap_X] = BOX; } else { break; } }
ucMap[iMap_Y][iMap_X] = ROAD; --iMap_Y; ucMap[iMap_Y][iMap_X] = TUTA; //iMan_X = iMan_X-X_SIZE; ++uiKeyCount; }
break; case VK_DOWN: SELBitmap = MapDown; if( TILE != ucMap[iMap_Y+1][iMap_X] ) { rc.bottom = rc.bottom + Y_SIZE; if( BOX == ucMap[iMap_Y+1][iMap_X] ) { if( ROAD == ucMap[iMap_Y+2][iMap_X] ) { rc.bottom = rc.bottom + Y_SIZE; ucMap[iMap_Y+2][iMap_X] = BOX; } else { break; } }
ucMap[iMap_Y][iMap_X] = ROAD; ++iMap_Y; ucMap[iMap_Y][iMap_X] = TUTA; //iMan_X = iMan_X-X_SIZE; ++uiKeyCount; } break; /* 페이지 업 */ case VK_PRIOR:
rc.left = 0; rc.top = 0; rc.right = X_SIZE*X_BLOCK; rc.bottom = Y_SIZE*Y_SIZE;
if( uiStage > 0 ) { --uiStage; } Init_Game(); break; /* 페이지 다운 */ case VK_NEXT:
rc.left = 0; rc.top = 0; rc.right = X_SIZE*X_BLOCK; rc.bottom = Y_SIZE*Y_SIZE;
if( MAXSTAGE - 1 > uiStage ) { ++uiStage; } Init_Game(); break; } InvalidateRect(hWnd,&rc,TRUE); return 0; }
LRESULT My_Paint(HWND hWnd, WPARAM wParam, LPARAM lParam) { HDC hdc; HDC MemDC; PAINTSTRUCT ps; wchar_t wcGameCnt[100]; /* 타이틀에 시간 표시 */ unsigned int ui_XCnt; unsigned int ui_YCnt; hdc = BeginPaint(hWnd,&ps);
/* 인수로 받는 핸들러와 같은 특성의 DC를 메모리에 만들어 핸들을 리턴 */ MemDC = CreateCompatibleDC(hdc);
uiM_Cnt = 0;
for(ui_YCnt = 0 ; ui_YCnt < Y_BLOCK ; ui_YCnt++) { for(ui_XCnt = 0 ; ui_XCnt < X_BLOCK ; ui_XCnt++ ) { if( TILE == ucMap[ui_YCnt][ui_XCnt] ) { /* MemDC 에 WM_CREATE 에서 저장한 Tile 그림을 저장 */ SelectObject(MemDC,Tile); } else if( TUTA == ucMap[ui_YCnt][ui_XCnt] ) { /* MemDC 에 WM_CREATE 에서 저장한 SELBitmap(움직이기 전 상태) 그림을 저장 */ SelectObject(MemDC,SELBitmap); } else if( BOX == ucMap[ui_YCnt][ui_XCnt] ) { SelectObject(MemDC,Box);
/* BOX와 GOAL의 위치가 같으면 */ if( GOAL == ucStageMap[uiStage][ui_YCnt][ui_XCnt] ) { ++uiM_Cnt; }
/* 다음 스테이지로 이동 */ if( uiM_Cnt == uiMatch ) { if( MAXSTAGE - 1 > uiStage ) { ++uiStage; }
/* 스테이지 넘어가기전 메세지 출력 */ MessageBox(hWnd,TEXT("다음 스테이지로 넘어갑니다!"), TEXT("메세지"), MB_OK); Init_Game(); InvalidateRect(hWnd,NULL,TRUE); break; } } else if( GOAL == ucStageMap[uiStage][ui_YCnt][ui_XCnt] ) { SelectObject(MemDC,Goal); } else { SelectObject(MemDC,Road); }
/* 메모리에 저장되어있는 그림을 크기를 변경하지않고 비트맵DC -> 화면DC 로 복사해서 출력 */ BitBlt(hdc, ui_XCnt*48 , ui_YCnt*48 , 48, 48 , MemDC , 0 , 0 , SRCCOPY);
} }
// SelectObject(MemDC,SELBitmap); // BitBlt(hdc, iMan_X , iMan_Y , 48, 48 , MemDC , 0 , 0 , SRCCOPY);
DeleteDC(MemDC); EndPaint(hWnd,&ps); wsprintf(wcGameCnt,TEXT("Tristana Couter : [%d]"), uiKeyCount); //wsprintf(wcGameCnt,TEXT("Tristana Couter : [%d]"), uiM_Cnt); SetWindowText(hWnd,wcGameCnt); return 0; return 0; }
LRESULT My_Destroy(HWND hWnd, WPARAM wParam, LPARAM lParam) { DeleteObject(MapUp); DeleteObject(MapDown); DeleteObject(MapLeft); DeleteObject(MapRight); DeleteObject(Tile); PostQuitMessage(0);
return 0; } |