Recent Changes - Search:

Documentation

Help

Tutorials

RoadMap

Help Docs for wiki writers:

PmWiki

edit SideBar

LessonThree

Lesson 3:First Game

In this lesson we are going to create a simple text game.
This tutorial is using the .331 version of the Epee Engine the .35 version will not work
Do to the change in StringFromNumericData
The game consists of 10 random math questions.
The user answers each question and then at the end the program tells the user how many they got correct.

Below is the code for the game it may look like a lot but it is a lot simpler than it looks.
Let now look at each line a see how this game is put together and uses the Epee Engine.
Since this code is so long I have but the code in a separate page.
Game code written out
Screen shot of the Game running

Explanation of code

We first define the max number allowed for the left and right number of the equation in this case 12.
const unsigned int LeftNumberMax=12;
const unsigned int RightNumberMax=12;

This function translates the operation number _opp (which we use to represent +,-,* operations) into a string that we can display to the user later.\\ In this case we assigning 0 to addition , 1 to subtraction, and 2 to multiplication.

std::string TranslateOppToString(unsigned int _opp)
{
	switch(_opp)
	{
		case 0:
			return "+";
		break;
		case 1: 
			return "-";
		break;
		case 2:
			return "*";
		break;
	}
	return "+";
}

This function is use to preform the operation _opp on the numbers _var1 and _var2.

int EvaluateQuestions(int _var1,int _var2,unsigned int _opp)
{

	switch(_opp)
	{
		case 0:
			return _var1+_var2;
		break;
		case 1: 
			return _var1-_var2;
		break;
		case 2:
			return _var1*_var2;
		break;

	}
	return _var1+_var2;
}

Here we define the order of the states and assign numbers to each state. Note this is not the most scalable way of creating a fine state machine but it is simple to understand and will work for this example.

enum State
{
	Restart=0,
	DisplayQuestion,
	WaitForAnwser,
	EvaluateAnwser,
	CheckForMoreQuestions,
	Done

};
This code should be familiar from the previous lessons. 
I chose 15 for the frame rate because we do not want to eat up all cpu cycles of the user's computer. 
This program will be running in a window and is not intend to hold the user attention all the time. So, eating up all the cpu cycle will annoy the end user.
Also 15 FPS is fast enough for our game logic as well.
Any FPS from 15 to 30 will work.
int main (int argc, char *argv[])
{
EpeeEngine GraphicsEngine;
GraphicsEngine.SetUp(800,600,false,"Math Questions",false,15,32);
EpeeEngine GraphicsEngine;
   GraphicsEngine.SetUp(800,600,false,"Math Questions",false,15,32);
   textBox * pMessage=GraphicsEngine.CreateTextBox("message",100,50,5,"1234","Current",-1,-1,"ARIAL.TTF",18,255,255,255,"C:\\WINDOWS\\Fonts\\");
   textBox * pVar1=GraphicsEngine.CreateTextBox("var1",100,100,5,"1234","Current",-1,-1,"ARIAL.TTF",18,255,255,255,"C:\\WINDOWS\\Fonts\\");
   textBox * pVar2=GraphicsEngine.CreateTextBox("var2",200,100,5,"1234","Current",-1,-1,"ARIAL.TTF",18,255,255,255,"C:\\WINDOWS\\Fonts\\");
   textBox * pOperatorText=GraphicsEngine.CreateTextBox("operator",150,100,5,"-","Current",-1,-1,"ARIAL.TTF",25,255,0,0,"C:\\WINDOWS\\Fonts\\");
   textBox * pAnwser=GraphicsEngine.CreateTextBox("Anwser",120,150,3,"Click and Type Answer Here","Current",-1,-1,"ARIAL.TTF",18,255,255,255,"C:\\WINDOWS\\Fonts\\");
   if(!(pVar1 && pVar2 && pOperatorText && pAnswer && pMessage))
   {
	cerr<<"could not create textbox see stderr for details"<<endl;
	return 0;
   }
  srand ( time(NULL) );

 pAnwser->SetBackGroundColor(0,255,0);
  pAnwser->SetColorChangedOnClick(true);
  pAnwser->SetQuality(FONT_QUALITY_SHADED);
  pAnwser->SetSelectBackGroundColor(255,0,0);
  pVar1->SetQuality(FONT_QUALITY_HIGH);
  pVar1->SetTextJustification(TEXT_RIGHT_JUSTIFIED);
  pVar2->SetQuality(FONT_QUALITY_HIGH);
  pVar2->SetTextJustification(TEXT_LEFT_JUSTIFIED);
  pOperatorText->SetQuality(FONT_QUALITY_HIGH);
  pOperatorText->SetTextJustification(TEXT_CENTER_JUSTIFIED);
  pMessage->SetQuality(FONT_QUALITY_HIGH);
  pAnwser->SetNumbersOnly(true);


  unsigned int uiCurrentQuestion=1;
  unsigned int uiNumberCorrect=0;



  State CurrentState=DisplayQuestion;
  int iLeftSide=0;
  int iRightSide=0;
  unsigned int uiOpp=0;
  int iAnwser=0;
  std::string message=" ";
  std::string temp="";




  SDL_Event event;
  while (1)
  {
     while(GraphicsEngine.GetEvent(&event))
     {


        switch(event.type)
         {
             case SDL_QUIT:
                       return 0;
              break;
            case  SDL_KEYUP:
              switch(event.key.keysym.sym)
                {
                      case SDLK_ESCAPE:
                         return 0;
                        break;
			case SDLK_KP_ENTER:
			case SDLK_RETURN:
			 pAnwser->SetEditable(false);
			 CurrentState=EvaluateAnwser;
			break;
			case SDLK_r:
			  if(CurrentState==Done)
			  {
				CurrentState=Restart;
			  }
			break;
                  }

              break;
           }//end of  switch(event.type)

	 }//end of while(GraphicsEngine.GetEvent(&event))
Next we will look at the state flow of the game.
Below is a switch statement that we are going to use to handle a small state flow.
Each case is a diffrent state and thus runs code specific to that game state.
we start our game out in DisplayQuestion with the following line from above: State CurrentState=DisplayQuestion.
The game will flow through the states as follows
DisplayQuestion
WaitForAnwser
EvaluateAnwser
CheckForMoreQuestions
Done or DisplayQuestion
Restart
DisplayQuestion

Here we have the code that is exicuted in the Restart State.
We need to clear out the varables that hold number of correct, which question we are on, and then set the state to DisplayQuestion

switch (CurrentState)
		{
		case Restart:
			  uiNumberCorrect=0;
			  uiCurrentQuestion=1;
			CurrentState=DisplayQuestion;
		break;

Next we define te code defines the behavior of the DisplayQuestion state.
In this state we first get a random numner for the left and right side of the equation
(iLeftSide=rand()%LeftNumberMax; iRightSide=rand()%RightNumberMax;)and get a random operand (uiOpp=rand()%3;). Then we display the right, left numbers and operand (after converting it to a sting) into the corresponding text boxes Finaly we set the state to WaitForAnswer state

       
           case DisplayQuestion:
	      iLeftSide=rand()%LeftNumberMax;
	      iRightSide=rand()%RightNumberMax;
	      uiOpp=rand()%3;
	      pVar1->SetTextFromInt(iLeftSide);
	      pVar2->SetTextFromInt(iRightSide); 
	      pOperatorText->SetText(TranslateOppToString(uiOpp));
	      CurrentState=WaitForAnwser;
	    break;

Now we define code for the WaitForAnswer state First we set the awnser text box editable to true so the user can type in there anwser(pAnwser->SetEditable(true);). Then we set the message text box with instructions for the user. We now wait for the user to put text into the answer text box before we change states (see case SDLK_RETURN: above)

                   case WaitForAnwser:
			pAnwser->SetEditable(true);
			pMessage->SetText("What is the Answer?");
		   break;
Once the user has enter an answer and pressed enter we will be in the EvaluateAnswer state.
We first get the text from the answer text box and covet it to an integer.
iAnwser=pAnwser->GetTextToInt();
Then we check to make sure the converting of the text to an integer was succesfull.
if(pAnwser->GetLastError().m_iErrorCode!=TEXTBOX_CONVERION_ERROR)
If it was successfully we then check to see if the answer was correct
if(EvaluateQuestions(iLeftSide,iRightSide,uiOpp)==iAnwser))
If it is we tell the user they are correct and increment the correct answers counter.
pMessage->SetText("That is Correct");
uiNumberCorrect++;
Other wise we tell the user they are incorrect
pMessage->SetText("That is Incorrect");
Then since the text from the answer text box converted correctly we then go to the CheckForMoreQuestions state
CurrentState=CheckForMoreQuestions;
If the text from the answer text box does not covert correctly we then tell the user and go back to the WaitForAnswer state.
pAnwser->SetText("Invalid input");
CurrentState=WaitForAnwser;
case EvaluateAnwser:
		  iAnwser=pAnwser->GetTextToInt();

		         if(pAnwser->GetLastError().m_iErrorCode!=TEXTBOX_CONVERION_ERROR)
			 {
				if(EvaluateQuestions(iLeftSide,iRightSide,uiOpp)==iAnwser)
				 {
					 pMessage->SetText("That is Correct");
					  uiNumberCorrect++;

				 }
				 else
				 {
					 pMessage->SetText("That is Incorrect");

				 }

				 CurrentState=CheckForMoreQuestions;

			 }
			 else
			 {

				 pAnwser->SetText("Invalid input");
				 CurrentState=WaitForAnwser;



			 }
		 break;
In CheckForMoreQuestion we sleep for a second(1000 milliseconds) so the user can read whether or not he got the answer correct.
SDL_Delay(1000);
This is really not the best way to do this since sleeping will stop our rendering of the screen.
The correct way is with timer which is a more advance topic out side the scope of this lesson,but we will save that for the next lesson.
Next we Check to see if they have answer 10 questions yet
if(uiCurrentQuestion>9)
Then we convert the integer number to a string and tell the user how many they got correct.
if(EpeeUtility::StringFromNumericData(temp,uiNumberCorrect))
				{
					message="You Got "+temp+" Out of "+"10 "+"Correct";
				}

Finally we go to the done state and wait for the r key to be pressed (see case SDLK_r: above)
CurrentState=Done;
If we still have more question to ask we increment the number of questions asked counter and go to the DisplayQuestions state.

 else
			{
				uiCurrentQuestion++;
				CurrentState=DisplayQuestion;
			}
case CheckForMoreQuestions:
			SDL_Delay(1000);
			if(uiCurrentQuestion>9)
			{ 
				temp="";
				if(EpeeUtility::StringFromNumericData(temp,uiNumberCorrect))
				{
					message="You Got "+temp+" Out of "+"10 "+"Correct";
				}
				pMessage->SetText(message);
				CurrentState=Done;

			}
			else
			{
				uiCurrentQuestion++;
				CurrentState=DisplayQuestion;
			}

			break;

Finally we have the Done state which does nothing because we are waiting for the user to press the r key.

case Done:
break;

And we then render the see with GraphicsEngine.RenderSeen(true);

		
case Done:
			break;


		}//end of switch logic


    GraphicsEngine.RenderSeen(true);

  }//end of while (1)
return 0;
} 

That is the end of our game loop. See the screen shot for what it should look like when it runs.
One last thing you will have to delete the text "Click and Type Answer Here" since there is no auto delete function.

Like always if you have problems check the stdout.txt and stderr.txt files first and if you still have problems PM or e-mail me on the forum I would be happy to answer any questions

Edit - History - Print - Recent Changes - Search
Page last modified on August 19, 2008, at 02:35 PM