TGB/MiniPlatformerTutorial

From TDN


Spanish language version of this tutorial available here.

Contents

Basic Platformer mechanics in 100 lines of script or less

The premise of this tutorial is to provide a quick and painless set of steps to get basic platformer game mechanics in TGB in under 30 min and under 100 lines of script.

Setting up the Project

To start, open up TGB (by clicking the TGB icon on your desktop). By default, the Level Builder will start with the last project that was loaded. This makes it really easy to pick up where you left off. If you have been playing around with the Level Builder before reading this you will see whatever you worked on last.

Image:1-1_newProject.png

Image:1-2 newProject.png

Figure 1.1Figure 1.2

To create a new project, select "New Project…" from the File menu. When you do this, the New Project dialog will appear. For the purposes of this tutorial we will call this project "miniPlatformer" (Figure 1.2). This will bring up the level builder (Figure 1.3).

Image:1-3_levelBuilder.jpg


Figure 1.3

Now save the project, this will create the projects directory structure inside your TGB/games folder. You will be prompted to save your level even though you haven't added anything yet. Save the level as "level1.t2d" (figure 1.4).

Image:1-4 saveLevel.PNG
Figure 1.4

Importing Art

It's time to start adding the content we will use in our platformer. Because we are trying to keep things simple we will only add two image files to the project. Copy the following two images to your ./games/miniPlatformer/data/images folder (Figure 2.1) (Figure 2.2).

Image:Player.png
Figure 2.1

Image:MiniTileMap.png
Figure 2.2

With that done we are now ready to import those images into the LevelBuilder. Click the "Create a new ImageMap" icon on the right sidebar (Figure 2.3). You will be prompted to pick between the two images we added to our images folder. Select the "MiniTileMap.png" file from the list. You will see a preview of it in the right panel of the dialog (Figure 2.4). Click the "Select" button to bring up the Image Builder dialog.

Image:2-3 addImageMap.png
Figure 2.3

Image:2-4 imageSelect.png
Figure 2.4

On the Image Builder dialog change the Image Mode to "CELL" You'll notice how this nicely separates the tiles into four separate chunks (Figure 2.5). This will be important later when we go to build our tile map.

Image:2-5 cell.png
Figure 2.5

Repeat the process for "Player.png", adding it as a new image map and then picking "CELL" for the Image Mode. You'll notice that things don't look exactly right this time. It appears that there are four player images per cell. To fix that we need to edit the "Cell Width" and "Cell Height" properties so they both read "128" (Figure 2.6).

Image:2-6 cellSize.png
Figure 2.6

Creating Animation

In this section we will create four animations for our player from the player1ImageMap. They are...

  1. playerRun
  2. playerJumpUp
  3. playerJumpDown
  4. playerStand

Some of these animations will only have one frame, but you will see how we could easily add more. Lets start with the Run animation since it's the most interesting. Start by clicking the "Create a new Animation" icon (Figure 2.7). On the Select Source dialog that appears choose "PlayerImageMap" and click "Use Selected ImageMap" (Figure 2.8). After that you will be presented with the animation builder dialog. Here you can drag frames from the imageMap onto animation time line.

Image:2-7 addAnim.png
Figure 2.7

Image:2-8 pickMap.png
Figure 2.8

Drag frames 4 to 11 from the imageMap onto the animation timeline, one after the other. When you have finished you should have something that looks like (Figure 2.9). Preview the animation to see if it seems intact and then save the animation as "playerRun".

Image:2-9 anim.png
Figure 2.9

The remaining animations are built in the same way except that they only have one frame of animation (in your own project you could add more). The list below shows what animations to create and what frames to assign them.

  1. playerJumpDown - Frame 0
  2. playerJumpUp - Frame 1
  3. playerStand - Frame 2

Create the remaining three single frame animations. When you are done your Animated Sprites rollout should look something like (Figure 2.10).

Image:2-10 sprites.png
Figure 2.10

Building a level

Now we will build a simple tileLayer for our level. Drag and drop the newLayer.lyr object from the Tilemaps rollout onto your scene (Figure 3.1). Once you've placed it on the scene you'll have to customize it a little to make it work with the rest of our art.

Image:3-1 tileMaps.png
Figure 3.1

With the tileLayer selected in the scene, click the Edit button on the right sidebar we want to edit the TileSize properties of the Tile Map. Set the X and Y Tile Size properties to 32 (Figure 3.2). This will make the tiles large enough to work well with our player art. It's easier to resize the entire tile map than to individually resize each player animation.

Image:3-2 tileSize.png
Figure 3.2

Image:3-3 before.png
Figure 3.3 (before)

Image:3-4 after.png
Figure 3.4 (after)

(Figure 3.3) and (Figure 3.4) show the tileLayer before and after setting the Tile Size.

Now we have a tile layer but it appears to be only big enough to hold one tile. We need to resize the TileLayer to cover the screen area. Using the blue control boxes, reposition and resize the tile layer such that it covers our camera's view. You can use the mouse wheel to zoom the scene view in and out to get enough room to resize the tile layer. Once your done your scene should look something like (Figure 3.5).

Image:3-5 resize.png
Figure 3.5

It's time to explore TGB's Tile Map editor. Hover your mouse over the tile layer in our scene until the set of action buttons appears at it's top left corner. Click the "Edit this Tile map" button (Figure 3.6). This will bring up the Tile Editor in the right sidebar (Figure 3.7).

Image:3-6 editMap1.png
Figure 3.6

Image:3-7 editMap2.png
Figure 3.7

From the Image drop down select MiniTileMapImageMap. Notice how a small "Frames" button appears below the image drop down showing 0 (Figure 3.8). This means that MiniTileMapImageMap contains multiple tiles. By default the first tile in the ImageMap is displayed on the right sidebar.

Image:3-8 image.png
Figure 3.8

Click the "Frames" button and select a good background tile (Figure 3.9). This tile will be behind our player as he runs around the level. We will fill the tilemap with these background tiles and then paint our platform tiles over-top.

Image:3-9 bgTile.png
Figure 3.9

Now use the "Flood fill" tool to fill the tile map (Figure 3.10) with background tiles. To place platform tiles we can use the "Paint" tool (Figure 3.11) to paint individual platform tiles onto the tilemap. The difference between platform tiles and background tiles is that the player can collide with platform tiles. Select a good platform tile from the available frames and make sure "Collision" is checked (Figure 3.12). This will enable our player to walk on and collide with these tiles.

Image:3-10 flood.pngImage:3-11 paint.png
Figure 3.10 (Flood)Figure 3.11 (Paint)

Now "Paint" some platform tiles onto the tile map to create a 'base' for your player to stand on.
Image:3-12 coll.png
Figure 3.12

Once you've finished you should have something that looks like (Figure 3.12). You'll notice that the platform tiles have a green border. This means that collisions are turned on for those tiles. Make sure all the tiles you want the player to interact with have collisions turned on and are displayed with green borders. If they are not, ensure the "Collision" checkbox is Checked and redraw the Tiles again.

Image:3-13 finished.png
Figure 3.13

The last thing to be done is to enable collision events on the tile map so that the player will respond to collisions when they occur. Expand the "Collisions" rollout with the tile layer still selected and set the collision properties to macth the figure below (Figure 3.14)

. Image:3-14 coll.png
Figure 3.14

Now save the tile layer as "layer1.lyr" and you are done.


The following step is ENTIRELY OPTIONAL; it is purely a cosmetic change. Feel free to skip to the next section [1].

There are times when you may not want a tiled background for your level, but instead a static picture. TGB gives you a lot of different ways to control how you build and display your levels. If you are unhappy with the repetitive patterns in the background tiles you could erase them and replace the background with a static image behind our tile layer.

To do this erase the background tiles we placed before using the "Eraser" tool, and leave those tiles transparent, as in (Figure 3.15).

Image:3-15 erase.png
Figure 3.15

Import the following image into the project by clicking the "Create" button on the right sidebar. Add the image the same way we did with the player and the tile images. When creating the ImageMap select "FULL" for the Image Mode.

Image:Background.png

Now drag and drop the background image onto the level, at first the image will appear on top of our tile layer. To send it to the background click the "Edit" button in the right sidebar, then locate the "Scene Object" rollout and change the image's render Layer to 30 (the render layer is visible in (Figure 3.16)). You may have to resize the image a bit to get it exactly behind the tilemap and looking good.

Image:3-16 bg.png
Figure 3.16

Creating a Player

The majority of the rest of the tutorial is going to be spent scripting the actions that will make our platformer work. But before we do that we need to add an object to our scene that will be the starting point for our player. From the "Animated Sprites" rollout in the "Create" section of right sidebar, drag the "playerStand" animation out onto the level. Try to position it as if the player was standing on a platform tile as shown in (Figure 4.1).

Image:4-1 player.png
Figure 4.1

Next hit "Edit" on the right sidebar to change some of the animation's properties. We are going to be looking at the "Scripting" rollout, we want to make this "playerStand" animation the main object that represents our player in script. Set the Class to "playerClass" and the Name to "pGuy" as show in (Figure 4.2).

Image:4-2 scripting.png
Figure 4.2

Now we need to turn on some collision detection for our player object. To do this edit the settings of the "Collision" rollout so that they look like those in (Figure 4.3).

Image:4-3 coll.png
Figure 4.3

With that done we are now ready to begin scripting the movement for our player object.

Keyboard Input

It's time to write a script that will control the actions of our player. In your "[i]./games/miniPlatformer/gameScripts[/i]" folder create a file named player.cs. Open this file with a text editor and add the following function at the beginning of the file.

function playerClass::onLevelLoaded(%this, %scenegraph)
{
     $pGuy = %this;
      
      moveMap.bindCmd(keyboard, "left", "playerLeft();", "playerLeftStop();");
      moveMap.bindCmd(keyboard, "right", "playerRight();", "playerRightStop();");
      moveMap.bindCmd(keyboard, "space", "playerJump();", "");
}

The playerClass::onLevelLoaded() function is called whenever an object with a class type of "playerClass" is loaded into the scene. If you recall when we were editing the Scripting properties of our player we set the Class field to "playerClass". That means when TGB loads our level with our player animation it will call this function.

The first line of the function stores a reference to the object being loaded to a global variable named $pGuy that we can use to reference the player in other functions.

Next you can see that we are binding the left and right arrow keys as well as the spacebar, when these keys are pressed or released they call their corresponding functions. For example, when the the left arrow key is pressed, the "playerLeft()" function will be called, when it is released the "playerLeftStop()" function will be called. We can use these functions to track what the player should be doing.

Let's add those key handler functions now.

function playerLeft()
{
    $pGuy.moveLeft = true;
}

function playerLeftStop()
{
    $pGuy.moveLeft = false;
}

function playerRight()
{
     $pGuy.moveRight = true;
}

function playerRightStop()
{
     $pGuy.moveRight = false;
}

function playerJump()
{

}

Here we are using that $pGuy variable we initialized in playerClass::onLevelLoaded() to store the movement state of the player. Just by using the .moveRight and .moveLeft members on the $pGuy object, we are adding them as playerClass dynamic variables, so that we can use them later.

Note: We are using a global variable, $pGuy, to communicate to our playerClass object from the functions bound to the keyboard (playerLeft(), playerLeftStop(), etc.). This means that there can be only one playerClass object in existence. If we wanted to have a game that could include more than one such object, we would have to do this part differently.

Player Movement

Great! Now we are tracking the keystates. But that doesn't really get us anywhere in terms of a game. We need our player to respond to those keystates and actually MOVE!

Let's add a movement handler function to take care of those keystates.

function playerClass::updateHorizontal(%this)
{
     if(%this.moveLeft)
     {
          %this.setLinearVelocityX(-60);
     }

     if(%this.moveRight)
     {
          %this.setLinearVelocityX(60);
     }

     if(!%this.moveLeft && !%this.moveRight)
     {
          %this.setLinearVelocityX(0);
     }
}

You'll notice our function is named with the "playerClass::" namespace identifier. This means that this function will work with any object who's class variable is set to "playerClass". What this function does is check the state of the moveLeft and moveRight class members and assigns a linear velocity to the object if it finds either to be true. If neither left nor right are pressed, we want to be sure to stop the player from moving. To do this we set the x velocity to 0.

Note: We have not defined what happens if both buttons are pressed. Currently, because of the order of our if statements, pressing both keys results in movement towards the right.

Previously we created a playerJump( ) function but it didn't do anything, let's now edit that function and add the following line.

function playerJump()
{
     if(!$pGuy.airborne)
     {
          $pGuy.setLinearVelocityY(-225);
          $pGuy.airborne = true;
     }
}

Now what happens is that any time you press the jump button a new boolean variable, "airborne" is checked. If "airborne" is false (you are on the ground) and and you your player will be given a considerable Y velocity straight up. (Notice that negative Y values in Torque move upwards on the screen.) The "airborne" variable is then set to true as we have just jumped.

For the final step, we want to continuously adjust the direction in which our player is moving based on what state the keys are in. To do this we need to call an updateMovement( ) function all the time. Add the following function to the end of your player.cs file.

function PlatformerSceneGraph::onUpdateScene()
{
     if (isObject($pGuy))
          $pGuy.updateMovement();
}

Additionally you will need to name your games SceneGraph object "PlatformerSceneGraph" by editing the "Name" textbox in the Scene Graph Scripting rollout. You can access this rollout by going into edit mode without any scene objects selected.

This handles the updateScene event of the t2dSceneGraph, the basic object responsible for managing our game's appearance. Every time it updates we want our movement updated so we call updateMovement( ) here. But wait a minute! We haven't defined updateMovement( ) yet. Add the updateMovement( ) function just below the updateHorizontal( ) function.

function playerClass::updateMovement(%this)
{
     %this.updateHorizontal();
}

updateMovement( ) is an important function. In previous versions of this tutorial it became long-in-the-tooth and difficult to read. We keep the code clean and maintainable by using it as a dispatcher for more specific functions.

We are just about ready to test our movement code for the first time. Before that, however, we need to tell TGB to load our player.cs file when we run the game. To do that locate the game.cs file in the same folder as your player.cs file. Open the game.cs file and add the following line to the top of the startGame function.

 exec("./player.cs");

When you are done the startGame function should look something like the following.

function startGame(%level)
{
      exec("./player.cs");

      // Set The GUI
      Canvas.setContent(mainScreenGui);
      Canvas.setCursor(DefaultCursor);
   
      moveMap.push();
   
      if( isFile( %level ) || isFile( %level @ ".dso"))
            sceneWindow2D.loadLevel(%level);
}

In order for TGB to load the file for the first time it will have to be restarted. Save your work if you haven't already and re-open the miniPlatformer project. Once you've done that you are ready to test your code. To try out your demo level hit the "Play" button in TGB (Figure 5.1).

Image:5-1 play.png
Figure 5.1

After playing around you'll notice some things are not quite right. The player slides left and right, but he doesn't seem to be falling. Then if you jump he just flies off the screen and never returns. It seems like we need to add some gravity to pull him down to earth. Fortunately TGB has a built in physics system to handle these kinds of things. Select your player and go to the "Edit" tab on the sidebar, edit the "Physics" rollout settings so they look like the following (Figure 5.2).

Image:5-2 grav.png
Figure 5.2

You'll notice the Constant Force Y has been set to 100, this applies a 100 unit force down on our player all the time. This acts like gravity pushing him back down after he jumps up. It's also what pushes him down when he walks off the edge of a platform. Force Scale just increases the affect of the gravity on the player making the equation a little less floaty and a little more like a jump. You can play with these until you get them how you like.

Go ahead and test the level.

Right off the bat you notice that your player object settles nicely onto the floor when the level starts. Then when you jump or walk off a platform he falls back down to earth like you would expect. But other weird things have started to happen. For one you can only jump once. This is because you don't yet set the "airborne" flag back to false, resetting the jumping ability. Sometimes it feels like the player is walking through mud and when you walk into a corner the player bounces around oddly and can get stuck. The reason for this is that TGB has a very sophisticated physics model, it simulates friction and all kind of other forces that we really don't want to handle. We really want the gravity physics to work for us when the player object is in the air, but not when it is on the ground walking around.

To fix this we are going to have to do a little scripting and actually take care of vertical movement.

Open up the player.cs file and append the following code to the end of the updateMovement( ) function

     %this.updateVertical();

Next you will need to add the script for the updateVertical( ) function. Don't be intimidated by the code. It's actually pretty straightforward! Add the updateVertical( ) function just below the updateHorizontal( ) function.

function playerClass::updateVertical(%this)
{
     %yVelocity = %this.getLinearVelocityY();

     if(%this.airborne)
     {
          %this.setLinearVelocityY(0);
          %collision = %this.castCollision(0.005);

          if(%collision !$= "")
               %this.setLinearVelocityX(0);
     }

     %this.setLinearVelocityY(100);
     %collision = %this.castCollision(0.005);
     	
     if(%collision $= "")
     {
          %this.airborne = true;
          %this.setConstantForceY(100);
     }
     else if(%yVelocity < 0 && %this.airborne)
     {
          %this.setConstantForceY(100);
     }
     else
     {
          %this.airborne = false;
          %this.setConstantForceY(0);
     }

     %this.setLinearVelocityY(%yVelocity);
} 

Let's go over this function section by section. The first thing we do is store the player's current Y velocity in a local variable (delineated by the percent sign in front of yVelocity). We then move on to the next section:

     if(%this.airborne)
     {
          %this.setLinearVelocityY(0);
          %collision = %this.castCollision(0.005);

          if(%collision !$= "")
               %this.setLinearVelocityX(0);
     }

This block of code and its location in the script are extremely important. First, we check to see if we are in the air. If so, we set the Y velocity to 0. This lets us do a collision check using castCollision( ) to see if we are running into anything directly right or left of our player. castCollision( ) takes a single parameter that defines how far in the future to check. Because we want to use this collision test to decide when to turn off our horizontal velocity when we are right next to a wall or platform, we use a very small unit of time.

If we find a collision directly to the left or right of us we want to set our linearVelocityX to 0 to keep us from repeatedly pushing into the wall and potentially getting stuck. (Note: This code helps fix a wall climbing issue that users of earlier versions of this tutorial experienced.) The rest of updateVertical( ) will handle the physics settings that govern vertical movement.

Now we do the same thing with castCollision( ) for the Y direction: we temporarily set a large Y velocity to test and see if we are hitting anything below us. We save the collision, if any, in the local "collision" variable and move into the next if statement:

     if(%collision $= "")
     {
          %this.airborne = true;
          %this.setConstantForceY(100);
     }

If there is no collision resulting from castCollision() then we know that the player is entirely airborne and it's time to turn on gravity. To do this we set airborne to true and set the Constant Y force to 100.

If there is collision then we move into the else-if:

     else if(%yVelocity < 0 && %this.airborne)
     {
          %this.setConstantForceY(100);
     }

This block checks for movement in the upwards direction and to see if we're airborne. If so we turn on gravity. Without this code you could walk into a wall, jump, and launch straight up until the wall ran out.

If we do find a collision and don't happen to be in the special case above then we know that we are on solid ground. As such we set "airborne" to false and turn off gravity by setting the Constant Y force to 0.

     else
     {
          %this.airborne = false;
          %this.setConstantForceY(0);
     }

In the last line of the function we know that we are done with our tests and can simply restore the Y velocity. Actual movement will be handled by the physics engine according to the constantForce that we set throughout updateVertical( ).

Now go and test the level.

Great, we're almost done! Sometimes the TGB can get a little sloppy in it's physics calculations. This is prone to show up when two objects get really close. For a lot of game systems this would be a major bug, but TGB provides an easy way for us to tell the physics on the player to be a little more careful.

Open up the player.cs file again and locate the playerClass::onLevelLoaded function. At the end of this function append the following line of code.

     %this.setCollisionMaxIterations(2);

This tells the physics to check a little more carefully when calculating collisions on our player. Go ahead and test the level again.

(Note: You may notice, depending on how you built your level, that the player sometimes gets stuck going though a narrow gap that at first appears he should fit through. This is because the bounding box for our player is a big box. To fix this problem you can edit the bounding box of the player and there are doc's on TDN that tell you how to do this.)

Awesome, now the guy is hopping around and there's no stickiness.

One last thing before we close this section. If you do decide to include ramps or sloped surfaces in your platformer, you may experience weird hops when letting go of a movement key while going up the ramp. The following code will fix this and will hopefully give you an idea of how to start thinking about similar bugs that you may encounter later on. Add the following to the last if statement in updateHorizontal( ).

          if(!%this.airborne)
               %this.setLinearVelocityY(0);

This code will ensure that we stop moving completely when we let go of movement keys on a ramp. Cool. Time to get the screen to scroll with our player.

Scrolling Camera

Normally a topic like this would require it's own section, so I gave it one to make it easy to find from the table of contents. But the fact of the matter is that TGB makes scrolling the camera really easy. All we have to do is mount the camera to our player and that can be done with a single line of code. We'll do it in two for clarity's sake. add the following lines of code to the end of playerClass::onLevelLoaded()

   %force = 20;
   sceneWindow2D.mount($pGuy, "0 0", %force, true);

Here we are telling the sceneWindow2D object to mount on our player $pGuy. "0 0" are the x and y offsets of that mount, and %force is the force that can be exerted pulling the camera around. We set it to 20, but you could set whatever you want. Lower numbers mean the camera will slowly follow the player around, higher numbers mean it will stick very rigidly to the player.

Go ahead and test the level, you should find the camera moving nicely with the player.

Animating the Player

So now that we have all the mechanics working, it's time to make our player animate. He looks kinda dumb running around the level in his stand frame facing right. In order to animate according to the movement onscreen, we will need to know how our player is currently moving. Add the following function to the player.cs file right above PlatformerSceneGraph::onUpdateScene().

function playerClass::setCurrentAnimation(%this)
{
     %xVelocity = %this.getLinearVelocityX();
     %yVelocity = %this.getLinearVelocityY();

     if(%xVelocity > 0)
     {
          %this.setFlip(false, false);
     }
     else if(%xVelocity < 0)
     {
          %this.setFlip(true, false);
     }
}

setFlip flips the orientation of our player object in the X and Y directions. When we are moving to the left we want to flip the art since all our art is facing right. When we move to the right we want to undo that flip so we call setFlip again with false to undo it.

Now lets add the jump animation.

Append the following code to the end of the setCurrentAnimation( ) function.

     if(%this.airborne)
     {
          if(%yVelocity < 0)
          {
               %this.playAnimation(playerJumpUp);
          }	
          else
          {
               %this.playAnimation(playerJumpDown);
          }
     }
     else
     {
     }

This code is extremely straightforward. We check that we are airborne. If so, we check the direction of our vertical velocity and animate appropriately. If not, we do nothing... yet.

The only thing left to animate is the standing and running! Lets take care of that by filling in that empty else statement. Put the following code inside the brackets of the empty else statement that we added above.

          if(%xVelocity == 0)
          {
               %this.playAnimation(playerStand);
          }
          else
          {
               if(%this.getAnimationName() $= "playerRun")
               {
                    if(%this.getIsAnimationFinished())
                    {
                         %this.playAnimation(playerRun);
                    }
               }
               else
               {
                    %this.playAnimation(playerRun);
               }
          }

If we reach this code then we are on the ground and want to animate properly. This code will set the active animation on our player based on the state of the player objects current horizontal velocity. First we check to see if the player is standing still. If he is, we set the animation to "playerStand". If he's not standing still then we know he is on the ground and running. The first thing we do is check to see if the "playerRun" animation is already playing. If the animatino is already playing it waits for it to finish before it tells it to play again. IIf the player is playing some other animation then it immediately tells the run animation to start.

We need to call this function from somewhere however. We want the animation to update whenever the movement updates so we will add a call to setCurrentAnimation( ) to the updateMovement( ) function. Append the following to the end of the updateMovement( ) function.

     %this.setCurrentAnimation();

Now you can play your level and see your guy running and jumping around, all properly animated.

If everything is working you are done, basic platformer functionality in around 100 lines of script. This should give you a good idea of how to start making your own platformer game using TGB.

If you performed the optional step when creating the level your platformer should look something like this...

Image:Finished.png

Stipulations, Caveats, and where to go from here

This tutorial is designed to give you a sense of what goes into a very basic platformer. If you have read this far then you have certainly learned a lot! Hopefully you're still chomping at the bit for more.

This tutorial should act as a spring board for your project, not a template. It does many things well but does not do everything. The tutorial, for instance, does not cover importing sloped surfaces.

The code in this tutorial was written with expandability in mind. Sloped surfaces can indeed be imported and used with the code from this tutorial but they are not perfect. You will experience some awkward quirks that you are encouraged to work out on your own and with the help of the community through the TGB forums. Some quirks include hopping at the top of any ramp, unclean movement down ramps, and some fun functionality when both left and right are pressed while on a ramp. Further, you must exercise extreme caution when importing your ramp into a level as even a tiny discrepancy in collision polygons between platform and ramp can cause your character to experience a collision instead of smooth movement. This is just an example of the issues you might bump up against when using this tutorial as a diving board for platformers in TGB.

The point is that this tutorial should not be viewed as a design document for your game. The Platformer is one of the most common genres in video gaming and the variety is endless. Does your design call for Sonic style gameplay with loops and uneven surfaces? Are you shooting for a Mario-esque style platformer where continuous sloped surfaces are less frequent? Or maybe your game design takes you into untested and exciting new territory.

Whatever your case may be, you are encouraged to take what you learn from this tutorial and run with it. If you get stuck, do not hesitate to ask in the forums. The community is growing every day and is very willing to help you out.

Now get out of here and make your game!




Mini Platformer Update

- by Wicked Sunny 24.06.2007


Ok no one updated this tutorial for a long time, so I am taking on my head to update it.

Many noobs including me had serious problems with the polygon collision of the ninja with tiles in this tutorial.

I have been working on it from last 2 days and have found few solutions, they are not perfect yet but solves most of the big headaches. I am not a programmer and hence do not expect scripting from my side, this is more or less TGB based solutions.

First the problems

1) If keep pressing the right( or left arrow key) against the side of the tile, slowly slowly the ninja starts rising until he jumps over the tile, without pressing the jump button. Literally gliding over the blockage.

2) When the player jumps and touches a wall ( more then one tiles) sometimes it just sticks to the wall.

3) When the ninja falls in between two tiles( say a pit) most of the time it sticks to the wall, sometimes even on the edge of the tile in a very unreal manner.


Solutions

Image:Scene-object.jpg Image:Scene-object2.jpg

First after making your tile map, DO NOT SELECT THE COLLISION BOXES. Yes we are not going to use it. :) 

Instead drag the scene object from the Others window in the Create menu. It is invisible. Now scale it and place it block wise on top of your tiles ( which you wanted as the platforms) in a different layer then the tile map. You will have to use many of them on top of separate blocks of tiles. In the image above each green collision block is a separate scene object. Now apply the collision boxes which we were supposed to apply on the tile map on these scene objects, to save time you can even clone them.

This will automatically solve the first problem.

Now 2nd and 3rd solution is mostly based on the character sprite.


Standing Ninja Sprite used here is a big problem, always create a much straighter sprite design then this one.

the main reason it sticks to the wall is because of this shape and the collision polygon points this shape creates.

I used the following collision points for especially standing ninja sprite -

Image:Ninja-polygons.jpg

This has advantages and disadvantages - advantage is that it will not stick , but a part of the image will appear going inside the tile. I liked this because it made it appear a bit 3d like, but if you wanna avoid it, be sure your sprites are designed properly.

Below image is of the character not sticking, if it sticks it will have standing sprite and not jumping animation. Check out the the collision points on the leg, they are in exact straight line , if one is jutting out in a angle the ninja might stick to the wall. If your character still gets stuck play with these collision points.

Image:Not-sticky.jpg

This is the problem of ninja part going in the tile, but can be solved with good initial design.

Image:Imageintile.jpg

This solves all the 3 problems, a good character design can save you lot of headaches later with TGB.

Polygon Collision is a bit bugged in TGB but if you know good scripting you can make custom collision property by code and remove the problem( I read in the forums). I hope it is fixed in 1.5.

You can easily make a mario kind game with this, or even which throws shurikens, but for using sword the ninja sprite needs to be changed.

I got few of the ideas here from the platformer starter kit of Torque x. It is very good, buy it if you need to learn more about platform games.

One way Platforms

by Wicked Sunny 25/06/2007

N.b.- If you know how to do this by scripting and triggers, please do not try this.

This is more of a sure shot way to create one way platforms without scripting.

You can do it two ways - either make a new tile (especially for this platform only) or apply collision settings to the whole tile map layer created previously.

Now edit tile map - check collision box above the tile image and make a square collision polygon covering the edges of the tile in the edit menu itself (marked by green line over the tile image below). Now bring the bottom two points straight up to the two top points . Make sure the lines are straight and a very very thin rectangle is made, it is very difficult as you cannot zoom in the edit panel, but try.

Image:Tile-editing.jpg

Now paint over the tiles which you want to jump through yet stand on the top. As simple as that. In the image I have used a wall image tile to distinguish the one way platforms. Other platforms are bounded by the invisible scene object. Just make sure the tile points and scene objects are in one line horizontally when placed side by side.

Image:One-way-platform.jpg

One way platforms have one more advantage - sometimes while jumping and trying to reach another platform because of the polygon points, the ninja gets stuck to another platforms (especially the top edge). Such tiles can replaced by one way tiles, so that next time it does not stick and falls, which you want.

Image:Advantage.jpg

What I have realized after lot of experimenting and reading forums is that the way TGB updates its collisions causes few of the above problems. Most of the time ninja wont get stuck, but suddenly you will find it shaking on a particular tile, jerking and jumping faster over one way platform or getting stuck as well. Jump and come back on it again and it will work fine. Now this is a bug but I think few of the advanced users can work around it by using scripting. Not sure about this.

Also I have noticed is that the above two polygon points of the tile makes the ninja(with the collision points I created above) stick most of the time. The bottom points sticks but maybe once in 100 times. Thats why the above advantage of one way tile works. If a ninja sticks its mainly because one of its point sticking with the collision points of the tile. You can check this by enabling the collision bounds setting in debug rendering and then playing the game.

Image:Collision-bounds.jpg

Hence try to use less tiles for one way platforms. The image below shows more then 5 such tiles used and this is where my ninja gets stuck most of the time while walking on it. This technique does not work with scene objects but with normal image maps( whose collision points are edited like the tiles above) works very well. So one long platform sprite can be used instead of 5 tiles.

Image:5-tiles.jpg

TGB is not TXB and hence there cannot be a comparison. I am simply providing this update so that more game designers try making platform games with TGB. Just don't give up, keep trying ;)

I will soon try to give a link of this game demo.

Demo

Ok here is the demo link. I have updated as the installer was not ok, if you have TGB this exe will work fine, no need to install it.


Media:Ninjademo.rar

I have done few changes -

1) I have used more of image maps for one way platform then tile maps. Its giving better results. I have left few tile maps as well so that users can deduce whats going wrong. The topmost 4 tile row in the level just straight above my 5 tiles (above pic) and the row just below the 5 tiles, will give you the idea.

2) the only problem left now is sudden jerky updating of the animation sometimes when the ninja jumps on one way platform. Now its either because of collision points interacting or because of VERY basic animation scripting used for the ninja. No sticking anymore. At least not on my laptop.

BTW if anyone cannot jump out of the bouncing pit, then better restart the game, no re pawn yet. If you reach the top most tile row, you can have fun with bungee jumping from that height. :D

You can jump below a one way platform by first jumping in air then using arrow keys to land on the lower platform.

Please if you have questions, solutions, feedback, look for a post named "Mini platformer updated on TDN" in TGB private forums > getting started. and post only there, so I can keep track of it.

Thank you and enjoy demo.