Torque 2D/Getting Started/FadingTutorial

From TDN

Image:Alert.png

A newer fading tutorial is available. Please visit the new tutorial here.

Torque Game Builder Tutorial – Fading Objects In and Out

by: Matthew "King BoB" Langley
edited by: Spider
edited by: Michael Woerister

This tutorial will cover
the following:


  • Extending the base object of T2D through Script
  • Creating fadeIn and fadeOut functions for T2D objects
  • T2D setBlendAlpha function for working with transparency
  • T2D schedule function for scheduling future function calls


THIS NOTE IS DEPRICATED (AND WILL BE REMOVED SOON) AS THE TUTORIAL IS UP-TO-DATE NOW<b>
<b>Note:
The command for setting transparency changed from T2D 1.0 (setBlendColour) to T2D 1.1 (setBlendAlpha). In order to make this tutorial work, calls to setBlendColour(r, g, b, alpha) need to be changed to setBlendAlpha(alpha), with alpha being a value from 0 to 1 instead of 0 to 255.

Note: This tutorial was written using the early release version of T2D, which has a default white background. To make your screenshots match those shown, open the SDK\games\T2D\data\gui\mainScreenGui.gui file and find/replace the text “logoblack” with “logowhite”.

Note: Any time you do a tutorial or experiment with TGB, it’s a good idea to create a new project in the level builder. This gives you a clean experimentation ground. After you have created a new project (e.g. "FadeTutorial"), a new folder with the same name will be created in you SDK/games/ folder. Copy the gglogo.png file (or some other image you want to use as your test graphics) from T2D/data/images/ to FadeTutorial/data/images/. Run TGB and use the ImageMap Builder to create an ImageMap from this graphics file. Then drag a StaticSprite with the new ImageMap into the level, not to small and well within the camera view. This will be our test object. Give it the name "testObject".


In this tutorial all script files are contained in (or are to be created in) the SDK/games/FadeTutorial/gameScripts folder. To set things up, let's make a couple changes in game.cs. Open it and add this

exec("./exec.cs");

somewhere at the top of the file, before the startGame() function.

Scroll down a little and exchange this line

sceneWindow2D.loadLevel(%level);

with this

$currentLevel = sceneWindow2D.loadLevel(%level);

It should then look about like this:

function startGame(%level)
{
   // Set The GUI.
   Canvas.setContent(mainScreenGui);
   Canvas.setCursor(DefaultCursor);
   
   moveMap.push();
   if( isFile( %level ) )
      $currentLevel = sceneWindow2D.loadLevel(%level);
}

Setting game.cs up this way allows us to exec all our scripts and GUI files in exec.cs so that we don't have to keep changing this T2D base file.
Next, create a script file called “exec.cs” and enter the following lines:

exec("./fading.cs");

Now create one more script file called “fading.cs”. This is the file where we're going to do the bulk of our scripting. Let's jump right in and add the following function to fading.cs:

function t2dSceneObject::startFadeOut(%this)
{ 
        %this.setBlendAlpha(1.0);  

        %this.schedule(50, fadeOut);
}

The first line of this function sets the alpha value of the object to 1.0. For those unfamiliar, an alpha value is basically how opaque an object is. So full alpha (in this case, 1.0) is completely opaque, while half alpha is pretty transparent and zero alpha is completely invisible because the object is completely transparent.

The second line in the function schedules, in 50 milliseconds, a call to fadeOut (which we're about to create) to do the actual fading of the object. So cool, let's make that fadeOut function. Add this to fading.cs:

function t2dSceneObject::fadeOut(%this)
{   
      // Fetch the current alpha value
      %alpha = %this.getBlendAlpha();

      // Decrease it
      %alpha -= 0.01; 

      if(%alpha < 0)
      {
      }
      else
      {
         %this.setBlendAlpha( %alpha );
         %this.schedule(50,fadeOut);
      }
}

Let's go through this. First, we fetch the current alpha value of the object, store it in %alpha and then decrease it by 0.01. That 0.01 controls the speed of our fading. Every 50 milliseconds, which is how often we'll be scheduling fadeOut, the alpha-value of the object is going to be reduced by 0.01. Since we're starting at 1.0, it'll take 100 calls to reduce the blend from fully opaque to totally transparent. 100 calls times 50 milliseconds equals 5000 milliseconds so as it stands, it will take 5 seconds for our object to fade out completely. So, if we reduced the blend by 0.02 every time fadeOut was called, instead of 0.01, we'd cut the fade time to 2500 milliseconds.
Moving on, the next thing we do is change the actual alpha-value of the object using the setBlendAlpha function.

Next, in the if clause we check to see if %alpha is less than 0. If it is, we don't need to do any more fading, but if it isn't then we need to schedule another call to fadeOut. This way, our function will keep getting called until our object is completely transparent.

Save your files and fire up T2D. You should see Level Builder. Be sure the right project is opened. Click on the Run Game button. Next, open up the console (using the “~” tilde key) and type this command:

testObject.startFadeOut(); 

Exit the console and you should see the block fading out like this:

Image:T2D_tut_Fading01.jpg

If not, compare your fading.cs to this:

function t2dSceneObject::startFadeOut(%this)
{ 
        %this.setBlendAlpha(1.0);  

        %this.schedule(50, fadeOut);
}

function t2dSceneObject::fadeOut(%this)
{   
      // Fetch the current alpha value
      %alpha = %this.getBlendAlpha();

      // Decrease it
      %alpha -= 0.01; 

      if(%alpha < 0)
      {
      }
      else
      {
         %this.setBlendAlpha( %alpha );
         %this.schedule(50,fadeOut);
      }
}

Now we have a fade out function... let's make a fade in. It won't be much different than fading out, so copy the startFadeOut and fadeOut functions, paste them below the originals.

In the copy of startFadeOut, change the name to “startFadeIn”, change the first line to set the alpha-value to zero, and change the schedule line to schedule a call to fadeIn instead of fadeOut.

Then, in a copy of the fadeOut function, rename it to “fadeIn” then change the blend line from “-=0.01” to “+=0.01”. Next, change the if clause to check if %alpha is greater than 1. Finally, change the schedule line to schedule a fadeIn function instead of a fadeOut.
After this, your script file should look like this:

function t2dSceneObject::startFadeOut(%this)
{ 
        %this.setBlendAlpha(1.0);  

        %this.schedule(50, fadeOut);
}

function t2dSceneObject::fadeOut(%this)
{   
      %alpha = %this.getBlendAlpha();

      %alpha -= 0.01; 

      if(%alpha < 0)
      {
      }
      else
      {
         %this.setBlendAlpha( %alpha );
         %this.schedule(50,fadeOut);
      }
}

function t2dSceneObject::startFadeIn(%this)
{ 
        %this.setBlendAlpha(0);  

        %this.schedule(50, fadeIn);
}

function t2dSceneObject::fadeIn(%this)
{   
      %alpha = %this.getBlendAlpha();

      %alpha += 0.01; 

      if(%alpha > 1)
      {
      }
      else
      {
         %this.setBlendAlpha( %alpha );
         %this.schedule(50,fadeIn);
      }
}

Fire up T2D and run the “testObject.startFadeOut();” function again from the console. You'll see it fade out like before. When it's done (be sure the object is completely faded) go back to the console and enter this command: “testObject.startFadeIn();”. Close the console and watch the object fade back in!

Excellent! We've got some basic fading in and out functions. Let's spruce them up a bit. These next steps will also show you how you can add usability and re-usability to functions like these.

First we'll change our startFadeOut function to look like this:

function t2dSceneObject::startFadeOut(%this, %speed, %blend)
{   

This way we pass it a %speed and %blend variable. We'll use %speed to control how much alpha gets altered each fade step and %blend will be the starting alpha-value (so we can start with a half faded object if we want). Next we will add:

        %this.fadingOut = true;

When we are starting a fade out, we set a fadingOut flag so we can check later if this object is fading out. In the next step we start to add a bit of clever functionality:

      if(%blend $= "")
      {
         %this.setBlendAlpha(1.0);
      }
      else if (%blend $= "current")
      {
          // Do nothing. Leave the alpha-value as it is
      }
      else
      {
         %this.setBlendAlpha(%blend);
      } 

First we check to see if the %blend argument is empty:

if(%blend $= "")

If it is, we set it to 1.0 as a fail safe. This way, if we don't specify a starting blend color, the function will set a default of 1.0 (full alpha). Next, we check to see if %blend is equal to the string "current". Note that “$=” is used for comparing strings, which is different from comparing numbers...

else if (%blend $= "current")

What we're doing here is allowing the user to pass “current” instead of a value for %blend. If this happens, we're going to leave the current blend value alone.
Finally we get to this,if the previous options didn't return true:

 } else
      {
         %this.setBlendAlpha(%blend);
      } 

This will set the alpha-value to the %blend we passed in. The last couple lines to finish up this revised function are:

        %this.schedule(50, fadeOut, %speed);
} 

We still schedule fadeOut, like before, but this time we pass in another parameter, “%speed”. This makes it so that when the schedule command calls fadeOut, it passes along the parameter (in this case, %speed). So your final startFadeOut should look like:

function t2dSceneObject::startFadeOut(%this, %speed, %blend)
{
      %this.fadingOut = true;
      
      if(%blend $= "")
      {
         %this.setBlendAlpha(1.0);
      }
      else if (%blend $= "current")
      {
          // Do nothing. Leave the alpha-value as it is
      }
      else
      {
         %this.setBlendAlpha(%blend);
      } 

      %this.schedule(50,fadeOut, %speed);
}

Cool. Now, let's modify the fadeOut function to operate with this new method. Here's the whole function, which we'll go over step by step:

function t2dSceneObject::fadeOut(%this, %speed)
{   
   if(%this.fadingOut)
   {
      %alpha = %this.getBlendAlpha();
      %alpha -= %speed;
      
      if(%alpha < 0)
      {
         %this.fadingOut = false;
         %this.onFadeOutEnd();
      } else
      {
         %this.setBlendAlpha( %alpha );
         %this.schedule(50, fadeOut, %speed);
      }
   }
}

First we check to make sure we're fading out:

if(%this.fadingOut)

Next, we do this:

      %this.blend -= %speed;

Here where the %speed argument comes in handy. Instead of always decreasing the blend by "0.01", we can now pass a number (when we call the startFadeOut function) that controls the speed that our object is blended at.

The next change is the addition of this call when our blend is finished:

       %this.onFadeOutEnd();

Here, we're creating a callback function. This allows you to put whatever needs to be done when an object is done fading into a function called “onFadeOutEnd”. A good example would be that you might want to delete the object, which is a common thing to do after something fades out.

The final change we made is:

         %this.schedule(50, fadeOut, %speed );

Here, we just added the %speed parameter to the schedule call. Next we're going to add a little function to stop a fade in the middle:

function t2dSceneObject::stopFadeOut(%this)
{
   %this.fadingOut = false;
}

Now you should have these three new functions that replace your old fading out functions:

function t2dSceneObject::startFadeOut(%this, %speed, %blend)
{
      %this.fadingOut = true;
      
      if(%blend $= "")
      {
         %this.setBlendAlpha(1.0);
      }
      else if (%blend $= "current")
      {
          // Do nothing. Leave the alpha-value as it is
      }
      else
      {
         %this.setBlendAlpha(%blend);
      } 

      %this.schedule(50,fadeOut, %speed);
}

function t2dSceneObject::fadeOut(%this, %speed)
{   
   if(%this.fadingOut)
   {
      %alpha = %this.getBlendAlpha();
      %alpha -= %speed;
      
      if(%alpha < 0)
      {
         %this.fadingOut = false;
         %this.onFadeOutEnd();
      } else
      {
         %this.setBlendAlpha( %alpha );
         %this.schedule(50, fadeOut, %speed);
      }
   }
}

function t2dSceneObject::stopFadeOut(%this)
{
   %this.fadingOut = false;
}

Now you can either copy and paste them over your fading in functions and change the appropriate names, like we did before. Here's what they'll look like when you're done:

function t2dSceneObject::startFadeIn(%this, %speed, %blend)
{
      %this.fadingIn = true;
      
      if(%blend $= "")
      {
         %this.setBlendAlpha(0.0);
      }
      else if (%blend $= "current")
      {
          // Do nothing. Leave the alpha-value as it is
      }
      else
      {
         %this.setBlendAlpha(%blend);
      } 

      %this.schedule(50, fadeIn, %speed);
}

function t2dSceneObject::fadeIn(%this, %speed)
{   
   if(%this.fadingIn)
   {
      %alpha = %this.getBlendAlpha();
      %alpha += %speed;
      
      if(%alpha > 1)
      {
         %this.fadingIn = false;
         %this.onFadeInEnd();
      } else
      {
         %this.setBlendAlpha( %alpha );
         %this.schedule(50, fadeIn, %speed);
      }
   }
}

function t2dSceneObject::stopFadeIn(%this)
{
   %this.fadingIn = false;
}

Okay now let's save things and fire up T2D. Bring up the console and type

testObject.startFadeOut(0.005);

This fades the box very slowly. Before it's completely faded out, enter this command to stop the fade in the middle:

testObject.stopFadeOut();

Here's where that "current" trick comes in handy. Run this command in the console:

testObject.startFadeIn(0.005, "current");

The box should start where you left off and slowly fade back in. If any of this doesn't work, compare your fading.cs to this:

function t2dSceneObject::startFadeOut(%this, %speed, %blend)
{
      %this.fadingOut = true;
      
      if(%blend $= "")
      {
         %this.setBlendAlpha(1.0);
      }
      else if (%blend $= "current")
      {
          // Do nothing. Leave the alpha-value as it is
      }
      else
      {
         %this.setBlendAlpha(%blend);
      } 

      %this.schedule(50,fadeOut, %speed);
}

function t2dSceneObject::fadeOut(%this, %speed)
{   
   if(%this.fadingOut)
   {
      %alpha = %this.getBlendAlpha();
      %alpha -= %speed;
      
      if(%alpha < 0)
      {
         %this.fadingOut = false;
         %this.onFadeOutEnd();
      } else
      {
         %this.setBlendAlpha( %alpha );
         %this.schedule(50, fadeOut, %speed);
      }
   }
}

function t2dSceneObject::stopFadeOut(%this)
{
   %this.fadingOut = false;
}

function t2dSceneObject::startFadeIn(%this, %speed, %blend)
{
      %this.fadingIn = true;
      
      if(%blend $= "")
      {
         %this.setBlendAlpha(0.0);
      }
      else if (%blend $= "current")
      {
          // Do nothing. Leave the alpha-value as it is
      }
      else
      {
         %this.setBlendAlpha(%blend);
      } 

      %this.schedule(50, fadeIn, %speed);
}

function t2dSceneObject::fadeIn(%this, %speed)
{   
   if(%this.fadingIn)
   {
      %alpha = %this.getBlendAlpha();
      %alpha += %speed;
      
      if(%alpha > 1)
      {
         %this.fadingIn = false;
         %this.onFadeInEnd();
      } else
      {
         %this.setBlendAlpha( %alpha );
         %this.schedule(50, fadeIn, %speed);
      }
   }
}

function t2dSceneObject::stopFadeIn(%this)
{
   %this.fadingIn = false;
}

These other variations of fading out will also work:

$obj1.startFadeOut(0.03);

You don't have to specify a blend color to start at, just a speed to fade at.

$obj1.startFadeOut(0.5, 0.7); 

This makes the object jump to alpha value 0.7, then fade out.

That concludes this tutorial. Hopefully you've learned a few useful tidbits, like extending the t2dSceneObject in script, using schedules, and creating your own "callbacks". Plus, you now have a nifty little fade in and out functionality.