How to Make a Game Like Jetpack Joyride using LevelHelper and SpriteHelper [Corona Edition] – Part 2

Bogdan Vladu

This is a post by special contributor Bogdan Vladu, an iOS application developer and aspiring game developer living in Bucharest, Romania.

Learn how to make a game like Jetpack Joyride with SpriteHelper and LevelHelper!

Learn how to make a game like Jetpack Joyride with SpriteHelper and LevelHelper!

Welcome back to our Jetpack Joyride tutorial series! In this tutorial series, we are making a game similar to Jetpack Joyride using Corona SDK, and the LevelHelper and SpriteHelper tools.

So far, we’ve got a working level with background art that scrolls continuously. Check out how we did it in Part One.

By now, you should be pretty comfortable working with LevelHelper and SpriteHelper, at least when it comes to the basics like adding objects to the levels.

In this second part of the tutorial, we’ll focus on adding some movement and activity to the game. Lasers, coins, a flying player-character, the beginnings of collisions… it’s all coming up!

To follow along with this tutorial, you’ll need to have the RocketMouse project where we left off in Part One. If you don’t have this already, you can grab a copy of the project so far here.

So let’s get that mouse flying!

Getting Started

The next step in creating our Jetpack Joyride game is to add some elements that the player will directly interact with: lasers and coins. Adding these elements is also a good way to begin learning how to implement animations and sensors using LevelHelper.

Since we want the lasers to go on and off, we need to make them animations. As for the coins, we want to know when the player collides with them, but we don’t want the player to bounce off them. To do this, we need to make them sensors.

Having grappled with the basics of animation and collision response, we’ll expand the concepts to other elements of our game, including the player. We’ll learn how to create tags to track collisions, then put it all together with some actual code!

Before we get started, you might want to open your current LevelHelper project and save the level as level03 (this way you’ll have the old level to look back on). If you do this, be sure to load the new level in your Corona project by updating the line that selects the level to choose level 3 like so:

loader = LevelHelperLoader:initWithContentOfFile("level03.plhs")

Working With Animations: Adding Lasers

How we’ll use the animations in gameplay is fairly simple. When the player makes contact with a laser, we’ll just test what frame the animation is on. If it’s the frame with the laser-off sprite, we’ll leave the player alone. If it’s the frame with the laser-on sprite, then we’ll kill the player.

To create an animation for our lasers, go to the available sprites list on the right panel in LevelHelper, and Control-Click (or right-click) on one of the laser sprites. Then choose “Open SpriteHelper scene” from the menu.

SpriteHelper will open with the correct scene. Navigate to the Animation section, click the + button to create a new animation, then double click on the animation name and call it “Laser.”

Now go in the sprites list and select the vertical laser. Go back to the animation section and click Add Frame. This will add the two sprites to the animation.

Arrange the frames in the correct order (off and then on, or laser1 and then laser2) by clicking the up and down arrows. Set the speed to 3 and make sure the Start At Launch and Loop Forever options are checked.

When you’re done, hit Command-S to save the scene.

Now let’s switch back to LevelHelper and work with the animation we just created. You’ll see that an Animations section has already been added for you in LevelHelper, as in the image below.

There are two ways to activate the animation. I will demonstrate both.

The first way is to drag the animation into the level just as we did with the sprites.

The second way is to attach the animation to a sprite that’s already in the level. In this case, I’m adding the animation to the laser sprite.

Go to the sprites section. We haven’t added the laser sprites to the level yet, so drag one of them (doesn’t matter which) from the list into the level, and make sure that sprite is selected. Then go to the General Properties section and select the Laser animation from the list.

Continue adding lasers to the level, until a satisfying amount of danger has been achieved. You can rotate and scale the lasers by using the handles that appear when you select a sprite.

My level now looks like this:

If you look at the laser shape you can see that the sprite is a full quad.

In our game we want the mouse to die only when it hits the actual laser in the sprite (the yellow part), so let’s make the shape smaller.

To do this we can define a shape like we did for the dog and cat, or we can modify the Shape Border property under the Physics menu using predefined values. Since you already know how to create a shape with points, let’s try it the second way.

Select the laser1 image from inside the Images section of LevelHelper. Right click on it and select Open SpriteHelper Scene.

Once the SpriteHelper scene is open, click on the “laser1” sprite. Because the laser is an animation, we need to modify the physics properties of the first frame of the animation – in this case the “laser1″ sprite. Animations have the physics properties of the first frame.

With laser1 selected, go to the Physics menu and enter 70 and 40 for the Shape Border values. This will make the shape of the sprite be equal to the sprite size, minus the values you enter here. You can see the visual representation in the view.

Back in LevelHelper, we can see that all lasers have been updated with the correct shape.

Now select all lasers and add them to our parallax. Enter 1 and 0 for the ratio.

Save the level, and if you build and run your game it will now have animating lasers!

Level with animating lasers

Working With Sensors: Adding Coins

Now for the coins. Remember, we want to make the coins sensors so that the mouse can pass straight through them without bouncing off, but still allow us to detect when there is a collision.

To make the coins sensors, select the coin sprite from the sprites list inside LevelHelper, right click (or Control-Click) and choose Open SpriteHelper Scene.

With the SpriteHelper scene opened, select the coin sprite and check the Is Sensor, Is Circle and Can Sleep options on the Physics menu. Then save the scene.

  • Is Sensor: makes the body trigger a collision, but not a collision response.
  • Is Circle: makes the shape of the body circle-based.
  • Can Sleep: speeds up simulation of the physics.

Now add the coin sprite to the level and place it as you see fit. Use the Clone Tool to easily clone the coin with the direction offset you prefer.

Now my level looks like this:

Add the coins to the parallax, set the ratio to 1 and 0 and save the level. Compile and run your project, and now you have coins!

Adding coins to the level

Adding the Player

Now that we have a good-looking level with all the basic components, let’s create the player and its accompanying animations.

Open SpriteHelper and go to File\New to create an empty sprite sheet. Then in Finder, navigate to the directory where you saved the art for this game. Once you’re there, select and drag onto the SpriteHelper window all the mouse sprites and the rocket flames.

We now need to create one single image with the art we just imported. This is an essential step before creating the animation. All engines supported by LevelHelper and SpriteHelper expect that frames in an animation are part of the same image file.

Switch to the Sheet Editor menu if you aren’t there already and deselect Crop, because we don’t want to trim the frames of the mouse animation. Click Pack Sprites to arrange all the sprites into the sprite sheet.

Next, switch to the Animation section of SpriteHelper. We’ll we’ll create all the animations we need here, exactly as we did for the laser.

Using the same technique you learned earlier, create five animations with the properties listed below.

If you forgot how to create animations, for each animation, click the + button, and double click to name it. Then select the required frames for that particular animation, set the speed, and make sure to check the Loop Forever option for the one that needs to loop.

1) Animation Name: mouseRun
Start At Launch: YES
Loop Forever: YES
Speed: 0.400 (default)
Repetition: 1.000 (default)
Frames: rocketmouse_1_run, rocketmouse_2_run, rocketmouse_3_run, rocketmouse_4_run

2) Animation Name: flame
Start At Launch: YES
Loop Forever: YES
Speed: 0.400 (default)
Repetition: 1.000 (default)
Frames: rocket_flame1, rocket_flame2

3) Animation Name: mouseFly
Start At Launch: YES
Loop Forever: YES
Speed: 0.400 (default)
Repetition: 1.000 (default)
Frames: rocketmouse_5_fly

4) Animation Name: mouseDie
Start At Launch: YES
Loop Forever: NO
Speed: 0.400 (default)
Repetition: 1.000 (default)
Frames: rocketmouse_7_die, rocketmouse_8_die

5) Animation Name: mouseFall
Start At Launch: YES
Loop Forever: NO
Speed: 0.400 (default)
Repetition: 1.000 (default)
Frames: rocketmouse_6_fall

Once you’re done, hit Command-S to save the scene. In the Save dialogue, navigate to the Images folder inside your Xcode project Resources folder, and save the scene as “mouse.”

Back in LevelHelper, we can find all of our new animations in the Animation section.

Drag the mouseRun animation onto the main screen (the one with a red border). Place it just to the left of the screen.

Then drag the flame sprite and place it right under the red tank on the back of the mouse.

The result should look something like this:

If you look closely, you’ll see that the flame sprite is on top of the red tank. Let’s put it behind the tank, so it looks more like the flame is coming out of the tank. Do this this, select the flame sprite and under General Properties, set Z Order to -1.

If you run the level at this point using Scene Tester (press Test Level button) you might or might not be able to see the mouse.

This is because the sprites are rendered using batch nodes (a special way of rendering sprites more efficiently). To make the mouse be on top of all the other sprites in the level, we need to change the Z Order of the batch node (the image file).

Inside LevelHelper go to the Images section and double click on the Z Order field for mouse.png. Enter a value of 4.

We want the player to always be on top of everything, and we’re going to add more images soon. That’s why we’re putting a larger value here.

Running the level now, you can see the mouse running on the scene, but it does not perform any collisions.

You can also simulate the Corona SDK rendering inside Scene Tester by selecting Scene Tester app while its running and going to “Actions” menu, then select “Simulate Corona SDK Drawing”

It actually is performing collisions with the dogs and cats, but because the mouse and other objects are all static, nothing happens.

Time to make the mouse and the flame sprites dynamic! Open the SpriteHelper scene for the mouse:

Then select all the sprites and make them dynamic. Because we don’t want the mouse to rotate when it collides with any other sprite, select the Fixed Rotation option also.

For the two rocket flame sprites, we also need to check the Is Sensor option. This is because later we’re going to be attaching the flame to the rocket tank.

Save the scene when you’re done!

Running Scene Tester again, we will see the mouse falling out of the screen. This is because the mouse is responding to gravity. Let’s make him stay on the screen.

Click the Physic Boundaries button.

From the Physic Boundaries window, click Create.

We’ve now created the boundary, but we want to edit it so that it’s right under the mouse in the middle of the floor, where the mouse will walk. Inside the Physic Boundaries window, click Edit.

You will now see four red handles on the corners of the physic boundary. Drag any of the bottom handles to move the boundary so that it’s under the mouse’s feet.

You should have something similar to this:

When you’re satisfied with your physic boundary, press the Editing button to stop the editing process.

Running the level in Scene Tester, you will see the mouse collides with the dogs and cats and stays on the screen, but, alas, there is yet another problem!

This time, the flame is falling off the screen. That’s because it’s a sensor and so it does not collide with any object and isn’t attached to the mouse’s body. But w can connect the flame to the mouse by creating a distance joint.

Go to the Joints section inside LevelHelper, select Distance Joint from the list and click the green + button.

Now let’s select the sprites we want the joint to connect.

Select the joint from the list (if not already selected), then on the Body A property, click and hold the circle icon. Then drag your mouse over the flame sprite. When the text says rocket_flame_1, release the mouse. (This is exactly the same process as connecting an outlet inside Interface Builder in Xcode.)

Now repeat the process for Body B, only this time select the mouse.

Now let’s put the joint’s anchor points closer together.

Select A in the joint property, drag the handle that shows the flame sprite, and put the anchor right on top of the tank.

Repeat the process for the other anchor point. Select anchor B, drag the handle and put the anchor point next to the other.

If you run the level in the Scene Tester, you’ll see the flame now stays attached to the mouse. w00t!

We now have almost everything we need in order to start coding the game!

Creating Tags to Perform Collisions

In order to perform collisions between our sprites, we need to have a way to register collisions between sprites of one type with sprites of other types.

We will need to separate our sprites into types using tags. So all dog sprites will have the tag “DOG” and all cat sprites will have the tag “CAT.”

To create the tags, inside LevelHelper click the Define Tags button.

In the Define Tags window, set the name for the new tag and click the Add button to create it. Create the following tags: DOG, CAT, LASER, COIN, PLAYER.

Now that we have the tags defined, we need to assign the tags to sprites.

Select all the dog sprites from the list of sprites on the left. Then under General Properties, assign the DOG tag to all of those sprites.

Repeat the process for all the sprites. Assign PLAYER to the mouse sprite, CAT to all the cat sprites, LASER to all the laser sprites, and COIN to all the coin sprites.

When you’re done, save the level with Command-S.

A project with all of our progress so far can be downloaded here.

Coding the Game Logic

We are now (finally) ready to start coding our game. So let’s move back to the Corona project, open our main.lua and start the real fun.

In order control the movement of the parallax and allow the player to jump, we need to have a few variables that will point to the objects created by LevelHelper. Add these lines in main.lua after you load the level.

loader = LevelHelperLoader:initWithContentOfFile("level03.plhs")
loader:instantiateObjects(physics)
loader:createPhysicBoundaries(physics)
 
local parallaxNode = loader:parallaxNodeWithUniqueName("Parallax_1")
if(nil == parallaxNode)then  print("Could not find parallax node.") end
 
local player = loader:spriteWithUniqueName("player")
if(nil == player)then  print("Could not find player.") end
 
local rocketFlame = loader:spriteWithUniqueName("flame")
if(nil == rocketFlame)then  print("Could not find rocket flame.") end
 
rocketFlame.alpha = 0 --You can do it in LH, but I do it here so you guys can see it in LH

Here we are taking the parallax by giving the unique name of the parallax assigned in LevelHelper.

Then we’re taking the player sprite, also by giving the unique name. You might need to modify the unique name to read “player” as shown in the screenshot below if it isn’t set to that already.

Similarly, you should change the unique name of the flame to “flame” so it matches the code.

When you use spriteWithUniqueName to look up a sprite, you get a display object instance, but with a few added methods and properties from LevelHelper.

We then take the flame sprite and make it invisible. We only need to see the flame when the player is flying. (We could also have done this inside LevelHelper by unchecking the Visible option in the General Properties section.)

Run the code, and if the flame is invisible when you run it, you know it’s working so far! :]

The flame is now invisible.

Making the Player Fly

Now that we have retrieved the player from the loaded level, let’s make him fly!

The first thing we need to do is enable the “mouseFly” animation on the player sprite. This used to be automatically but because Corona uses to much memory, this need to be done by the user now. However next LevelHelper update will make this automatically (without memory issues) by introducing animations list specifically for Corona. (all other engines don’t have this problem).
For more info about this, please visit this page.

Add the following before loading the level.

local animationMgr = LHAnimationsMgr:sharedInstance();
animationMgr:registerAnimationWithNameOnSpriteWithName("mouseFly", "player");
 
loader = LevelHelperLoader:initWithContentOfFile("level03.plhs")

Now lets declare a couple of variables that we will need to make the player fly.

Add the following somewhere at the top of main.lua:

local playerVelocity = 0;
local playerWasFlying = false;
local playerShouldFly = false;

We will use this to make the mouse fly when the user touches the screen.

Now lets define 2 methods we will need to make the player fly and make the player fall on the ground.

function startPlayerFly()
	playerVelocity = 0.5;
        playerShouldFly = true;
   	rocketFlame.alpha = 1;
   	player:startAnimationWithUniqueName("mouseFly")
end
--------------------------------------------------------------------------------
function cancelPlayerFly()
    playerShouldFly = false;
    rocketFlame.alpha = 0;
    playerWasFlying = true;
    playerVelocity = 0.0;
end

The first method will make the player fly by setting an initial velocity that we will later apply on the player. This method also starts the flame on the rocket by setting it to visible and starts the fly animation on the mouse sprite.

The second method is canceling the flight and hides the rocket flame.

Since now we have everything we need, lets register for “touch” events. We will use the touch events to start and cancel the fly.

Add the following at the end of your main.lua file:

local onTouch = function( event ) 
 
	if(event.phase == "began")then
		startPlayerFly()
	elseif (event.phase == "ended" or event.phase == "cancelled")then
		cancelPlayerFly()
	end
end 
Runtime:addEventListener( "touch", onTouch )

Inside the touch began, we’re saying that when the user touches the screen, the player should start flying, the rocket flame should become visible and the flying animation should start on the player sprite.

Next we start the animation name “mouseFly” on the player display object that we retrieved at the beginning of the file.

When the player stops touching the screen, or the touch is canceled, we stop making the player fly by calling the new method “cancelPlayerFly.” We also hide the flame because the player is no longer flying.

But this isn’t enough. We set up when to show the player flying, but we haven’t implemented the actual flight. That requires registering for “enterFrame” event:

local onEnterFrame = function( event ) 
 
	if(playerShouldFly == true)then
 
    	player:applyLinearImpulse(0, -playerVelocity, player.x, player.y);        
 
	    playerVelocity = playerVelocity + 0.01;
 
    	if(playerVelocity > 1.5)then
        	playerVelocity = 1.5;
        end
	end
 
end 
 
Runtime:addEventListener( "enterFrame", onEnterFrame )

Here, we check if the player should fly and if the test is true, we apply a linear impulse with a horizontal direction (on Y) on the mouse body.

We then make the velocity bigger and bigger, so the player will look like they are taking off from the ground, gaining speed with time.

If the player’s velocity reaches a certain speed (1.5), we stop the speed from increasing further.

Run the game, and now you can make the mouse fly by touching the screen!

A flying rocket mouse!

Where to Go From Here?

You can download the full project up to this point here.

Thanks for staying with me this far! We’ve made a huge amount of progress for one tutorial. And we’re only at the end of Part Two!

You won’t want to miss Part Three, where we’ll fully implement collisions, animate the player’s flight and landings, and add sounds. We’ll also make the player die when it touches the dogs, cats or lasers and add a restart screen.

Then in the fourth and final part, we’ll add bunnies that will run through the level to give the player more scoring opportunities, add a score display, and finally, create a scrolling background scene that will be visible through the windows.

Clearly our fun is just getting started. Keep your questions, comments and suggestions coming!


This is a post by special contributor Bogdan Vladu, an iOS application developer and aspiring game developer living in Bucharest, Romania.

User Comments

18 Comments

[ 1 , 2 ]
  • Hey,

    For SpriteHelper, what it does is rescale your original images to

    image.png (for use on non retina iphone) (4x smaller)
    image-hd.png (for use with iphone retina, ipad non retina, ipad mini) (2x smaller)
    image-ipadhd.png (for use with ipad retina) (original size)

    LevelHelper will use image.png and then on simulator/device will use the appropriate image.

    Thats why you may think its downgraded - but its not. Your original images will be in image-ipadhd.png.

    Of course you can choose to do a iphone only or ipad only game which will result in image.png, image-hd.png and image-ipad.png and image-ipadhd.png



    For autocomplete, right now it only displays engine related functions, and he functions available from the required files (files in project) - a new update will make it code sense orientated.
    vladubogdan
  • Wow, you replied... Didn't think I would get one here since this thread is rather dated. I was just getting ready to post my questions to you on gamedev website. Thanks for your help with that!

    Also, what do you think the odds of updating this tutorial would be? This tutorial is really the only decent tutorial on how to use your software in Corona but there are several things that just don't match up with this tutorial and the new software. For example, I can't seem to get the laser to work (can't get it to switch it's physics when the animation changes.) Other code specific things would be like calling the parallax function. You have it as something like "loader:parallaxNode..." but the "node" portion of it is deprecated. It took quite a bit of digging for me to find this. Also, you have "preLoadColision" but that too is deprecated. I pretty much stopped right where you start talking about storyboarding and haven't gone any further. Trying to get the most out of your software before the trial is up but alas, I only have about 2 days.

    And again, thanks for all you do for the community and keep putting out great software!

    Jesse
    jtsmith
  • Hey,

    I have the source code of this updated somewhere. Contact me using gamedevhelper contact page to send it to you. also contact me by mail or gamedev forum to help you with other issues you may have.
    vladubogdan
[ 1 , 2 ]

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in May: Procedural Level Generation in Games with Kim Pedersen.

Sign Up - May

Coming up in June: WWDC Keynote - Podcasters React! with the podcasting team.

Sign Up - June

Vote For Our Next Book!

Help us choose the topic for our next book we write! (Choose up to three topics.)

    Loading ... Loading ...

Our Books

Our Team

Tutorial Team

  • Brian Broom

... 55 total!

Editorial Team

... 22 total!

Code Team

  • Orta Therox

... 1 total!

Translation Team

  • Sungwook Yeom

... 38 total!

Subject Matter Experts

... 4 total!