윈도우프로그래밍및실습블록게임 VS 2015 Part 1 001. 블록게임만들기 2008. 10. 30 update 2011. 11. 3 update 2012. 10. 23 Update 2015. 09. 24 http://idb.korea.ac.kr DB & Data Mining LAB. Korea University 이종욱 eastwest9@korea.ac.kr 참조한책 : Windows Programming 제대로배우기, 영진출판사. 1
강의목표 API 정복을통해배운 API 프로그램에대한전반적인이해도를높 이기위해블럭게임을작성한다. 블록게임강의자료 1 API 의기본적인내용을반복숙지한다. 기본적인블럭게임을작성하기위해필요한함수들에대해학습한다 2
Multi-byte, Unicode 호환함수 //temp 문자열길이구하기 num = _tcslen(temp); // 문자열에쓰기 1 _stprintf_s(temp, _T("Cown Down: %2d"), Count); // 문자열에쓰기 2 _tcscpy_s(temp, _T(" 호환성지원 ")); 3
헤더파일 #include<windows.h> - 여러헤더파일을포함하는헤더파일이다. - 대부분의윈도우 API 함수의원형, 각종데이터타입, 구조체, 매크로상수등이선언됨. - HINSTANCE, LPCTSTR, HWND WINDEF.H : 기본타입정의 WINNT.H : 유니코드지원을위한타입정의 WINBASE.H : Kernel 함수 WINUSER.H : 사용자인터페이스함수 WINGDI.H : 그래픽장치인터페이스함수 4
Test (1/2) Test 프로젝트생성 VS 2015를실행시킨다. API 프로젝트이름은 Test 파일이름은 Test.cpp Apistart.txt에있는내용을 Test.cpp 에복사한다. WndProc( ) 수정 5
Test (2/2) // 문자열추가 // 문자열에쓰고, 해당문자열출력 6
Step 1: 중앙에문장을출력하고좌우이동 프로젝트 : Moving Star 사각형의중앙위치를어떻게구하는가? 이동은어떻게할것인가? WM_LBUTTONDOWN WM_RBUTTONDOWN 7
1) POINT + RECT 중앙위치정보를저장할 POINT 구조체와사각형을의미하는 RECT 구 조체의모습은다음과같다. Windef.h 파일내부를보면다음과같다. typedef struct tagpoint { LONG x; LONG y; } POINT, *PPOINT, NEAR *NPPOINT, FAR *LPPOINT; typedef struct tagrect { LONG LONG LONG LONG left; top; right; bottom; } RECT, *PRECT, NEAR *NPRECT, FAR *LPRECT; 8
2) 윈도우의중앙위치얻어내기 GetClientRect(hWnd, &Rect 변수 ) 함수! 인자 : 현재윈도우의정보와, 해당윈도우의크기를저장할 Rect 변수주소를전달 GetClientRect( ) 함수를이용하여윈도우크기정보를얻는다. 다음 CenterPoint( ) 함수를사용자가정의하여, 중앙위치를포인트구조 체에저장한후리턴 9
3) 글자좌우로움직이기 (1/4) Moving Star 프로젝트생성 Moving Star 프로젝트를만들고, 코드를생성한다. 헤더파일위치에 CenterPoint( ) 함수원형추가 10
3) 글자좌우로움직이기 (2/4) CenterPoint( ) 함수정의는코드의하단에다음과같이먼저추가한다! 11
3) 글자좌우로움직이기 (3/4) WndProc( ) 함수정의는작성! 12
3) 글자좌우로움직이기 (4/4) 13
Toggle 1, 0 Toggle int flag = 1; flag =!flag; 1, -1 Toggle int flag = 1; flag = flag * -1; or flag *= -1; 0,1,2 를순차적으로반복하는 Round Toggle int flag = 0; flag++; flag %= 3; 왼쪽마우스를클릭할때마다 Toggle Exe 문장이보여졌다가사라지도 록하는프로그램작성. 14
Step 2: 사각형그리고이동하기 윈도우중앙에사각형그리고, 해당사각형을아래로이동한다. 1) 중앙위치찾기 2) 사각형그리기 3) 사각형이동 4) 마우스왼쪽버튼을클릭하면왼쪽이동 5) 마우스오른쪽버튼을클릭하면오른쪽이동 15
1) 사각형그림. OffsetRect 이용움직이기 1 사각형설정 : SetRect( ) http://msdn.microsoft.com/en-us/library/dd145085.aspx 사각형이동 : OffsetRect( ) 역할 http://msdn.microsoft.com/en-us/library/dd162746.aspx 16
2) 윈도우중앙에적당한직사각형그리기 DrawRect 프로젝트생성 윈도우의중앙위치를찾아낸다. 윈도우중앙점을이용하여적당한직사각형그리기 : SetRect( ) 직사각형이동 : offsetrect( ) 을이용 마우스왼쪽, 오른쪽버튼클릭에따른이동!!! 문제점 ) 벽을만나게되면어떻게되는가? 프로젝트생성 DrawRect 이라는프로젝트생성. DrawRect.cpp 생성 화살표 < 클릭! 화살표 > 클릭! ApiStart.txt 의내용을 DrawRect.cpp 에복사 다음강의자료에있는내용으로 DrawRect.cpp 를완성한다! 17
3) 사각형그리기코드 (1/5): DrawRect // 코드상단부분추가및변경 18
3) 사각형그리기코드 (2/5): DrawRect // 코드맨하단부분에 CenterPoint( ) 정의작성 19
3) 사각형그리기코드 (3/5): DrawRect // WndProc( ) 함수작성! 20
3) 사각형그리기코드 (4/5): DrawRect 21
3) 사각형그리기코드 (5/5): DrawRect 22
User module 작성 DrawRect_User 프로젝트생성 현재까지코드들을 *.cpp 파일에모두넣어작성하였다. 함수의원형또는 define 과관련된것들은헤더파일 (*.h) 로옮기고, 함수정의는함수정의를모아두는소스코드 (*.cpp) 를작성해보자. 현재작성한 DrawRect 프로젝트를모듈별로나누는과정을배운다!!! DrawRect_User 프로젝트생성, DrawRect_User.cpp 파일생성 기존에작성한 DrawRect 프로젝트의 DrawRec.cpp 파일의내용을, DrawRect_User 라는프로젝트의 DrawRect_User.cpp 로복사한다. 23
DrawRect_User (1/7): MyUtil.h 추가 1) Solution Explorer 창의 Header Files 오른쪽마우스클릭 Add New Item 24
DrawRect_User (2/7): MyUtil.h 추가 2) 팝업창에서, Header File (.h) 선택 Name 에 MyUtil.h 입력 Add 클릭 25
DrawRect_User (3/7): MyUtil.h 추가 3) MyUtil.h 파일에다음코드를작성한다. // #ifndef ~ #endif 의의미는? // POINT 와 RECT 에빨간물결밑줄이있어도일단은무시 // 코드를모두완성하면사라짐 주의 ) 작성한후반드시, drawrect_user.cpp 에있었던 CenterPoint( ) 원형을삭제한다. 26
DrawRect_User (4/7): MyUtil.cpp 추가 4) Solution Explorer 창의 Source Files 오른쪽마우스클릭 Add New Item 27
DrawRect_User (5/7): MyUtil.cpp 추가 5) 팝업창에서, C++ File (.cpp) 선택 Name 에 MyUtil.cpp 입력 Add 클릭 28
DrawRect_User (6/7): MyUtil.cpp 추가 6) MyUtil.cpp 파일은 CenterPoint( ) 정의를이동시키고, #include 구문추가함 주의 ) 작성한후반드시, drawrect_user.cpp 에있었던 CenterPoint( ) 정의부분삭제한다. 29
DrawRect_User (7/7): MyUtil.cpp 추가 7) drawrect_user.cpp 코드상단에도반드시 #include MyUtil.h 추가한다. 8) 코드를 모두저장 한후실행해본다. 30
알아두면좋은함수 Rect( 영역 ) 을사용하고조작하는함수 1. BOOL OffsetRect(LPRECT lprc, int dx, int dy) 주어진 Rect 를 dx, dy 만큼이동 2. BOOL InflateRect(LPRECT lprc, int dx, int dy) 주어진 Rect 를 dx, dy 만큼늘이거나줄임 3. BOOL IntersectRect(LPRECT lprcdst, CONST RECT *lprcsrc1, CONST RECT *lprcsrc2) 주어진 Rect1 과 2 가교차되었는지검사, 교차된작은영역은 lprcdst 로 4. BOOL UnionRect (LPRECT lprcdst, CONST RECT *lprcsrc1, CONST RECT *lprcsrc2) 주어진 Rect1 과 2 를 Union 시킴, Union 된영역은 lprcdst 로 5. BOOL PtInRect(CONST RECT *lprc, POINT pt); 특정좌표 pt 가 lprc 영역안에있는지검사 31
Step 3: bar 가주기에따라자동으로이동 현재작성한프로그램은마우스왼쪽 / 오른쪽버튼을누르면 bar 가움직인다. 목표 : bar 를자동으로움직이게 (AutoMove) 하고싶다. 필요한것 1) 자동으로움직이기 : 주기적으로메시지발생시켜야함 Timer 필요한것 2) 윈도우범위를벗어남 : bar가윈도우왼쪽 or 오른쪽벽과부딪치는지여부를확인해야함 CheckStrikeX( ) 필요한것 3) 사각형그리기전용함수 최종 4) AutoMove 프로젝트작성 32
Timer 복습 Timer 를설정하면 System 이주기적으로 Timer Message 를발생시킴 SetTimer(hWnd, 1, 200, NULL); 타이머설치 (0.2 초뒤부터, 0.2 초간격메시지발생 ) UINT SetTimer( HWND hwnd, UINT nidevent, UNT uelapse, // handle of window for timer messages // timer identifier // time-out value TIMERPROC lptimerfunc // address of timer procedure ); KillTimer(hWnd, 1); 사용된타이머를 destroy ( 메모리정리 ) BOOL KillTimer( HWND hwnd, UINT nidevent, // handle of window that installed timer // timer identifier ); 문제 : 10 초뒤에프로그램이자동종료되는 AutoKill 프로그램을작성하시오 33
1. AutoKill (1/2) AutoKill 프로젝트생성 34
1. AutoKill (2/2) 35
2. 사각형좌우자동이동 (1/4) 1. 사각형 bar 를좌우 (x 방향 ) 로왔다갔다이동하게할것 : 이에대한토글 ( 왼쪽 -1, 오 른쪽 1) 정보에사용할변수선언 static int alphax; 2. 처음이동방향은, WM_CREATE 에서오른쪽을의미하도록초기화 alphax = 1; // 오른쪽방향으로초기화 3. 사각형 (bar Rectangle) 을움직이는 Timer 에서이변수를기준으로 Offset 을하게 될것이며, 이변수값이 1 이라면 barr 은 OffsetRect(&barR, 1, 0); // 오른쪽이동 1 4. m_alpha 값이 -1 이된다면 OffsetRect(&barR, -1, 0); // 왼쪽이동 -1 5. 언제 m_alpha 값이변경하는가?! 오른 / 왼쪽윈도우벽과부딪칠때 36
2. 사각형좌우자동이동 (2/4) 1. WM_PAINT에서 Pen과 Brush를만들어설정하고초기화된 Rect의영역을가지고 Rectangle을출력한다. 이때 Pen과 Brush에대한색상을 COLORREF 변수를사용. static COLORREF barcolor; // switch 문시작전에선언 WM_PAINT: barcolor = RGB(0, 255, 0); hpen = CreatePen(PS_SOLID, 1, barcolor); holdpen = (HPEN) SelectObject(hdc, hpen); hbrush = CreateSolidBursh(barColor); holdbrush = (HBRUSH) SelectObject(hdc, hbrush); Rectangle(hdc, barr.left, barr.top, barr.right, barr.bottom); 37
2. 사각형좌우자동이동 (3/4) 1. WM_CREATE 에 SetTimer 설정. SetTimer(hWnd, 1, 10, NULL); 2. WM_Timer Message 부분을코딩 case WM_TIMER: if(checkstrikex(barr, BoundX)) alphax *= -1; OffsetRect(&barR, 2 * alphax, 0); // bar의위치변화시킴, x 변화량확인 InvalidateRect(hWnd, NULL, TRUE); break; AlphaX = 1 로진행 벽에부딪히면, AlphaX = -1 로토글시킴 38
2. 사각형좌우자동이동 (4/4) CheckStrikeX( ) 작성 // 화면의정중앙찾기 POINT CenterPoint(RECT& r) { POINT p; p.x = (r.left + r.right) /2; p.y = (r.top + r.bottom) /2; return p; } // bar가 x좌표로이동할때벽에부딪침확인함수 int CheckStrikeX(RECT& r, RECT& bound) { if(r.left <= bound.left r.right >= bound.right) return 1; // 벽에부딪쳤음 true else return 0; // 벽에부딪치지않음 false } 39
3. 그리기전용함수 DrawObject( ) 작성 앞으로사각형과원을한화면에그릴것이다. 사각형을위한코드, 원을위한코드를모두작성하는것보다, type을전달받은후그 type에맞게원을그리는함수를작성하는것이더효과적! DrawObject( ) 함수가 2개 : 함수오버로딩 ( 중복 ) 인자 4개인 DrawObject( ) 는색상하나를 Pen과 Brush에모두사용하도록인자 5개 DrawObject( ) 를호출! 실제그리기와관련한코드는인자 5개 DrawObject( ) 에서담당 40
4. 최종코드작성 (1/5): AutoMove AutoMove 프로젝트생성 1) AutoMove 프로젝트생성. 2) AutoMove.cpp 파일생성, ApiStart.txt 파일을 AutoMove.cpp 에복사 WinMain( ) 에서바탕색을검은색으로변경!!! 41
4. 최종코드작성 (2/5): AutoMove 3) WndProc( ) 함수작성 42
4. 최종코드작성 (3/5): AutoMove 43
4. 최종코드작성 (4/5): AutoMove 4) 추가함수정의작성 44
4. 최종코드작성 (5/5): AutoMove 45
윈도우프로그래밍및실습블록게임 Part 2. VS 2015 002. 블록게임만들기 last update 2010. 10. 28 Renewal 2011. 11. 3 2010 version: 2012. 10. 23 2015 version: 2015. 9. 24 2015 version: 2015. 11. 02 (p.21 오타수정 ) http://idb.korea.ac.kr DB & DataMining LAB. Korea University 이종욱 46
Step 1: 키보드화살표이용, 상하좌우이동 강의목표 : 키보드를이용동그란원을움직이게한다. 목표 : 원을자동으로움직이게하고싶다. 필요한것 1) 자동으로움직이기 : 주기적으로메시지발생시켜야함 Timer: 이전 chapter 에서참조 필요한것 2) 윈도우범위를벗어남 : bar 가윈도우와부딪치는지여부를확인해야 함 CheckStrikeX( ) 함수 : 이전 chapter 에서참조 필요한것 3) 키보드메시지 ( ) 가들어오면방향을전환 47
화살표키를이용하여원이동 (1/4) Virtual key VK_LEFT, VK_RIGHT 등 컴퓨터의키보드에화살표키가두개있다.( 숫자키패드의 Num-Lock을포함 ) 어느곳의화살표를눌러도동일하게작동해야하는데, 이처럼키보드의키값들을 Virtual-Key라는개념으로일괄처리한다. 원그리기함수 : Ellipse( 해당핸들 dc, left_x, top_y, right_x, bottom_y) 48
화살표키를이용하여원이동 (2/4) OS는 WndProc에게어디서 (hwnd), 무엇이 (imessage), 어떻게 (wparam and lparam) 발생하였는지에대한모든정보를전달한다. wparam, lparam : 특정 Message가발생할때그에따른세부정보를전달받는 Parameter로 32bit or 64bit 값. wparam: 간단한값, 1개의 Data 개념을갖는경우 lparam: 2개의값 or 좀더복잡한경우 ( 포인터등 ) KeyBorad 와관련한메시지 WM_KEYDOWN WM_KEYUP WM_SYSKEYDOWN WM_SYSKEYUP 49
화살표키를이용하여원이동 (3/4) Where What How. LRESULT CALLBACK WndProc(HWND hwnd, UINT imessage, WPARAM wparam, LPARAM lparam) { PAINTSTRUCT ps; HDC hdc; } switch(umsg) { case WM_ KEYDOWN : switch(wparam) { case VK_LEFT : // break; case VK_RIGHT : // break; case VK_UP : // break; case VK_DOWN : // break; } break; } return DefWindowProc(hWnd, umsg, wparam, lparam); 50
x, y 좌표토글이해 ) Event 간 Sequence Y - X - + + alphax alphay 방향 -1 0 1 0 0-1 0 1 WM_KEYDOWN alphax, alphay 값을결정 WM_TIMER alphax, alphay 값에따라 ballr 를변경 WM_PAINT ballr 출력! 51
화살표키를이용하여원이동 (4/4) 윈도우의중앙에 원 을출력, 키보드입력에따라 원 이상하좌우로이동하는 프로그램을작성 시작시방향은오른쪽, Timer가자동으로원을현재의방향으로계속진행시킨다. 이때 Keyboard의상하좌우화살표키를이용하여원의이동방향을변경. 볼의움직임방향은 X축성분과 Y축성분으로구분할수있는데, 오른쪽으로가능경우 X 방향은 +, Y 방향은 0이된다. Timer에의한처음이동방향은오른쪽이지만, 키보드에의해방향이변경될수있다 현재, 벽과의부딪침은고려하지않음 009_ 윈프블럭게임 2015 part 1 의 AutoMove 내용과유사! 52
1) CircleMove 프로젝트 (1/6) CircleMove 프로젝트생성 1) CircleMove 프로젝트생성 2) CircleMove.cpp 파일생성, ApiStart.txt 파일내용을복사하여 CircleMove.cpp 붙여넣기! 배경색상검정색 WinMain( ) 에서변경 53
1) CircleMove 프로젝트 (2/6) 3) WndProc( ) 부분작성!!! 54
1) CircleMove 프로젝트 (3/6) 55
1) CircleMove 프로젝트 (4/6) 56
1) CircleMove 프로젝트 (5/6) 4) 추가함수정의작성!!! 57
1) CircleMove 프로젝트 (6/6) 58
과제 1 현재작성한 CircleMove 프로그램에서다음두가지조건을추가한 CircleMove2 를작성하시오! 1) 움직이는원을적당한간격으로깜박이며이동하도록프로그램을수정. 힌트 ) 별도의 Timer 사용 힌트 ) Timer 에서는깜박임을결정할 Flag 를 Toggle 시키고, PAINT 에 서는이 Flag 에따라조건적으로출력하도록한다. 2) 벽에부딪치면반대방향으로진행 59
Step 2: 신호등시물레이션 Traffic Signal 일정시간이지나면다른색으로변경됨 첨부한 Traffic Signal.EXE 실행해본다. // Winmain 에서윈도우사이즈조절 hwnd = CreateWindow(szAppName, sztitle, WS_OVERLAPPEDWINDOW, 450, 200, 125, 360, NULL, NULL, hinstance, NULL); 60
힌트 : 신호등그리기 (1/2) 신호등원위치조절및그리기 GetClientRect( ), InflateRect( ) 61
힌트 : 신호등그리기 (2/2) 1. ( 빨강, 노랑, 녹색 ) 각 Lamp 의영역을 Rect 배열로사용하자 static RECT lampr[3]; 2. 3 개의 Lamp 에대한배경색과전경색을가지고있도록 COLORREF Type 의 Data 들을배열로선언 ( 배경은전경보다조금어두운색 ) static COLORREF lampbackco[3] = { RGB(100, 0, 0), RGB(100, 100, 0), RGB(0, 100, 0) }; static COLORREF lampforeco[3] = { RGB(255, 0, 0), RGB(255, 255, 0), RGB(0, 255, 0) }; 3. 상태변환을위한 Flag static int lampflag; lampflag 값이 0 : 빨간색 1 : 노란색 2 : 녹색 62
2) TrafficSignal 프로젝트 (1/6) TrafficSignal 프로젝트생성 1) TrafficSignal 프로젝트생성. 2) TrafficSignal.cpp 파일생성, ApiStart.txt 내용을복사하여 TrafficSignal.cpp 에붙여넣기! 배경검은색 윈도우사이즈조정 63
2) TrafficSignal 프로젝트 (2/6) 3) WndProc( ) 코드작성 64
2) TrafficSignal 프로젝트 (3/6) 65
2) TrafficSignal 프로젝트 (4/6) lampforeco[lampflag] 66
2) TrafficSignal 프로젝트 (5/6) 4) 추가함수정의작성 67
2) TrafficSignal 프로젝트 (6/6) 68
Step 3: 드래깅하여원이동 적당한위치에빨간색원을하나출력 해당원을왼쪽마우스클릭하여드래그하면원이이동한다. 움직이는경우에만, 원색상이노란색으로변경된다! 마우스드래깅은 WM_LBUTTONDOWN 과 WM_MOUSEMOVE 그리고 WM_LBUTTONUP 이 3 개의 Message 간에걸쳐서일어난다. 2. WM_MOUSEMOVE p( 200, 0 ) q( 201, 0 ) 1. WM_LBUTTONDOWN 3. WM_LBUTTONUP 69
힌트 ) PtInRect() (1/2) 특정영역내에마우스 Point 가클릭되었는가에대한검사 PtInRect( ) http://msdn.microsoft.com/en-us/library/dd162882(v=vs.85).aspx 70
힌트 ) PtInRect() (2/2) case WM_LBUTTONDOWN: p.x = LOWORD(lParam); p.y = HIWORD(lParam); if(ptinrect(&ballr, p)) { flag = true; // 버튼이원 ( 사각형 ) 안에눌려져있음 TRUE // ncount++; // catch me에서사용 } break; 마우스무브에서 flag 값이 true 인지확인하고, 위치정보를받아와서해당위치로원이출력되도록한다. 왼쪽마우스버튼이 up 되면 flag 값을 false 로만들어더이상움직이지않도록한다. 71
3) Drag Circle 프로젝트 (1/6) Drag Circle 프로젝트생성 1) Drag_Circle 프로젝트생성. 2) Drag_Circle.cpp 파일생성 ApiStart.txt 내용을복사하여 Drag_Circle.cpp 에붙여넣기 배경검은색 72
3) Drag Circle 프로젝트 (2/6) 3) WndProc( ) 코드작성 73
3) Drag Circle 프로젝트 (3/6) 74
3) Drag Circle 프로젝트 (4/6) 75
3) Drag Circle 프로젝트 (5/6) 4) WndProc( ) 코드마무리및추가함수정의작성 76
3) Drag Circle 프로젝트 (6/6) 77
과제 2) Catch Me 처음에는 1 초간격으로임의의위치정보 (x, y 좌표 ) 를만들어낸다. (Timer ID 1) 그값을이용하여적당한원 ( 공 ) 을만들어낸다. 주의 : 원은윈도우를벗어나서출력되면안됨. 원의중심위치를화면에출력 이때원의내부를마우스로클릭하면 hitcount 를증가하고화면에 hitcount 값을표시 2 초가지날때마다원이다른위치에서출력되는속도를빠르게한다. (Timer ID 2) 30 초뒤프로그램을종료 (Timer ID 3) 종료시최종점수를 메시지박스 로출력 CatchMe.exe 실행파일참조 78
윈도우프로그래밍및실습블록게임 Part 3, VS 2015 003. 블록게임만들기 last update 2010. 11. 2 Renewal 2011. 11. 7 2010 version: 2012. 10. 24 2015 version: 2015. 09. 25 http://idb.korea.ac.kr DB & Mining LAB. Korea University 이종욱 eastwest9@korea.ac.kr 79
1 차목표 : 벽과사각형 bar 에부딪치는공 ver 0.9 실행파일모습을확인한다!!! 80
사각형블록 + 공을만들기위해고려해야할것 공 (ball) 사각형블럭 (bar) 공의움직임 사각형블록 (bar) 움직임 (key + 마우스 ) 공 (ball) 이윈도우에부딪쳤을때 : 상단, 왼쪽, 오른쪽, 하단? 사각형블록 (bar) 이윈도우에부딪쳤을때 : 왼쪽, 오른쪽 공 (ball) 이사각형블록 (bar) 에부딪쳤을때 : 상단, 왼쪽, 오른쪽, 하단? 81
Ver.0.1: 사각형 bar 만들기 (1/8) 82
Ver.0.1: 사각형 bar 만들기힌트 (2/8) 필요한변수선언 static RECT barr, clientr; // 사각형 barr, 윈도우크기정보저장할 clientr static COLORREF barcolor; // bar 색상 POINT p; // 중앙위치구한후, bar 만들때사용 Bar 색상초기화 barcolor = RGB(255, 0, 0); 사각형을그리기위해클라이언트의크기를구하는 GetClientRect 함수이용하여그크기를 RECT 구조체 (clientr) 에저장 GetClientRect(hWnd, &clientr); 중앙위치를구하는 CenterPoint 함수를이용하여중앙 POINT p 구함 p = CenterPoint(clientR); 일정크기의사각형 (bar) 구함 SetRect(&barR, p.x - 50, p.y - 15, p.x + 50, p.y + 15); 사각형의위치를아래로이동 OffsetRect(&barR, 0, 200); // x 는그대로 y 를아래로 200 이동 83
Ver.0.1: 사각형 bar 만들기힌트 (3/8) WM_PAINT 에서는 DrawObject 함수호출을통해 bar 그리기. 중앙위치를찾기위한함수, DrawObject( 사각형및원그리는 ) 함수선언및정의 POINT CenterPoint(RECT& ); // 함수원형선언추가 void DrawObject(HDC, RECT&, COLORREF, int); void DrawObject(HDC, RECT&, COLORREF, COLORREF, int); 84
Ver.0.1: Block_Game 코드 (4/8) BkGame_0_1 프로젝트생성 1) BkGame_0_1 프로젝트생성 2) BkGame_0_1.cpp 생성 ApiStart.txt 내용을복사하여 BkGame_0_1.cpp 에붙여넣기 3) 필요한전역변수, 함수선언 85
Ver.0.1: Block_Game 코드 (5/8) 4) WndProc( ) 함수부분 : 코드작성 86
Ver.0.1: Block_Game 코드 (6/8) 87
Ver.0.1: Block_Game 코드 (7/8) 5) 관련함수정의코드추가 88
Ver.0.1: Block_Game 코드 (8/8) 89
Ver.0.2: 좌우 (, ) 로움직이는 bar (1/9) 키보드의, 를누르면좌우로움직이는 bar 화면출력 90
Ver.0.2: 좌우로움직이는 bar 코드 (2/9) 왼쪽방향은 x 좌표에서 -1, 오른쪽은 1 로 toggle 하는변수추가및설정 alphax 는왼쪽 -1, 오른쪽 1 값을가진다. WM_KEYDOWN: 에서해당화살표에맞게 bar 가움직일수있도록코딩 91
Ver.0.2: 좌우로움직이는 bar 코드 (3/9) BkGame_0_2 프로젝트생성 1) BkGame_0_2 프로젝트생성 2) BkGame_0_1.cpp 를기존프로젝트에서복사하여, BkGame_0_2 프로젝트폴더에위치시 킴 92
Ver.0.2: 좌우로움직이는 bar 코드 (4/9) 3) [Solution Explorer] [Source Files] 오른쪽마우스클릭 Add Existing Item 선택 93
Ver.0.2: 좌우로움직이는 bar 코드 (5/9) 4) 현재 BkGame_0_2 프로젝트폴더에복사했던 BkGame_0_1.cpp 파일을선택 Add 클릭! 94
Ver.0.2: 좌우로움직이는 bar 코드 (6/9) 5-1) 현재프로젝트에등록된 BkGame_0_1.cpp 확인됨 이름수정필요! 5-2) [BkGame_0_1.cpp] 오른쪽마우스클릭 Rename 선택 95
Ver.0.2: 좌우로움직이는 bar 코드 (7/9) 6) 이름변경확인및 더블클릭 하여파일 Open! 7) 클래스이름등으로쓰이는 lpszclass 문자열수정! 96
Ver.0.2: 좌우로움직이는 bar 코드 (8/9) 8) WndProc( ) 함수내부의상단부분에 alphax 변수추가 // 추가된변수 97
Ver.0.2: 좌우로움직이는 bar 코드 (9/9) 9) WndProc( ) 함수내부에 WM_KEYDOWN 메시지와관련된코드추가 98
Ver.0.2 코드분석 문제점 : 클라이언트영역을인지하지못하고그범위밖으로 bar 가이동 해결책 : 윈도우벽에부딪쳤을때움직이지못하도록한다. 부딪침체크 99
Ver.0.3: 벽에부딪치면움직이지않는다 (1/4) 벽에부딪침확인함수작성 부딪침발생 x 방향정보가변하지않도록설정! CheckStrikeX( ) : 왼쪽 1 or 오른쪽 2 부딪침확인 + 부딪치지않음 0: 3 가지상태리턴 부딪쳐도움직이지않음 100
Ver.0.3: 코드작성 (2/4) BkGame_0_3 프로젝트생성 1) BkGame_0_3 프로젝트생성 2) BkGame_0_2.cpp 를복사하여, BkGame_0_3 프로젝트폴더에위치시키고업데이트! // 부딪침체크함수원형추가 101
Ver.0.3: 코드작성 (3/4) 3) WndProc( ) 에서 WM_KEYDOWN 부분수정. 102
Ver.0.3: 코드작성 (4/4) 3) 추가된함수인 CheckBoundX( ) 의정의부분을코드하단에작성한다! 103
Ver.0.4: 마우스로도움직이는 bar (1/4) 선택된 bar 가드래그를통해이동하기위해선, 2. WM_MOUSEMOVE p( 200, 0 ) q( 201, 0 ) 1. WM_LBUTTONDOWN 3. WM_LBUTTONUP 특정 Rect 영역내에마우스 Point 가클릭되었는가에대한검사 PtInRect( ) 예, PtInRect(&Rect, p); 현재입력된포인트가사각형 bar에위치해있는지확인하는함수! 104
Ver.0.4: 마우스로도움직이는 bar 코드작성 (2/4) BkGame_0_4 프로젝트생성 1) BkGame_0_4 프로젝트생성 2) BkGame_0_3.cpp 를복사하여, BkGame_0_4 프로젝트폴더에위치시키고업데이트! 105
Ver.0.4: 마우스로도움직이는 bar 코드작성 (3/4) 3) WndProc( ) 함수의변수선언부분수정또는추가한다. 106
Ver.0.4: 마우스로도움직이는 bar 코드작성 (4/4) 4) WndProc( ): 3 개의윈도우메시지처리구문추가 107
Ver.0.5: 정중앙에적당한크기의공출력 BkGame_0_5 프로젝트생성 정중앙에적당한크기의공을출력하기위한코드추가. WndProc( ) 의변수선언부분에서 ball 을출력하기위한사각형선언 static RECT ballr; // ball 을출력하기위한 Ball_Rect 선언 WM_CREATE 에서 SetRect(&ballR, p.x - 10, p.y - 10, p.x + 10, p.y +10); WM_PAINT 에서 DrawObject(hdc, ballr, RGB(0, 0, 0), RGB(255, 0, 255), 1); 1) BkGame_0_5 프로젝트생성 2) BkGame_0_4.cpp 를복사하여, BkGame_0_5 프로젝트폴더에위치시키고업데이트! 3) 위에언급된부분추가! 108
Ver.0.6: 공이자동으로좌우로이동 (1/5) Timer 이용 : 메시지가특정한간격으로발생 공의좌표변경 공을이동시킴 오른쪽으로이동하다가벽에부딪치면왼쪽으로이동 공의좌우방향토글은 static int balltogglex; 를이용하여 -1 or 1 Ball 이클라이언트윈도우좌우벽에부딪침을확인후방향전환을위해 int CheckBoundBallX(RECT &r, RECT &bound); 함수를이용 공을이동하게하기위한타이머를 WM_CREATE 에만든다. SetTimer(hWnd, 1, 10, NULL); 타이머메시지를처리하기위해 WM_TIMER: 생성및코드 생성된타이머의메모리정리코드 109
Ver.0.6: 공이자동으로좌우로이동코드추가 (2/5) BkGame_0_6 프로젝트생성 1) BkGame_0_6 프로젝트생성 2) BkGame_0_5.cpp 를복사하여, BkGame_0_6 프로젝트폴더에위치시키고업데이트! // 코드추가! a) #include 부분 : ball 이벽에부딪치는지여부확인하는함수원형선언을추가! 110
Ver.0.6: 공이자동으로좌우로이동코드추가 (3/5) b) WndProc( ) 함수의변수선언부분에 static int balltogglex; 추가! 111
Ver.0.6: 공이자동으로좌우로이동코드추가 (4/5) c) switch(imessage) 의 WM_CREATE: 내부의변수선언부분에다음코드추가! // 공의처음이동방향 toggle 값과 Timer 설치 112
Ver.0.6: 공이자동으로좌우로이동코드추가 (5/5) d) switch(imessage) 의 WM_TIMER: 코드추가! + WM_DESTROY: KillTimer() e) ball 이클라이언트벽에부딪치는지확인하는함수 CheckBallBoundX( ) 정의추가! 113
Ver.0.7: 45 도각도로공이이동 (1/4) b_toggley= -1 b_togglex = 1 b_togglex = -1 b_togglex = 1 b_toggley = 1 b_toggley = 1 114
Ver.0.7: 45 도각도로공이이동코드추가 (2/4) BkGame_0_7 프로젝트생성 1) BkGame_0_7 프로젝트생성 2) BkGame_0_6.cpp 를복사하여, BkGame_0_7 프로젝트폴더에위치시키고업데이트! a) #include 부분 : 함수원형선언부분에 CheckBallBouncY( ) 원형추가! b) WndProc( ) 변수선언부분 : balltoggley 추가! 115
Ver.0.7: 45 도각도로공이이동코드추가 (3/4) c) switch(imessage) 의 WM_CREATE: balltoggley 초기화부분추가! d) switch(imessage) 의 WM_TIMER: CheckBallBoundY( ) 추가, and OffsetRect( ) 수정! 116
Ver.0.7: 45 도각도로공이이동코드추가 (4/4) e) 코드하단 : CheckBallBoundY( ) 함수정의부분추가! 117
Ver.0.7: 문제점 공도 45 도로밖에움질일수없지만자동으로이동! 사각 bar 도마우스 or 키보드화살표로이동가능! But, 공이 bar 에맞는경우에대한처리가필요! 공 or bar 가 윈도우 에부딪치는것과는조금다름. 충돌판단기준 : 공과 bar 가 겹치는영역 이생기는지확인 IntersectRect( ) 함수제 공! 118
IntersectRect http://msdn.microsoft.com/en-us/library/dd145001.aspx 119
Ver.0.8: 공이사각형 bar 와부딪칠때 (1/3) int HitTest(RECT &, RECT &); // 원형선언 HitTest(BallRect, BarRect); // 호출, 어디에있어야하는가? 움직임정보를발생시키는곳! int HitTest(RECT &r1, RECT &r2) { RECT temp; int w, h; if(intersectrect(&temp, &r1, &r2)) { w = temp.right - temp.left; h = temp.bottom - temp.top; if(w < h) // 옆에맞은경우 return 1; else return 2; // 위에맞은경우 } else return 0; // 맞이않은경우 } HitTest( ) 함수는 IntersectRect( ) 함수를이용하여 ball과 bar의충돌확인! IntersectRect( ) 는 r1과 r2의교차된영역을첫번째파라미터에전달한다 교차된영역이 width < Height 이다 교차된영역이 Width > Height 이다 1_8 버전결과확인 120
Ver.0.8: 공이사각형 bar 와부딪칠때코드 (2/4) BkGame_0_8 프로젝트생성 1) BkGame_0_8 프로젝트생성 2) BkGame_0_7.cpp 를복사하여, BkGame_0_8 프로젝트폴더에위치시키고업데이트! a) #include 부분 : 함수원형선언부분에 HitTest( ) 함수원형추가! 121
Ver.0.8: 공이사각형 bar 와부딪칠때코드 (3/4) b) WndProc( ) 변수선언부분 : ball 이 bar 의어디에부딪쳤는지저장할 hitpoistion; 추가! c) switch(imessage) 의 WM_Timer 부분 : bar 와 ball 이 Hit 하는지확인및 toggle 값변환 122
Ver.0.8: 공이사각형 bar 와부딪칠때코드 (4/4) e) 코드의하단 : HitTest( ) 정의추가! 123
다음기능들추가 1. 특정시간이지나면 (15초) 가지나면종료여부를묻는타이머추가 2. Bar에공이부딪칠때 score 1점 3. 화면오른쪽상단에 score 표시 4. 화면검정색!!! 검정색화면 : WinMain( ) 에서다음과같이변경한다. 1) 타이머하나더추가 15 초후메시지발생하도록함 WM_Timer 에서관련코드작성 - 종료메시지가나올때프로그램종료! 2) HitTest( ) 를호출한곳에, 점수를업데이트하는변수를미리만들어둔후추가한다. 3) 투명한바탕의흰색텍스트를이용하여화면오른쪽에점수결과출력 124
Ver.0.9: 기본기능추가 (1/4) BkGame_0_9 프로젝트생성 1) BkGame_0_8 프로젝트생성 2) BkGame_0_7.cpp 를복사하여, BkGame_0_8 프로젝트폴더에위치시키고업데이트! a) WndProc( ) 변수선언부분 : str[100], hit_numcount 추가! b) switch(imessage) 의 WM_CREATE 부분 : 변수초기화및타이머추가! 125
Ver.0.9: 기본기능추가 (2/4) c) WinMain( ) 함수에서 : 윈도우배경검은색 d) WndProc( ) 함수의 WM_PAINT: 화면오른쪽에점수를출력하기위한코드추가 126
Ver.0.9: 기본기능추가 (3/4) e) switch(imessage) 의 WM_TIMER: 2 개의타이머를제공하도록기존코드를수정 ( 새로작 성 ) 127
Ver.0.9: 기본기능추가 (4/4) 128
윈도우프로그래밍및실습블록게임 Part 4, VS 2015 004. 블록게임만들기 update 2010. 11. 11 Renewal 2011. 11. 10 2010 version 2012. 10. 26 2015 Version: 2015. 09. 25 http://idb.korea.ac.kr DB & Mining LAB. Korea University 이종욱 129
Part 1: 문제제기 현재작성한 blockgame_0_9 를보게되면, ball 과 bar 가깜박인다. 화면을모두지우고그리기때문에, 깜빡임발생 어떻게해결할것인가? BeginPaint( ) 와 GetDC( ) 함수에대해서복습 130
그리는방법 2 가지 : BeginPaint( ) BeginPaint( ) WM_PAINT 에서만사용가능 ( 다른곳에서사용해도출력되지않는다 ) // 해당윈도우에대해 Painting 에필요한 // 준비를한다음현재윈도우의 DC 반환 BeginPaint는해당윈도우의 Update해야할영역 (Clipping Region: 클라이언트영역의특정부분에그리기를한정하는영역 ) 을자동으로파악한다. 해당영역은윈도우가생성되거나, 움직여지거나, 사이즈가변경되거나스크롤이이루어지는등윈도우상 (Client Area) 의화면상의변화이며, 변화에맞는화면처리가행해지도록한다. * 일부메시지 ( 키보드등 ) 는화면변화가아니기때문에, 자동으로화면변화를감지하지못한다. User는 InvalidateRect() 나 InvalidateRgn() 함수를호출함으로써강제로화면변화가있다고 WM_PAINT 메시지를강제로발생시킴. 131
그리는방법 2 가지 : GetDC( ) GetDC( ) GetDC 함수는특정윈도우의 Client 영역에대한 DC 핸들을얻을때사용. WM_PAINT 이외의곳에서사용가능 GetDC( ) 에의한출력은즉각적이며, 일시적인출력방법 배경과관계없이특정출력을일시적, 또는즉각반영하고자하는경우에사용됨 윈도우의타이틀바영역에대한 DC 를얻기위해서는 GetWindowDC 함수사용 132
BeginPaint( ) Vs. GetDC( ) 두함수의차이점을파악하기위하여, 두개의프로젝트를작성한다. 1) CirclePaint 프로젝트 WM_PAINT 에서 BeginPaint( ) 를이용하여원출력 2) CircleLBD 프로젝트 WM_PAINT 에서 BeginPaint( ) 를이용하여원출력 WM_PAINT 가아닌다른메시지들중하나인 WM_LBUTTONDOWN 에서도 GetDC( ) 를이용하여원출력 133
1) CirclePaint 프로젝트 (1/4): BeginPaint( ) CirclePaint 프로젝트생성 // 블럭게임에서이용하던 CenterPoint( ), DrawObject( ) 를이곳에서도이용 134
1) CirclePaint 프로젝트 (2/4): BeginPaint( ) 135
1) CirclePaint 프로젝트 (3/4): BeginPaint( ) 136
1) CirclePaint 프로젝트 (4/4): BeginPaint( ) 137
2) CircleLBD 프로젝트 : GetDc( ) CircleLBD 프로젝트생성 1) CircleLBD 프로젝트생성 2) CirclePaint.cpp 를복사하여, CircleLBD 프로젝트폴더에위치시키고업데이트! // switch(imessage) 부분에 WM_LBUTTONDOWN: 코드추가 Invalidate( ) 함수호출하지않아도바로출력가능. 그러나, 그려진후복구에는관심이없음! 138
결과분석 작성한두프로젝트를실행하여결과를확인한다. LBUTTONDOWN 의주석처리된부분을해지한후실행한다. CirclePaint 프로젝트 CircleLBD 프로젝트 처음부터출력됨 윈도우업데이트되어도계속출력됨 WM_PAINT 의 BeginPaint( ) 윈도우에항상출력됨! GetDc() 로출력된나머지 파란색원은 윈도우가가려지면사라짐! 139
정적 - 동적출력 정적 (Static) 출력 윈도우틀이출력되는것처럼기본적으로출력되도록할수있다. WM_PAINT 에서 BeginPaint( ) 이용 동적 (Dynamic) 출력 마우스동작에따라 GetDC( ) 를이용하여즉각적인출력을한다 일시적인출력이다. ( 최소화하거나다른화면에가려지면지워짐 ) 상황에따라서출력내용이달라질수있음 출력가이드 1. 배경이나윈도우가정적인상태가되었을때화면출력이필요하면 WM_PAINT 에서처리 2. 움직이거나동적으로표현되는상태를나타내는출력은그효율성으로보아, 배경을모두재출력할필요가없으므로, GetDC( ) 로해당객체만즉각출력 140
think about it!!! WM_PAINT 에정적으로출력을나타내지만, 마우스가클릭되었을때는윈도우전체 를다시그리지않고즉각적으로현재위치에대한원을하나만나타낼수있는가? WM_LBUTTONDOWN에서는 GetDC( ) 를이용하여현위치에대한원을그린다면, InvalidateRect( ) 를사용하지않아도그릴수있다. But, 윈도우에는마지막현재위치에하나의원만나타나야한다. 모순!!! ( 불가능함 ) GetDC( ) 는이전출력상태에대해상관하지않는다. 마지막원하나만을나타내기위해서 는이전의원을지워야하는문제는어떻게해결할것인가? 대안 : Raster Operation 1. 그림은어떻게지우는가? 2. 변경시이전그림을지우고새로이나타나는문제 - 전체영역을모두다지우는것이아닌, 특정영역을덧그리기형식으로지운다. 141
Raster Operation 점, 선을그릴때, 원하는픽셀과해당디스플레이표면사이의 Bitwise bool 연산을수행 Raster Operation: 두픽셀사이에 ( 변경하려는픽셀과원래의디스플레이 표면 ) bit 연산을수행하는것을의미 Raster : 그래픽디스플레이장치의방식에관한용어, 이미지를점들의패 턴으로표현하는방식 윈도우시스템은 DC 에대한출력시사용되는 Raster Operation 에대한 Mix 모드 (bit 연산 ) 를설정할수있는 SetROP2 라는기능제공 142
SetROP2 (1/3) int SetROP2( HDC hdc, // handle of device context int fndrawmode // drawing mode ); 143
SetROP2 (2/3) // 출력시 Source 는 Destination Pixel 에무조건덮어씌움 SetROP2(hdc, R2_XORPEN); X Y XOR 0 0 0 XOR 의직관적인의미는원하는 bit 를 지우는데 (Erase) 사용할수있음 0 1 1 1 0 1 1 1 0 X 0100 Y 0011 // 최초 XOR -------------------- Result 0111 Y 0011 // 여기에 Y 패턴, 두번째 XOR ---------------------- Result 0100 XOR 연산을이용하면특정 Pattern을최초에는쓰게되고, 두번째 XOR는그특정 Pattern만을배경에관계없이지울수있게됨결론적으로그림을배경과관계없이지우는데에는 XOR연산이사용됨 144
SetROP2 (3/3) InvalidateRect( ) 를호출하지않고도, 이전그림을즉각적으로지운후다 시새로운좌표에그릴수있음 SetROP2(hdc, R2_XORPEN); // 코드추가!!! DrawObject(hdc, ball_rect, RGB(0,255,0), 1); // 이전 Rect 지움 ( 덧그리기 ) // 좌표변경 DrawObject(hdc, ball_rect, RGB(0,255,0), 1); // 새로운위치에다시그림 R2_XORPEN : 화면색상과새로운색상의 XOR 실습 : 원출력을 ROP mode 로변경하여출력 기존 CircleLBD 프로젝트를변경하여 CircleROP 를만든다. 145
3) CircleROP 프로젝트 (1/2): ROP 모드이해 CircleROP 프로젝트생성 1) CircleROP 프로젝트생성 2) CircleLBD.cpp 를복사하여, CircleROP 프로젝트폴더에위치시키고업데이트! 146
3) CircleROP 프로젝트 (2/2): ROP 모드로변경 // switch(imessage) 부분의일부코드를추가및수정! // 주의 : 색상은모두통일함!!! // 이전에작성되었던원위에또원을그림. // ROP 모드인 XORPEN 에의해지워짐! // 현재마우스클릭한위치에새로원을그림! // 실행해보면이전과다른부분이있다! 분석하시오! 147
애니메이션의원리 1) (1,1) 위치에공을그린다. 2) (1,1) 위치에공을덮어쓴다 이전의공이사라진것처럼느껴짐. 3) 이동한위치 (1,2) 에공을새로그린다. 타이머에의해움직이는그림은시각적으로애니메이션효과를나타냄 BkGame_0_9 프로젝트는 RasterOperation을사용하여코드를변경하면, 기존에깜박임현상이없어진다! 이전예제는 InvalidateRect( ) 를호출하여 WM_PAINT에서그렸다. 즉, 화면을모두지운후다시그렸기때문에, 심한깜박임현상이나타남 BkGame_0_9 프로젝트파일의코드를 ROP 모드로변경한다 BkGame_0_9_ROP 프로젝트로업데이트!!! 148
4) BkGame_0_9_ROP (1/7) CircleROP 프로젝트생성 기존에작성된 BkGame_0_9 프로젝트의 cpp 코드를 ROP 모드로수정 수정 1) DrawObject( ) 함수에 ROP 모드를위한파라미터 ( 매개변수 ) 를추가 선언과동시에 default 값제공 : R2_XORPEN 수정 2) 점수가출력되는부분도 WM_PAINT 에위치함 이것도 ROP 모드로 수정 1) BkGame_0_9_ROP 프로젝트생성 2) BkGame_0_9.cpp 를복사하여, BkGame_0_9_ROP 프로젝트폴더에위치시키고업데이트! 149
4) BkGame_0_9_ROP (2/7) 1 2 개의 DrawObject( ) 함수원형 : 각각 rop 모드용디폴트인자추가 2 개의 DrawObject( ) 함수정의 : 각각 rop 모드용디폴트인자추가및일부코드수정 // 주의 : Default 값은함수의원형에만작성한다! // DrawObject( ) 내에서 Raster Mode 를지정하도록하면, // 다른곳에서매번지정하지않아도됨 // 이하부분동일하므로생략 150
4) BkGame_0_9_ROP (3/7) 2 점수출력을위한전용함수 : DisplayCount( ) 선언및정의코드추가 // 주의 : WM_PAINT 에점수출력과관련한내용과거의동일, 추후 WM_PAINT 에서는해당코드삭제예정 151
4) BkGame_0_9_ROP (4/7) 3 WndProc( ) 의변수선언위치 : 점수가출력에사용할사각형구조체선언 textr WM_CREATE: textr 의속성을설정해주는코드추가 152
4) BkGame_0_9_ROP (5/7) // 주의 : WM_PAINT 에 4 ROP 모드에서는 bar 가반드시 WM_PAINT 에그려질필요없음 애니메이션기법적용하여, 깜빡임방지! WM_MOUSEMOVE 에서처리! WM_MOUSEMOVE: bar 가움직이는것을출력하도록코드를변경 // ROP 모드를이용하여, 자연스럽게 bar 가이동하는것처럼그림 // GetDC( ) 를이용하여그리기때문에, WM_PAINT 메시지발생시키지않아도됨 // 메모리정리 153
5 ROP 모드에서는 ball 도반드시 WM_PAINT 에그려질필요없음 WM_TIMER 에서처리! 4) BkGame_0_9_ROP (6/7) // ball 그리기 // 코드위치변경및수정함 // ball 을그리도록 WM_PAINT 발생시키던함수필요없음 154
4) BkGame_0_9_ROP (7/7) 6 WM_PAINT: bar 와 ball 모두다른곳에서그려지도록변경됨. 코드수정 // 색상다른 ball 출력과일치 BkGame_0_9_ROP 수행한결과자연스럽게움직이는가? 155
Blockgame 최종목표 : BkGame ver 1.0 156
윈도우프로그래밍및실습블록게임 Part 5, VS 2015 005. 블록게임만들기 last update 2010. 11. 11 Renewal 2011. 11. 10 2010 Ver. 2012. 10. 27 2015 Ver. 2015. 09. 26 http://idb.korea.ac.kr DB & Mining LAB. Korea University 이종욱 157
Blockgame 최종 : BkGame_1_0 추가로필요한것 : 1) 벽돌그리기 2) 공이벽돌에맞으면벽돌사라지기 3) 종료조건수정 : 공이 bar보다아래로가면종료 기존버전은일정시간지나면종료됨. 4) 소리넣기 158
소리실행위해다음부분추가 (1/3) BkGame_1_0 으로프로젝트생성 기존에작성했던 BkGame_0_9_Rop 프로젝트의 BkGame_0_9.cpp파일을 BkGame_1_0 폴더에복사한다. BkGame_1_0 프로젝트에서소스를새로생성하지않고, Existing Item을가져온후, 이름을수정한다. [ 코드 ] 헤더추가 : #include <MMSystem.h> 159
소리실행위해다음부분추가 (2/3) [ 설정 ] 1) Solution Explorer에서 BkGame_1_0 이선택된상황에서! 2) Project/ Properties( 속성 ) Project Settings 팝업됨 3) Link/ Input( 입력 ) 선택 4) Additional Dependencies( 추가종속성 ) 에서 winmm.lib; 추가후확인 세미콜론은추가될 lib와구분위함 160
소리실행위해다음부분추가 (3/3) [ 설정 ] 5) 프로젝트폴더에관련소리 4 개 (bar.wav, CLAP.wav, hf_inc.wav, LASER.wav) 를저장한다! 161
Ver_1_0: (1/10) 함수원형, 블록패턴추가, timer 제거 // 실제벽의값을가지는 brick_patterns[5][5], 블록초기화 InitBlocks( ), 블록그리기 DrawBlocks( ) // bar 보다아래로가면게임끝 CheckGameOver( ), 블록과 bar 가부딪침 HitTest( ) 함수오버로딩 // 다음 m_patterns[5][5] 변수와함수들은 WinMain( ) 이전에추가함. ( 즉, 전역변수공간 ) 162
Ver_1_0: (2/10) 블록영역만들기위한함수정의 163
Ver_1_0: (3/10) 블록그리기, 게임종료조건함수정의 164
Ver_1_0: (4/10) 블록에공이맞을때함수정의 165
Ver_1_0: (5/10) 변수추가, 함수호출 // WndProc( ) 함수에 Blocks 배열과블록과공 Hit 결과저장할변수선언추가 // WM_CREATE 에 InitBlocks(); 함수호출부분추가. 다른코드는그대로사용 166
Ver_1_0: (6/10) 함수호출 ( 블록그리기 ) // WM_PAINT 에블록을그리기위하여 DrawBlocks( ) 함수호출추가. 다른코드는그대로사용 주의 case WM_MOUSEMOVE: 의맨마지막을보게되면, InvalidateRect(hWnd, NULL, TRUE); 코드가있다면, 해당코드를삭제하기바랍니다!!! 167
Ver_1_0: 개발자가만드는 윈도우메시지 주의 윈도우메시지 는 WIN API 에서제공해주는것만이아닌, 사용자가정의하여사용할수있다. GameOver 메시지생성 볼이 bar보다아래로내려가는경우가종료조건이다. 이때종료메시지를발생시켜야하며, 해당종료메시지를전달받아프로그램을종료또는재시작하는팝업창을보여주어야한다! 해결방안 : 개발자가메시지를추가! WM_USER 윈도우프로그램에서는사용자를위하여 0x0400 ~ 0x7fff 의영역을사용자메시지영역으로제공. 0x0400 은 WM_USER 이라고정의를지원하고있음 168
Ver_1_0: 주의사항 주의!!! 기존 ver_0_9 에서, 자동종료를위해사용한 ID 2 번타이머관련부분반드시삭제. 1) SetTimer(hWnd, 2, 1000 * 20 * 1, NULL); // WM_CREATE 부분, 반드시삭제한다 2) KillTimer(hWnd, 2); // WM_TIMER 부분, 반드시삭제한다 3) WM_TIMER 윈도우메시지처리부분에서, case 2: 타이머 2 와관련한부분삭제! // UM_GAMEOVER 메시지정의부분에서사용하게됨! 169
Ver_1_0: (7/10) UM_GAMEOVER 코드추가 // 개발자가만드는메시지 UM_GAMEOVER 를전역변수에추가!!! // WndProc( ) 함수의메시지처리부분에, // UM_GAMEOVER 메시지를처리를위한코드추가! 170
Ver_1_0: (8/10) WM_TIMER 코드전체변경 (1/2) // 게임종료조건을확인하여, 종료되면 UM_GAMEOVER 메세지발생! 종료가아니면계속진행! 171
Ver_1_0: (9/10) WM_TIMER 코드전체변경 (2/2) 172
Ver_1_0: (8/10) WM_TIMER 코드전체변경 (1/2) // 게임종료조건을확인하여, 종료되면 UM_GAMEOVER 메세지발생! 종료가아니면계속진행! // 다음페이지연결위치 173
Ver_1_0: (9/10) WM_TIMER 코드전체변경 (2/2) // 앞페이지연결위치 174
Ver_1_0: (10/10) WM_PAINT 의코드일부수정 // 상단블록에부딪칠때, 점수를얻는다. 해당점수는 gamescore 에저장됨. // 출력부분수정! 175