Basically the class is designed to handle keyboard events and give me easy to use functions for 4 types of key events:
Key Press (happens only once, the moment the key is pressed)
Key Down (whether the key is down/pressed)
Key Release (happens only once, the moment the key is released)
Key Up (whether the key is up/released)
Now I needed to make sure that key events where not being handled during the execution of my Main game loop(otherwise bad things happen...), thus I've got a stop and start function designed to basically freeze the state of the keys during the loop.
Now it all works great, except for one small problem.
The first time I press A, G, H, Escape, or a few other keys when they're being handled as "key Press" events, they wont execute the first time, but the second time you press them they will.
The application I wrote uses A/D for key Press movement, and W/S for key Down movement.
As you can see Pressing "A" for the first time does not move the block, but pressing "D" always does (even after a restart of the app and D being the first key ever pressed)
I'd greatly appreciate it if someone could help me fix this problem.
Random speculation is welcome.
Here is my application:
Code: Select all
#include <iostream>
#include <wchar.h>
// Change this to where you store irrlicht.
#include "./irrlicht/irrlicht.h"
// Change this to where you store MastEventReceiver.cpp (or just inline it)
#include "../projects/MastEventReceiver.cpp"
using namespace std;
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
#pragma comment(lib, "Irrlicht.lib")
ISceneNode* node = 0;
IrrlichtDevice* device = 0;
ICameraSceneNode *camera = 0;
///////////////
//Start Main
///////////////
int main()
{
MastEventReceiver receiver;
device = createDevice(EDT_OPENGL, dimension2d<s32>(640,480), 16, false, false, false, &receiver);
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
//Stationary Box Model
node = smgr->addCubeSceneNode();
node->setPosition(vector3df(0,0,30));
node->setMaterialTexture(0, driver->getTexture("C:/Irrlicht/media/wall.bmp"));
//Create Camera
ICameraSceneNode *camera = smgr->addCameraSceneNodeMaya();
int lastFPS = -1;
while (device->run())
{
receiver.endEventProcess();
// On Key Press
if (receiver.keyPressed(KEY_KEY_A))
{
core::vector3df v = node->getPosition();
v.X += -15.0f;
node->setPosition(v);
}
if (receiver.keyPressed(KEY_KEY_D))
{
core::vector3df v = node->getPosition();
v.X += 15.0f;
node->setPosition(v);
}
if (receiver.keyPressed(KEY_ESCAPE))
{
device->closeDevice(); // stop Irrlicht!!!
cout << "Now Closing the Irrlicht Device\n";
}
// On Key Down
if (receiver.keyDown(KEY_KEY_W))
{
core::vector3df v = node->getPosition();
v.Z += 0.1f;
node->setPosition(v);
}
if (receiver.keyDown(KEY_KEY_S))
{
core::vector3df v = node->getPosition();
v.Z += -0.1f;
node->setPosition(v);
}
// Draw everything.
driver->beginScene(true, true, SColor(255,90,90,156));
smgr->drawAll();
driver->endScene();
int fps = driver->getFPS();
if (lastFPS != fps)
{
wchar_t tmp[1024];
swprintf(tmp, 1024, L"Movement Example - Irrlicht Engine (%s)(fps:%d)", driver->getName(), fps);
device->setWindowCaption(tmp);
lastFPS = fps;
}
receiver.startEventProcess();
}
//END OF while (device->run())
device->drop();
cout << "Program has Ended, Press Enter to Continue.\n";
cin.get();
return 0;
}
And here is the MastEventReceiver Class file:
Code: Select all
// Change this to the path where your Irrlicht Header Files are.
#include "./irrlicht/irrlicht.h"
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
////////////////////////////////////////////////////////////////////////////
//
// To use this Class create an instance of it like so: MastEventReceiver eventReceiver;
// Then inside your Main Game Loop place "eventReceiver.endEventProcess();" in the beginning of your game loop, before anything -
// that would require input, then put "eventReceiver.startEventProcess();" at the very end of your Main Game Loop.
// yeah I know it's confusing, but it makes alot more sense in the internals of the class.
//
////////////////////////////////////////////////////////////////////////////
/// ==============================
/// MastEventReceiver EVENT RECEIVER FOR KEY PRESS/RELEASE HANDLING.
/// ==============================
class MastEventReceiver : public IEventReceiver
{
public:
// Definitions for UP, DOWN, PRESSED and RELEASED key states.
#define UP 0
#define DOWN 1
#define PRESSED 2
#define RELEASED 3
MastEventReceiver();
char keyState[KEY_KEY_CODES_COUNT];
bool processState; // 1 = started, 0 = ended.
virtual bool keyPressed(char keycode)
{
if (keyState[keycode] == 2)
{
return true;
}
else
{
return false;
}
}
virtual bool keyDown(char keycode)
{
if (keyState[keycode] == 1 || keyState[keycode] == 2)
{
return true;
}
else
{
return false;
}
}
virtual bool keyUp(char keycode)
{
if (keyState[keycode] == 0 || keyState[keycode] == 3)
{
return true;
}
else
{
return false;
}
}
virtual bool keyReleased(char keycode)
{
if (keyState[keycode] == 3)
{
return true;
}
else
{
return false;
}
}
// This is used so that the Key States will not be changed during execution of your Main game loop.
// Place this at the very START of your Main Loop
void endEventProcess()
{
processState = 1;
}
// This is used so that the Key States will not be changed during execution of your Main game loop.
// Place this function at the END of your Main Loop.
void startEventProcess()
{
processState = 0;
for (int i = 0; i <= KEY_KEY_CODES_COUNT; i++)
{
if (keyState[i] == RELEASED)
{
keyState[i] = UP;
}
if (keyState[i] == PRESSED)
{
keyState[i] = DOWN;
}
}
}
//
//
//
virtual bool OnEvent(SEvent event)
{
bool eventprocessed = false;
if (event.EventType == EET_KEY_INPUT_EVENT)
{
//////////////////////////////
// Keyboard Input Event
//////////////////////////////
// if key is Pressed Down
if (event.KeyInput.PressedDown == true && processState == 0)
{
// If key was not down before
if (keyState[event.KeyInput.Key] == UP || keyState[event.KeyInput.Key] == RELEASED)
{
// if key was not down before
keyState[event.KeyInput.Key] = PRESSED; // Set to Pressed
}
else
{
// if key was down before
keyState[event.KeyInput.Key] = DOWN; // Set to Down
}
}
else
{
if (processState == 0)
{
// if the key is not down
if (keyState[event.KeyInput.Key] == UP)
{
keyState[event.KeyInput.Key] = UP; // Set to Up
}
else
{
// if key was down before
keyState[event.KeyInput.Key] = RELEASED; // Set to Released
}
}
}
eventprocessed = 1;
}
return eventprocessed;
}
};
MastEventReceiver::MastEventReceiver()
{
char keyState[KEY_KEY_CODES_COUNT];
for (int i = 0; i <= KEY_KEY_CODES_COUNT; i++)
{
keyState[i] = UP;
}
bool processState = 0; // 0 = started, 1 = ended.
}
/// ==========================================
/// END OF MastEventReceiver Class Definitions
/// ==========================================