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.

Leave a rating/review
Save for later
Share
You are currently viewing page 4 of 5 of this article. Click here to view the first page.

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:

  1. 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.
  2. 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.

Creating an animation with LevelHelper

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.’

The physics settings for the arms in LevelHelper

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!

Our hero - fully armed and dangerous!  :]

Jake Gundersen

Contributors

Jake Gundersen

Author

Over 300 content creators. Join our team.