Torque 2D/GenreTutorials/PlatformerGUI

From TDN

Contents

Introduction


In this tutorial, we will be replacing the in game interface so that it includes a life bar and shows the number of remaining lives. We will also create a menu, a level select dialog, and a game over screen.

There have been a couple of people doing work in setting up a GUI system using T2D’s sprites. You can create some really cool stuff with this, but it is more complex than using the standard Torque GUI system and there is no editor for it. So, we are going to go the conventional route and use the standard GUI editor. I am going to assume that you have read the basic GUI editor documentation and thus know your way around.





In Game Interface


First of all, you are going to need two image files for the life bar. One of them will be the outline, and one the fill. Here are the very simple images I made.

Image:PlatformerLifeBar.png

Image:PlatformerLifeBarOutLine.png

Either right click on each of these and save them as lifeBar.png and lifeBarOutline.png to the T2D/data/images directory, or create your own with the same names.

Now, start up the game and press F10 to open Torque’s GUI editor. Select File->New GUI from the menu which should bring up a dialog. In the GUI Name text box, type “gameHUDGui”, and select GuiControl from the Class list box, then press the Create button. You should see a blank turquoise-ish rectangle that is basically the canvas on which we will build.

Since we don’t want this GUI to be see-through where it doesn’t have controls, click on gameHUDGui from the tree view on the upper right. Now find the profile field in the inspector and change its value to GuiContentProfile. The screen should turn white. Now create a new t2dSceneWindow control by selecting it from the New Control list box. Click on the newly created control, change its profile to GuiContentProfile, and check the fitParentWidth and fitParentHeight check boxes.

Now create two GuiBitmapCtrls. Set one of the control’s bitmap field to T2D/data/images/lifeBar and the other’s to T2D/data/images/lifeBarOutline. Position and size them however you want, but keep them both the same. You will also need to name them LifeBar and LifeBarOutline respectively.

The last control we will create is a GuiTextControl. This will show the number of lives the player currently has. Create the control and position it wherever you want. You’ll probably want to set the profile to GuiBigTextProfile or to a profile of your own creation. The afore linked GUI editor tutorial should cover profile creating. To make it track the player’s lives, set the variable field to $player.lives.

That’s it for this GUI, so select Save from the File menu and save it as gameHUD.gui to the T2D/data/gui directory. Now we need to set up the interaction between the game variables and our new GUI elements.

of course, we have to exec this file in the usual spot:

   exec(“~/data/gui/gameHUD.gui”);

Also in the client.cs file, change the line

   Canvas.setContent(mainScreenGUI);

to

   Canvas.setContent(gameHUDGui);

Now open player.cs and add this line to the resetPlayer function:

   LifeBar.extent = LifeBarOutline.extent;

This is resetting the size of the life bar to equal the size of the life bar outline, effectively displaying full life. Updating the length of the life bar when the player gets hit is similar. Add this to the end of the playerHit function:

   %newX = getWord(LifeBarOutline.extent, 0) * ($player.life / 100);
   LifeBar.extent = %newX SPC getWord(LifeBar.extent, 1);

This will set the length of the life bar proportionately to the length of the life bar outline based on the amount of life the player currently has.






Menu Screens


The first thing we need to do is restructure the client.cs file. As it is now, the in game interface is the first gui that is shown. We need to change that. Open client.cs and change these three lines:

   Canvas.setContent(gameHUDGui);
   Canvas.setCursor(DefaultCursor);
   setupT2DScene();

to this:

   loadT2DIntro();

This new function will eventually set the T2D splash screen. For now, we are going to use it to load the main menu. We will define it after we create the actual gui. Before we do that, let’s finish off the client.cs changes. We are going to need exec statements for each of our GUIs. Here they are:

   exec("~/data/gui/t2dIntro.gui");
   exec("~/data/gui/mainMenu.gui");
   exec("~/data/gui/levelSelect.gui");
   exec("~/data/gui/levelIntro.gui");
   exec("~/data/gui/gameOver.gui");

We will also be creating a new file called gui.cs that manages all the GUI transitions and such. Add its exec statement as well:

   exec("./gui.cs");

Since we aren’t going to be starting the actual game right at engine startup, we need start game and end game functions and we can get rid of the setupT2DScene function. Here are the functions and a variable declaration:

$gameStarted = false;

function startGame()
{
   if ($gameStarted)
      return;
   
   $gameStarted = true;
   
   new t2dSceneGraph(t2dScene);
   sceneWindow2D.setSceneGraph(t2dScene);
   sceneWindow2D.setCurrentCameraPosition("0 0 100 75");
   
   createPlayer();
   createCamera();
}

function endGame()
{
   $gameStarted = false;
   
   if (isObject($camera))
      $camera.delete();
      
   if (isObject($player))
      $player.delete();
      
   if (isObject(t2dScene))
      t2dScene.delete();
}

The $gameStarted variable just tracks whether or not the actual game has started (not just the menus). The first thing we do in startGame is make sure the game isn’t already started. Starting it again would make no sense. The rest is basically the same as setupT2DScene.

The endGame function just deletes the objects we created in startGame if they exist. Replace the contents of the destroyClient function with a call to endGame so everything is cleaned up when the engine is shutdown:

function destroyClient()
{
   endGame();
}

Now create the gui.cs file and add these functions to it:

function loadT2DIntro()
{
   Canvas.setCursor(DefaultCursor);
   loadMainMenu();
}

function loadMainMenu()
{
   Canvas.setContent(MainMenuGUI);
}

For now, loadT2DIntro is just passing things on to loadMainMenu, which sets the MainMenuGui that we are now creating.

The MainMenuGui is going to consist of a background image and four buttons that start the game, quit, open the options dialog, and open the level select dialog. So first create yourself a background image and save it as menuBackground.png to the client/images folder. Now open up the GUI editor, select File->New GUI from the menu, and set the Class to GuiBitmapCtrl and the name to MainMenuGui.

Since my goal here isn’t so much to show how to create nice looking GUIs as much as to show how to use said GUIs, this menu is going to be purely functional and probably pretty ugly. The concepts apply equally to ugly and pretty GUIs, though. So, create four GuiButtonCtrls and place and size them however you want. Set the text fields to “Play”, “Level Select”, “Options”, and “Quit”, and the command fields to “loadFirstLevel();”, “Canvas.pushDialog(LevelSelectGui);”, “Canvas.pushDialog(OptionsDlg);”, and “quit();”. Save this gui to the gui folder as mainMenu.gui.

Now add this function to gui.cs:

function loadFirstLevel()
{
   startGame();
   loadLevel("~/data/levels/testLevel.cs");
}

Go ahead and run the game to make sure everything is as expected. The quit button should quit the game, the options button will open the T2D default options dialog, and the play button will start the game. Now let’s hook up the level select dialog.






Level Selection Dialog


The level select dialog will probably not make it into your final game, but it can be very useful for testing by letting you access any level at any time. Most of the functionality will be provided with code, but we do need a simple gui to interact with, so open up the GUI editor again.

Create a new gui (File->New GUI) and name it LevelSelectGui with class GuiControl. Now create a GuiWindowCtrl and set up its parameters however you see fit. Right click on the new GuiWindowCtrl, then create a new GuiScrollCtrl and two new GuiButtonCtrls. Position the buttons at the bottom of the GuiWindowCtrl and set the text fields to “Play >>” and “<< Back” and the command fields to “loadSelectedLevel();” and “Canvas.popDialog(LevelSelectGui);”. Position and size the GuiScrollCtrl to fill the remaining space in the window control. Now, right click on the GuiScrollCtrl and create a GuiTextListCtrl. Name it “LevelSelectList”, assign it the “GuiTextListProfile” and size it to fill the GuiScrollCtrl. Save this gui as “levelSelect.gui” in the gui folder.

To hook up the actual functionality of this GUI, add these functions to gui.cs:

function LevelSelectGui::onWake()
{
   %levelSpec = "~/data/levels/*.cs";
   LevelSelectList.clear();
   %row = 0;
   for(%file = findFirstFile(%levelSpec);
      %file !$= ""; %file = findNextFile(%levelSpec))
      LevelSelectList.addRow(%row++, fileBase(%file) TAB %file);
   
   LevelSelectList.sort(0); 
   LevelSelectList.setSelectedRow(0);
   LevelSelectList.scrollVisible(0);
}

function loadSelectedLevel()
{
   %id = LevelSelectList.getSelectedId();
   %level = getWord(LevelSelectList.getRowTextById(%id), 1); 
   startGame();
   loadLevel(%level);
}

The onWake function will be called automatically by the engine anytime the LevelSelectGui is activated (i.e. by the Canvas.pushDialog function). Its purpose is to populate the level list with all of the levels in the game. The levels are found by scanning the levels folder. First we set up the file spec which we will use to tell certain functions which files we want to know about (cs files in the levels folder). Then we clear the list in case we are setting the gui a second time. The for loop just loops through every file that matches our file spec and adds it to our LevelSelectList.

The loadSelectedLevel function grabs the filename that we have selected in the dialog, and passes it onto the loadLevel function to load it.

Any .cs file you put in the levels folder will now show up in this gui. Weird things will happen if you try to load a cs file that is not a valid level file, so don’t.






Splash Screens


Any game you release with T2D requires that you have a T2D logo in the startup sequence. We will now create one of these, as well as a game over screen. These are both extremely simple, consisting of one gui control each. First the T2D splash screen.

Create a new gui in the gui editor as a GuiFadeinBitmapCtrl named T2DIntroGui. Now just set the bitmap field to “T2D/data/images/logoWhite”, the fadeinTime and fadeoutTime fields to 125, and the waitTime field to 3000. Save it as t2dIntro.gui.

Now change the loadT2DIntro function to this:

function loadT2DIntro()
{
   Canvas.setCursor(DefaultCursor);
   Canvas.setContent(T2DIntroGui);
   $GUISchedule = schedule(3250, 0, "loadMainMenu");
}

With this function, we are setting the T2DIntroGui and scheduling the main menu to load in 3.25 seconds. The schedule is being assigned to $GUISchedule so it can be canceled by this:

function T2DIntroGui::click()
{
   cancel($GUISchedule);
   loadMainMenu();
}

This just allows us to end the splash screen early with a mouse click or keypress.

The game over splash screen is very similar. You will need an image to set as the background. Create one and save it as gameOver.png.

Create the gui just like the T2DIntroGui, except name it GameOverGui, set the bitmap field to “T2D/data/images/gameOver” and save it as gameOver.gui.

Add this click handler to gui.cs:

function GameOverGui::click()
{
   cancel($GUISchedule);
   loadMainMenu();
}

And to set this gui, change this line in the playerDie function of player.cs:

      echo(“Game Over”):

to:

      schedule(1000, 0, "gameOver");

And add this function to level.cs:

function gameOver()
{
   Canvas.setContent(GameOverGui);
   $GUISchedule = schedule(3250, 0, "loadMainMenu");
   endLevel();
   endGame();
}

That should be enough to get you started creating all sorts of GUIs for your games. T2D’s GUI system is extremely powerful and this tutorial barely scratched the surface of what it can do. There are a bunch of other tutorials and such to help you in this area, and you should be able to experiment on your own to figure out more and make things look nicer.

That’s it for the official tutorials on the subject of platformers, but be sure to check the additional topics section for more platformer related functionality. And, if you add something to your project not in this tutorial, consider adding to the additional topics section for the rest of the world to see.