godurum/일반
2D테트리스만들기 2. 화면다루기 2) 타임함수이용하기
민성아빠
2004. 5. 13. 10:37
####################################################
2D테트리스만들기
2. 화면다루기
2) 타임함수이용하기
####################################################
지금 부터 진행 하는 과정은 테트리스를 만들기 위한 필요한 기능이 각각 무엇인지 인지하는
것입니다. 각각의 기능을 인지하였다면 그 기능을 합쳐서 게임엔진을 만드는 과정으로
넘어가게 되는 것입니다. 이런 전체적인 그림을 그려놓구 기능 분석을 하도록 하겠습니다.
이번에 다룰 내용은 타임함수를 이용해서 사각형 박스를 내려오게 하려구 합니다. 먼저 타임
함수를 만들구 사용자 정의 메세지함수를 만들어야하는데 생소한 부분이 있더라도 아무 생각없이
따라하시면 됩니다. ^^;;;;
//------------실전 예 시작------------------
// time함수를 사용하려면 project-settings-link에 winmm.lib를 추가해야한다.
...
#define HANDLE_WM_USER(hwnd, wParam, lParam, fn) \\
((fn)(hwnd), 0L) // 사용자 정의 된 윈도우메세지의 인자값선언
// 윈도우메세지 기본형
...
UINT TimerId;
short CurFPS = 5;// 설정된 현재 재생율 (FPS)
...
BOOL InitTimer();
// 타이머초기화
void CALLBACK TimerProc (UINT iTimerID, UINT iMsg, DWORD User, DWORD dw1, DWORD dw2);
// 타이머프록
void OnUser(HWND hwnd);
// 타이머프록함수
...
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
MSG msg ;
DWORD sTime, lTime;
...
lTime = GetTickCount(); // 난수 발생을 위해필요
InitTimer();
while(sTime < 5500) // (6초간 기다려준다.)
{
sTime = GetTickCount() - lTime;
}
...
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
...
HANDLE_MSG(hwnd, WM_USER, OnUser);
...
}
...
void OnDestroy(HWND hwnd)
{
TIMECAPS caps;
timeGetDevCaps ( &caps, sizeof(caps));
timeEndPeriod(caps.wPeriodMin);
timeKillEvent(TimerId);
PostQuitMessage(0);
}
void CALLBACK TimerProc (UINT iTimerID, UINT iMsg, DWORD User, DWORD dw1, DWORD dw2)
{
SendMessage(hMainWnd, WM_USER, 0, 0);
}
BOOL InitTimer()
{
TIMECAPS caps;
timeGetDevCaps ( &caps, sizeof(caps));
// time함수를 사용하려면 project-settings-link에 winmm.lib를 추가해야한다.
timeBeginPeriod(caps.wPeriodMin);
TimerId = timeSetEvent (1000 / CurFPS , caps.wPeriodMin, TimerProc, 0, (UINT)TIME_PERIODIC);
return TRUE;
}
void OnUser(HWND hwnd)
{
HDC hdc;
static x=400, y=110;
hdc = GetDC(hMainWnd);
SelectObject(hdc, GetStockObject(WHITE_PEN));
Rectangle(hdc, x, y, x+10, y+10);
SelectObject(hdc, GetStockObject(BLACK_PEN));
y = y+10;
Rectangle(hdc, x, y, x+10, y+10);
}
//------------실전 예 끝------------------
2) 타임함수 이용하기
(★★★★★★★★★)
처음 보이는 것이 HANDLE_WM_USER일 것이다. 이것은 사용자 정의 메세지 함수로
얼마든지 활용 가치가 크니 무조건 알아두어야합니다. (별표10개)
이것을 알기전에 윈도우기본 메세지함수는 어떻게 구성되어있길래 따로 선언없이 사용이 가능한지
궁금해 할 것이다. 제가 주로 사용하는 방법인데, 항상 근본을 파고드는 습관을 기르자 그래야
윈도우의 기본함수를 사용자의 편의에 맞게 변경이 가능하기 때문이다. 이 방법만 알면 재미나구
쉽게 자기만의 함수를 개발할 수 있다. 그럼 WM_CREATE를 메뉴판 Edit-Find In Fiels에서
VC++이 설치된 곳을 선택하구 검색을 시작하자. 그럼 여러 검색 결과가 나오는데 이중
\\vc98\\include\\windowsx.h 에 #define로 함수가 선언이 된것을 보실수 있을것이다. 이것이
바로 우리가 별다른 선언없이 사용하게 하는 이유이다. 그렇다면 당연히 이 구조를 이용해서 사용자
정의 메세지함수를 만들 수 있는 것이다. ^^;;; (잘 모르시겠다면 그냥 넘어가길 바랍니다.)
그래서 간단한 WM_USER를 만들 수 있는 것입니다. 당연히 함수명은 변경이 가능합니다.
다음 전역 변수로 UINT TimerId; short CurFPS = 5; 을 선언햇습니다.
Timerid : 타이머를 생성한 아이디값 뒤에 id로 들어간 것은 사람의 주민등록번호라 생각하심됩니다
나중에 타이머를 죽일때 쓰입니다.
CurFPS : 타이머를 일정한 프레임으로 돌려야하는데 그 프레임 간격을 기억합니다.
새로운 함수를 선언합니다.
BOOL InitTimer();
// 타이머초기화
void CALLBACK TimerProc (UINT iTimerID, UINT iMsg, DWORD User, DWORD dw1, DWORD dw2);
// 타이머프록
void OnUser(HWND hwnd);
// 타이머프록함수
그리구 앞으로 윈도우 초기에 발생 시킬 명령은 WinMain에 담아 둡니다.
lTime = GetTickCount(); // 난수 발생을 위해필요
InitTimer();
while(sTime < 5500) // (6초간 기다려준다.)
{
sTime = GetTickCount() - lTime;
}
여기서 GetTickCount함수는 난수 발생을 위해 선언한 것입니다. 별다른 의미는 없습니다.
WndProc에 사용자 메세지 함수를 선언합니다.
HANDLE_MSG(hwnd, WM_USER, OnUser);
타임 함수는 생성후 죽이지 않는 다면 리소스에 문제가 생기겠져. 잊지말구 죽여주세요
void OnDestroy(HWND hwnd)
{
TIMECAPS caps;
timeGetDevCaps ( &caps, sizeof(caps));
timeEndPeriod(caps.wPeriodMin);
timeKillEvent(TimerId);
PostQuitMessage(0);
}
(★★★)
여기서 또 중요한 내용인데 콜벡프록함수는 발생후 죽이지 않는 이상 발생했던 프로세스에서
계속 실행이 됩니다. 이것은 나중에 배울 쓰레드에도 이용이 되니 기억해 두시기 바랍니다.
void CALLBACK TimerProc (UINT iTimerID, UINT iMsg, DWORD User, DWORD dw1, DWORD dw2)
{
SendMessage(hMainWnd, WM_USER, 0, 0);
}
SendMessage는 윈도우에 지정한 메세지를 보내는 것입니다. 당연히 WndProc함수가 받겠지요
왜냐 첫번째 인자인 hMainWnd핸들에 보내라구 했기 때문이져 제가 hWnd를 hMainWnd로 선언한
것은 윈도우 핸들의 움직임을 파악하기 위해서입니다. 이것은 복잡한 프로그램에서는 메세지를 전달할
대상이 윈도우만이 아니라 더 많아 질 수 있기 때문입니다. 자세한건 그때 설명하겠습니다.
타임함수 초기화 이 순서는 그냥 외우시기 바랍니다. 별거 없습니다.
BOOL InitTimer()
{
TIMECAPS caps;
timeGetDevCaps ( &caps, sizeof(caps));
// time함수를 사용하려면 project-settings-link에 winmm.lib를 추가해야한다.
timeBeginPeriod(caps.wPeriodMin);
TimerId = timeSetEvent (1000 / CurFPS , caps.wPeriodMin, TimerProc, 0, (UINT)TIME_PERIODIC);
return TRUE;
}
여기서 1000/CurFPS는 프레임수를 결정하는 것이구 TimerProc은 프레임수마다 이 프록 함수를
실행하라는 내용입니다. 이것으로 테트리스의 난이도를 결정할 수 있는 것입니다. ^^;;;
사용자 정의 함수는 이전 강의에서 배운 내용입니다.
void OnUser(HWND hwnd)
{
HDC hdc;
static x=400, y=110;
hdc = GetDC(hMainWnd);
SelectObject(hdc, GetStockObject(WHITE_PEN));
Rectangle(hdc, x, y, x+10, y+10);
SelectObject(hdc, GetStockObject(BLACK_PEN));
y = y+10; // 박스크기가 10픽셀이므로 한칸씩 내려오게한다.
Rectangle(hdc, x, y, x+10, y+10);
}
static으로 선언하여 변수값이 기억되게 하였습니다. 그리구 이전 그림은 흰색으로 사라지게 만들었구
한칸씩 아래로 내려오게 하는 내용입니다.
2D테트리스만들기
2. 화면다루기
2) 타임함수이용하기
####################################################
지금 부터 진행 하는 과정은 테트리스를 만들기 위한 필요한 기능이 각각 무엇인지 인지하는
것입니다. 각각의 기능을 인지하였다면 그 기능을 합쳐서 게임엔진을 만드는 과정으로
넘어가게 되는 것입니다. 이런 전체적인 그림을 그려놓구 기능 분석을 하도록 하겠습니다.
이번에 다룰 내용은 타임함수를 이용해서 사각형 박스를 내려오게 하려구 합니다. 먼저 타임
함수를 만들구 사용자 정의 메세지함수를 만들어야하는데 생소한 부분이 있더라도 아무 생각없이
따라하시면 됩니다. ^^;;;;
//------------실전 예 시작------------------
// time함수를 사용하려면 project-settings-link에 winmm.lib를 추가해야한다.
...
#define HANDLE_WM_USER(hwnd, wParam, lParam, fn) \\
((fn)(hwnd), 0L) // 사용자 정의 된 윈도우메세지의 인자값선언
// 윈도우메세지 기본형
...
UINT TimerId;
short CurFPS = 5;// 설정된 현재 재생율 (FPS)
...
BOOL InitTimer();
// 타이머초기화
void CALLBACK TimerProc (UINT iTimerID, UINT iMsg, DWORD User, DWORD dw1, DWORD dw2);
// 타이머프록
void OnUser(HWND hwnd);
// 타이머프록함수
...
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
MSG msg ;
DWORD sTime, lTime;
...
lTime = GetTickCount(); // 난수 발생을 위해필요
InitTimer();
while(sTime < 5500) // (6초간 기다려준다.)
{
sTime = GetTickCount() - lTime;
}
...
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
...
HANDLE_MSG(hwnd, WM_USER, OnUser);
...
}
...
void OnDestroy(HWND hwnd)
{
TIMECAPS caps;
timeGetDevCaps ( &caps, sizeof(caps));
timeEndPeriod(caps.wPeriodMin);
timeKillEvent(TimerId);
PostQuitMessage(0);
}
void CALLBACK TimerProc (UINT iTimerID, UINT iMsg, DWORD User, DWORD dw1, DWORD dw2)
{
SendMessage(hMainWnd, WM_USER, 0, 0);
}
BOOL InitTimer()
{
TIMECAPS caps;
timeGetDevCaps ( &caps, sizeof(caps));
// time함수를 사용하려면 project-settings-link에 winmm.lib를 추가해야한다.
timeBeginPeriod(caps.wPeriodMin);
TimerId = timeSetEvent (1000 / CurFPS , caps.wPeriodMin, TimerProc, 0, (UINT)TIME_PERIODIC);
return TRUE;
}
void OnUser(HWND hwnd)
{
HDC hdc;
static x=400, y=110;
hdc = GetDC(hMainWnd);
SelectObject(hdc, GetStockObject(WHITE_PEN));
Rectangle(hdc, x, y, x+10, y+10);
SelectObject(hdc, GetStockObject(BLACK_PEN));
y = y+10;
Rectangle(hdc, x, y, x+10, y+10);
}
//------------실전 예 끝------------------
2) 타임함수 이용하기
(★★★★★★★★★)
처음 보이는 것이 HANDLE_WM_USER일 것이다. 이것은 사용자 정의 메세지 함수로
얼마든지 활용 가치가 크니 무조건 알아두어야합니다. (별표10개)
이것을 알기전에 윈도우기본 메세지함수는 어떻게 구성되어있길래 따로 선언없이 사용이 가능한지
궁금해 할 것이다. 제가 주로 사용하는 방법인데, 항상 근본을 파고드는 습관을 기르자 그래야
윈도우의 기본함수를 사용자의 편의에 맞게 변경이 가능하기 때문이다. 이 방법만 알면 재미나구
쉽게 자기만의 함수를 개발할 수 있다. 그럼 WM_CREATE를 메뉴판 Edit-Find In Fiels에서
VC++이 설치된 곳을 선택하구 검색을 시작하자. 그럼 여러 검색 결과가 나오는데 이중
\\vc98\\include\\windowsx.h 에 #define로 함수가 선언이 된것을 보실수 있을것이다. 이것이
바로 우리가 별다른 선언없이 사용하게 하는 이유이다. 그렇다면 당연히 이 구조를 이용해서 사용자
정의 메세지함수를 만들 수 있는 것이다. ^^;;; (잘 모르시겠다면 그냥 넘어가길 바랍니다.)
그래서 간단한 WM_USER를 만들 수 있는 것입니다. 당연히 함수명은 변경이 가능합니다.
다음 전역 변수로 UINT TimerId; short CurFPS = 5; 을 선언햇습니다.
Timerid : 타이머를 생성한 아이디값 뒤에 id로 들어간 것은 사람의 주민등록번호라 생각하심됩니다
나중에 타이머를 죽일때 쓰입니다.
CurFPS : 타이머를 일정한 프레임으로 돌려야하는데 그 프레임 간격을 기억합니다.
새로운 함수를 선언합니다.
BOOL InitTimer();
// 타이머초기화
void CALLBACK TimerProc (UINT iTimerID, UINT iMsg, DWORD User, DWORD dw1, DWORD dw2);
// 타이머프록
void OnUser(HWND hwnd);
// 타이머프록함수
그리구 앞으로 윈도우 초기에 발생 시킬 명령은 WinMain에 담아 둡니다.
lTime = GetTickCount(); // 난수 발생을 위해필요
InitTimer();
while(sTime < 5500) // (6초간 기다려준다.)
{
sTime = GetTickCount() - lTime;
}
여기서 GetTickCount함수는 난수 발생을 위해 선언한 것입니다. 별다른 의미는 없습니다.
WndProc에 사용자 메세지 함수를 선언합니다.
HANDLE_MSG(hwnd, WM_USER, OnUser);
타임 함수는 생성후 죽이지 않는 다면 리소스에 문제가 생기겠져. 잊지말구 죽여주세요
void OnDestroy(HWND hwnd)
{
TIMECAPS caps;
timeGetDevCaps ( &caps, sizeof(caps));
timeEndPeriod(caps.wPeriodMin);
timeKillEvent(TimerId);
PostQuitMessage(0);
}
(★★★)
여기서 또 중요한 내용인데 콜벡프록함수는 발생후 죽이지 않는 이상 발생했던 프로세스에서
계속 실행이 됩니다. 이것은 나중에 배울 쓰레드에도 이용이 되니 기억해 두시기 바랍니다.
void CALLBACK TimerProc (UINT iTimerID, UINT iMsg, DWORD User, DWORD dw1, DWORD dw2)
{
SendMessage(hMainWnd, WM_USER, 0, 0);
}
SendMessage는 윈도우에 지정한 메세지를 보내는 것입니다. 당연히 WndProc함수가 받겠지요
왜냐 첫번째 인자인 hMainWnd핸들에 보내라구 했기 때문이져 제가 hWnd를 hMainWnd로 선언한
것은 윈도우 핸들의 움직임을 파악하기 위해서입니다. 이것은 복잡한 프로그램에서는 메세지를 전달할
대상이 윈도우만이 아니라 더 많아 질 수 있기 때문입니다. 자세한건 그때 설명하겠습니다.
타임함수 초기화 이 순서는 그냥 외우시기 바랍니다. 별거 없습니다.
BOOL InitTimer()
{
TIMECAPS caps;
timeGetDevCaps ( &caps, sizeof(caps));
// time함수를 사용하려면 project-settings-link에 winmm.lib를 추가해야한다.
timeBeginPeriod(caps.wPeriodMin);
TimerId = timeSetEvent (1000 / CurFPS , caps.wPeriodMin, TimerProc, 0, (UINT)TIME_PERIODIC);
return TRUE;
}
여기서 1000/CurFPS는 프레임수를 결정하는 것이구 TimerProc은 프레임수마다 이 프록 함수를
실행하라는 내용입니다. 이것으로 테트리스의 난이도를 결정할 수 있는 것입니다. ^^;;;
사용자 정의 함수는 이전 강의에서 배운 내용입니다.
void OnUser(HWND hwnd)
{
HDC hdc;
static x=400, y=110;
hdc = GetDC(hMainWnd);
SelectObject(hdc, GetStockObject(WHITE_PEN));
Rectangle(hdc, x, y, x+10, y+10);
SelectObject(hdc, GetStockObject(BLACK_PEN));
y = y+10; // 박스크기가 10픽셀이므로 한칸씩 내려오게한다.
Rectangle(hdc, x, y, x+10, y+10);
}
static으로 선언하여 변수값이 기억되게 하였습니다. 그리구 이전 그림은 흰색으로 사라지게 만들었구
한칸씩 아래로 내려오게 하는 내용입니다.