NOGDUS $1670.00 has been donated to NOGDUS!
July 20, 2017, 11:40:15 PM *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Help Search Login Register  
Pages: [1]   Go Down
  Print  
Author Topic: ASK Technique 01 - Game State  (Read 2465 times)
0 Members and 1 Guest are viewing this topic.
Richard Marks
Administrator
Offline Offline

Respect: 3425
« on: May 23, 2010, 11:43:00 AM »

ASK Technique 01 - Game State

Hey there, here is a small technique tutorial where I'm going to show you an easy method of implementing a game state system. I don't have much time today, so I'll be rushing things and just pasting in code.
If it doesn't make sense from the code dumps, then reply to this post and I'll explain it later when I have more time. Cool

First thing that I'll say is that you should already have gone through the ASK tutorials and know how to get started.

In PrimaryWindow.h we need a few things:
Code:
// first we create an enumeration for every state we will need
enum EGameState
{
TitleScreenState,
GameScreenState,
PausedScreenState,
GameOverScreenState,
CreditsScreenState,

// this state is special and does not have any methods
EndState
};

// your game variables here

// now we create a variable for tracking the current state that the game is in
EGameState state_;

// every state will need to render and update, so we create two member function pointers
void (PrimaryWindow::*UpdateStateMethod)();
void (PrimaryWindow::*RenderStateMethod)(BITMAP*);

// your game methods here

// next we create a method to change the current state
void ChangeState(EGameState state);

// now we create the methods for each state
// don't forget that we need 2 methods for each state

// state update methods
void UpdateTitleScreenState();
void UpdateGameScreenState();
void UpdatePausedScreenState();
void UpdateGameOverScreenState();
void UpdateCreditsScreenState();

// state render methods
void RenderTitleScreenState(BITMAP* target);
void RenderGameScreenState(BITMAP* target);
void RenderPausedScreenState(BITMAP* target);
void RenderGameOverScreenState(BITMAP* target);
void RenderCreditsScreenState(BITMAP* target);

And in PrimaryWindow.cpp lets make the magic happen:
Code:

/**
 * boolean Action::Triggered(boolean trigger reference, boolean condition)
 *
 * When condition changes between calls to this function,
 * the function will return true.
 *
 * The trigger reference should be unique for each condition you test.
 */
class Action { public: static bool Triggered(bool& trigger, bool condition)
{
if (condition)
{
if (!trigger) { trigger = true; }
}
else
{
if (trigger)
{
trigger = false;
return true;
}
}
return false;
}};

PrimaryWindow::PrimaryWindow()
{
}

PrimaryWindow::~PrimaryWindow()
{
}

bool PrimaryWindow::UpdateFrame()
{
// update stuff here

// update if the state update member function pointer is set
// otherwise close the window / end the program
if (this->UpdateStateMethod)
{
(this->*UpdateStateMethod)();
}
else
{
return false;
}

return ASKWindow::UpdateFrame();
}

void PrimaryWindow::RenderFrame()
{
clear_bitmap(_backBuffer);

// draw here

// render if the state render member function pointer is set
if (this->RenderStateMethod)
{
(this->*RenderStateMethod)(_backBuffer);
}

ASKWindow::RenderFrame();
}

bool PrimaryWindow::LoadContent()
{
// load your content here

// always init pointers to zero!
this->UpdateStateMethod = 0;
this->RenderStateMethod = 0;

// set the first state to the title screen
this->ChangeState(PrimaryWindow::TitleScreenState);

return ASKWindow::LoadContent();
}

void PrimaryWindow::UnloadContent()
{
// unload your content here

ASKWindow::UnloadContent();
}

void PrimaryWindow::ChangeState(EGameState state)
{
switch(state)
{
case PrimaryWindow::TitleScreenState:
{
// set the member function pointers
this->UpdateStateMethod = &PrimaryWindow::UpdateTitleScreenState;
this->RenderStateMethod = &PrimaryWindow::RenderTitleScreenState;

// set the state tracking var
state_ = state;
} break;

case PrimaryWindow::GameScreenState:
{
// set the member function pointers
this->UpdateStateMethod = &PrimaryWindow::UpdateGameScreenState;
this->RenderStateMethod = &PrimaryWindow::RenderGameScreenState;

// set the state tracking var
state_ = state;
} break;

case PrimaryWindow::PausedScreenState:
{
// set the member function pointers
this->UpdateStateMethod = &PrimaryWindow::UpdatePausedScreenState;
this->RenderStateMethod = &PrimaryWindow::RenderPausedScreenState;

// set the state tracking var
state_ = state;
} break;

case PrimaryWindow::GameOverScreenState:
{
// set the member function pointers
this->UpdateStateMethod = &PrimaryWindow::UpdateGameOverScreenState;
this->RenderStateMethod = &PrimaryWindow::RenderGameOverScreenState;

// set the state tracking var
state_ = state;
} break;

case PrimaryWindow::CreditsScreenState:
{
// set the member function pointers
this->UpdateStateMethod = &PrimaryWindow::UpdateCreditsScreenState;
this->RenderStateMethod = &PrimaryWindow::RenderCreditsScreenState;

// set the state tracking var
state_ = state;
} break;

case PrimaryWindow::EndState:
{
// set the member function pointers
this->UpdateStateMethod = 0;
this->RenderStateMethod = 0;

// set the state tracking var
state_ = state;
} break;

default: break;
}
}

void PrimaryWindow::UpdateTitleScreenState()
{
// pressing ESC from the title screen will change to the credits screen state
// pressing ENTER from the title screen will change to the game screen state

static bool escKey = false;
static bool enterKey = false;

if (Action::Triggered(escKey, 0 != key[KEY_ESC]))
{
this->ChangeState(PrimaryWindow::CreditsScreenState);
}

if (Action::Triggered(enterKey, 0 != key[KEY_ENTER]))
{
this->ChangeState(PrimaryWindow::GameScreenState);
}
}

void PrimaryWindow::UpdateGameScreenState()
{
// pressing ESC from the game screen will change to the game over screen state
// pressing P from the game screen will change to the paused screen state

static bool escKey = false;
static bool pauseKey = false;

if (Action::Triggered(escKey, 0 != key[KEY_ESC]))
{
this->ChangeState(PrimaryWindow::GameOverScreenState);
}

if (Action::Triggered(pauseKey, 0 != key[KEY_P]))
{
this->ChangeState(PrimaryWindow::PausedScreenState);
}
}

void PrimaryWindow::UpdatePausedScreenState()
{
// pressing SPACEBAR or ENTER from the pause screen will change to the game screen state

static bool resumeKey = false;

if (Action::Triggered(resumeKey, (key[KEY_SPACE] || key[KEY_ENTER])))
{
this->ChangeState(PrimaryWindow::GameScreenState);
}
}

void PrimaryWindow::UpdateGameOverScreenState()
{
// pressing ESC, ENTER, or SPACEBAR from the game over screen will change to the title screen state

static bool continueKey = false;

if (Action::Triggered(continueKey, (key[KEY_ESC] || key[KEY_ENTER] || key[KEY_SPACE])))
{
this->ChangeState(PrimaryWindow::TitleScreenState);
}
}

void PrimaryWindow::UpdateCreditsScreenState()
{
// pressing ESC, ENTER, or SPACEBAR from the credits screen will end the program

static bool endKey = false;

if (Action::Triggered(endKey, (key[KEY_ESC] || key[KEY_ENTER] || key[KEY_SPACE])))
{
this->ChangeState(PrimaryWindow::EndState);
}
}

void PrimaryWindow::RenderTitleScreenState(BITMAP* target)
{
// display "Game Title" centered on the screen in white letters

const char* text = "Game Title";
int textX = target->w / 2 - (text_length(font, text) / 2);
int textY = target->h / 2 - (text_height(font) / 2);
int textColor = makecol(0xFF, 0xFF, 0xFF);

textprintf_ex(target, font, textX, textY, textColor, -1, "%s", text);
}

void PrimaryWindow::RenderGameScreenState(BITMAP* target)
{
// bounce the letter "R" on the screen
// we're updating in the render method for just illustrative purposes.
// in doing this, we cannot "reset" the game. every time the game is started,
// we are currently resuming from where we left off the last time.
// so in a real game project, don't do updates in the render method!
static float x = 0.0f;
static float y = 0.0f;
static float xd = (float)1 + rand() % 4;
static float yd = (float)1 + rand() % 4;

const int w = text_length(font, "R");
const int h = text_height(font);

x += xd;
y += yd;

if (x < 0 || x > target->w - w)
{
xd = -xd;
x += xd;
}

if (y < 0 || y > target->h - h)
{
yd = -yd;
y += yd;
}

textprintf_ex(target, font, x, y, makecol(0xFF, 0xFF, 0xFF), -1, "R");
}

void PrimaryWindow::RenderPausedScreenState(BITMAP* target)
{
// flash the word "Paused" in cyan letters centered on the screen

// flasher
const int flashDelay = 16;
static int flashCounter = 0;
static int textColor = 0;

if (++flashCounter >= flashDelay)
{
flashCounter = 0;
textColor = (!textColor) ? makecol(0x00, 0xFF, 0xFF) : 0;
}

const char* text = "Paused";
int textX = target->w / 2 - (text_length(font, text) / 2);
int textY = target->h / 2 - (text_height(font) / 2);

textprintf_ex(target, font, textX, textY, textColor, -1, "%s", text);
}

void PrimaryWindow::RenderGameOverScreenState(BITMAP* target)
{
// display "G a M e  O v E r" centered on the screen in red letters

const char* text = "G a M e  O v E r";
int textX = target->w / 2 - (text_length(font, text) / 2);
int textY = target->h / 2 - (text_height(font) / 2);
int textColor = makecol(0xFF, 0x00, 0x00);

textprintf_ex(target, font, textX, textY, textColor, -1, "%s", text);
}

void PrimaryWindow::RenderCreditsScreenState(BITMAP* target)
{
// display "Credits" centered on the screen in white letters

const char* text = "Credits";
int textX = target->w / 2 - (text_length(font, text) / 2);
int textY = target->h / 2 - (text_height(font) / 2);
int textColor = makecol(0xFF, 0xFF, 0xFF);

textprintf_ex(target, font, textX, textY, textColor, -1, "%s", text);
}

OK, coolness. Done. Enjoy. Cool
Gotta run!
Logged

Tags:
Pages: [1]   Go Up
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines
.: Theme by Richard Marks :.
Valid XHTML 1.0! Valid CSS!