[TIL] 24-01-23

Lev·2024년 1월 24일
0

📓TIL Archive

목록 보기
28/33

stl

string_view

// 마치 문자열만 전문적으로 처리하는 포인터와 같다.

#include <iostream>
#include <vector>
#include <string>
#include <string_view>

class MyString
{
public:
    static char SSO[25];
    /*
    Small/Short String Optimization
    
    25글자 이하는 동적할당이 아니라 전역을 통해 해결하기도 한다.
    하지만 그럼에도 string_view가 빠르다(?).
    */

    char* Test;

    MyString(const char* _Ptr)
    {
        Test = new char[strlen(_Ptr)];  // 동적할당
    }
};

class MyString_View
{
public:
    const char* Test;
		/*
		string_view는 포인터 역할일 뿐, 실제 데이터를 갖고 있지는 않다.
		게다가 const나 마찬가지기 때문에 내부의 내용을 변경하는 것도 불가하다.
		*/

    MyString_View(const char* _Ptr)
    {
        Test = _Ptr;    // 얕은 복사
    }
};

void FunctionString(const MyString& _Value)
{

}

void FunctionView(MyString_View Name)
{
    /*
		Name.data();
		.data()의 역할...?
		*/
}

int main()
{
    FunctionString("AgjksflhgjsklhgsdfjkAAAA");
    /*
    MyString NewString = "AgjksflhgjsklhgsdfjkAAAA";
    FunctionString(NewString);

    실제론 위와 같이 새로운 메모리에 할당이 발생한다.
    함수가 종료되면 할당된 메모리의 삭제도 필요하다.

    따라서, const std::string& 으로 받는 것보다, string_view 로 받으면
    해당 값의 위치를 반환받을 수 있어 연산이 줄어들고 빠르다.
    */
}

WinAPI

#include "framework.h"
#include "WindowsProject1.h"

#define MAX_LOADSTRING 100

// 전역 변수 : 
// [HINSTANCE = 프로그램 핸들]
HINSTANCE hInst;                        // 현재 인스턴스
WCHAR szTitle[MAX_LOADSTRING];          // 제목 표시줄 텍스트
WCHAR szWindowClass[MAX_LOADSTRING];    // 기본 창 클래스 이름

bool Live = true;

// 함수 선언 :
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 wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    // 사용하지 않은 인자 사용
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // 전역 문자열 초기화
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // 애플리케이션 초기화
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = 0; // 단축키 (사용X)

    MSG msg;

    // 기본 메시지 루프
    while (Live)
    // while (GetMessage(&msg, nullptr, 0, 0))
    {
        /*
        GetMessage()
        - 메세지가 없으면 프로그램을 정지시키고, 메세지가 올 때까지 대기한다.
    
        PeekMesaage()
        - 메세지가 없으면 return

            PM_REMOVE
            - 메세지 버퍼 삭제
            - 한번 실행되면 누적된 메세지를 삭제하여 마지막에 전해진 메세지만 실행한다

            PM_NOREMOVE
            - 윈도우 메세지를 지속적으로 삭제하지 않기 때문에 계속 쌓인다
            - 너무 많이 쌓이게 되면 윈도우가 정지한 것처럼 보일 수 있다
        */
        if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
        // if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        // 게임에서는 단축키를 사용하지 않기 때문에 단축키를 처리하는 구문은 필요 없다.
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        // (TODO)

        /*
        (Tip?) 만약 인자를 이해할 수 없다면, 대부분의 함수에서
        0을 넣으면 디폴트 옵션으로 실행시켜준다(...).
        */
    }

    return (int) msg.wParam;
}

// 창 클래스 등록 : 
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    /*
    앞이나 뒤에 W 또는 A가 붙어있는 함수
	- A => 멀티바이트 함수
	- W => 와이드바이트 함수

    따라서 이 경우, wcex.lpszClassName을 직접 입력해주고 싶다면 "" 앞에 L을 붙여야 한다.
    */
    WNDCLASSEXW 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_WINDOWSPROJECT1));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = nullptr;  // 상단메뉴 (사용X)
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    // 윈도우 창 클래스 만들기
    return RegisterClassExW(&wcex);
}

// 인스턴스 핸들 저장, 주 창 만들기 :
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   // 인스턴스 핸들
   hInst = hInstance;

   // 윈도우 창 생성
   // [HWND = 윈도우 핸들]
   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
   /*
   szTitle => const char* 형
   
   만약 const std::string& _Title 을 인자로 넣고 싶다면...
   const std::string& 은 내부에 std::vector<char> 이 존재한다고 생각하면 된다.
   &_Title[0]
   _Title.c_str()

	...혹은 조금 다르지만 std::string_view _Title 을 사용할 수 있다!
	_Title.data()
   */

   if (!hWnd)
   {
      return FALSE;
   }

   // 윈도우 창 띄우기
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

// 주 창 메시지 처리 : 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    /*
    // 애플리케이션 메뉴 처리
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 메뉴 선택을 구문 분석
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;

    게임에서는 상단 메뉴를 사용하지 않기 때문에 삭제해도 된다.
    */

    // 주 창 그리기
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // [HDC = 윈도우에 그림을 그릴 수 있는 권한]

            Rectangle(hdc, 100, 100, 200, 200); // (왼쪽 위, 오른쪽 아래)

            EndPaint(hWnd, &ps);
        }
        break;
    // 종료 메세지 게시하고 반환
    case WM_DESTROY:
        PostQuitMessage(0);
        /*
        GetMessage()는 평소에 1을 return한다.
        PostQuitMessage()가 호출되면 GetMessage()가 0을 호출해서 while문에서 탈출한다.
        */
        Live = false;
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        /*
        사용자가 할일을 정의하지 않은 메세지들은 윈도우가 디폴트로 처리하는 방식으로 실행시켜준다.
        WM_SETFOCUS, WM_KILLFOCUS, ... 등 여러 종류의 메세지가 존재한다.
        */
    }
    return 0;
}

// 정보 대화 상자 메시지 처리기 :
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) == 2)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

/*
HINSTANCE => 프로그램 핸들
e.g. 내 프로그램이 4800번일 경우
     윈도우에게 4800번 프로그램이 창 하나 만들어달라고 전달
     윈도우에게 4800번 프로그램이 키보드 연결을 끊고 싶다고 전달

HWND => 윈도우 핸들
e.g. 윈도우에게 4800번 프로그램의 530번 창 크기를 바꾸고 싶다고 전달

HDC => 윈도우에 그림을 그릴 수 있는 권한
e.g. 윈도우에게 4800번 프로그램의 530번 창의 230번 그림권한에서 사각형을 그리고 싶다고 전달

HMENU, HCURSOR, HICON, ... 등 여러 권한이 존재한다.
*/

Kirby's Adventure w/ WinAPI

공통 설정

  • 속성
    • 모든 구성, 모든 플랫폼 → 구성 속성
      • 일반 → 출력 디렉터리 → $(SolutionDir)Bin\$(Platform)\$(Configuration)\
      • 일반 → 중간 디렉터리 → $(SolutionDir)Bin\$(Platform)\$(Configuration)\$(ProjectName)\

        Q) bin을 따로 설정해주는 이유?
        출력된 요소들을 한곳으로 모으기 위해

      • 일반 → 구성 형식 → 정적 라이브러리(.lib)
      • 일반 → C++ 언어 표준 → ISO C++20 표준(/std:c++ 20)
      • 고급 → 문자 집합 → 멀티바이트 문자 집합 사용
      • VC++ 디렉터리 → 포함 디렉터리 → ..\; 추가
      • C/C++ → 일반 → 경고를 오류로 처리 → 예(/WX)
  • 참조 추가
    • 상위 level 프로젝트 전부 추가

구조

Level0 : EngineBase

  • 윈도우 프로그래밍 시 언제 어디서나 쓰일 코드
  • 디버깅, 스트링, …

Level1 : EnginePlatform

  • 운영체제의 영향을 크게 받는 클래스
  • window, 사운드, …

Level2 : EngineCore

  • 게임엔진이 처리해야 할 내용
  • 오브젝트 구조, 렌더링 구조, 삭제 구조, …

Level3 : Contents

  • 구현하고자 하는 게임의 컨텐츠

Level4 : App

  • 속성
    • 모든 구성, 모든 플랫폼 → 구성 속성
      • 일반 → 구성 형식 → 애플리케이션(.exe)
      • 링커 → 시스템 → 하위 시스템 → 창(/SUBSYSTEM:WINDOWS)
profile
⋆꙳⊹⋰ 𓇼⋆ 𝑻𝑰𝑳 𝑨𝑹𝑪𝑯𝑰𝑽𝑬 ⸝·⸝⋆꙳⊹⋰

0개의 댓글