반응형

Message 란?

 

메세지는 사용자나 시스템의 특정 이벤트(내부적인 동작)에 의해 발생하는 변화의 정보를 담은 구조체이다.
Ex) 키보드의 입력, 마우스를 눌렀을 때, 마우스를 누르고 있을 때, 마우스를 뗏을 때, 윈도우를 축소시켰을 때 등등....
윈도우는 발생하는 메세지를 쌓아서 먼저 들어온 순서대로 처리하는데, 이를 메세지 큐라고 한다.윈도우는 위 과정을 거치며 쌓인 메세지 큐를 처리하는 과정을 반복하게 되는데, 이를 메세지 루프라고 한다. 발생하는 메세지의 종류는 아래에서 다룰 윈도우 프로시저에서 볼 수 있다.

메세지 루프의 일반적인 형태 (혹은 Getmessage를 사용한다.)

 
 

(BOOL) GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax) : 메세지에 WM_QUIT를 받아오면 false를 반환하고 그 외의 메세지는 true를 반환한다. 메세지 큐에 메세지가 발생할 때 까지 대기(블러킹)한다.

lpMsg 메세지 큐에서 발생한 MSG(메세지)의 구조체에 대한 포인터
hWnd 이벤트가 발생한 윈도우에 대한 핸들
wMsgFilterMin 조사할 메세지의 최소 값
wMsgFilterMax 조사할 메세지의 최대 값

https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/nf-winuser-getmessage
 
 
(BOOL) PeekMessage(LPMSG lpMsgHWND hWndUINT wMsgFilterMinUINT wMsgFilterMax, UINT wRemoveMsg) : 메세지 큐에 메세지가 발생하면 true, 아니면 false를 반환한다. 대기하는 과정이 없기 때문에 논 블러킹이다.

lpMsg 메세지 큐에서 발생한 MSG(메세지)의 구조체에 대한 포인터
hWnd 이벤트가 발생한 윈도우에 대한 핸들
wMsgFilterMin 조사할 메세지의 최소 값
wMsgFilterMax 조사할 메세지의 최대 값
wRemoveMsg 메세지를 처리하는 방법 (PM_매크로를 사용)

https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/nf-winuser-peekmessagea
 
 
RemoveMsg의 매개 변수에는 다음 값이 올 수 있다.

더보기

메세지를 처리하는 방법

PM_NOREMOVE PeekMessage에서 처리한 후 큐에서 메시지가 제거되지 않습니다.
PM_REMOVE PeekMessage에서 처리한 후 큐에서 메시지가 제거됩니다.
PM_NOYIELD 시스템에서 호출자가 유휴 상태가 될 때까지 대기 중인 스레드를 해제하지 못하도록 합니다. 이 값을 PM_NOREMOVE 또는 PM_REMOVE 결합합니다.
PM_QS_INPUT 마우스 및 키보드 메시지를 처리합니다.
PM_QS_PAINT 그리기 메시지를 처리합니다.
PM_QS_POSTMESSAGE 타이머 및 바로 가기 키를 포함하여 게시된 모든 메시지를 처리합니다.
PM_QS_SENDMESSAGE 전송된 모든 메시지를 처리합니다.

 

 
 
 

(BOOL) TranslateMessage (CONST MSG lpMsg) : 키보드 입력에 관련된 메세지를 받을 때 무슨 키를 입력받았는지 등의 상태를 받아서 메세지 큐에 덧붙입니다.

lpMsg 메세지 큐에서 발생한 MSG(메세지)의 구조체에 대한 포인터

https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/nf-winuser-translatemessage
 

 
(BOOL) DispatchMessage(CONST MSG lpMsg) : 메세지 값을 받아서 윈도우 프로시저 함수를 호출해준다.

lpMsg 메세지 큐에서 발생한 MSG(메세지)의 구조체에 대한 포인터

https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/nf-winuser-dispatchmessage
 
 


WndProc(윈도우 프로시저) 란?

 

WinMain함수는 특정 이벤트를 통해 발생한 메세지를 메세지 루프를 통해 받고 큐에 저장한다. 
WndProc(윈도우 프로시저)는 위와 같은 메세지큐에 저장된 메세지를 처리하기 위한 메세지 처리 전용 함수이다.
윈도우 프로시저는 사용자가 호출할 수 없고 윈도우만이 호출할 수 있는데, 이러한 함수를 콜백 함수(CallBack Function)이라고 한다.
아래는 윈도우 프로시저 함수에 대한 문법 및 매개변수이다.
 
(LRESULT) CALLBACK WndProc(HWND hWndUINT messageWPARAM wParamLPARAM lParam) : CALLBACK함수 호출 규약(Calling Convention)으로, 생략해도 컴파일 할 때 자동으로 선택된다. 하지만 예외적으로 호환성을 위해 명시적으로 호출 규약을 지정해야 할 때가 있을수도 있다. wParam과 lParam은 부가적인 메세지를 받아온다. 예를 들면 키 입력에 관한 메세지를 받았을 때, 키보드의 무슨 값을 입력 받았는지, 마우스의 x, y좌표는 몇인지 등등의 정보이다.

hWnd Window의 핸들 값
message 처리하기 위해 호출 된 메세지(이벤트)
wParam 부가적인 메세지 정보
lParam 부가적인 메세지 정보

https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/nc-winuser-wndproc

더보기

매개변수로 받는 message중 주로 사용되는 메세지는 아래와 같다.

WM_KEYDOWN  키보드를 눌렀을 때 발생되는 메세지.
WM_KEYUP  키보드를 눌렀다 뗄 때 발생되는 메세지.
WM_LBUTTONDOWN  마우스 왼쪽 버튼을 눌렀을 때 발생되는 메세지.
WM_LBUTTONUP  마우스 왼쪽 버튼을 눌렀다 뗄 때 발생되는 메세지.
WM_RBUTTONDOWN  마우스 오른쪽 버튼을 눌렀을 때 발생되는 메세지.
WM_RBUTTONUP  마우스 오른쪽 버튼을 눌렀다 뗄 때 발생되는 메세지.
WM_MOUSEMOVE  마우스가 움직일 때 발생되는 메세지.
WM_MOUSEHWHEEL 마우스 휠을 드래그할 때 발생되는 메세지.
WM_CREATE 윈도우가 처음 만들어질 때 발생되는 메세지.
WM_CHAR 키보드로부터 문자가 입력될 때 발생되는 메세지.

그 외 매개변수는 아래 링크에서 확인

https://learn.microsoft.com/ko-kr/windows/win32/winmsg/about-messages-and-message-queues#system-defined-messages

 
 


DC(Device_Context) 란?

 

출력에 필요한 모든 정보를 가진 데이터 구조체이다. 주로 그래픽 렌더링, 텍스트 출력, 비트맵 조작 등처럼 화면의 출력을 할 때 사용한다. DC는 할당받는 순간 메모리를 차지하기 때문에, 동적할당과 비슷하게 다 쓰고 난 후에는 메모리를 직접 해제해야 메모리 누수가 일어나지 않는다.
 
 
HDC GetDC(HWND hWnd) : 지정한 창(윈도우)에 대한 DC핸들을 반환받는다.

hWnd DC핸들을 얻어 올 윈도우 핸들을 지정해준다. 0(NULL)을 넣어주면 전체 화면에 대한 핸들이 된다.

https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/nf-winuser-getdc
 
 

int ReleaseDC(HWND hWndHDC hDC) : 할당된 DC를 해제해준다. DC가 성공적으로 해제되면 1을 반환해주고, 아닐 경우 0을 반환해준다.

hWnd DC를 해제할 윈도우 핸들을 지정해준다. 0(NULL)을 넣어주면 전체 화면에 대한 핸들이 된다.
hDC 해제할 DC에 대한 핸들을 지정해준다.

https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/nf-winuser-releasedc

 


[Windows API] Win32 API의 그래픽, GDI와 스톡 오브젝트(Stock Object) — CHAN-GPT (tistory.com)

개정: WinAPI 프로그래밍 강좌 - GDI.. : 네이버블로그 (naver.com)

GDI_Object(GDI 객체) 란?

 

펜, 브러쉬, 비트맵, 폰트 등 다양한 출력 객체를 다루는 데 사용하는 함수와 핸들의 모음이다.
아래는 GDI_Object와 관련된 각종 함수와 핸들이다. GDI_Object는 다 쓴 후에는 Default값으로 돌려놓아야 한다.


 
GDI_Object 핸들 종류

GDI_Object 핸들 타입 기본 값(Defalt)
펜(Pen) HPEN Type : Solid (실선)
Width : 1 (두께)
Color : BLACK (검은색)
브러쉬(Brush) HBRUSH Color : White
폰트(FONT) HFONT Font : Tahoma
비트맵(Bitmap) HBITMAP -
팔레트(PALETTE) HPALETTE -
영역(RGN) HRGN -

 
GDI_Object 종류
 
(HPEN)  CreatePen(int iStyle, int cWidth, COLORREF color) : 펜의 속성을 반환하는 함수다. SelectObject() 함수를 사용할 때 HPEN 자료형으로 캐스팅해 사용할 수 있음.

iStyle (펜 매크로) 선 스타일을 지정한다. (_PS로 시작하는 펜 매크로를 사용)
cWidth (펜의 굵기) 펜의 굵기를 지정한다. 0일 경우 디폴트 값(1)로 지정된다.
color (RGB) 펜의 색깔을 지정한다. RGB매크로를 통해 값(각 0~255의 값) 을 전달한다.

CreatePen 함수(wingdi.h) - Win32 apps | Microsoft Learn

더보기

펜 매크로 종류

(* RGB매크로 : R,G,B 값을 입력하면 내부에서 비트시프트(R << 0, G << 8, B << 16)를 통해  B(1btye) G (1btye) R (1btye) 순의 3바이트 값에 저장된다.)
 
 
(HBRUSH)  CreateSolidBrush(COLORREF color) : 브러쉬의 색깔을 반환하는 함수다. SelectObject() 함수를 사용할 때 HBRUSH 자료형으로 캐스팅해 사용할 수 있음.

color (RGB) 브러쉬의 색깔을 지정한다. RGB매크로를 통해 값(각 0~255의 값) 을 전달한다.

CreateSolidBrush 함수(wingdi.h) - Win32 앱 | 마이크로소프트 런(Microsoft T
이 외에 CreateHatchBrush, CreatePatternBrush 등이 있다.
 
(HGDIOBJ)  GetStockObject(int i) : 윈도우가 기본적으로 제공하는 GID_Object이며, 스톡 오브젝트라고 한다. 사용 후 해지하지 않아도 된다는 특성이 있다. (해제해도 상관은 없음.)

i (스톡 매크로) 스톡 매크로를 통해 GDI_Object를 지정할 수 있다.

GetStockObject 함수(wingdi.h) - Win32 앱 | 마이크로소프트 런(Microsoft T

더보기

스톡 매크로 종류

의미
BLACK_BRUSH 검은 브러시.
DKGRAY_BRUSH 짙은 회색 브러시입니다.
DC_BRUSH 단색 브러시입니다. 기본 색상은 흰색입니다. SetDCBrushColor 함수를 사용하여 색을 변경할 수 있습니다.
GRAY_BRUSH 회색 브러시.
HOLLOW_BRUSH 속이 빈 브러시(NULL_BRUSH에 해당).
LTGRAY_BRUSH 밝은 회색 브러시입니다.
NULL_BRUSH Null 브러시(HOLLOW_BRUSH에 해당).
WHITE_BRUSH 화이트 브러시.
BLACK_PEN 검은 펜.
DC_PEN 단색 펜 색상입니다. 기본 색상은 검은색입니다. SetDCPenColor 함수를 사용하여 색을 변경할 수 있습니다. 
NULL_PEN Null 펜. null 펜은 아무 것도 그리지 않습니다.
WHITE_PEN 흰색 펜.
ANSI_FIXED_FONT Windows 고정 피치(고정 폭) 시스템 글꼴입니다.
ANSI_VAR_FONT Windows 가변 피치(비례 공간) 시스템 글꼴입니다.
DEVICE_DEFAULT_FONT 장치 종속 글꼴입니다.
DEFAULT_GUI_FONT 메뉴 및 대화 상자와 같은 사용자 인터페이스 개체의 기본 글꼴입니다. 대화 상자와 창에서 사용하는 글꼴을 얻기 위해 DEFAULT_GUI_FONT 또는 SYSTEM_FONT를 사용하지 않는 것이 좋습니다. 기본 글꼴은 Tahoma입니다.
OEM_FIXED_FONT OEM(주문자 상표 부착 방식) 종속 고정 피치(고정 폭) 글꼴입니다.
SYSTEM_FONT 시스템 글꼴. 기본적으로 시스템은 시스템 글꼴을 사용하여 메뉴, 대화 상자 컨트롤 및 텍스트를 그립니다. 대화 상자와 창에서 사용하는 글꼴을 얻기 위해 DEFAULT_GUI_FONT 또는 SYSTEM_FONT를 사용하지 않는 것이 좋습니다. 자세한 내용은 설명 섹션을 참조하세요.기본 시스템 글꼴은 Tahoma입니다.
SYSTEM_FIXED_FONT 고정 피치(고정 폭) 시스템 글꼴입니다. 이 스톡 개체는 3.0 이전의 16비트 Windows 버전과의 호환성을 위해서만 제공됩니다.
DEFAULT_PALETTE 기본 팔레트입니다. 이 색상표는 시스템 색상표의 정적 색으로 구성됩니다.

 
 
(HGDIOBJ)  SelectObject(HDC hdc, HGDIOBJ h) : hdc에 저장된 GDI_Object의 핸들 값을 h로 바꾼다. 이전 GDI핸들 값을 반환하기 때문에 디폴트 값을 저장하기 위해 대체로 호출과 동시에 변수에 이전 GDI핸들 값을 저장한다.

hdc (DC의 핸들) DC의 핸들
h (DC에 전달할 GDI오브젝트 핸들) DC에 전달할 GDI오브젝트 핸들

SelectObject 함수(wingdi.h) - Win32 apps | Microsoft Learn

 


아래 사진은 DC및 GDI_Object의 사용법이다.

사실 GDI_Object를 다 사용하고 디폴트 값으로 되돌리지 않는다고 에러가 뜨거나 동작이 안되진 않는다. 하지만 다 쓰고 디폴트 값으로 되돌리는게 올바른 사용법이므로 습관화해야한다.


 

반응형
반응형

https://drive.google.com/file/d/1bMvEyE0OpJd5UDxcQ7aIpQMBeLpfFRVG/view?usp=drive_link

 

 

<조작법>

방향키 : 이동

스페이스 : 자리에 놓기

컨트롤 : 물리기 (되돌아가기)


 

이번엔 콘솔로 게임을 만들어보려고 많은 공부를 했다!!!!

첫 콘솔게임으로 오목게임을 만들어 보았다. 사실 미로게임도 만들긴 했는데 나중에 올려야겠다.

 

오목을 구현하는거 자체는 쉬웠는데 더블 버퍼링 기법이 너무 복잡하고 구현에 제약이 많았던게 힘들었다.

특히 원래 오른쪽 창에 턴 수와 플레이어가 어디에 뒀는지 좌표를 나타내 주려고 했는데, 더블 버퍼링은 int자료형을 출력하기가 어려워서 끙끙 싸매다가 버그가 줄줄이 터져서 그냥 포기했다.....

스택 자료구조를 클래스로 구현해볼 겸 오목을 만들어 봤는데(물리기를 구현하기 위해) 성공적으로 되서 좋은 경험이 되었다 

반응형
반응형

소수점을 쓰다보면 자리수가 너무 많아질 때가 있다. 아래와 같은 경우다.

#include <iostream>

using namespace std;

int main() {
    double a = 10, b = 3;
    
    cout << a / b;

    return 0;
}
// 출력 : 3.333333....

 

이와 같은 경우 함수를 통해 조정 할 수 있다.

 cout.precision(n); // 다음 출력부터 n자리 만큼 표기

 

이 함수를 통해 3자리까지 나타내 보자.

#include <iostream>

using namespace std;

int main() {

    double a = 10, b = 3;
   
    cout.precision(3);

    cout << a / b;

    return 0;
}
//출력 : 3.33

 

하지만 문제가 생겼다.

3.333이 나와야 하는데, 3.33이 나와버린것!!!!!

cout.precision() 함수는 소수점이 아니라 전체 숫자부의 자리수를 디폴트값으로 하고있다. 즉, 소수부의 자리만이 아닌 정수부도 포함인 것이다. 따라서 3.333이 아니라 3.33이 출력된것.

그럼 소수부만 제어하기 위해선 어떤 방법을 써야할까....

바로 cout << fixed; 를 사용하면 된다.

#include <iostream>

using namespace std;

int main() {

    double a = 10, b = 3;

    cout << fixed;
    cout.precision(3);

    cout << a / b;

    return 0;
}
//출력 : 3.333

 

cout << fixed; 는 소수부의 자리만을 가리킨다는 뜻으로 봐도 된다.

따라서 소수점이 3자리로 정상적으로 나오는 모습을 확인 할 수있다!!

fixed를 해제하기 위해선 cout.unsetf(ios::fixed); 를 사용하여 해제 할 수있다.

 

 

반응형
반응형

최근에 유니티공부를 시작하고 플래시는 이제 안만질 것 같아서 기록겸 추억겸 복습겸 만들던거 올림.

 

 

무려 5년 전에 만들었던 플래시 던파 모작이다..... 현생 살다 보니 플래시가 망했다 ㅠ

저 때 플래시로 던파 그대로 카피하는게 꿈이었는데 실력이 안돼서 포기했었다.

그러다 퇴사하고 프로그래밍 공부를 다시 해보려고 마음먹고 공부하다보니 다시금 이 모작이 생각났다.

예전에 막혔던 상당부분들의 파훼법이 막 생각이 나서 다시 만들어 보기로 했다.

2024.01.19 ~ 02.05 정도? 약 2주 정도 전력을 다해서 다시 빡세게 만들어보았다.


 

작업 환경_1

 

작업 환경_2

 

이건 몬스터 처치 시 아이템 드롭 액션(코드)중 일부

 

이건 몬스터 액션중 일부


 

어쨌든 3주간의 결과


던파를 5년 전부터 지금까지 모작해보면서 느낀 점이 참 많다. 던파가 옛날 게임인데도 불구하고 정말 심오한 부분이 많았음.

 

1. 일단 오브젝트보다 뒤에 있으면 캐릭터가 오브젝트보다 뒤로 가고, 앞에 있으면 다시 캐릭터가 오브젝트보다 앞으로 오고... 이걸 플래시로 구현하려면 "swapDepth"라는 심도를 조절해 주는 명령어를 써야 하는데, 인게임에 같은 심도 값을 가진 무비클립(객체)들이 하나라도 존재한다면 객체가 사라져 버리는 치명적인 약점이 있어서 충돌하지 않게 하려고 머리를 진짜 많이 썼다...

 

2. 그리고 2D게임인데 x(양 옆), y(점프하는 축), z(위 아래)축이 구현돼있어서Hit판정을 구현하는데 참 애먹었다. 공격할 때 HitBox에 몬스터가 닿더라도 캐릭터와 피격자의 Y축이 일정 범위 안에 닿았는지도 판정해야 하고... 몬스터가 다운 중에도 때릴 수 있는 공격이 있고, 아닌 공격이 있고.... 생각할게 참 많았다.

 

3. 플래시로 인벤토리같은 슬롯 시스템과 Drag&Drop을 처음 도전해 본 건데, 나름 문제없이 상상대로 잘 구현돼서 뿌듯했다. 특히 이거 덕분에 배열공부에 은근히 도움 된듯. (슬롯마다 [아이템 넘버, 강화 수치, 부가 효과 ... 등등])

 

4. 플래시로 공격속도를 완전하게 구현은 불가능한 줄 알았는데... 이것도 머리를 꽁꽁 싸매고 잔머리 막 굴리니까 어떻게든 구현이 됨...

 - 5년전에 만들던 공격속도 구현방식

공격모션의 프레임이 5틱마다 넘어간다고 할 때, 공격속도(1~4)의 변수 값만큼 틱을 뺌. 이 방식은 메이플처럼 공격속도를 단계식으로 구현하는 방식으론 채택할만은 한데 던파처럼 %값만큼 오르게는 못함.

 - 그래서 현재 채용한 공격속도 구현방식

공격모션의 프레임이 5틱마다 넘어간다고 할 때, 틱을 1에서 추가로 공격속도/100만큼을 더 뺀다. 공격속도가 70%라면 틱은 1이 아니라 1+0.7=1.7의 값만큼 계산된다. 초과된 틱은 다음 모션의 틱에서 추가로 뺀다. (예를들어 1.7씩 틱이 깎이다 보면 5.1이 되어서 잉여 값이 남아버리는데 다음 모션에서 이 값을 추가로 빼줘서 다음 모션은 4.9틱 후에 넘어가는 식으로) 이러면 공격속도를 %만큼 온전히 구현할 수 있다....

 

5. 그리고 은근 어려웠던 것 >> Hp, Mp_Bar와 같이 동그란 모양의 Bar는 Scale값을 조절하면 타원형이 돼서 평범한 사각형 모양의 Bar처럼 Scale로 날먹처리를 할 수가 없었다. 머리 꽁꽁 싸매다가 Layer Mask로 이미지를 덮는 방식을 채용했다. (이거 말곤 답이 없는듯?)

(네모칸에 닿은 이미지만 보임. 100 프레임으로 나눠서 Hp를 백분율로 나눴을 때, 해당 프레임으로 가도록 설정.)

 

5개만 말했지만 이 외에도 이것저것 공부가 정말 많이 되었다. 일단 안 쓰는 엔진으로 게임 만들었다고 시간낭비한 기분은 안 들었다.

아무리 플래시가 망했다곤 하지만 이런거 알아두면 나중에 다른 게임엔진에서도 잘 써먹을 수 있을듯. 

최근엔 유니티를 공부해 봤는데, 너무 쉬워서 좀 허무한 느낌도 받았다. 아니면 초반단계라 쉬운 건가?

당연한거지만 유니티가 기능면에서 압도적으로 좋다. 렉도 압도적으로 적다.

이제 플래시는 보내줄 때 인가보다...

반응형

+ Recent posts