일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 패스트캠퍼스
- AI
- 패스트캠퍼스후기
- 한번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지 Online
- 알버트
- albert
- 한번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지
- SKT
- R
- 패캠챌린지
- 한번에끝내는Java/Spring웹개발마스터초격차패키지
- 직장인자기계발
- 직장인인강
- 한번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지 Online.
- Today
- Total
제주 탈출 일지
[1]Hello, World - 2D game Programming 본문
원래 공부에는 게임 제작이 최고라 하였다.
목표는 (내가 자주 하는) 퍼즐앤 드래곤과 던전앤 파이터의 아라드 어드벤처를 합쳐서 하나의 프로토타입 형태의 게임을 만들어보는 것이 목표이다. 두 개를 합치면 재밌을 것 같다는 생각을 많이 했다.
C++로 짜려고 하니 DirectX라는 어떤 라이브러리를 요구했고 그 제공하는 함수들로 프로그래밍을 진행하는 것 같았다. 버전이 2010년이 마지막으로 더이상 업데이트는 되지 않는것 같다.
http://blog.naver.com/PostView.nhn?blogId=j099450&logNo=221450305286
비주얼 스튜디오 2017에 DirectX SDK설치하기
몇시간 삽질하다가 겨우 알아내서 기억하기 편하게,또 고생하지 마시라고 올립니다. https://www.micro...
blog.naver.com
설치방법에 대해서 아주 잘 나와있었다.
http://www.programming2dgames.com/chapter2.html
Programming 2D Games
Keys Down Displays a grid that represents the current key press state of every key on the keyboard. Uses the WM_KEYDOWN and WM_KEYUP messages to determine the state of the keys on a keyboard. Download......(Source included)
www.programming2dgames.com
이 사이트에서 간단하게 2D 게임을 어떻게 프로그래밍하는지에 대한 내용을 소스코드로 제공하고 있었다.
오늘은 그 중 "Hello World" 소스코드를 분석하고자 한다.
// Programming 2D Games
// Copyright (c) 2011 by:
// Charles Kelly
// Chapter 2 "Hello World" Windows Style v1.0
// winmain.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// Function prototypes
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
bool CreateMainWindow(HINSTANCE, int);
LRESULT WINAPI WinProc(HWND, UINT, WPARAM, LPARAM);
// Global variable
HINSTANCE hinst;
// Constants
const char CLASS_NAME[] = "WinMain";
const char APP_TITLE[] = "Hello World"; // title bar text
const int WINDOW_WIDTH = 400; // width of window
const int WINDOW_HEIGHT = 400; // height of window
//=============================================================================
// Starting point for a Windows application
// Parameters are:
// hInstance - handle to the current instance of the application
// hPrevInstance - always NULL, obsolete parameter, maintained for backwards compatibilty
// lpCmdLine - pointer to null-terminated string of command line arguments
// nCmdShow - specifies how the window is to be shown
//=============================================================================
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
// Create the window
if (!CreateMainWindow(hInstance, nCmdShow))
return false;
// main message loop
int done = 0;
while (!done)
{
// PeekMessage is a non-blocking method for checking for Windows messages.
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
//look for quit message
if (msg.message == WM_QUIT)
done = 1;
//decode and pass messages on to WinProc
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
//=============================================================================
// window event callback function
//=============================================================================
LRESULT WINAPI WinProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
//tell Windows to kill this program
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
//=============================================================================
// Create the window
// Returns: false on error
//=============================================================================
bool CreateMainWindow(HINSTANCE hInstance, int nCmdShow)
{
WNDCLASSEX wcx;
HWND hwnd;
// Fill in the window class structure with parameters
// that describe the main window.
wcx.cbSize = sizeof(wcx); // size of structure
wcx.style = CS_HREDRAW | CS_VREDRAW; // redraw if size changes
wcx.lpfnWndProc = WinProc; // points to window procedure
wcx.cbClsExtra = 0; // no extra class memory
wcx.cbWndExtra = 0; // no extra window memory
wcx.hInstance = hInstance; // handle to instance
wcx.hIcon = NULL;
wcx.hCursor = LoadCursor(NULL,IDC_ARROW); // predefined arrow
wcx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // black background brush
wcx.lpszMenuName = NULL; // name of menu resource
wcx.lpszClassName = CLASS_NAME; // name of window class
wcx.hIconSm = NULL; // small class icon
// Register the window class.
// RegisterClassEx returns 0 on error.
if (RegisterClassEx(&wcx) == 0) // if error
return false;
// Create window
hwnd = CreateWindow(
CLASS_NAME, // name of the window class
APP_TITLE, // title bar text
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // default horizontal position of window
CW_USEDEFAULT, // default vertical position of window
WINDOW_WIDTH, // width of window
WINDOW_HEIGHT, // height of the window
(HWND) NULL, // no parent window
(HMENU) NULL, // no menu
hInstance, // handle to application instance
(LPVOID) NULL); // no window parameters
// if there was an error creating the window
if (!hwnd)
return false;
// Show the window
ShowWindow(hwnd, nCmdShow);
// Send a WM_PAINT message to the window procedure
UpdateWindow(hwnd);
return true;
}
소스코드를 보면 주석이 굉장히 자세하게 나와있는데, 처음이니까 세세하게 한번 분석해보려고 한다.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// Function prototypes
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
bool CreateMainWindow(HINSTANCE, int);
LRESULT WINAPI WinProc(HWND, UINT, WPARAM, LPARAM);
// Global variable
HINSTANCE hinst;
// Constants
const char CLASS_NAME[] = "WinMain";
const char APP_TITLE[] = "Hello World"; // title bar text
const int WINDOW_WIDTH = 400; // width of window
const int WINDOW_HEIGHT = 400; // height of window
먼저 선언부이다.
WIN32_LEAN_AND_MEAN을 정의했다. #define WIN32_LEAN_AND_MEAN를 #include "windows.h" 문장 이전에 선언해 준다면 수많은 헤더를 인클루드 하면서 중복 인클루드 되는 헤더를 방지하고 데이터의 중복정의를 제거하며 SDK 프로그래밍에 필요없는 정의들을 건너뛴다. 그래서 프로그램을 날씬하게 만들어 준다.
출처: https://javawoo.tistory.com/42 []
windows.h는 윈도우 응용 프로그램을 만들기 위한 다양한 함수 및 매크로가 포함되어 있다라고 한다. -위키-
함수로는 WinMain(), CreateMainWindow(), WinProc() 3가지를 사용한다.
- WinMain()은 window프로그램의 시작점으로 main과 비슷한 역할이다.
winmain과 int 사이에는 WINAPI라는 매크로가 있는데, 그에 대해 정리한 글이다.
Windows API :: int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 의 의미
윈도우즈 API에서 "int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)" 와 같은 메인 함수를 발견할 수 있다. 이러한 함수가 무슨 역할을 하는지 궁금했는데, 이..
vallista.tistory.com
인수들은 4가지가 존재한다. 다음과 같다.
- hInstance : 프로그램의 인스턴스 핸들 //실제로 메모리에 올라온 프로그램의 실체를 의미, 프로그램마다 고유하다.
시스템 프로그래밍에서 공부했던 리눅스의 inode?(정확한 명칭이 기억이 안난다.) 와 비슷한 의미를 가진다고 생각이 든다.
- hPrevInstance : 바로 앞에 실행된 현재 프로그램의 인스턴스 핸들, WIN32에서는 항상 NULL, 호환성을 위해 존재
- lpCmdLine : 명령행, 도스의 argv인수에 해당
- nCmdShow : 프로그램이 실행될 형태, 최소화, 보통모양이 전달
출처: https://hoidu.tistory.com/entry/Windows-Api-정복-정리-WinMain-윈도우-클래스 [Du의 재미있는 프로그래밍 세상]
winmain만 봤는데도 쉽지 않다.. 다음 createmainwindow이다.
- bool CreateMainWindow(HINSTANCE, int);
함수이름에서 알 수 있듯이 메인 Window화면을 생성해주는 함수이다. 그를 위해서는 프로그램의 고유 인스턴스 핸들을 알아야 하고(HINSTANCE), int는 윈도우 및 컨트롤의 표시/숨김 및 최대화/최소화 상태에 대한 flag이다.(nCmdShow 인수)
- LRESULT WINAPI WinProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
winProc은 window procedure라는 뜻이다. 윈도우에서 메세지 전송을 통해서 프로그램과 소통하는데, 이러한 메세지들은 사용자 작업과 윈도우 명령을 알려주는데 사용된다. 다양한 메세지들이 존재하는데, 그 중 응답할 메세지를 정하여 WinProc 내에 코드를 배치한다.
이제 WinMain의 내용을 한번 보도록 하겠다.
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
// Create the window
if (!CreateMainWindow(hInstance, nCmdShow))
return false;
// main message loop
int done = 0;
while (!done)
{
// PeekMessage is a non-blocking method for checking for Windows messages.
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
//look for quit message
if (msg.message == WM_QUIT)
done = 1;
//decode and pass messages on to WinProc
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
첫번째 if문에서는 CreateMainWindow를 호출하여 1이 오게 되면 false를 리턴하고 있다. 윈도우즈 창이 제대로 생성되지 못한 모양. 그 후 while문으로 무한 루프를 호출한다. 메세지를 Peek(몰래 엿보다)하는데 PM_REMOVE가 있는지 확인하고(아마 PeekMessage는 bool타입 리턴을 해줄 것이다.), 있다면 mes.message가 WM_QUIT일 경우 반복을 끝내게 된다. (done을 1로 만듬.)
PeekMessage와 GetMessage가 CPU 유휴 상태에 대해서 중요한 issue가 존재하는 것 같은데, 이 소스코드는 맛보기이므로 다음에,..,.,.,
PeekMessage -> TranslateMessage(&msg) -> DispatchMessage(&msg);
GetMessage가 메시지를 읽고(여기서는 PeekMessage) TranslateMessage가 문자 메시지로 변환을 하며 DispatchMessage가 메시지를 윈도우 프로시저로 보내진다.
출처: https://kjin2sm.tistory.com/167 [K_JIN2SM]
이렇게 프로그램( done이 1으로 바뀌게 되면)이 종료되면, msg. Wparam을 반환한다.
wparam은 전달된 메시지에 대한 부가적인 정보를 가진다. 어떤 의미를 가지는가는 메시지별로 다르다. 32비트값이다.
다음은 WinProc의 정의부이다.
//=============================================================================
// window event callback function
//=============================================================================
LRESULT WINAPI WinProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
//tell Windows to kill this program
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
winproc의 모든 인수는 메세지와 관련된 정보들이다.(메세지 구조체의 4가지 정보이다. hwnd는 메세지를 받은 윈도우의 핸들이다.) 이 msg를 받아서 WM_DESTROY라면 윈도우즈에게 이 프로그램을 종료하라고 전달한다.(PostQuitMessage(0))
DefWindowProc은 WinProc에서 처리하지 않은 나머지 메세지를 처리한다.
마지막으로 bool CreateMainWindow(HINSTANCE, int)이다.
//=============================================================================
// Create the window
// Returns: false on error
//=============================================================================
bool CreateMainWindow(HINSTANCE hInstance, int nCmdShow)
{
WNDCLASSEX wcx;
HWND hwnd;
// Fill in the window class structure with parameters
// that describe the main window.
wcx.cbSize = sizeof(wcx); // size of structure
wcx.style = CS_HREDRAW | CS_VREDRAW; // redraw if size changes
wcx.lpfnWndProc = WinProc; // points to window procedure
wcx.cbClsExtra = 0; // no extra class memory
wcx.cbWndExtra = 0; // no extra window memory
wcx.hInstance = hInstance; // handle to instance
wcx.hIcon = NULL;
wcx.hCursor = LoadCursor(NULL,IDC_ARROW); // predefined arrow
wcx.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // black background brush
wcx.lpszMenuName = NULL; // name of menu resource
wcx.lpszClassName = CLASS_NAME; // name of window class
wcx.hIconSm = NULL; // small class icon
// Register the window class.
// RegisterClassEx returns 0 on error.
if (RegisterClassEx(&wcx) == 0) // if error
return false;
// Create window
hwnd = CreateWindow(
CLASS_NAME, // name of the window class
APP_TITLE, // title bar text
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // default horizontal position of window
CW_USEDEFAULT, // default vertical position of window
WINDOW_WIDTH, // width of window
WINDOW_HEIGHT, // height of the window
(HWND) NULL, // no parent window
(HMENU) NULL, // no menu
hInstance, // handle to application instance
(LPVOID) NULL); // no window parameters
// if there was an error creating the window
if (!hwnd)
return false;
// Show the window
ShowWindow(hwnd, nCmdShow);
// Send a WM_PAINT message to the window procedure
UpdateWindow(hwnd);
return true;
}
해당 함수는 윈도우 프로그램창을 생성해주기 때문에 wndclassex를 정의하는데, 굉장히 많은 멤버들을 초기화하는 것을 확인할 수 있었다. 윈도우 클래스를 등록하고 클래스의 이름등등으로 CreateWindow함수를 호출하여 윈도우를 생성한다.
이렇게 Hello, World 제목을 가진 윈도우 프로그램 창 하나를 띄우는 과정에 대해서 세세하게 살펴보았다.
윈도우 프로그램 만드는 것 자체가 C나 C++에서의 느낌과는 전혀 다른 생소한 느낌이었고, 익숙해지려면 많이 보는 수 밖에는 없을 듯 하다. 좋은 경험이었다.
'윈도우 프로그래밍(DirectX)' 카테고리의 다른 글
[3]Keys Down - 2D game programming (0) | 2020.09.10 |
---|---|
[2]Character input - 2D game programming (0) | 2020.09.09 |