How To Make a Game Like Doodle Jump with Corona Tutorial Part 1
This is a blog post by iOS Tutorial Team member Jacob Gundersen, an indie game developer who runs the Indie Ambitions blog. Check out his latest app – Factor Samurai! I’m willing to bet that when you woke this morning your first thought was “I wish there was a way to create a doodle jump […] By Jake Gundersen.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How To Make a Game Like Doodle Jump with Corona Tutorial Part 1
35 mins
- What is Corona?
- Corona vs Cocos2D
- Getting Started with Corona
- Creating the Sprite Sheet
- Creating the Level with LevelHelper
- Adding the Player
- Loading the Level
- Adding Collisions and Jumping
- Event Listeners in Corona
- Additional Collisions
- Creating a Shooting Animation
- Adding the Arms
- Where To Go From Here?
Event Listeners in Corona
This might be a good time to give a general explanation of event listeners in Corona.
You’ve actually already seen an example above with the collision event listener, but let’s talk about exactly how they work.
Event listeners are Corona’s callback methods. There are event listeners that handle touch and accelerometer input, changes in orientation, input from the GPS system, collisions, exiting or suspending the application, etc.
There are two kinds of event listeners:
- Events that are broadcast to all objects. These are known as runtime events, and include things like orientation changes or input from the GPS. Another example is the enterFrame listener, which is an event that is called every time a frame is drawn.
- Events that are sent to a single object. These include touch or collision events (like the one you used earlier).
In our case, we created a collision function, the pCollision function. We registered the event listener with the player, so when the player collides with another object, this object will be called. The function has two arguments, the self object, which is the player in this case, and the event object. The event object is created and populated with information by the collision event type.
Different event listeners have different event objects that provide different information. For example, there is also a ‘postCollision’ event type that provides collision forces. The regular collision event object doesn’t have this information.
For more information about Corona’s event types, go here.
Additional Collisions
Now that are player is jumping off white clouds, lets add the grey and blue clouds. Blue clouds actually require no additional code. They share the CLOUD tag with the white clouds and are static bodies (meaning that you must jump around them rather than through them like the white clouds).
Go into the pCollision function once again and add extra code so it looks like this:
if event.phase == "began" then
vx, vy = self:getLinearVelocity()
if vy > 0 then
if object.tag == LevelHelper_TAG.CLOUD then
self:setLinearVelocity(0, -350)
elseif object.tag == LevelHelper_TAG.BCLOUD then
loader:removeSpriteWithUniqueName(object.uniqueName)
end
end
end
If the tag is BCLOUD, then we want the grey cloud to disappear, so we call loader:removeSpriteWithUniqueName and we pass in the name of the object that we’ve collided with. Remember that here in our code, “object” is a variable where we stored event.other.
Creating a Shooting Animation
Love is in the air – and soon to be arrows as well! :]
But first things first – let’s create an animation for the shooting in LevelHelper.
Switch back to LevelHelper, select the animation tab on the right, and click the ‘New’ button to create a new animation. It will bring up the animation builder dialogue. Add the sprites called front_arm, arm_front_shoot1, arm_front_shoot2, and an additional front_arm to the list by selecting them and clicking the plus button. Untick the loop option. The default values are fine on the remaining attributes.
Click ‘Create Animation’ to save. Rename the animation to ‘shoot’ by double clicking on it.
Drag the animation object onto the grey area, outside of the level. Anywhere is fine. We need this available to our code, but we are going to position the arms around the player in code, so we don’t need then inside the level here. If we don’t drag them into our level, we can’t get a pointer to them using the levelHelper loader object.
Once you’ve dragged it into the level, select the animation object and set the Physics type to ‘No Physic’ to avoid strange physics behavior when we attach it to the hero.
Adding the Arms
Click on the sprite button to go back to the list of sprites. Drag in the ‘back_arm’ sprite outside of the level as well. Set the new animation (which is called ‘front_arm’ because that’s the first sprite in the set) and ‘back_arm’ to ‘No Physic.’
Change the code in the newPlayer function so that it looks like this:
local backarm = loader:spriteWithUniqueName("back_arm")
local p = loader:spriteWithUniqueName("char_jump2")
local frontarm = loader:spriteWithUniqueName("front_arm")
loader:pauseAnimationOnSprite(frontarm)
Here we just get variables for each of the player pieces. In LevelHelper these method calls will get us a variable we can use to refer to these objects. The objects are created automatically and added outside the level by levelHelper, but we need a variable to refer to them.
The loader:pauseAnimationOnSprite(frontarm) line keeps the animation from running when we start the game. We will call for that animation to run each time we shoot, but the default behavior is for the animation to run automatically on startup.
The player will be inside the view but his arms will be outside. To fix that we’ll create an enterFrame function.
An enterFrame event type fires every time the screen is drawn. This function will reposition the arms and bow with our player each frame. It will also cause the player to face the direction he’s moving and wrap around the screen if he falls off the edge.
Add the following code inside the newPlayer() function at the end before the line ‘return p’:
function p:enterFrame(event)
backarm.x = player.x
backarm.y = player.y
frontarm.x = player.x
frontarm.y = player.y
if self.x < 0 then
self.x = 320
end
if self.x > 320 then
self.x = 0
end
px, py = player:getLinearVelocity()
if px < 0 then
frontarm.xScale = -1
backarm.xScale = -1
self.xScale = -1
elseif px > 0 then
frontarm.xScale = 1
backarm.xScale = 1
self.xScale = 1
end
end
Most of this code should be easy to follow.
We declare the function with the p: prefix. A function declared with an object:functionName declaration gives us access to a ‘self’ variable which refers to the object we declared the function on. When we create an enterFrame listener on a specific object, it must be called ‘enterFrame’ and is case sensitive.
The last section is recording the linear velocity of the player in the px and py variables. We then use this information to set the xScale property of all three. Like most other engines, a negative value in the scale property flips the sprite.
Next we need to add the enterFrame event listener to the Runtime object:
Runtime:addEventListener("enterFrame", p)
Runtime is a system object created by Corona. We create global listeners by registering them with this object.
If you save and run now, your player will have arms. Armed and Dangerous . . . Yay!