

최종 완성본...
드디어 뭔가 끝냈다는 성취감이 드네요.
리소스를 입히진 못했지만, 게임같은 게임의 구성은 완료.
인터페이스 조금에... 난이도별 점수 및 속도 차등화까지...
다만, 아쉬운것은... 제대로 공부하지 않고, 책만 보고 했기 때문에... 옳게 썼는지, 틀리게 썼는지...
구별하기가 힘든 정도...
내생에 더러운 goto를 쓸 줄이야...
지금보니, 소스코드도 정말 더럽고...
(일부는 for문을로 돌린게 아니라, 직접 작성했다는... 이건 수정대상이네요.)
공부하면 할수록 도전의식이 드는 느낌이네요.
방학때는 더 심도있는 공부를 토대로, 여러가지 프로젝트를 혼자서 해볼까 생각중.
// Jirungii.cpp : 응용 프로그램에 대한 진입점을 정의합니다.
//
#include "stdafx.h"
#include "Jirungii.h"
#define MAX_LOADSTRING 100
// 전역 변수:
HINSTANCE hInst; // 현재 인스턴스입니다.
TCHAR szTitle[MAX_LOADSTRING]; // 제목 표시줄 텍스트입니다.
TCHAR szWindowClass[MAX_LOADSTRING]; // 기본 창 클래스 이름입니다.
#define random(num) (rand()%(num))
#define J_MAX 25
#define UP 0x111111
#define DOWN 0x222222
#define LEFT 0x333333
#define RIGHT 0x444444
RECT rt_start = {100, 100, 100, 100}; // 지렁이 움직임을 통제.
RECT rt_HEAD;
RECT* rt;
int mode = 0; // 최초 방향모드 : 없음
int flag = 0; // 최초 방향모드 : 없음
int j_size = 0; // 맨 최초 지렁이 몸 길이 : 3
int Score = 0; // 점수임 : 최초 0점
int Life = 3; // 최초잔기 : 3개
int Stage = 1; // 최초 스테이지 : 1스테이지
int item_count = 27;
RECT item = {0}; // 아이템을 그리는 사각형
RECT Wall[92]; // 사각 테두리 벽의 배열임
BOOL DotEat = TRUE; // 점이 랜덤하게 생길 때 먹으면 트루
BOOL TIME = FALSE; // 타임키(스페이스)를 누르면 TRUE로 바뀐다.
TCHAR score_output[100]; // 점수출력 문자열
TCHAR stage_output[100]; // 스테이지출력 문자열
TCHAR life_output[100]; // 목숨출력 문자열
TCHAR bool_time[100]; // 타임여부출력 문자열
TCHAR item_counter[100]; // 아이템개수출력 문자열
TCHAR user_place[300]; // 사용자위치정보(헤드) 문자열
TCHAR item_place[300]; // 아이템위치정보 문자열
RECT output[7];
int temp;
int temp1;
// 이 코드 모듈에 들어 있는 함수의 정방향 선언입니다.
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 여기에 코드를 입력합니다.
MSG msg;
HACCEL hAccelTable;
int i;
// 상단 가로벽의 초기화
Wall[0].left = J_MAX;
Wall[0].top = 0;
Wall[0].right = 2*J_MAX;
Wall[0].bottom = J_MAX;
for(i=1; i<=24; i++)
{
Wall[i].left = Wall[i-1].left + J_MAX;
Wall[i].top = Wall[i-1].top;
Wall[i].right = Wall[i-1].right + J_MAX;
Wall[i].bottom = Wall[i-1].bottom;
} // 루프 탈출후 i : 25
// 오른쪽 세로벽의 초기화
Wall[25].left = Wall[24].left;
Wall[25].right = Wall[24].right;
Wall[25].top = Wall[24].top + J_MAX;
Wall[25].bottom = Wall[24].bottom + J_MAX;
for(i=26; i<=45; i++)
{
Wall[i].left = Wall[i-1].left;
Wall[i].right = Wall[i-1].right;
Wall[i].top = Wall[i-1].top + J_MAX;
Wall[i].bottom = Wall[i-1].bottom + J_MAX;
}
Wall[46].left = Wall[45].left - J_MAX;
Wall[46].right = Wall[45].right - J_MAX;
Wall[46].bottom = Wall[45].bottom;
Wall[46].top = Wall[45].top;
for(i=47; i<=70; i++)
{
Wall[i].left = Wall[i-1].left - J_MAX;
Wall[i].right = Wall[i-1].right - J_MAX;
Wall[i].top = Wall[i-1].top;
Wall[i].bottom = Wall[i-1].bottom;
}
Wall[71].left = Wall[70].left;
Wall[71].right = Wall[70].right;
Wall[71].bottom = Wall[70].bottom - J_MAX;
Wall[71].top = Wall[70].top - J_MAX;
for(i=72; i<=91; i++)
{
Wall[i].left = Wall[i-1].left;
Wall[i].right = Wall[i-1].right;
Wall[i].bottom = Wall[i-1].bottom - J_MAX;
Wall[i].top = Wall[i-1].top - J_MAX;
}
// 스테이지의 벽은 가로세로 25칸으로 하자. // 라이트,보턴값이 25*25 = 625네.
// 전역 문자열을 초기화합니다.
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_JIRUNGII, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 응용 프로그램 초기화를 수행합니다.
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_JIRUNGII));
// 기본 메시지 루프입니다.
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// 함수: MyRegisterClass()
//
// 목적: 창 클래스를 등록합니다.
//
// 설명:
//
// Windows 95에서 추가된 'RegisterClassEx' 함수보다 먼저
// 해당 코드가 Win32 시스템과 호환되도록
// 하려는 경우에만 이 함수를 사용합니다. 이 함수를 호출해야
// 해당 응용 프로그램에 연결된
// '올바른 형식의' 작은 아이콘을 가져올 수 있습니다.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_JIRUNGII));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_JIRUNGII);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// 함수: InitInstance(HINSTANCE, int)
//
// 목적: 인스턴스 핸들을 저장하고 주 창을 만듭니다.
//
// 설명:
//
// 이 함수를 통해 인스턴스 핸들을 전역 변수에 저장하고
// 주 프로그램 창을 만든 다음 표시합니다.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// 함수: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 목적: 주 창의 메시지를 처리합니다.
//
// WM_COMMAND - 응용 프로그램 메뉴를 처리합니다.
// WM_PAINT - 주 창을 그립니다.
// WM_DESTROY - 종료 메시지를 게시하고 반환합니다.
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
HBRUSH MyBrush, OldBrush;
int i = 0; // 지렁이 배열 인덱스 업!
//int flag = false;
output[0].left = 675;
output[0].top = 20;
output[0].right = 900;
output[0].bottom = 40;
output[1].left = 675;
output[1].top = 60;
output[1].right = 900;
output[1].bottom = 80;
output[2].left = 675;
output[2].top = 100;
output[2].right = 900;
output[2].bottom = 120;
output[3].left = 675;
output[3].top = 180;
output[3].right = 900;
output[3].bottom = 200;
output[4].left = 675;
output[4].top = 140;
output[4].right = 900;
output[4].bottom = 160;
output[5].left = 675;
output[5].top = 220;
output[5].right = 900;
output[5].bottom = 260;
output[6].left = 675;
output[6].top = 280;
output[6].right = 900;
output[6].bottom = 320;
wsprintf(score_output, TEXT("획득점수 : %06d\n"), Score);
wsprintf(stage_output, TEXT("스테이지 : %d\n"), Stage);
wsprintf(life_output, TEXT("현재목숨 : %d개\n"), Life);
wsprintf(bool_time, TEXT("게임재개 : 스페이스키\n"));
wsprintf(item_counter, TEXT("%2d개를 더 드십시오.\n"), item_count);
wsprintf(item_place, TEXT("아이템위치 : \n(%4d,%4d) - (%4d,%4d)\n"), (int)item.left, (int)item.top, (int)item.right, (int)item.bottom);
wsprintf(user_place, TEXT("현재 위치 : \n(%4d,%4d) - (%4d,%4d)\n"), (int)rt_HEAD.left, (int)rt_HEAD.top, (int)rt_HEAD.right, (int)rt_HEAD.bottom);
switch(iMessage)
{
case WM_CREATE :
게임계속 :
mode = 0; // 최초 방향모드 : 없음
flag = 0; // 최초 방향모드 : 없음
j_size = 3; // 맨 최초 지렁이 몸 길이 : 3
item_count = 27;
SetTimer(hWnd, Stage, 400-(Stage-1)*60, NULL); // 0.5초마다 지렁이 갱신
rt = new RECT[30];
rt[0].left = rt_start.left;
rt[0].top = rt_start.top;
rt[0].right = rt_start.right + J_MAX;
rt[0].bottom = rt_start.bottom + J_MAX;
item.left = (random(20)+1)*25;
item.top = (random(20)+1)*25;
item.right = item.left + J_MAX;
item.bottom = item.top + J_MAX;
wsprintf(user_place, TEXT("현재 위치 : (%3d,%3d)-(%3d,%3d)\n"), (int)rt[0].left, (int)rt[0].top, (int)rt[0].right, (int)rt[0].bottom);
for(i=1; i<j_size; i++)
{
rt[i].left = rt[i-1].left - J_MAX;
rt[i].right = rt[i-1].right - J_MAX;
rt[i].top = rt[i-1].top;
rt[i].bottom = rt[i-1].bottom;
}
rt_HEAD = rt[0];
return 0;
case WM_COMMAND :
switch(LOWORD(wParam))
{
case ID_NEWGAME : // 새게임 메뉴를 누를 시
KillTimer(hWnd, Stage);
temp = MessageBox(hWnd, TEXT("게임을 새로 할까요?"), TEXT("새게임?"), MB_YESNO);
if(temp == IDYES)
{
Score = 0;
Stage = 1;
Life = 3;
KillTimer(hWnd, Stage);
goto 게임계속;
}
else
{
SetTimer(hWnd, Stage, 400-(Stage-1)*60, NULL);
break;
}
case ID_EXIT : // EXIT 메뉴를 누를 시
KillTimer(hWnd, Stage);
delete []rt;
goto 게임그만;
break;
case ID_INFOMATION : // 게임방법 메뉴를 누를 시
KillTimer(hWnd, Stage);
temp = MessageBox(hWnd, TEXT("##키조작##\n1. 방향 : 방향키를 누르세요.\n2. 타임 : 스페이스키\n\n##게임규칙##\n1. 맵에있는 아이템을 먹으면 지렁이가 길어집니다.\n2. 지렁이 몸체나 벽에 부딪치면 죽습니다.\n3. 최대한 먹으면 스테이지가 올라가고, 획득점수가 커집니다.\n4. 죽으면 점수를 잃게됩니다. 조심하세요."), TEXT("게임방법"), MB_OK);
if(temp == IDOK)
SetTimer(hWnd, Stage, 400-(Stage-1)*60, NULL);
break;
case ID_ABOUT : // 정보 메뉴를 누를 시
KillTimer(hWnd, Stage);
temp = MessageBox(hWnd, TEXT("##하고싶은말##\n1. 제작 : 한해대 IT공학부 아치셈틀 KDS\n2. 도움주신분들 : 셈틀 여러분☆\n3. 11 연말전시회 출품작"), TEXT("제작자정보"), MB_OK);
if(temp == IDOK)
SetTimer(hWnd, Stage, 400-(Stage-1)*60, NULL);
break;
}
return 0;
case WM_TIMER :
switch(wParam)
{
case 1 :
case 2 :
case 3 :
case 4 :
case 5 :
switch(mode)
{
case LEFT :
if(flag == RIGHT)
{
mode = RIGHT;
break;
}
if(TIME) break;
rt_HEAD = rt[0];
for(i=j_size-1; i>0; i--)
{
rt[i].left = rt[i-1].left;
rt[i].bottom = rt[i-1].bottom;
rt[i].right = rt[i-1].right;
rt[i].top = rt[i-1].top;
}
rt[0].right -= J_MAX;
rt[0].left -= J_MAX;
flag = LEFT;
break;
case RIGHT :
if(flag == LEFT)
{
mode = LEFT;
break;
}
if(TIME) break;
rt_HEAD = rt[0];
for(i=j_size-1; i>0; i--)
{
rt[i].left = rt[i-1].left;
rt[i].bottom = rt[i-1].bottom;
rt[i].right = rt[i-1].right;
rt[i].top = rt[i-1].top;
}
rt[0].right += J_MAX;
rt[0].left += J_MAX;
flag = RIGHT;
break;
case UP :
if(flag == DOWN)
{
mode = DOWN;
break;
}
if(TIME) break;
rt_HEAD = rt[0];
for(i=j_size-1; i>0; i--)
{
rt[i].left = rt[i-1].left;
rt[i].bottom = rt[i-1].bottom;
rt[i].right = rt[i-1].right;
rt[i].top = rt[i-1].top;
}
rt[0].top -= J_MAX;
rt[0].bottom -= J_MAX;
flag = UP;
break;
case DOWN :
if(flag == UP)
{
mode = UP;
break;
}
if(TIME) break;
rt_HEAD = rt[0];
for(i=j_size-1; i>0; i--)
{
rt[i].left = rt[i-1].left;
rt[i].bottom = rt[i-1].bottom;
rt[i].right = rt[i-1].right;
rt[i].top = rt[i-1].top;
}
rt[0].top += J_MAX;
rt[0].bottom += J_MAX;
flag = DOWN;
break;
}
if(rt[0].left == item.left && rt[0].bottom == item.bottom)
{
j_size++; // 지렁이도 늘리고
Score += 500*Stage-200; // 점수도 늘리고
item_count--;
item.left = (random(20)+1)*25;
item.top = (random(20)+1)*25;// 아이템 자리도 새로 할당한다.
item.right = item.left + J_MAX;
item.bottom = item.top + J_MAX;
} // 템 먹으면 아이템이 사라지고, 지렁이가 늘어난다.
if(j_size == 30) //최대로 먹을 경우.
{
Score += 3000*Stage; // 점수 업
KillTimer(hWnd, Stage);
Stage++; // 스테이지 업
if(Stage == 5) // 스테이지 올클 시,
{
for(i=0; i<j_size; i++)
rt[i].left = rt[i].top = rt[i].right = rt[i].bottom = 0;
item.left = item.top = item.right = item.bottom = 0;
rt_HEAD.left = rt_HEAD.top = rt_HEAD.right = rt_HEAD.bottom = 0;
InvalidateRect(hWnd, NULL, TRUE);
KillTimer(hWnd, Stage-1);
delete []rt;
temp = MessageBox(hWnd, TEXT("올클!! 더하실래요?"), TEXT("올클리어!!"), MB_YESNO);
if(temp == IDYES)
{
Stage = 1;
Score = 0;
Life = 3;
goto 게임계속;
}
else
goto 게임그만;
}
delete []rt;
goto 게임계속;
}
for(i=1; i<j_size; i++) // 몸과의 충돌을 검사한다.
if(rt[0].left == rt[i].left && rt[0].top == rt[i].top)
{
Life--; //목숨도 잃고
if(Score<3000)
Score = 0;
else
Score -= 3000*Stage;
KillTimer(hWnd, Stage);
delete []rt;
goto 게임계속;
break;
}
for(i=0; i<=91; i++) // 벽에 충돌을 검사한다.
if(rt[0].left == Wall[i].left && rt[0].top == Wall[i].top) // 충돌하면
{
Life--; //목숨도 잃고
if(Score<3000)
Score = 0;
else
Score -= 3000*Stage;
goto 게임계속;
break;
}
if(Life == 0)
{
for(i=0; i<j_size; i++)
rt[i].left = rt[i].top = rt[i].right = rt[i].bottom = 0;
item.left = item.top = item.right = item.bottom = 0;
rt_HEAD.left = rt_HEAD.top = rt_HEAD.right = rt_HEAD.bottom = 0;
InvalidateRect(hWnd, NULL, TRUE);
KillTimer(hWnd, Stage);
delete []rt;
temp1 = MessageBox(hWnd, TEXT("지렁이가 모두 죽었습니다 ㅠㅠ\n 더 하실건지...?"), TEXT("게임오버!!"), MB_YESNO);
if(temp1 == IDYES)
{
Stage = 1;
Life = 3;
Score = 0;
goto 게임계속;
}
else
goto 게임그만;
}
}
InvalidateRect(hWnd, NULL, TRUE);
return 0;
case WM_KEYDOWN :
switch(wParam)
{
case VK_SPACE :
if(!TIME)
TIME = TRUE;
else
TIME = FALSE;
break;
case VK_LEFT :
mode = LEFT;
break;
case VK_RIGHT :
mode = RIGHT;
break;
case VK_UP :
mode = UP;
break;
case VK_DOWN :
mode = DOWN;
break;
}
//InvalidateRect(hWnd, NULL, TRUE);
return 0;
case WM_PAINT :
hdc = BeginPaint(hWnd, &ps);
MyBrush = (HBRUSH)GetStockObject(GRAY_BRUSH);
OldBrush = (HBRUSH)SelectObject(hdc, MyBrush);
Rectangle(hdc, rt[0].left, rt[0].top, rt[0].right, rt[0].bottom);
Rectangle(hdc, item.left, item.top, item.right, item.bottom); // 랜덤하게 아이템 출력
SelectObject(hdc, OldBrush);
MyBrush = (HBRUSH)GetStockObject(BLACK_BRUSH);
OldBrush = (HBRUSH)SelectObject(hdc, MyBrush);
for(i=0; i<=91; i++)
Rectangle(hdc, Wall[i].left, Wall[i].top, Wall[i].right, Wall[i].bottom);
SelectObject(hdc, OldBrush);
for(i=1; i<j_size; i++)
Rectangle(hdc, rt[i].left, rt[i].top, rt[i].right, rt[i].bottom);
if(TIME)
DrawText(hdc, bool_time, -1, &output[3], DT_LEFT);
DrawText(hdc, score_output, -1, &output[0], DT_LEFT);
DrawText(hdc, stage_output, -1, &output[1], DT_LEFT);
DrawText(hdc, life_output, -1, &output[2], DT_LEFT);
DrawText(hdc, item_counter, -1, &output[4], DT_LEFT);
DrawText(hdc, user_place, -1, &output[5], DT_LEFT);
DrawText(hdc, item_place, -1, &output[6], DT_LEFT);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY :
게임그만 :
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, iMessage, wParam, lParam);
}
// 정보 대화 상자의 메시지 처리기입니다.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;




덧글
다음부턴 함수를 많이많이 만들어서 이용해야겠다는 생각이 듭니다. (...)