Alongside the basics of
game development is something called Events. All videogames, from pong to the highly complex PC games and console titles, use events to interact with the player. These events can come from keyboards, mice, joysticks, gamepads, and so on, or events from our operating system. It's important to understand how events work if we are to appropriately interact a user with a game. We've already been using events, but only for closing our window, now we'll look at how to receive events from the user.
If you haven't caught on, each tutorial builds off the previous, so we'll be using the code from the previous lesson. In order to track all these events and throw them into nice functions, lets create a new class. Create two files called CEvent.h and CEvent.cpp. These two files will handle our events, and call the appropriate function. CApp will inherit this class, so when we need to catch an event we simply override a function.
Open up CEvent.h and add the following code:
#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
Pretty hefty class right? Alright, open up CEvent.cpp, and add the following code:
#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
}
Lots of code, but all the
SDL events should be covered. What we basically are doing is taking an
SDL_Event pointer, and switching through the types, and then calling the appropriate function. It just looks like a lot since they are quite a bit of events.
Now that this has been all setup, let's jump over to CApp.h and link the two together:
#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 just fine. We have the event class setup, now lets actually link events to our new class structure. Open up CApp_OnEvent.cpp and edit the following function:
#include "CApp.h"
void CApp::OnEvent(SDL_Event* Event) {
CEvent::OnEvent(Event);
}
We're passing the Event structure to our class now, it will take care of the correct function calls. Now when we want to check for an event, we override the function. Since we got rid of checking for the
SDL_QUIT event, lets use the function instead. Open up CApp.h again, and add the following function:
#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 handles the
SDL_QUIT events. Now that we have the prototype, lets define what it does. Open up CApp_OnEvent.cpp, and add the following:
#include "CApp.h"
void CApp::OnEvent(SDL_Event* Event) {
CEvent::OnEvent(Event);
}
void CApp::OnExit() {
Running = false;
}
Recompile, and try it out. You should be able to close the application just like before.
I encourage you to look through some of the various events that we can check. Later on we'll use some of these events in our games, but for now try to familiarize yourself with them.
Jump on over to the next tutorial to take a look at creating our first game, Tic-Tac-Toe.
Where, for example, would one exactly put in the code to do something under a certain keypress? Would it go each specific case in the switch/case block in CEvent? What is OnEvent for?
Email (required, not published):
Website:
case SDL_KEYDOWN: {
SDL_GetKeyName(Event->key.keysym.sym);
if ( Event->key.keysym.sym == SDLK_ESCAPE ) //quit if 'ESC' pressed
SDL_Quit();
the program exit on the pressing of escape but another window appear "call stack" and sign kind of error in SDL_Flip
i tried also to make him writing something on SDL screen with the following script similar to the previous but nothing yet anyone can help please?
if ( Event->key.keysym.sym == SDLK_g ) //if g pressed print Hello
printf("Hello");
Email (required, not published):
Website:
what i want to do it is simple i want to print in the SDL screen the caracter pressed just to test SDL_keydown
first i prevent the program to load any bmp so i have only the sdl screen (done)
second in CEvent.h
virtual void OnKeyDown(SDLKey sym, SDLMod mod, Uint16 unicode);
become
virtual void OnKeyDown(SDLKey sym);
third in CEvent.ccp
case SDL_KEYDOWN: {
OnKeyDown(Event->key.keysym.sym,Event->key.keysym.mod,Event->key.keysym.unicode);
break;
}
become
case SDL_KEYDOWN: {
printf("The %s key was pressed!\n",
SDL_GetKeyName(Event->key.keysym.sym));
break;
}
and
void CEvent::OnKeyDown(SDLKey sym, SDLMod mod, Uint16 unicode){}
become
void CEvent::OnKeyDown(SDLKey sym) {}
pressing any button on the keybord nothing happen nor in the prompt nor in SDL
thanks if somebody can help
Email (required, not published):
Website:
be patience check spelling and comments help
and everything will go ok
thanks for another great tutorial
Email (required, not published):
Website:
Email (required, not published):
Website:
There are "usual" and "virtual" methods. "Usual" methods work pretty simple: if you have CEvent::UsualMethod() and CApp::UsualMethod(), and call myApp.UsualMethod, then compiler looks at how myApp was declared (it was declared as CApp), and accordingly puts a call for CApp::UsualMethod().
But it causes a lot of troubles, as you may guess. If we call myApp.OnEvent(), and it calls CEvent's version of OnEvent(), but CEvent's OnEvent() then would simply call CEvent's OnExit()---CEvent doesn't know about any CApp which inherits it.
That's when virtual methods come to save the day! When you call a virtual method, the compiler puts a code to determine object's actual type and call the correct version of the method. That's why OnExit() must be declared virtual: inside of myApp.AnyMethod() call, of calls of OnExit() will actually be CApp::OnExit(), not CEvent::OnExit().
Email (required, not published):
Website:
"error: cannot call member function 'virtual void CEvent::OnEvent(SDL_Event*)' without object"
Which makes sense because OnEvent() needs to be a member of an object no? Why does this work for you? am I missing something?
Email (required, not published):
Website:
Email (required, not published):
Website:
Email (required, not published):
Website:
CEvent::OnEvent(Event);
}
I get this error:
In member function 'void TankesApp::CEvento(SDL_Event*)':
error: cannot call member function 'virtual void Eventos::OnEvent(SDL_Event*)' without object
Email (required, not published):
Website:
Email (required, not published):
Website:
void TankesApp::CEvento(SDL_Event* Event) {
CEvent::OnEvent(Event);
}
error: cannot call member function 'virtual void CEvent::OnEvent(SDL_Event*)' without object
Email (required, not published):
Website:
If all of the events member functions apart from OnEvent are not being implemented then why not make them pure virtual in the header file e.g.
virtual void OnInputFocus() = 0;
Then there would be no need for empty implementations such as...
void CEvent::OnInputFocus() {
//do nothing
}
Email (required, not published):
Website:
Email (required, not published):
Website:
And my question. Why I can't do this:
void CApp::OnEvent ( SDL_Event * Event )
{
// CEvent::OnEvent ( Event );
OnEvent ( Event );
}
When CApp is child of CEvent it should work, or not?
Email (required, not published):
Website:
I had to remove CApp:OnEvent(..) method, so now it's calling OnEvent from CEvent class. But I still don't unerstand why it is made this way in this tutorial.
Does it have any reason? Because it CApp doesn't have to be CEvents child then.
Email (required, not published):
Website:
Email (required, not published):
Website:
However, what you are saying above about changing CEvent::OnEvent(Event) to OnEvent(Event) will not work. Calling just "OnEvent" from inside of CApp will make it call itself, and cause the program to crash. What I am doing is calling the OnEvent of CEvent (which CApp inherits), so that it can continue to do its own thing.
To reply to "value" below, what you want to do is have Event Listeners. Your Event Manager will capture all events, loop through a list of listeners, and then send the data out to each one of those. One way of doing listeners is simply any class that wants to capture events inherits some Listener class. You then register your objects with the Event Manager: EventManager->AttachListener(&App);
Email (required, not published):
Website:
void CApp::OnEvent(SDL_Event* Event) {
CEvent::OnEvent(Event);
}
in CApp_OnEvent.cpp I get the error
"illegal call of non-static member function"
I am using Visual Studio; could it be a remnant of that? I've tried coding it up myself as well as a straight copy.
Anyway, if anyone has seen this before, thanks for the help.
Email (required, not published):
Website:
class CApp {
to
class CApp : public CEvent {
So probably something really basic no one else will ever miss but just in case I've posted it here (for the other beginners out there =) ).
Email (required, not published):
Website:
Email (required, not published):
Website: