Tag Archives: c++

Simple KeyPress Buffer

Using a keyboard buffer for intuitive user inputs

Objective: Using a keyboard buffer for intuitive user inputs
Difficulty: Beginner
Code length: Short
 
Until recent years, user inputs had often been neglected in software development. After all, controllers and keyboards are rather idiot proof, there are only so many ways to use them Is it?
 
In a simple walk around the world program, the user press  ‘a’, the avatar move left. Alright now the user press ‘s’, so the avatar move down. Now the user press both ‘a’ and ‘s’, intuitively the avatar move south west.
 
What happen if the gameplay do not support diagonal movement?. The avatar move the direction of the last key pressed. However if the player release the ‘s’ key while holding ‘a’ key. This is where keyboard buffering come into play.
 
In many gameplay situations, it may not be feasible to process certain key inputs simultaneously. This article will explain how to create a simple keyboard buffer for an arcade style game movement.
 
This is a simple buffer for two keys, which I am going to store as a player actions.
_lastActions[1] is the latest player action.
_lastAction[0]  is the action buffer.
 
The default action for the buffer is  PLAYER_NOT_MOVING, this is what happens when the player releases both keys
 
int _lastActions[2] = {PLAYER_NOT_MOVING, PLAYER_NOT_MOVING};
 
//When key is pressed, save the previous action.
void keyPressed(KeyEvent e)
{
   if(e.key == keyMap[PLAYER_MOVE_UP])
   {
      _lastActions[0] = _lastActions[1];
      _lastActions[1] = PLAYER_MOVE_UP;
      //player move up
   }
}
 
Here will check which key the player release, did he release the latest key?, If so process the buffer.
In any case got to reset the action buffer.
 
void keyReleased(KeyEvent e)
{
   if(_lastActions[1] == PLAYER_MOVE_UP)
   {
      _lastActions[1] = _lastKeys[0];
      //process the previous player action.
      _lastActions[0] = PLAYER_NOT_MOVING;
   }
   else if(_lastActions[0] == PLAYER_MOVE_UP)
      _lastActions[0] = PLAYER_NOT_MOVING;
}
 
It is not a good idea to map the keyPressed to the keycode as in “if(e.key == key.ESCAPE)”. A better pratice is to store all the keycodes in an array and use an enum of player actions  to reference them. In this way not only your keys configuration can be read from an external file, you can also customise your keys during gameplay.
 
Here is an example of how to reference your keycodes from an enum.
 
enum playerInputs
{
   PLAYER_NOT_MOVING = 0,
   PLAYER_MOVE_UP,
   PLAYER_MOVE_DOWN,
   PLAYER_INPUTS_COUNT
};
 
KeyCode[] keyMap = new keyMap[PLAYER_INPUTS_COUNT]; //populate your array.
 

Boost Bind

Boost Bind imo is one of the most useful library in C++, yet at times can be the most frustrating one too!

For the uninitiate
This is a small example on the usefulness of boost bind. We have a FunctionClass which that in a function, and will execute the function sometime later. I will not go into detail on why the function will be executed later, below is the class.

class FunctionClass
{
public:
typedef boost::function Callback;
Callback callback_;

FunctionClass (const Callback & callback) :
callback_(callback)
{
}

virtual void executeCallback()
{
callback_();
}
};

Now the class will only take in a function that take in no parameters and return no parameters. If we writing our own function, we can still ensure it work with the Callback. Let say we need to call a function from a third pty library.

Eg. SceneNode::setPosition at Vector3(0, 0, 0);

We could always create a helper function

void setSceneNodePositionToZero()

What happen if we need to call setPosition at multiple differnt location???

This is where boost bind come to the rescue!!!

FunctionClass

Callback myCallback = boost

bind(&SceneNode::setPosition, myNode, Vector3(0, 0, 0));

A simple one line of code to fufill our needs!!!

…. more examples to follow

Create a simple mini-map using Ogre3D and CEGUI

Objective: Creating a mini-map display using Ogre 3D and CEGUI.

Difficulty: Beginner
Code Length: Short
 
This tutorial explains how to render the whole scene from a top down view and render it to a CEGUI StaticImage.
 
//calculate the height of camera to view the whole scene
 
Ogre::Radian fieldOfView = _camera->getFOVy();
float height = _sceneLength/2 / Ogre::Math::Sin(fieldOfView / 2);
 
Vector3 cameraPosition = Vector3(_sceneLength/2,_sceneWidth/2, height);
Vector3 lookAt = Vector3(_sceneLength/2,_sceneWidth/2, 0);
 
//create a texture for the mini-map to render on
 
TexturePtr texture = TextureManager::getSingleton().createManual(“mmTex”,
   ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D,
   512, 512, 0, PF_R8G8B8, TU_RENDERTARGET );
 
RenderTarget rt = texture->getBuffer()->getRenderTarget();
{
   //create a minimap camera, use the same settings as main camera
   _mmCamera = _sceneManager->createCamera(“minimapCamera”);
   _mmCamera->setNearClipDistance(_camera->getNearClipDistance());
   _mmCamera->setFarClipDistance(_camera->getFarClipDistance());
 
   //AspectRatio(1) is for a square minimap
   _mmCamera->setAspectRatio(1);
   _mmCamera->setPosition(cameraPosition);
   _mmCamera->lookAt(lookAt);
   Viewport *vp = _rt->addViewport(_mmCamera);
   vp->setClearEveryFrame(true);
   vp->setOverlaysEnabled(false);
   vp->setBackgroundColour(ColourValue::Black);
}
 
//Create a CEGUI texture from mmTex
CEGUI::Texture* cetex = GUIManager::instance()->_guiRenderer->createTexture((CEGUI::utf8*) “mmTex”);
 
//CEGUI require an imageset to store the texture
CEGUI::Imageset* imageset = CEGUI::ImagesetManager::getSingleton().createImageset((CEGUI::utf8*)”minimapTexImageset”, cetex);
 
imageset->defineImage((CEGUI::utf8*)”minimapImage”,
CEGUI::Point(0.0f, 0.0f),
CEGUI::Size(cetex->getWidth(), cetex->getHeight()),
CEGUI::Point(0.0f,0.0f));
 
//retrieve the CEGUI StaticImage(window) used to render the minimap
CEGUI::Window* si = CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)”MiniMap”);
si->setProperty(“Image”, CEGUI::PropertyHelper::imageToString(
   &imageset->getImage((CEGUI::utf8*)|CEGUI::utf8*)”minimapImage”)));