Übersetzung der SDL Game Framework-Reihe. Teil 3 - SDL Events

Ursprünglicher Autor: Tim Jones
  • Übersetzung
  • Tutorial
Eine der Grundlagen der Spieleentwicklung ist die Verarbeitung von Nachrichten, die während eines Ereignisses ( Events ) eintreffen . Alle Videospiele, vom Tennis bis zu sehr komplexen Spielen für PCs und Konsolen, nutzen die sogenannte. Ereignisse für die Interaktion mit dem Spieler. Diese Ereignisse können von Tastaturen, Mäusen, Joysticks, Gamepads usw. sowie vom Betriebssystem selbst ausgehen. Es ist wichtig zu verstehen, wie sie funktionieren, wenn wir die Benutzerinteraktion mit dem Spiel richtig handhaben möchten. Wir haben bereits Ereignisse verwendet, aber nur, um unser Fenster zu schließen. Jetzt werden wir genauer untersuchen, wie Ereignisse vom Benutzer empfangen werden.

Wie Sie bereits bemerkt haben, baut jede Lektion auf der Grundlage der vorherigen Lektion auf, sodass wir vorerst nicht von dieser Tradition abweichen werden. Um alle Ereignisse zu verfolgen und in den dafür vorgesehenen Funktionen zu verarbeiten, müssen Sie eine neue Klasse anlegen. Fügen Sie die beiden Dateien projizieren CEvent.h und CEvent.cpp . In diesen beiden Dateien werden eingehende Nachrichten verarbeitet und die entsprechende Funktion aufgerufen. Unsere CApp- Klasse erbt von dieser Klasse. Wenn wir mit der Verarbeitung von Ereignissen beginnen, überschreiben wir einfach ihre Funktionen.

Öffnen Sie CEvent.h und fügen Sie den folgenden Code hinzu:

CEvent.h
#ifndef _CEVENT_H_
    #define _CEVENT_H_
#include 
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


Das ist kränklich eine Klasse geworden? Öffnen Sie nun CEvent.cpp und fügen Sie den folgenden Code hinzu:

CEvent.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
}


Ja ... Viel Code, aber alle SDL- Ereignisse sollten abgedeckt werden (d. H. Irgendwie behandelt werden). In diesem Handler akzeptieren wir einen Zeiger auf ein Ereignis vom Typ SDL_Event und rufen dann je nach Ereignistyp (Drücken einer Taste oder Bewegen der Maus) die entsprechende Funktion auf. Lassen Sie sich von dieser Menge an Code nicht beunruhigen. Tatsächlich ist hier alles extrem einfach. Nachdem
alles für uns eingerichtet ist, gehen wir zu CApp.h und fügen die erstellte Klasse hinzu:

CApp.h
#ifndef _CAPP_H_
    #define _CAPP_H_
#include 
#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


Alles sollte normal kompiliert werden. Wir haben eine angepasste Event-Handling-Klasse, die wir der Hauptklasse des Spiels zuordnen müssen. Öffnen Sie CApp_OnEvent.cpp und bearbeiten Sie die folgenden Funktionen:

CApp_OnEvent.cpp
#include "CApp.h"
void CApp::OnEvent(SDL_Event* Event) {
    CEvent::OnEvent(Event);
}


Nun wird unsere Nachricht an die Klasse weitergeleitet und dort korrekt verarbeitet. Unsere Ereignisvalidierungsfunktion wird jetzt überschrieben. Wir haben die SDL_Quit-Prüfung aufgehoben und übergeben stattdessen das Ereignis an die interne Funktion. Öffnen Sie CApp.h erneut und fügen Sie die folgenden Funktionen hinzu:

CApp.h
#ifndef _CAPP_H_
    #define _CAPP_H_
#include 
#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


Die OnExit- Funktion verarbeitet das SDL_Quit- Ereignis (Klicken auf das Kreuz). Wir haben also einen Prototyp, dessen Funktionalität noch programmiert werden muss. Öffnen Sie CApp_OnEvent.cpp und fügen Sie Folgendes hinzu:

CApp_OnEvent.cpp
#include "CApp.h"
void CApp::OnEvent(SDL_Event* Event) {
    CEvent::OnEvent(Event);
}
void CApp::OnExit() {
    Running = false;
}


Neu kompilieren und ausführen. Sie können die Anwendung wie zuvor schließen.
Ich empfehle, dass Sie sich mit anderen Arten von Ereignisereignissen vertraut machen und versuchen, die Antwort in den entsprechenden Handlerfunktionen zu registrieren, da wir in Zukunft einige dieser Ereignisse in unseren Spielen verwenden werden.
In der nächsten Lektion erwartet uns eine aufregende Reise, an deren Ende wir unser erstes richtiges Spiel erstellen werden - Tic-Tac-Toe (Tic Tac Toe).
Trotz der großen Menge an Code stellte sich eine kleine Lektion heraus. Anscheinend muss ich es mit einem kleinen Beispiel für die Bearbeitung der Tasten AUF , AB , RECHTS und LINKS (Pfeile) ergänzen .

Öffnen Sie CEvent.cppSuchen Sie dort die CEvent :: OnKeyDown- Funktion und schreiben Sie Folgendes hinein:

CEvent.cpp
Fügen Sie ganz am Anfang der Datei hinzu
#include 
using namespace std;

Und schreiben Sie dann die Funktionalität von CEvent :: OnKeyDown neu
void CEvent::OnKeyDown(SDLKey sym, SDLMod mod, Uint16 unicode) {
    switch (sym)
    {
        case SDLK_ESCAPE:
        {
            cout << "Hey, HABR! Escape pressed by m0sk1t\n";
            break;
        }
        case SDLK_UP:
        {
            cout << "Hey, HABR! UP pressed by m0sk1t\n";
            break;
        }
        case SDLK_DOWN:
        {
            cout << "Hey, HABR! DOWN pressed by m0sk1t\n";
            break;
        }
        case SDLK_LEFT:
        {
            cout << "Hey, HABR! LEFT pressed by m0sk1t\n";
            break;
        }
        case SDLK_RIGHT:
        {
            cout << "Hey, HABR! RIGHT pressed by m0sk1t\n";
            break;
        }
        default: break;
    }
}


Kompiliere und starte, klicke auf die Pfeile und schließe das Spielfenster. Sie sollten Folgendes beachten:


Siehe Konsolenausgabe? Es zeigt das Ergebnis der Tatsache an, dass wir in der Funktion CEvent :: OnKeyDown nun die Tatsache verfolgen, auf einen der Pfeile zu klicken, und eine Beschreibung dessen anzeigen, welcher gedrückt wurde (nun, die Escape- Taste ist da).

Quellcode-Links:


Links zu allen Lektionen:

Jetzt auch beliebt: