U E D R S I H C RSS
ID
Password
Join
κΈ°νšŒλž€ νšƒλŒ€μ— μ•‰λŠ” 일이라곀 μ—†λŠ” μƒˆι³₯와 같은 것. ―C.M.

ο»Ώ

Contents

1 μ‹œμž‘ν•˜κΈ°μ „μ—
2 STATE_MANAGER ?
3 μ†ŒμŠ€
3.1 state_manager.hpp
3.2 state_manager.cpp
3.3 ν…ŒμŠ€νŠΈμš© main.cpp

1 μ‹œμž‘ν•˜κΈ°μ „μ— #

이 κ°•μ˜μš”μ•½μ„ μ΄ν•΄ν•˜κΈ° 전에 λ‹€μŒκ³Ό 같은 사항에 λŒ€ν•œ 지식이 ν•„μš”ν•©λ‹ˆλ‹€.
  • 클래슀 기초 - struct ν‚€μ›Œλ“œμ •λ„μ˜ ν™œμš©μ΄λ©΄ λ©λ‹ˆλ‹€. λ§΄λ²„λ³€μˆ˜μ™€ λ©”μ†Œλ“œ κ°œλ…μ •λ„.
  • C++ static ν‚€μ›Œλ“œμ˜ μš©λ²•
  • ν•¨μˆ˜ν¬μΈν„° - ν•¨μˆ˜ν¬μΈν„°λ₯Ό μ°Έμ‘°ν•˜μ„Έμš”.

미리 λ§μ”€λ“œλ¦¬μ§€λ§Œ, μ™„λ²½ν•œ λΌμ΄λΈŒλŸ¬λ¦¬λŠ” μ•„λ‹™λ‹ˆλ‹€. κ·Έμ € C++을 κ³΅λΆ€ν•˜λŠ”λ° μžˆμ–΄μ„œ μ˜ˆμ œμ •λ„λ‘œ μƒκ°ν•΄μ£Όμ„Έμš”. λ‚΄λΆ€ μžλ£Œκ΅¬μ‘°λ„ μ›λž˜ 효율적으둜 μ‚¬μš©ν•˜λ €λ©΄ STL의 map μ»¨ν…Œμ΄λ„ˆμ™€ 같은 μ—°κ΄€ μ»¨ν…Œμ΄λ„ˆλ₯Ό μ‚¬μš©ν•΄μ•Όν•˜μ§€λ§Œ μ—¬κΈ°μ„œλŠ” κ·Έλƒ₯ 보톡 λ°°μ—΄λ‘œ μ²˜λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€.

2 STATE_MANAGER ? #

win32api/μš΄μ„ν”Όν•˜κΈ°3 예제λ₯Ό 보면 타이틀화면과 κ²Œμž„ν™”λ©΄μ„ μ „μ—­ ν•¨μˆ˜ν¬μΈν„°λ‘œ κ΅μ²΄ν•˜λ“―μ΄ λ§Œλ“€μ—ˆλ˜ 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λ•Œ 맀번 μ „μ—­ν•¨μˆ˜ν¬μΈν„°λ³€μˆ˜λ₯Ό μ„ μ–Έν•΄μ•Όν•˜κ³  μ½”λ“œμƒμ˜ 버그가 일어날 ν™•λ₯ λ„ λ†’μœΌλ―€λ‘œ κ°„λ‹¨ν•œ 클래슀둜 μ •λ¦¬ν•΄λ³΄μž... ν•΄μ„œ λ§Œλ“€μ–΄μ§„ 것이 STATE_MANAGERμž…λ‹ˆλ‹€.

State_Manager ν΄λž˜μŠ€λŠ” λ‹€μŒκ³Ό 같은 νŠΉμ§•μ„ κ°€μ Έμ•Όλ§Œ(?) ν•©λ‹ˆλ‹€.
  • 싱글톀일 것 - ν—€λ”ν™”μΌλ§Œ include되면 마치 μ–΄λ””μ„œλ“  μΈμŠ€ν„΄μŠ€λ₯Ό μ„ μ–Έν•˜μ§€ μ•Šκ³  λΆˆλŸ¬μ“Έ 수 μžˆμ–΄μ•Όν•©λ‹ˆλ‹€.
  • ν•¨μˆ˜ν¬μΈν„°μ™€ μƒνƒœ μ—΄κ±°ν˜•λ³€μˆ˜λ₯Ό μ—°κ΄€μ‹œν‚¬ 것 - κ·Έλž˜μ„œ μƒνƒœλ₯Ό λ³€κ²½ν•  λ•Œμ—λŠ” μ—΄κ±°ν˜• κ°’λ§Œ κ΅μ²΄ν•˜λ©΄ λ˜λ„λ‘ κ΅¬ν˜„ν•©λ‹ˆλ‹€.

μ—¬κΈ°μ„œ μ‹±κΈ€ν†€μœΌλ‘œ κ΅¬ν˜„ν•˜μ§€ μ•ŠμœΌλ©΄, ν•΄λ‹Ή 클래슀의 μ „μ—­ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λ₯Ό μ„ μ–Έν•œλ‹€μŒ 맀번 κ·Έ λ³€μˆ˜λ₯Ό extern μ„ μ–Έν•˜μ—¬ κ°€μ Έμ™€μ•Όν•˜λŠ” λ²ˆκ±°λ‘œμ›€μ΄ μžˆμŠ΅λ‹ˆλ‹€. 싱글톀은 "ν”„λ‘œκ·Έλž¨ 전체에 걸쳐 ν•˜λ‚˜λ°–μ— μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” 객체"λ₯Ό λ§ν•˜λ―€λ‘œ static λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ 이λ₯Ό μ–»μ–΄λ‚΄λŠ” μ‹œμ μ—μ„œ μžλ™μœΌλ‘œ μƒμ„±ν•˜κ³  이에 λŒ€ν•œ 포인터λ₯Ό μ–»μ–΄μ˜€κ²Œ ν–ˆμŠ΅λ‹ˆλ‹€.

state_manager.hpp의 ν•˜λ‹¨μ— 보면 STATEMANAGERλΌλŠ” 맀크둜λ₯Ό μ„ μ–Έν•΄λ†“μ•˜λŠ”λ°, μ΄λŠ” μ†ŒμŠ€μ½”λ“œκ°€ κΈΈμ–΄μ§€λŠ” 것을 λ°©μ§€ν•˜κΈ° μœ„ν•΄μ„œ μž…λ‹ˆλ‹€.

3 μ†ŒμŠ€ #

3.1 state_manager.hpp #

#ifndef __STATE_MANAGER_HPP__
#define __STATE_MANAGER_HPP__

#include <windows.h>

#define MAX_STATE_NUM 255
#define WM_ENTERSTATE (0x7FFF - 1)
#define WM_LEAVESTATE (0x7FFF - 2)

enum StateType { stTitle, stGame, stHighScore, stGameOver };

struct State {
    StateType type;
    WNDPROC winproc;
}; 

struct State_Manager {
    State m_state[MAX_STATE_NUM];
    int m_statenum;
    StateType m_current_type;
    WNDPROC m_current_proc;
    
    // μƒˆλ‘œμš΄ μƒνƒœλ₯Ό μ„€μ •
    bool SetState(StateType type_, WNDPROC ptrWinProc);
    // ν˜„μž¬ μƒνƒœλ₯Ό λ³€κ²½ 
    bool SwitchState(StateType type_, HWND hwnd_);
    // ν˜„μž¬ μƒνƒœμ— λŒ€μ‘ν•˜λŠ” μœˆλ„μš° ν”„λ‘œμ‹œμ Έλ₯Ό μ‹€ν–‰ 
    LRESULT ExecuteWinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
    
    // 정적 λ©”μ†Œλ“œ. State_Manager μ „μ—­ 싱글톀 객체 포인터λ₯Ό λ°˜ν™˜ 
    static State_Manager *instance();
};

#define STATEMANAGER (State_Manager::instance())

#endif

3.2 state_manager.cpp #

#include "State_Manager.hpp"

static State_Manager *g_instance = NULL;

State_Manager *State_Manager::instance() {
    // ν˜„μž¬ State_Managerλ₯Ό 처음 ν˜ΈμΆœν•œ 것이라면 μƒˆλ‘œ μΈμŠ€ν„΄μŠ€λ₯Ό 생성 
    if (!g_instance) { 
        g_instance = new State_Manager();
        g_instance->m_statenum = 0;
        g_instance->m_current_proc = NULL;
    }
    return g_instance;
}

bool State_Manager::SetState(StateType type_, const WNDPROC ptrWinProc) {
    State *pState = NULL;
    for (int i = 0; i < this->m_statenum; i++) {
        if (this->m_state[i].type == type_) {
            pState = &(this->m_state[i]);
            break;
        }
    }
    if (!pState) {
        this->m_state[this->m_statenum].type = this->m_current_type = type_;
        this->m_state[this->m_statenum].winproc = this->m_current_proc = ptrWinProc;
        this->m_statenum++;
        return true;
    }
    else {
        this->m_current_type = type_;
        pState->winproc = this->m_current_proc = ptrWinProc;
        return false;
    }
}

bool State_Manager::SwitchState(StateType type_, HWND hwnd_) {
    State *pState = NULL;
    for (int i = 0; i < this->m_statenum; i++) {
        if (this->m_state[i].type == type_) {
            pState = &(this->m_state[i]);
            break;
        }
    }
    if (!pState) return false;
    else {
        SendMessage(hwnd_, WM_LEAVESTATE, (WPARAM) this->m_current_type, (LPARAM) NULL);
        this->m_current_type = pState->type;
        this->m_current_proc = pState->winproc;
        SendMessage(hwnd_, WM_ENTERSTATE, (WPARAM) this->m_current_type, (LPARAM) NULL);
        return true;
    }
}

LRESULT State_Manager::ExecuteWinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    if (this->m_current_proc != NULL) {
        WNDPROC tmpProc = this->m_current_proc;
        return tmpProc(hwnd, message, wParam, lParam);
    }
    else return DefWindowProc(hwnd, message, wParam, lParam);
}

3.3 ν…ŒμŠ€νŠΈμš© main.cpp #

κ°„λ‹¨νžˆ ν˜„μž¬ μƒνƒœλ₯Ό λ³€κ²½ν•΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€. 각 state μ§„μž…κ³Ό ν•΄μ œμ‹œμ— λ©”μ„Έμ§€λ°•μŠ€λ₯Ό λ„μ›€μœΌλ‘œμ„œ 흐름을 μ•Œ 수 있게 ν–ˆμŠ΅λ‹ˆλ‹€.
#include <windows.h>
#include "state_manager.hpp"

LRESULT CALLBACK CoreWinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    return STATEMANAGER->ExecuteWinProc(hwnd, message, wParam, lParam);
}

LRESULT CALLBACK TitleWinProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK GameWinProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

/* μœˆλ„μš° 클래슀λͺ…을 μ •ν•©λ‹ˆλ‹€ */
char szClassName[ ] = "State λ³€ν™˜λ°λͺ¨";

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nCmdShow)

{
    HWND hwnd;               /* μœˆλ„μš° ν•Έλ“€ */
    MSG messages;            /* μœˆλ„μš° λ©”μ„Έμ§€λ₯Ό μž„μ‹œμ μœΌλ‘œ λ‹΄μ•„λ‘˜ λ³€μˆ˜. λ©”μ„Έμ§€ λ£¨ν”„μ—μ„œ μ‚¬μš©. */
    WNDCLASSEX wincl;        /* μœˆλ„μš°ν΄λž˜μŠ€ 데이타 ꡬ쑰체 */

    /* μœˆλ„μš° 클래슀 데이타 ꡬ쑰체에 값을 μ±„μš΄λ‹€ */
    wincl.hInstance = hThisInstance;       /* ν˜„μž¬ μΈμŠ€ν„΄μŠ€ ν•Έλ“€κ°’ μ§€μ • */
    wincl.lpszClassName = szClassName;     /* 클래슀 이름. 보톡 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ 이름을 μ§€μ •. */
    wincl.lpfnWndProc = CoreWinProc;   /* μœˆλ„μš° ν”„λ‘œμ‹œμ Έ ν•¨μˆ˜ 포인터 */
    wincl.style = CS_DBLCLKS;              /* 더블클릭 이벀트λ₯Ό λ°›μ•„λ“€μž…λ‹ˆλ‹€ */
    wincl.cbSize = sizeof (WNDCLASSEX);    /* 이 ꡬ쑰체 크기 μ„€μ •. (λ°˜λ“œμ‹œ 해야함) */

    /* 마우슀 μ»€μ„œ μ΄λ―Έμ§€λ‘œμ„œ κΈ°λ³Έ μ‹œμŠ€ν…œ μ»€μ„œλ₯Ό μ„€μ •ν•©λ‹ˆλ‹€ */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* 메뉴섀정 μ•ˆν•¨ */
    wincl.cbClsExtra = 0;                      /* μœˆλ„μš° ν΄λž˜μŠ€μ— μ²¨λΆ€λœ 데이타 μ—†μŒ. λŒ€λΆ€λΆ„μ˜ 경우 0 */
    wincl.cbWndExtra = 0;                      /* 뢀가적인 μœˆλ„μš° μΈμŠ€ν„΄μŠ€ λ˜λŠ” ꡬ쑰체 μ—†μŒ. λŒ€λΆ€λΆ„μ˜ 경우 0 */
    /* μœˆλ„μš° κΈ°λ³Έ 배경색상을 μ§€μ •. κΈ°λ³Έ ν…Œλ§ˆ μƒ‰μƒμœΌλ‘œ μ μš©ν•©λ‹ˆλ‹€. */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* μœˆλ„μš° 클래슀λ₯Ό λ“±λ‘ν•˜κ³  μ‹€νŒ¨ν•  κ²½μš°μ—λŠ” ν”„λ‘œκ·Έλž¨μ„ μ’…λ£Œν•©λ‹ˆλ‹€ */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* ν΄λž˜μŠ€κ°€ λ“±λ‘λ˜μ—ˆμœΌλ©΄ 이제 μœˆλ„μš°λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€! */
    hwnd = CreateWindowEx (
           0,                   /* μœˆλ„μš° ν™•μž₯ μ˜΅μ…˜ */
           szClassName,         /* ν΄λž˜μŠ€μ΄λ¦„ */
           "ν…ŒμŠ€νŠΈμ–΄ν”Œλ¦¬μΌ€μ΄μ…˜",       /* μœˆλ„μš° 타이틀 바에 적힐 λ¬Έμžμ—΄ */
           WS_OVERLAPPEDWINDOW, /* κΈ°λ³Έ μœˆλ„μš° ν˜•νƒœ */
           CW_USEDEFAULT,       /* μœˆλ„μš° μœ„μΉ˜ x μ’Œν‘œ */
           CW_USEDEFAULT,       /* μœˆλ„μš° μœ„μΉ˜ y μ’Œν‘œ */
           544,                 /* μœˆλ„μš° 폭 */
           375,                 /* μœˆλ„μš° 높이 */
           HWND_DESKTOP,        /* μœˆλ„μš°λŠ” λ°μŠ€ν¬νƒ‘μ— λŒ€ν•΄ μžμ‹μœˆλ„μš°λ‘œμ„œ 생성 */
           NULL,                /* λ©”λ‰΄μ—†μŒ */
           hThisInstance,       /* ν”„λ‘œκ·Έλž¨ μΈμŠ€ν„΄μŠ€ ν•Έλ“€ */
           NULL                 /* μœˆλ„μš° μƒμ„±μ‹œ μ‚¬μš©ν•  μΆ”κ°€ 데이타 μ—†μŒ */
           );

    /* 화면에 μœˆλ„μš°κ°€ 보이도둝 ν•œλ‹€. nCmdShowλŠ” WinMain()μ—μ„œ 4번째 λ§€κ°œλ³€μˆ˜μž„. */
    ShowWindow (hwnd, nCmdShow);

    /* 각 state에 λŒ€μ‘ν•˜λŠ” μœˆλ„μš°ν”„λ‘œμ‹œμ Έ 포인터λ₯Ό μ„€μ • */ 
    STATEMANAGER->SetState(stGame, GameWinProc);
    STATEMANAGER->SetState(stTitle, TitleWinProc); // 이 stateκ°€ 처음 stateκ°€ λœλ‹€ 

    /* 메세지루프 μ‹€ν–‰. GetMessage()κ°€ 0을 λ°˜ν™˜ν•  λ•ŒκΉŒμ§€ 계속 루프λ₯Ό λ°˜λ³΅ν•©λ‹ˆλ‹€. */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* 가상 ν‚€ λ©”μ„Έμ§€(WM_KEYDOWN)을 문자 λ©”μ„Έμ œ(WM_CHAR)둜 λ²ˆμ—­ν•©λ‹ˆλ‹€ */
        TranslateMessage(&messages);
        /* μœˆλ„μš° ν”„λ‘œμ‹œμ Έλ‘œ λ©”μ„Έμ§€λ₯Ό λ³΄λƒ…λ‹ˆλ‹€ */
        DispatchMessage(&messages);
    }

    /* ν”„λ‘œκ·Έλž¨ λ°˜ν™˜κ°’μ€ 0μž…λ‹ˆλ‹€. μ΄λŠ” PostQuitMessage() ν•¨μˆ˜μ—μ„œ λ§€κ°œλ³€μˆ˜λ‘œ λ„˜κ²Όλ˜ 값이 λ„˜μ–΄μ˜€κ²Œ λ©λ‹ˆλ‹€. (μ•„λž˜ μ°Έμ‘°) */
    return messages.wParam;
}

LRESULT CALLBACK GameWinProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_ENTERSTATE:
            MessageBox(hwnd, "GameStateμ§„μž…","Game",MB_OK);
            break;
        case WM_LEAVESTATE:
            MessageBox(hwnd, "GameStateμ’…λ£Œ","Game",MB_OK);
            break;
        case WM_LBUTTONDOWN:
            STATEMANAGER->SwitchState(stTitle, hwnd);
            InvalidateRect(hwnd, NULL, TRUE);
            break;
        case WM_PAINT :
            {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            TextOut(hdc, 10, 10, "Game!", 5); 
            EndPaint(hwnd, &ps);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

LRESULT CALLBACK TitleWinProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                  /* handle the messages */
    {
        case WM_ENTERSTATE:
            MessageBox(hwnd, "TitleStateμ§„μž…","Title",MB_OK);
            break;
        case WM_LEAVESTATE:
            MessageBox(hwnd, "TitleStateμ’…λ£Œ","Title",MB_OK);
            break;
        case WM_LBUTTONDOWN:
            STATEMANAGER->SwitchState(stGame, hwnd);
            InvalidateRect(hwnd, NULL, TRUE);
            break;
        case WM_PAINT :
            {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            TextOut(hdc, 10, 10, "타이틀!", 7); 
            EndPaint(hwnd, &ps);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2010-10-28 12:42:54
Processing time 0.5594 sec