📜 ⬆️ ⬇️

Translation SDL Game Framework Series. Part 3 - SDL Events

One of the foundations of game development is the processing of messages arriving during any Events ( Events ). All video games, from tennis to very complex PC games and consoles, use the so-called. events to interact with the player. These events can come from keyboards, mice, joysticks, gamepads, etc., as well as from the operating system itself. It is important to understand how they work if we want to properly handle user interaction with the game. We have already used events, but only to close our window, now we will deal deeper with how to receive events from the user.

As you have already noticed, each lesson is built on the basis of the previous one, so we will not for the time being depart from this tradition. In order to track all the events and process them in the intended functions, you need to create a new class. Add two CEvent.h and CEvent.cpp files to the project. In these two files we will process incoming messages, and call the corresponding function. Our CApp class will inherit from this class, so when we start processing events, we will simply override its functions.

Open CEvent.h and add the following code:

CEvent.h
#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 


Not a good class? Now open CEvent.cpp , and add the following code:
')
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 } 


Yes ... A lot of code, but all SDL events must be covered (i.e., handled somehow). In this handler, we take a pointer to an event of type SDL_Event , and then, depending on the type of event (keystroke or mouse movement), we call the corresponding function. Do not be intimidated by this amount of code, in fact everything is very simple here.
Now that everything is set up for us, let's move to CApp.h and add the created class:

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 


Everything should compile normally. We have a customized event handling class, it remains to associate it with the main class of the game. Open CApp_OnEvent.cpp and edit the following functions:

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


Now our message will be transferred to the class and processed correctly there. Our event check function is now redefined. We got rid of the SDL_Quit check , and instead pass the event to an internal function. Again open CApp.h again, and add the following functions:

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 


The OnExit function will handle the SDL_Quit event (the user clicks the cross). So, we have a prototype, it remains to program its functionality. Open CApp_OnEvent.cpp , and add the following:

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


Recompile, and run. You can close the application, just like before.
I recommend that you familiarize yourself with other types of event events, try to register the answer to them in the corresponding handler functions, because in the future we will use some of these events in our games.
In the next lesson we will have an exciting journey, at the end of which we will create our first real game - Tic-Tac-Toe (Tic / Tac-Toe ).
Some small turned out lesson, despite the large amount of code. Apparently I'll have to supplement it with a small example of processing the keys UP , DOWN , RIGHT and LEFT (arrows).

Open CEvent.cpp , find the CEvent :: OnKeyDown function and write the following in it:

CEvent.cpp
At the very beginning of the file add
 #include <iostream> using namespace std; 

And then rewrite the CEvent :: OnKeyDown functionality
 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; } } 


Compile and run, then click the arrows and close the game window. You should observe something like this:


See the console output? It displays the result of the fact that in the CEvent :: OnKeyDown function we now monitor the fact of pressing one of the arrows and display a description of which of them was pressed (well, the Escape key got there).

Links to source code:


Links to all lessons:

Source: https://habr.com/ru/post/167245/


All Articles