In university as a way to learn C++ from a games development point of view I was asked to develop a Finite State Machine (FSM). The video below shows how the Blue arrow object wanders around the screen until the Red arrow object moves into its path, the the Blue arrow follows the Red for some time and then reverts back to wandering around again.

 

Code Snippet:

/****************************************************************
* Game.cpp
*
*
*
****************************************************************/

/****************************************************************
* Header Files.
****************************************************************/
#include "Game.h"

// Namespaces.
using namespace WlvGameFramework;
using namespace std;

/****************************************************************
* Public Methods.
****************************************************************/

/****************************************************************
* The Game class constructor.
****************************************************************/
Game::Game(HINSTANCE hInstance, bool gameWindowed, bool useDepthStencilView) :
GameManager(hInstance, gameWindowed, useDepthStencilView) // constructor initializer list.
{ // This calls the parent class constructor.

}

/****************************************************************
* The Game class destructor.
****************************************************************/
Game::~Game(){

}

/****************************************************************
* Private Methods.
****************************************************************/

/****************************************************************
* Load game content.
****************************************************************/
void Game::loadContent(){

vector myTextures;
/****************************************************************
* humanShip_BasicEntity.
****************************************************************/
humanShip_BasicEntity.initializeEntity(1.0f, 1.0f);
myTextures.push_back("graphics/movementExamplesGraphics/shipHuman.png"); // frame 1.
humanShip_BasicEntity.setTexture(myTextures, 0);
humanShip_BasicEntity.setCollisionRangeX(0.1f);
humanShip_BasicEntity.setCollisionRangeY(0.1f);
humanShip_BasicEntity.setAnimationId(0);
humanShip_BasicEntity.setPositionX(5.0f);
humanShip_BasicEntity.setPositionY(-4.0f);
humanShip_BasicEntity.setSpeed(10);
myTextures.clear();

humanShip_CharacterProp.position = humanShip_BasicEntity.getPosition();

/****************************************************************
* aiShip_BasicEntity.
****************************************************************/
aiShip_BasicEntity.initializeEntity(1.0f, 1.0f);
myTextures.push_back("graphics/movementExamplesGraphics/shipAI.png"); // frame 1.
aiShip_BasicEntity.setTexture(myTextures, 0);
aiShip_BasicEntity.setAnimationId(0);
aiShip_BasicEntity.setCollisionRangeX(0.1f);
aiShip_BasicEntity.setCollisionRangeY(0.1f);
aiShip_BasicEntity.setPositionX(2.0f);
aiShip_BasicEntity.setPositionY(7.0f);
aiShip_BasicEntity.setSpeed(1);
myTextures.clear();

aiShip_CharacterProp.position = aiShip_BasicEntity.getPosition();

/****************************************************************
* spaceAnimatedBackgroundBasicEntity.
****************************************************************/
spaceAnimatedBackgroundBasicEntity.initializeEntity(6.3f, 6.3f);
myTextures.push_back("graphics/movementExamplesGraphics/stars.jpg"); // background 1.
spaceAnimatedBackgroundBasicEntity.setTexture(myTextures);
spaceAnimatedBackgroundBasicEntity.setDirectionUpX();
spaceAnimatedBackgroundBasicEntity.setSpeed(0.025f);
myTextures.clear();

// Game menu (FSM) variables.
// ****************************************************************

/****************************************************************
* menuBackgroundEntity.
****************************************************************/
menuBackgroundEntity.initializeEntity(6.3f, 6.3f);
myTextures.push_back("graphics/spaceGameMenu/menuBackground.jpg"); // background 1.
menuBackgroundEntity.setTexture(myTextures);
menuBackgroundEntity.setDirectionUpX();
menuBackgroundEntity.setSpeed(0.005f);
myTextures.clear();

/****************************************************************
* menuBackgroundTextEntity.
****************************************************************/
menuBackgroundTextEntity.initializeEntity(6.3f, 6.3f);
myTextures.push_back("graphics/spaceGameMenu/menuText.png"); // background 1.
menuBackgroundTextEntity.setTexture(myTextures);
menuBackgroundTextEntity.setDirectionUpX();
menuBackgroundTextEntity.setSpeed(0.0f);
myTextures.clear();

/****************************************************************
* menuSpaceShipPointerEntity.
****************************************************************/
// First initialize the entity. This call creates the vertex buffer.
menuSpaceShipPointerEntity.initializeEntity(1.0f,0.5f);

// Next create a list using a vector to store your frames of animation
// (or textures).
// Add all the frames of animation for a particular direction.
myTextures.push_back("graphics/spaceGame/spaceship1.png"); // frame 1.
myTextures.push_back("graphics/spaceGame/spaceship2.png"); // frame 2.
// Add the textures to the entity.
// myTextures = the frames of animation for a particular direction.
// animationId - Use an id / index for the animation. This could indicate direction - E.g. 0 = up, 1 = right, etc.
// 1 = the animationId. You use this index to identify the frames of animation.
menuSpaceShipPointerEntity.setTexture(myTextures, 0);

// Set the current animationId. 2 = a left direction in this case.
menuSpaceShipPointerEntity.setAnimationId(0);
// Set the speed of the entity.
menuSpaceShipPointerEntity.setSpeed(2);
// Set how long each frame of animation should last.
menuSpaceShipPointerEntity.setMillisecondsPerAnimationFrame(0.1f);
// Set the position of the space ship.
menuSpaceShipPointerEntity.setPositionX(2.0f);
menuSpaceShipPointerEntity.setPositionY(2.0f);
myTextures.clear();

/****************************************************************
* menuStartEntity.
****************************************************************/
menuStartEntity.initializeEntity(1.0f, 1.0f);
myTextures.push_back("graphics/spaceGameMenu/start.png"); // background 1.
menuStartEntity.setTexture(myTextures);
menuStartEntity.setDirectionUpX();
menuStartEntity.setSpeed(0.0f);
menuStartEntity.setPosition(4.5f,2.0f,0.0f);
myTextures.clear();

/****************************************************************
* menuOptionsEntity.
****************************************************************/
menuOptionsEntity.initializeEntity(1.0f, 1.0f);
myTextures.push_back("graphics/spaceGameMenu/options.png"); // background 1.
menuOptionsEntity.setTexture(myTextures);
menuOptionsEntity.setDirectionUpX();
menuOptionsEntity.setSpeed(0.0f);
menuOptionsEntity.setPosition(4.5f,0.0f,0.0f);
myTextures.clear();

/****************************************************************
* menuExitEntity.
****************************************************************/
menuExitEntity.initializeEntity(1.0f, 1.0f);
myTextures.push_back("graphics/spaceGameMenu/exit.png"); // background 1.
menuExitEntity.setTexture(myTextures);
menuExitEntity.setDirectionUpX();
menuExitEntity.setSpeed(0.0f);
menuExitEntity.setPosition(4.5f,-2.0f,0.0f);
myTextures.clear();

}

/****************************************************************
* Initialize game content.
****************************************************************/
void Game::InitializeContent(){

// Setup the game score. Param - halfwidth, halfheight.
myGameScore.initialize(0.5, 0.5);
// Param - x, y, z.
myGameScore.setPosition(3.5,5.5,0);
myGameScore.setScore(5);
// Switch on the mouse cursor.
this->showCursor(true);
// Switch debug info on.
this->setDisplayInfo(true);

// Set the game state to the main menu.
gameState = 0;
// Set the game event to on enter.
gameEvent = 0;

// Set the current menu option to start.
// Current menu option. 0 == exit. 1 == start. 2 == options.
currentMenuOption = 1;

menuGameFrameDelayCount = 0.0f;
}

/****************************************************************
* The game loop. The update method.
****************************************************************/
void Game::gameLoop(GameTime gameTime){

// We want to check for input here so we need to get the state objects.
KeyboardState myKeyboardState = this->getkeyboardState();
MouseState myMouseState = this->getMouseState();

switch(gameState){
// The main menu..
case 0:
if (gameEvent == 0){
// Enter the state.
gameEvent = 1;
break;
}
if (gameEvent == 1){
// Update the state.
menuSpaceShipPointerEntity.setEntityMoved(true);

if(menuGameFrameDelayCount >= 0){
menuGameFrameDelayCount -= gameTime.elpasedTimeSinceLastFrame_Seconds;
}
if(menuGameFrameDelayCount <= 0){ if ( myKeyboardState.IsKeyDown( VK_ESCAPE ) ){ this->quitGame();
}

if ( myKeyboardState.IsKeyDown( VK_UP ) ){
if(currentMenuOption == 0){
// Current = Exit. Move up to Options.
menuSpaceShipPointerEntity.setPositionY(0.0f);
currentMenuOption = 2;
menuGameFrameDelayCount = 0.2f;
break;
}
if(currentMenuOption == 1){
// Current = Play. No where to move up to.
break;
}
if(currentMenuOption == 2){
// Current = Options. Move up to Play.
menuSpaceShipPointerEntity.setPositionY(2.0f);
currentMenuOption = 1;
menuGameFrameDelayCount = 0.2f;
break;
}
}

if ( myKeyboardState.IsKeyDown( VK_DOWN ) ){
if(currentMenuOption == 0){
// Current = Exit. No where to move down to.
break;
}
if(currentMenuOption == 1){
// Current = Play. Move down to options.
menuSpaceShipPointerEntity.setPositionY(0.0f);
currentMenuOption = 2;
menuGameFrameDelayCount = 0.2f;
break;
}
if(currentMenuOption == 2){
// Current = Options. Move down to Exit.
menuSpaceShipPointerEntity.setPositionY(-2.0f);
currentMenuOption = 0;
menuGameFrameDelayCount = 0.2f;
break;
}
}

if ( myKeyboardState.IsKeyReleased( VK_RETURN ) ){
if(currentMenuOption == 1){
gameEvent = 2;
}
if(currentMenuOption == 0){
this->quitGame();
}

}
break;
}
}
if(gameEvent == 2){
//Exit the state.
gameEvent = 0;
gameState = 1;
break;
}
break;

// The Main game..
case 1:
if (gameEvent == 0){
// Enter the state.
gameEvent = 1;
break;
}
if (gameEvent == 1){
// The main gameloop code for the main game.

//get current time
time_t currentTime;
struct tm * timeinfo;
time (&currentTime);
timeinfo = localtime ( &currentTime );

int seconds = timeinfo->tm_sec;
int startTime = seconds;

if ( myKeyboardState.IsKeyDown( VK_ESCAPE ) ){
gameEvent = 2;
menuGameFrameDelayCount = 0.2f;
}

// Keyboard test..
if ( myKeyboardState.IsKeyDown( VK_RIGHT ) ){
humanShip_BasicEntity.moveUpX(gameTime.elpasedTimeSinceLastFrame_Seconds);
humanShip_CharacterProp.position = humanShip_BasicEntity.getPosition();
}
if ( myKeyboardState.IsKeyDown( VK_LEFT ) ){
humanShip_BasicEntity.moveDownX(gameTime.elpasedTimeSinceLastFrame_Seconds);
humanShip_CharacterProp.position = humanShip_BasicEntity.getPosition();
}
if ( myKeyboardState.IsKeyDown( VK_UP ) ){
humanShip_BasicEntity.moveUpY(gameTime.elpasedTimeSinceLastFrame_Seconds);
humanShip_CharacterProp.position = humanShip_BasicEntity.getPosition();
}
if ( myKeyboardState.IsKeyDown( VK_DOWN ) ){
humanShip_BasicEntity.moveDownY(gameTime.elpasedTimeSinceLastFrame_Seconds);
humanShip_CharacterProp.position = humanShip_BasicEntity.getPosition();
}

// Always set the entity to moved so the animation will always play.
humanShip_BasicEntity.setEntityMoved(true);

//collison detection decrease score & respwan ai ship

if(humanShip_BasicEntity.collision(aiShip_BasicEntity)){
myGameScore.decreaseScore();
aiShip_BasicEntity.setPositionX(2.0f);
aiShip_BasicEntity.setCollisionRangeY(2.0f);
}

if (( seconds < 20)|| (seconds > 40)){

// Update the AI character.
myCharacterMovement.wander_1(aiShip_CharacterProp, aiShip_KinematicSteeringOutput);
// Update the characters
myCharacterMovement.updateKinematic(aiShip_CharacterProp, aiShip_KinematicSteeringOutput, gameTime);

// Finally set the game entity information.
aiShip_BasicEntity.setPosition(aiShip_CharacterProp.position.x, aiShip_CharacterProp.position.y, aiShip_CharacterProp.position.z);
aiShip_BasicEntity.setRotationZ(aiShip_CharacterProp.orientation);

// Force a reset of the entity position. Stops the entity moving of the screen.
// This makes the game world toroidal. mmmmmmm toroidal.
if(aiShip_CharacterProp.position.x > 8){
aiShip_CharacterProp.position.x = -8;
}
if(aiShip_CharacterProp.position.x < -8){ aiShip_CharacterProp.position.x = 8; } if(aiShip_CharacterProp.position.y > 8){
aiShip_CharacterProp.position.y = -8;
}
if( aiShip_CharacterProp.position.y < -8){
aiShip_CharacterProp.position.y = 8;
}
}else{

// seek algorithm.
myCharacterMovement.KinematicSeek_1(aiShip_CharacterProp, humanShip_CharacterProp, aiShip_KinematicSteeringOutput);
// Update the characters
myCharacterMovement.updateKinematic(aiShip_CharacterProp, aiShip_KinematicSteeringOutput, gameTime);

// Finally set the game entity information.
aiShip_BasicEntity.setPosition(aiShip_CharacterProp.position.x, aiShip_CharacterProp.position.y, aiShip_CharacterProp.position.z);
aiShip_BasicEntity.setRotationZ(aiShip_CharacterProp.orientation);
}

}
}
}

/****************************************************************
* Draw the scene.
****************************************************************/
void Game::render(GameTime gameTime){

switch(gameState){
case 0:
if (gameEvent == 0){
// Enter the state.
break;
}
if (gameEvent == 1){
// Update the state.

// DRAW THE BACKGROUND FIRST. Entities need to be drawn in order.
menuBackgroundEntity.renderEntity(gameTime.elpasedTimeSinceLastFrame_Seconds);
menuBackgroundTextEntity.renderEntity(gameTime.elpasedTimeSinceLastFrame_Seconds);

menuStartEntity.renderEntity(gameTime.elpasedTimeSinceLastFrame_Seconds);
menuOptionsEntity.renderEntity(gameTime.elpasedTimeSinceLastFrame_Seconds);
menuExitEntity.renderEntity(gameTime.elpasedTimeSinceLastFrame_Seconds);

// Draw the spaceship.
menuSpaceShipPointerEntity.renderEntity(gameTime.elpasedTimeSinceLastFrame_Seconds);

break;
}
if(gameEvent == 2){
//Exit the state.
break;
}
break;
case 1:
if (gameEvent == 0){
// Enter the state.
break;
}
if (gameEvent == 1){
// DRAW THE BACKGROUND FIRST. Entities need to be drawn in order.
spaceAnimatedBackgroundBasicEntity.renderEntity(gameTime.elpasedTimeSinceLastFrame_Seconds);

// Draw the spaceship.
humanShip_BasicEntity.renderEntity(gameTime.elpasedTimeSinceLastFrame_Seconds);

// Draw the ai entity.
aiShip_BasicEntity.renderEntity(gameTime.elpasedTimeSinceLastFrame_Seconds);

// Draw the score.
myGameScore.renderText();

break;
}
if(gameEvent == 2){
//Exit the state.
break;
}
break;
}

}

/****************************************************************
* Unload game content.
****************************************************************/
void Game::UnloadContent(){

}