TGB/Tutorials/Asteroids/Section4

From TDN


Asteroids Tutorial

Written for TGB Version: 1.6


Section 4

A simple text based GUI element was made in the last section, now let's see something more graphical for the player life display.


New Behavior


To display the amount of player lives, we could take a similar approach as seen in the last section and use a text object which counts down the number of lives left. But why not something a bit different and more visual? With the text editor of your choice, create the following script file and save it to your behavior folder.

displayLives.cs

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

if (!isObject(DisplayLivesBehavior))
{
   %template = new BehaviorTemplate(DisplayLivesBehavior);
   
   %template.friendlyName = "Display Lives";
   %template.behaviorType = "GUI";
   %template.description  = "Displays the number of player lives";
   
   %template.addBehaviorField(object, "The object to clone as an icon", object, "", t2dSceneObject);
   %template.addBehaviorField(height, "Height of the icon", float, 3.0);
   %template.addBehaviorField(width, "Width of the icon", float, 3.0);
   %template.addBehaviorField(lives, "The number of lives the player has (for GUI display only!)", int, 5);
}

function DisplayLivesBehavior::onAddToScene(%this, %scenegraph)
{
   new SimSet(LifeIcons);
   $currentLife = %this.lives;
   %this.spawnCount = 0;
   %this.schedule(100, "spawn");
}

function DisplayLivesBehavior::onRemoveFromScene(%this, %scenegraph)
{
   LifeIcons.delete();
}

function DisplayLivesBehavior::spawn(%this)
{
   if (!isObject(%this.object))
      return;

   %clone = %this.object.clone();
   %modifier = %this.spawnCount * %this.width;
   %xPos = getWord(%this.owner.getAreaMin(), 0) + %modifier;
   %yPos = %this.owner.position.y;
   
   %clone.position = %xPos SPC %yPos;
   %clone.size = %this.height SPC %this.width;
   
   LifeIcons.add(%clone);
   
   %this.spawnCount++;
   if (%this.spawnCount < $currentLife)
   {
      %this.spawn();
   }
}

function DisplayLivesBehavior::update(%this)
{
   %count = LifeIcons.getCount();
   
   for(%i=0;%i<%count;%i++)
   {
      %icon = LifeIcons.getObject(%i);
      %tempArray[%i] = %icon;
   }
   
   LifeIcons.clear();
   
   for(%i=0;%i<%count;%i++)
   {
      %tempArray[%i].safeDelete();
   }
   
   $currentLife--;
   
   if ($currentLife > 0)
   {
      %this.spawnCount = 0;
      %this.spawn();
   }
}

Now open up the takesDamage behavior. As we start adding more complexity to our game, we need to consider that certain behaviors are shared between multiple objects. The takesDamage behavior being one of them, for example, on both the player ship and both asteroids. The way this behavior is currently set up has given us no problems, as long as the asteroids only have 1 life. Give them more lives and they start to behave more like the player ship. We could copy takesDamage and rename it uniquely for the player ship or we can add a way inside the behavior to let the functions know we are dealing with the player and not the asteroid game objects. For this tutorial, the check box method inside takesDamage is used.

Edit the following functions to match what's below:

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

if (!isObject(TakesDamageBehavior))
{
   %template = new BehaviorTemplate(TakesDamageBehavior);
   
   %template.friendlyName = "Takes Damage";
   %template.behaviorType = "Game";
   %template.description  = "Set the object to take damage from DealsDamage objects that collide with it";

   %template.addBehaviorField(isPlayer, "Check this box if object is player controlled", bool, 0);
   %template.addBehaviorField(health, "The amount of health the object has", int, 100);
   %template.addBehaviorField(lives, "The number of times the object can lose all its health", int, 3);
   %template.addBehaviorField(tintRedForDamage, "Tint the object red as it takes damage", bool, 0);
   %template.addBehaviorField(respawnTime, "The time between death and respawn (seconds)", float, 2.0);
   %template.addBehaviorField(invincibleTime, "The time after spawning before damage is applied (seconds)", float, 1.0);
   %template.addBehaviorField(respawnEffect, "The particle effect to play on spawn", object, "", t2dParticleEffect);
   %template.addBehaviorField(explodeEffect, "The particle effect to play on death", object, "", t2dParticleEffect);
   %template.addBehaviorField(lifeCounter, "The GUI object that keeps track of lives", object, "", t2dSceneObject);
}

Above we have two new behavior fields, isPlayer and lifeCounter. Now change the kill function to:

function TakesDamageBehavior::kill(%this)
{
   %check = %this.isPlayer;
   %this.lives--;
   
   if (%this.lives <= 0)
   {
      if (%check == false)
      {
         %this.owner.safeDelete();
         return;
      }else
      {
         %this.lifeCounter.update();
         %this.owner.safeDelete();
         return;
      }
   }
   
   if (%check == true)
   {
      %this.invincible = true;
      %this.owner.visible = false;
      %this.owner.control = 0;
      %this.owner.setAtRest();
      %this.owner.collisionActiveReceive = false;
      %this.schedule(%this.respawnTime * 1000, "spawn");
   
      %counter = %this.lifeCounter.getBehavior("DisplayLivesBehavior");
      if (!isObject(%counter))
         return;
      
      %counter.update();
   }
}

The additions ensure a couple things: 1. When an object is deleted, only the player ship deletion will update the display. (Wouldn't want the asteroid kills to take away your player life icons!) 2. All other respawn functions will also only apply to the player object.

So with that out of the way, start up TGB.

Adding the Display


From the create tab, drag another copy of the player ship sprite into the scene and place it out of the way by the asteroids, for example. You do not have to modify any of the new sprite's properties, just give it a name in the scripting section. Here it is called playerIcon.

Image:TGB Asteroids Tutorial 4 1.jpg

Now drag a new t2dSceneObject into the scene. The exact placement within the camera view is up to you, here it is under the Score text. Give it the name lifeDisplay and the following behavior:

Image:TGB Asteroids Tutorial 4 2.jpg

The icon will be displayed as a 3x3 sprite, so the height of the scene object is also 3. The lives field in the displayLives behavior is not associated in any way with the lives field on the actual player ship takesDamage behavior, so if you change the amount of lives on one remember to change the other as well.

Finally, click on the player ship sprite. You should now see the updated takesDamage behavior fields. Check the box for isPlayer and set the life counter to lifeDisplay.

Image:TGB Asteroids Tutorial 4 3.jpg

Save your scene and try it out. If everything went right, you should now have a nice icon display for the amount of player lives left.

Image:TGB Asteroids Tutorial 4 4.jpg

Now that we have a basic but functional GUI, the next section will improve on the gameplay aspect by adding waves of respawing asteroids.


Return to Asteroids Tutorial Hub