디시인사이드 갤러리

갤러리 이슈박스, 최근방문 갤러리

갤러리 본문 영역

적분시리즈: 리듬게임을 만들수 있을까? 9. 키보드/마우스 처리

∫ 2t dt=t²+c갤로그로 이동합니다. 2009.07.20 22:55:32
조회 149 추천 0 댓글 3




한동안 코딩에 열중하느라 강좌가 늦어졌다. 그 사이에 많은 부분을 뜯어고쳤으니, 어디 어디가 바뀌었는지부터 설명하겠다.

class MState
{
protected:
    GGame* const m_pGame;
public:
    MState(GGame* pGame) : m_pGame(pGame){}
    virtual ~MState(){};
    virtual void OnProc()=0;
    virtual void OnPostProc()=0;
    virtual void OnDraw()=0;
    virtual void OnLost()=0;
    virtual void ()=0;
    virtual void (int KeyCode)=0;
    virtual void (int KeyCode)=0;
    virtual void OnDrawSkip()=0;
};

가장 큰 변화라고 할 수 있는 것은 MState가 이벤트호출시 매번 받던 Game* pGame인자를 받지 않게했다. 그 대신아예 멤버변수로 Game* const m_pGame을 선언했다. 그리고 생성자에서 Game* pGame을 받아서 m_pGame에저장한다.
이에 따라서 MState를 상속받는 MPlayGame클래스에서도 마찬가지의 변화가 일어났다.

또한 위 코드에서 볼 수 있듯이 전체적인 이벤트처리가 다양해졌다.
키보드이벤트 과 이 추가되었고
그리기가 생략될 경우에 OnDraw대신에 OnDrawSkip이 호출된다.

GGame클래스에서도 변화가 일어났다.

class GGame
{
    friend class MState;
protected:
    ......
    bool m_activated;
    BYTE m_keystate[256];
    bool m_drawskip;
    void _getkeystate();
    void _getcursorpos();
    void OnDraw();
    void (int keycode);
    void (int keycode);
    void OnDrawSkip();
public:
    enum{
        KS_Pressed=1,
        KS_Down=2,
        KS_Up=4,
    };/*
      GetKeyState함수의 리턴값으로 사용된다.
      */
    POINT m_cursorpos;
    ......
    GRET SetDrawSkip(bool skip);
    bool GetDrawSkip();
    int GetKeyState(BYTE keycode);
};

바뀐 부분만 살펴보자면 먼저 MState클래스가 friend클래스로 선언되어서 MState클래스에서 GGame의 protected,private에도 접근할수 있게 하였다.
그리고 OnRender를 OnDraw로 이름을 바꿔서 통일시켰다. 또 ,,OnDrawSkip이추가되었고, ,을 처리할수 있게 m_keystate[256]변수가 추가되고, 열거형KS_Pressed, KS_Down, KS_Up이 추가되었다.
OnDrawSkip을 처리할 수 있게 m_drawskip변수도 추가되었다.
현재 키보드의 상태를 알아오는 _getkeystate함수와 마우스좌표를 알아오는 _getcursorpos함수가 추가되었다.
마지막으로 현재 키상태를 조사하는 GetKeyState함수가 추가되었다.

GGame::GGame() : ...... m_drawskip(false)
{
    ......
    memset(m_keystate, 0, sizeof(m_keystate));
}

생성자에서 m_drawskip를 false초기화하고, m_keystate를 0으로 초기화했다.

void GGame::_getkeystate()
{
    for(int i=0;i<256;i++)
    {
        if(m_keystate[i] & KS_Pressed)
        {
            if(GetAsyncKeyState(i))
            {
                m_keystate[i]=KS_Pressed;
            }
            else
            {
                m_keystate[i]=KS_Up;
            }
        }
        else
        {
            if(GetAsyncKeyState(i))
            {
                m_keystate[i]=KS_Down | KS_Pressed;
            }
            else
            {
                m_keystate[i]=0;
            }
        }
    }
}

현재 키보드상태를 조사해오는 함수이다. 함수 설명에 앞서서 WinApi 중 GetAsyncKeyState함수와 GetKeyState함수에 대해서 간략히 설명하겠다.
둘 다 키보드 상태를 조사해오는 함수지만, GetKeyState는 큐에 쌓여있는 키보드상태를 가져오고, GetAsyncKeyState는 큐는 무시하고, 현재 키보드 상태를 가져온다.
보통 때에는 큰 차이가 없을지 몰라도, 컴퓨터가 버벅거리거나해서 키가 제때에 처리되지 않고 큐에 쌓이게 되면, GetKeyState함수는 이전의 키 상태를 가져와버리는 문제가 있다.
따라서 키보드처리가 중요한 게임에서는 GetAsyncKeyState함수를 쓰는게 바람직하다.

처음에 m_keystate를 256개의 배열로 선언한 이유는 키코드 0~255번 사이에 키보드의 모든 키가 할당되기 때문이다.즉, 그 256개만 검사하면 모든 키를 검사한것이라는 얘기이다. m_keystate에 현재 키의 상태, 눌려졌는가, 떼어졌는가의모든 정보를 담기 위해서 KS_Pressed=1, KS_Down=2, KS_Up=4라고 정의했다.
KS_Pressed는 현재 키가 눌려있을때 셋되고, KS_Down은 막 키가 눌러졌을때, KS_Up은 막 키가 떼어졌을때 셋된다.

(m_keystate[i] & KS_Pressed)를 하여 1이 나오면 키가 눌려있는 것이고, 0이 나오면 키가 눌리지 않은 것이다.
GetAsyncKeyState가 0이 아닌값을 리턴하면 키가 놀려져있는 것이고, 0을 리턴하면 키가 눌려지지 않은것이다.
각각의 경우를 따져 4가지로 분기하여 KS_Pressed, KS_Down, KS_Up을 설정했다.

void GGame::_getcursorpos()
{
    GetCursorPos(&m_cursorpos);
    if(!m_dev.fullscreen)
    {
        ScreenToClient(m_dev.hwnd, &m_cursorpos);
    }
}

이 함수는 현재 마우스커서의 위치를 알아온다. 그러기 위해서 WinApi함수인 GetCursorPos를 호출하는데, 이 함수는 모니터 좌상단을 (0,0)으로 보고 화면상의 커서의 위치를 알아낸다.
따라서 전체화면 모드가 아닌 경우에는 화면상의 위치가 아닌 작업영역상의 위치를 알아와야 하므로,
ScreenToClient함수를 사용하여 화면상의 좌표를 현재 윈도우의 작업영역상의 좌표로 변환해준다.

GRET GGame::SetDrawSkip(bool skip)
{
    m_drawskip=skip;
    return 0;
}

bool GGame::GetDrawSkip()
{
    return m_drawskip;
}

그리기 생략여부를 설정하고 알아오는 함수이다. 설명할게 없을 정도로 간단하다.

void GGame::OnCreate()
{
    GStrings strs;
    strs.Load(&DataInFile(L"textures.str"));
    for(size_t i=0;i<strs.size();i++)
    {
        LoadTexture(strs[i].c_str());
    }
    LoadSprites(&DataInFile(L"sprites.dat"));
    SetState(new MPlayGame(this));
}

void GGame::OnProc()
{
    if(m_pstate)m_pstate->OnProc();
}


void GGame::OnDraw()
{
    if(m_pstate)m_pstate->OnDraw();
}


void GGame::OnPostProc()
{
    if(m_pstate)m_pstate->OnPostProc();
}

void GGame::OnLost()
{
    if(m_pstate)m_pstate->OnLost();
}


void GGame::()
{
    if(m_pstate)m_pstate->();
}


void GGame::(int keycode)
{
    if(m_pstate)m_pstate->(keycode);
}


void GGame::(int keycode)
{
    if(m_pstate)m_pstate->(keycode);
}


void GGame::OnDrawSkip()
{
    if(m_pstate)m_pstate->OnDrawSkip();
}

이벤트 처리부분이다. 특별한거는 없고, 주목해야할 부분은 OnCreate에서 new MPlayGame을 할때 MPlayGame의생성자가 GGame*pGame을 필요하게 바뀌었으므로 (MState의 생성자가 바뀐것을 기억하라.) this포인터를 넘겨주었다.

GRET GGame::MessageLoop()
{
    bool islost=false;
    MSG msg;
    if(m_pd3dd)OnCreate();
    while(1)
    {
        if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
        {
            if(msg.message==WM_QUIT)return 0;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            if(m_pnewstate)
            {
                if(m_pstate)delete m_pstate;
                m_pstate=m_pnewstate;
                m_pnewstate=NULL;
            }
            _getkeystate();
            _getcursorpos();
            OnProc();
            for(int i=0;i<256;i++)
            {
                if(m_keystate[i] & KS_Down) (i);
                if(m_keystate[i] & KS_Up) (i);
            }
            if(islost)
            {
                if((!m_dev.fullscreen || m_activated) && Reset3DDevice()==0)
                {
                    islost=false;
                    m_pspr->Device();
                    ();
                }
            }
            else if(m_drawskip)
            {
                OnDrawSkip();
            }
            else
            {
                m_pd3dd->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(64,128,192), 1.f, 0);
                if( SUCCEEDED(m_pd3dd->BeginScene()) )
                {
                    m_pspr->Begin(D3DXSPRITE_ALPHABLEND);
                    OnDraw();
                    m_pspr->End();
                    m_pd3dd->EndScene();
                    if(m_pd3dd->Present(NULL, NULL, NULL, NULL)==D3DERR_DEVICELOST)
                    {
                        islost=true;
                        m_pspr->OnLostDevice();
                        OnLost();
                    }
                }
            }
            OnPostProc();
            m_drawskip=false;
        }
    }
    return 0;
}

메시지루프부분이 좀 바뀌었다. OnProc을 호출하기 바로전에 _getkeystate, _getcursorpos를 호출하여키보드상태, 커서좌표를 얻어온다. 그리고 OnProc이 호출된 후에 m_keystate에서 KS_Down이 셋된 것은이벤트를 호출해주고, KS_Up이 셋된 것은 이벤트를 호출해준다.
그리고 m_drawskip이 참일 경우에는 그리기부분에 돌입하지 않고 OnDrawSkip을 호출하고 m_drawskip이 거짓일때 그리기부분에 돌입한다. 그리고 m_drawskip은 매 프레임 마지막부분에서 거짓으로 다시 설정한다.
        

추천 비추천

0

고정닉 0

0

댓글 영역

전체 댓글 0
본문 보기

하단 갤러리 리스트 영역

왼쪽 컨텐츠 영역

갤러리 리스트 영역

갤러리 리스트
번호 제목 글쓴이 작성일 조회 추천
설문 이번주 설문은 탈모 걱정 없어 보이는 머리숱 금수저 스타는? 운영자 25/07/14 - -
AD 휴대폰 액세서리 SALE 운영자 25/07/15 - -
273163 형들 보통 자바스크립트 600줄 짜리 코드 짜는데 얼마나걸려요?? [2] 123(218.236) 11.09.18 107 0
273161 C++ 개병쉰같다 진짜 왜 병쉬같이 쳐 나눈게 많을까? [8] lol(110.174) 11.09.18 207 0
273160 IT 관련 직업중에 제일 스트레스 안쌓이는것은? [5] 파인애플사갤로그로 이동합니다. 11.09.18 184 0
273159 지하철밀인대 [1] Unia갤로그로 이동합니다. 11.09.18 81 0
273157 컴터 관련된 갤을 전부다 합치는거다. [4] 파인애플사갤로그로 이동합니다. 11.09.18 93 0
273156 궁금한게 잇는데 빈프로젝트 꼭 눌러야해? [2] 힙꼬맹갤로그로 이동합니다. 11.09.18 72 0
273155 찔질찌질 [1] Adelposs갤로그로 이동합니다. 11.09.18 48 0
273154 횽들 c랑 자바랑 버블 정렬 시켰는데 원래 코딩에서 차이 나는거임? [4] aaaa(58.235) 11.09.18 72 0
273152 가가라이브 보안코드 해시충돌을 시켰는데 [5] 나 프갤할레갤로그로 이동합니다. 11.09.18 94 0
273151 요즘 펌웨어하면 어떨까 [1] ㅁㄴㅇ(116.42) 11.09.18 103 0
273150 프로그래밍쪽으로 나가면 답이없나요? [1] 프로그래밍쪽(121.182) 11.09.18 89 0
273149 안드로이드에서도 Unia갤로그로 이동합니다. 11.09.18 33 0
273147 요즘 가요 중 그나마 들을 만한 곡 [3] 거칠게갤로그로 이동합니다. 11.09.18 91 0
273146 꿀레얌 [1] Adelposs갤로그로 이동합니다. 11.09.18 61 0
273145 삼성 태블릿 VS 소니 태블릿 비교 동영상 [1] 분당살람갤로그로 이동합니다. 11.09.18 71 0
273144 버츄어 박스 안 깔린다. [2] 로하로하알로하갤로그로 이동합니다. 11.09.18 38 0
273143 웹디자인 어케 접근해야 함? [7] (61.255) 11.09.18 132 0
273141 안드로이드 개발할려면... [6] 봉제인형포포리갤로그로 이동합니다. 11.09.18 143 0
273140 예전에 제온 존나 비싸지 않았냐? ㅋㅋ [3] 분당살람갤로그로 이동합니다. 11.09.18 69 0
273139 제대하고 오니까 프갤러 다 어디갔냐? [10] ㅇㅍ(175.113) 11.09.18 110 0
273137 역시 게입이 프로그래밍의 꽃이구나 ㅡㅜ [2] 거칠게갤로그로 이동합니다. 11.09.18 158 0
273136 후 기계어배워야지 [1] ♥♡정수정♡♥갤로그로 이동합니다. 11.09.18 60 0
273135 웹 앱이면 다운 받을 필요가 없는거야 ㅡㅡ?? [2] 거칠게갤로그로 이동합니다. 11.09.18 79 0
273134 고1 질문좀 할게요 [2] afaf(119.69) 11.09.18 52 0
273133 웹앱이 뜬다고 언플하는데 이거 언플 같다 [1] 거칠게갤로그로 이동합니다. 11.09.18 81 0
273132 서울에 있는 횽아들 질문있어 monoless갤로그로 이동합니다. 11.09.18 34 0
273131 횽들아 아이폰 개발책 추천 좀 거칠게갤로그로 이동합니다. 11.09.18 49 0
273130 구구싱 [2] ♥♡정수정♡♥갤로그로 이동합니다. 11.09.18 35 0
273127 사람마다 생각이 다르다는게 너무 싫다. 고등 교육을 좀 더 획일화했으면 [2] ㅇㅇ(222.107) 11.09.18 79 0
273126 아씨 형들 [2] Adelposs갤로그로 이동합니다. 11.09.18 41 0
273125 솔직히 사람들이 C++이 어렵다고 생각하는 이유가 뭔지모르겠따 [2] lol(110.174) 11.09.18 171 0
273124 아싸 학교 숙제 다해간다 2틀만에 거의 다했네 [3] lol(110.174) 11.09.18 130 0
273123 [자바] 제발 이거 오류좀 잡아주셈 형들 .ㅠㅠ [3] 이히(118.130) 11.09.18 66 0
273122 난 디자이너도 좋던데 쿄스케갤로그로 이동합니다. 11.09.18 39 0
273121 형들 여기 매틀랩도 질문하면 받아줘????.jpg [5] Matlab(125.128) 11.09.18 133 0
273120 보안 or 게임 둘중 하나 ........... 보안보안(118.35) 11.09.18 54 0
273119 근데 롯데리아는 왜 [1] 분당살람갤로그로 이동합니다. 11.09.18 62 0
273117 자바 case문 질문이요 ㅠ [1] 이하(118.130) 11.09.18 57 0
273116 [돈벌레의 T4정보] 형들 이거 프로젝트 T4라는 프로그램인데 돈벌레(121.137) 11.09.18 71 0
273115 C#에서 난수 표현을 할 때 [8] 좌우지장지지(211.246) 11.09.18 118 0
273114 갑자기 왜 보안관련 얘기가 나오는거야?? [1] 1234(110.11) 11.09.18 59 0
273112 형님들. 해킹 관심 많은 고딩 질문좀 받아줘요. [3] KY0N갤로그로 이동합니다. 11.09.18 149 0
273111 형들 싸이월드 일촌공개 일촌 아닌데도 볼수 있는 방법 없을까요? [5] !_!(61.105) 11.09.18 590 5
273110 나도 이문동에 사는데... [5] 궁금이(121.129) 11.09.18 92 0
273109 리눅스 할 줄 아는 형아들 [4] 나물이흥건해(61.102) 11.09.18 155 0
273108 이문동쮸쮸바 [3] 궁금한게..(125.141) 11.09.18 60 0
273107 64비트로 프로그램으로 설정하고 컴파일 하면 int형은... [8] 궁금이(121.129) 11.09.18 119 0
273106 아이작노턴 이셍키도 사라질땐 자료 다 지우고 가네 [5] 이문동쮸쮸바갤로그로 이동합니다. 11.09.18 128 0
273105 안랩 신입사원 모집 공고문보니까 [6] Regi☆갤로그로 이동합니다. 11.09.18 341 0
273104 보안이고 웹디고 三didas갤로그로 이동합니다. 11.09.18 51 0
뉴스 서영택, 첫 싱글 ‘러브 스펠’ 자켓 촬영 비하인드 공개! “팬들을 위한 사랑 고백” 디시트렌드 10:00
갤러리 내부 검색
제목+내용게시물 정렬 옵션

오른쪽 컨텐츠 영역

실시간 베스트

1/8

뉴스

디시미디어

디시이슈

1/2