TGB/Tutorials/Asteroids/Section7

From TDN


Asteroids Tutorial

Written for TGB Version: 1.6


Section 7

What happens when the game is over? How about saving that great high score you just got.


Prelude


Before we get started with the main goal of this section, a quick note on the creation of behaviors. For the majority of the behaviors added or modified so far, care was taken to try and make them as general and flexible as possible so you can take them and apply the behaviors to other types of games besides Asteroids. When making a game and adding layers upon layers of complexity to objects in order to achieve the outcome you want, it is sometimes a lot easier to just "hardwire" certain function calls to get the script/behavior working. In this section, you will see a bit of that. It will not make the behavior in any way useless if you want to apply it to another game type, but keep in mind it might need some minor modifications.

Hopefully you have been following the suggestions in previous sections and have been giving all your objects a unique name in the scripting rollout under the edit tab. This gives us an easy way to tell those objects what to do in script.


Create and Modify


Create a new script file and call it highScore.cs:

//-----------------------------------------------------------------------------
// Torque Game Builder
// Copyright (C) GarageGames.com, Inc.
// Behavior by Mike Lilligreen for TDN Asteroids Tutorial
//-----------------------------------------------------------------------------

if (!isObject(HighScoreBehavior))
{
   %template = new BehaviorTemplate(HighScoreBehavior);
   
   %template.friendlyName = "High Score";
   %template.behaviorType = "GUI";
   %template.description  = "Controls the text of the high score table";
   
   %template.addBehaviorField(maxAmount, "The number of scores in table", int, 5);
   %template.addBehaviorField(waitTime, "Number of seconds to wait before displaying table", float, 5.0);
}

function HighScoreBehavior::onAddToScene(%this)
{
   new SimSet(HighScoreList);
   %file = new FileObject();
	
	if(%file.openForRead("~/highScore.txt"))
	{
                echo("High Score File found");
	}else
	{
		echo("Creating High Score File");
		
		%initialize = new FileObject();
		
		if(%initialize.openForWrite("~/highScore.txt"))
		{
			%initialize.close();
			%initialize.delete();
		}
	}

	%file.close();
	%file.delete();
}

function HighScoreBehavior::onRemoveFromScene(%this)
{
   HighScoreList.delete();
}

function HighScoreBehavior::runSchedule(%this)
{
   %this.schedule(3000, "recordScore");
   %this.schedule(%this.waitTime * 1000, "displayHighScores");
}

function HighScoreBehavior::recordScore(%this)
{
   %file = new FileObject();
   
   if (%file.openForAppend("~/highScore.txt"))
   {
      %file.writeLine($currentScore);
      echo("high score updated");
   }else
   {
      error("file not open for writing");
   }
   
   %file.close();
   %file.delete();
}

function HighScoreBehavior::displayHighScores(%this)
{
   %this.readTextFile();
   %this.sort();
   %this.reduceToLimit();
   
   for(%i=0;%i<HighScoreList.getCount();%i++)
   {
      %list = HighScoreList.getObject(%i);
      switch(%i)
      {
         case 0:
            if (isObject(%list))
               hs1.text = %list.score;
            
         case 1:
            if (isObject(%list))
               hs2.text = %list.score;
            
         case 2:
            if (isObject(%list))
               hs3.text = %list.score;
            
         case 3:
            if (isObject(%list))
               hs4.text = %list.score;
            
         case 4:
            if (isObject(%list))
               hs5.text = %list.score;
      }
   }
   
   %this.owner.setPosition(0, 0);
}

function HighScoreBehavior::readTextFile(%this)
{
   %file = new FileObject();
	
	if(%file.openForRead("~/highScore.txt"))
	{
            while(!%file.isEof())
            {
                %temp = %file.readLine();
         
                %obj = new ScriptObject()
                {
                     score = %temp;
                };
         
                HighScoreList.add(%obj);
             }
	}
	echo("File read");
	%file.close();
	%file.delete();
}

function HighScoreBehavior::sort(%this)
{
   %copy = %this.copySimSet(HighScoreList);
   HighScoreList.clear();
   
   while (%copy.getCount() > 0 && %trap < 100)
   {
      %high = null;
      %x = -1;
      
      for(%i=0;%i<%copy.getCount();%i++)
      {
         if (%x == -1)
         {
            %high = %copy.getObject(%i).score;
            %x = %i;
         }else
         {
            if (%copy.getObject(%i).score >= %high)
            {
               %high = %copy.getObject(%i).score;
               %x = %i;
            }
         }
      }
      
      HighScoreList.add(%copy.getObject(%x));
      %copy.remove(%copy.getObject(%x));
   }
}

function HighScoreBehavior::copySimSet(%this, %set)
{
   %obj = new SimSet();
   
   for(%i=0;%i<%set.getCount();%i++)
   {
      %obj.add(%set.getObject(%i));
   }
   
   return %obj;
}

function HighScoreBehavior::reduceToLimit(%this)
{
   %currentAmount = HighScoreList.getCount();
   %limit = %this.maxAmount;
   
   if (%currentAmount > %limit)
   {
      %file = new FileObject();
   
      if (%file.openForWrite("~/highScore.txt"))
      {
         %first = HighScoreList.getObject(0);
         %file.writeLine(%first.score);
      }else
      {
         error("file not open for writing");
      }
   
      %file.close();
      
      if (%file.openForAppend("~/highScore.txt"))
      {
         for(%i=1;%i<%limit;%i++)
         {
            %list = HighScoreList.getObject(%i);
            %file.writeLine(%list.score);
         }
      }else
      {
         error("file not open for writing");
      }
      
      %file.close();
      %file.delete();
   }
}


This is a rather large behavior with a quite a few functions so let's go over what they do. onAddToScene creates a SimSet that will hold the high scores and checks if the high score file exists. If it doesn't, it will create it. recordScore does just that, it takes the current score the player just got and adds it to the text file.

Note that openForAppend is used instead of openForWrite. If you have a text file with 5 scores saved, OpenForWrite would erase all of them and write the current score. OpenForAppend keeps everything that is already in the text file and adds the current score to a new line.

displayHighScores does four things, reads the text file and copies the scores into the SimSet (readTextFile), sorts the SimSet from highest score to lowest (sort), reduces the amount of saved scores to the amount you want to display (reduceToLimit), and then finally displays those scores. If you are wondering what hs1 through hs5 are, those are text objects that will be created shortly. A bit of "hardwiring" as mentioned above.

For this tutorial, the high score list will save and display the top 5 scores.

Save this new behavior in the behaviors folder and now open up takesDamage.cs. In the kill function change the first if{} to this:

   if (%this.lives <= 0)
   {
      if (%check == false)
      {
         %this.owner.safeDelete();
         return;
      }else
      {
         %this.lifeCounter.update();
         gameText.gameOverText();
         hsTable.runSchedule();
         %this.owner.safeDelete();
         return;
      }
   }


Here again is a bit of direct function calling. gameText is the object that was created in the last section that handles level number display and now game over as well. hsTable will be the object that has the high score behavior attached.

Save the file and start TGB.


The High Score Table


To start off, put a t2dSceneObject (create tab, other) in the scene outside of the camera view. Give this scene object the hsTable name in the scripting rollout. Give it the high score behavior as well. This object will be the frame of our high score table, so to speak.

Create a lot of new t2dTextObjects - we will need a header that displays the text "High Scores", the numbers 1 through 5 and five text objects of dashes whose text will be modified in script to display the scores.

Image:TGB Asteroids Tutorial 7 1.jpg

Now name the text objects with dashes hs1 through hs5. Your object tree should look similar to this:

Image:TGB Asteroids Tutorial 7 2.jpg

Also, mount each of the text objects to the hsTable scene object. This way when we move the scene object hsTable, all of the text comes with it in the table format you set up. When all of this is done, save the scene and play a few rounds! When the game is over, a high score table should appear like this:

Image:TGB Asteroids Tutorial 7 3.jpg

If you are wondering where this text file is that contains the high scores, please read TGB/FileIO for a bit more information. Continue on when you are ready.


Return to the Asteroids Tutorial Hub