2015년 2월 15일 일요일

[일기] SDL EVENTS

일기. 출처 - http://www.sdltutorials.com/sdl-events

게임 개발의 기초와 문맥을 같이 하는 것이 이벤트이다. 핑퐁게임에서부터 난감할 정도로 복잠한 PC 게임과 콘솔 게임까지 모든 비디오게임들은 플레이어와 상호작용하기 위해 이벤트를 사용한다. 이벤트는 키보드, 마우스, 조이스틱, 게임패드 등으로부터 올 수도 있고 혹은 운영체제로부터 올 수도 있다. 게임에서 사용자와 적절하게 상호작용하기 위하여 이벤트가 어떻게 동작하는지를 이해하는 것은 분명 중요하다. 이제 이벤트를 사용할 준비가 되었다. 그러나 윈도우 창을 닫는 이벤트만을 살펴볼 것이며 동시에 사용자로부터 이벤트를 어떻게 받아내는지도 알아볼 것이다.

알아차렸을지 모르지만, 각각의 튜토리얼들은 이전의 것으로부터 구축되고 있다. 따라서 이번에도 역시 이전의 튜토리얼의 결과 코드를 사용하여 확장해 나갈 것이다. 모든 이벤트를 추적하고 이 이벤트들을 근사한 함수들에게 전달하기 위해 새 클래스를 하나 만들어 보자. CEvent.h 파일과 CEvent.cpp 파일을 만든다. 이 두 파일은 이벤트를 다루고 적절한 함수를 호출할 것이다. CApp은 이 클래스를 상속받도록 만들어, 만일 우리가 특정 이벤트를 추적하고자 한다면 단순하게 함수를 오버라이드하기만 하면 되도록 만들 것이다.

헤더 파일은 다음과 같다.

#ifndef _CEVENT_H_
    #define _CEVENT_H_

#include <SDL.h>

class CEvent {
    public:
        CEvent();

        virtual ~CEvent();

        virtual void OnEvent(SDL_Event* Event);

        virtual void OnInputFocus();

        virtual void OnInputBlur();

        virtual void OnKeyDown(SDLKey sym, SDLMod mod, Uint16 unicode);

        virtual void OnKeyUp(SDLKey sym, SDLMod mod, Uint16 unicode);

        virtual void OnMouseFocus();

        virtual void OnMouseBlur();

        virtual void OnMouseMove(int mX, int mY, int relX, int relY, bool Left,bool Right,bool Middle);

        virtual void OnMouseWheel(bool Up, bool Down);    //Not implemented

        virtual void OnLButtonDown(int mX, int mY);

        virtual void OnLButtonUp(int mX, int mY);

        virtual void OnRButtonDown(int mX, int mY);

        virtual void OnRButtonUp(int mX, int mY);

        virtual void OnMButtonDown(int mX, int mY);

        virtual void OnMButtonUp(int mX, int mY);

        virtual void OnJoyAxis(Uint8 which, Uint8 axis, Sint16 value);

        virtual void OnJoyButtonDown(Uint8 which, Uint8 button);

        virtual void OnJoyButtonUp(Uint8 which, Uint8 button);

        virtual void OnJoyHat(Uint8 which, Uint8 hat, Uint8 value);

        virtual void OnJoyBall(Uint8 which, Uint8 ball, Sint16 xrel, Sint16 yrel);

        virtual void OnMinimize();

        virtual void OnRestore();

        virtual void OnResize(int w,int h);

        virtual void OnExpose();

        virtual void OnExit();

        virtual void OnUser(Uint8 type, int code, void* data1, void* data2);
};

#endif

클래스가 꽤 무겁다. 이제 CPP 파일을 열고 다음을 코딩하자.

#include "CEvent.h"

CEvent::CEvent() {
}

CEvent::~CEvent() {
    //Do nothing
}

void CEvent::OnEvent(SDL_Event* Event) {
    switch(Event->type) {
        case SDL_ACTIVEEVENT: {
            switch(Event->active.state) {
                case SDL_APPMOUSEFOCUS: {
                    if ( Event->active.gain )    OnMouseFocus();
                    else                OnMouseBlur();

                    break;
                }
                case SDL_APPINPUTFOCUS: {
                    if ( Event->active.gain )    OnInputFocus();
                    else                OnInputBlur();

                    break;
                }
                case SDL_APPACTIVE:    {
                    if ( Event->active.gain )    OnRestore();
                    else                OnMinimize();

                    break;
                }
            }
            break;
        }

        case SDL_KEYDOWN: {
            OnKeyDown(Event->key.keysym.sym,Event->key.keysym.mod,Event->key.keysym.unicode);
            break;
        }

        case SDL_KEYUP: {
            OnKeyUp(Event->key.keysym.sym,Event->key.keysym.mod,Event->key.keysym.unicode);
            break;
        }

        case SDL_MOUSEMOTION: {
            OnMouseMove(Event->motion.x,Event->motion.y,Event->motion.xrel,Event->motion.yrel,(Event->motion.state&SDL_BUTTON(SDL_BUTTON_LEFT))!=0,(Event->motion.state&SDL_BUTTON(SDL_BUTTON_RIGHT))!=0,(Event->motion.state&SDL_BUTTON(SDL_BUTTON_MIDDLE))!=0);
            break;
        }

        case SDL_MOUSEBUTTONDOWN: {
            switch(Event->button.button) {
                case SDL_BUTTON_LEFT: {
                    OnLButtonDown(Event->button.x,Event->button.y);
                    break;
                }
                case SDL_BUTTON_RIGHT: {
                    OnRButtonDown(Event->button.x,Event->button.y);
                    break;
                }
                case SDL_BUTTON_MIDDLE: {
                    OnMButtonDown(Event->button.x,Event->button.y);
                    break;
                }
            }
            break;
        }

        case SDL_MOUSEBUTTONUP:    {
            switch(Event->button.button) {
                case SDL_BUTTON_LEFT: {
                    OnLButtonUp(Event->button.x,Event->button.y);
                    break;
                }
                case SDL_BUTTON_RIGHT: {
                    OnRButtonUp(Event->button.x,Event->button.y);
                    break;
                }
                case SDL_BUTTON_MIDDLE: {
                    OnMButtonUp(Event->button.x,Event->button.y);
                    break;
                }
            }
            break;
        }

        case SDL_JOYAXISMOTION: {
            OnJoyAxis(Event->jaxis.which,Event->jaxis.axis,Event->jaxis.value);
            break;
        }

        case SDL_JOYBALLMOTION: {
            OnJoyBall(Event->jball.which,Event->jball.ball,Event->jball.xrel,Event->jball.yrel);
            break;
        }

        case SDL_JOYHATMOTION: {
            OnJoyHat(Event->jhat.which,Event->jhat.hat,Event->jhat.value);
            break;
        }
        case SDL_JOYBUTTONDOWN: {
            OnJoyButtonDown(Event->jbutton.which,Event->jbutton.button);
            break;
        }

        case SDL_JOYBUTTONUP: {
            OnJoyButtonUp(Event->jbutton.which,Event->jbutton.button);
            break;
        }

        case SDL_QUIT: {
            OnExit();
            break;
        }

        case SDL_SYSWMEVENT: {
            //Ignore
            break;
        }

        case SDL_VIDEORESIZE: {
            OnResize(Event->resize.w,Event->resize.h);
            break;
        }

        case SDL_VIDEOEXPOSE: {
            OnExpose();
            break;
        }

        default: {
            OnUser(Event->user.type,Event->user.code,Event->user.data1,Event->user.data2);
            break;
        }
    }
}

void CEvent::OnInputFocus() {
    //Pure virtual, do nothing
}

void CEvent::OnInputBlur() {
    //Pure virtual, do nothing
}

void CEvent::OnKeyDown(SDLKey sym, SDLMod mod, Uint16 unicode) {
    //Pure virtual, do nothing
}

void CEvent::OnKeyUp(SDLKey sym, SDLMod mod, Uint16 unicode) {
    //Pure virtual, do nothing
}

void CEvent::OnMouseFocus() {
    //Pure virtual, do nothing
}

void CEvent::OnMouseBlur() {
    //Pure virtual, do nothing
}

void CEvent::OnMouseMove(int mX, int mY, int relX, int relY, bool Left,bool Right,bool Middle) {
    //Pure virtual, do nothing
}

void CEvent::OnMouseWheel(bool Up, bool Down) {
    //Pure virtual, do nothing
}

void CEvent::OnLButtonDown(int mX, int mY) {
    //Pure virtual, do nothing
}

void CEvent::OnLButtonUp(int mX, int mY) {
    //Pure virtual, do nothing
}

void CEvent::OnRButtonDown(int mX, int mY) {
    //Pure virtual, do nothing
}

void CEvent::OnRButtonUp(int mX, int mY) {
    //Pure virtual, do nothing
}

void CEvent::OnMButtonDown(int mX, int mY) {
    //Pure virtual, do nothing
}

void CEvent::OnMButtonUp(int mX, int mY) {
    //Pure virtual, do nothing
}

void CEvent::OnJoyAxis(Uint8 which,Uint8 axis,Sint16 value) {
    //Pure virtual, do nothing
}

void CEvent::OnJoyButtonDown(Uint8 which,Uint8 button) {
    //Pure virtual, do nothing
}

void CEvent::OnJoyButtonUp(Uint8 which,Uint8 button) {
    //Pure virtual, do nothing
}

void CEvent::OnJoyHat(Uint8 which,Uint8 hat,Uint8 value) {
    //Pure virtual, do nothing
}

void CEvent::OnJoyBall(Uint8 which,Uint8 ball,Sint16 xrel,Sint16 yrel) {
    //Pure virtual, do nothing
}

void CEvent::OnMinimize() {
    //Pure virtual, do nothing
}

void CEvent::OnRestore() {
    //Pure virtual, do nothing
}

void CEvent::OnResize(int w,int h) {
    //Pure virtual, do nothing
}

void CEvent::OnExpose() {
    //Pure virtual, do nothing
}

void CEvent::OnExit() {
    //Pure virtual, do nothing
}

void CEvent::OnUser(Uint8 type, int code, void* data1, void* data2) {
    //Pure virtual, do nothing
}

거 무지 기네... 그렇지만 모든 이벤트가 처리되어야 하므로 어쩔 수 없었다. 이제 할일은 SDL_Event 포인터를 얻는 것이다. 그리고 이벤트 타입에 따라 스위칭을 하고 그리고 적절한 함수를 호출한다. 코드가 길어 보인다. 위는 꽤 잦게 발생하는 이벤트다.

모든게 준비되었으니, CApp.h를 열고 상위 두개 파일을 연결시키자.

#ifndef _CAPP_H_
    #define _CAPP_H_

#include <SDL.h>

#include "CEvent.h"
#include "CSurface.h"

class CApp : public CEvent {
    private:
        bool            Running;

        SDL_Surface*    Surf_Display;

        SDL_Surface*    Surf_Test;

    public:
        CApp();

        int OnExecute();

    public:
        bool OnInit();

        void OnEvent(SDL_Event* Event);

        void OnLoop();

        void OnRender();

        void OnCleanup();
};

#endif

컴파일은 모두 잘된다. 우리는 준비된 이벤트 클래스를 갖고 있다. 이제 이벤트를 우리의 새 이벤트 동작 구조(방식)에 연결시켜보자. CApp_OnEvent.cpp를 열고 다음과 같이 편집한다.

#include "CApp.h"

void CApp::OnEvent(SDL_Event* Event) {
    CEvent::OnEvent(Event);
}

이벤트 구조체를 새 클래스에 전달하고 있다. 위 코드는 정확한 함수 호출을 보장할 것이다. 이제 특정 이벤트를 확인하고자 할 때, 함수를 오버라이딩하기만 하면 된다. SDL_QUIT 이벤트를 체크하는 기능을 없앴으므로 새 함수를 대신 사용해보자. CApp.h를 다시 열고 다음 함수를 추가하자.

#ifndef _CAPP_H_
    #define _CAPP_H_

#include <SDL.h>

#include "CEvent.h"
#include "CSurface.h"

class CApp : public CEvent {
    private:
        bool            Running;

        SDL_Surface*    Surf_Display;

        SDL_Surface*    Surf_Test;

    public:
        CApp();

        int OnExecute();

    public:
        bool OnInit();

        void OnEvent(SDL_Event* Event);

        void OnExit();

        void OnLoop();

        void OnRender();

        void OnCleanup();
};

#endif

OnExit 메서드는 SDL_QUIT 이벤트를 다룬다. 우리는 이제 프로토타입을 가졌으므로 이것이 무슨 일을 할지 정의해보자. CApp_OnEvent.cpp를 열고서 다음을 추가한다.

#include "CApp.h"

void CApp::OnEvent(SDL_Event* Event) {
    CEvent::OnEvent(Event);
}

void CApp::OnExit() {
    Running = false;
}

다시 컴파일하고, 실행시켜보라. 이제 전에 닫히지 않던 응용프로그램을 종료할 수 있을 것이다.

 확인가능한 다양한 이벤트를 살펴보기를 추천한다. 나중에 게임에서 이와 같은 이벤트 중 일부를 사용할 것이다. 단지 지금은 이들과 친숙해져야 한다.

댓글 없음:

댓글 쓰기