How To Make a Breakout Game with Corona

This is a post by Tutorial Team Member Greg Pugh, author of the Colin Turtle children’s eBook app series. You can also find him on Google+. If you like to play video games, you’ve most likely played some variant of the classic game Breakout. The goal of Breakout is to move a paddle on the […] By .

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

Let’s Get Physical

Now that you have the player and bullet on screen, you’ll need to give them some physics properties. But wait a second…didn’t you already enable physics in the game in the very beginning?

That’s correct, you did. However, just because the physics routines exist, that doesn’t mean that they apply to anything on the screen – unless you write some code! :]

Paste the following into main.lua above “main();” and save:

-- When the game starts, add physics properties to player and bullet
function startGame()
	physics.addBody(player, "static", {density = 1, friction = 0, bounce = 0});
	physics.addBody(bullet, "dynamic", {density = 1, friction = 0, bounce = 0});
	player:removeEventListener("tap", startGame);
	gameListeners("add");
end

In the code above, you tell the player object and bullet object how dense they are, if they have any friction and if they’ll add any bounce to the collision. The call to “removeEventListener” on the player is there so the game doesn’t listen for a user tap once the game has already started.

Note: It’s good practice to remove event listeners when they aren’t needed to free up memory and device resources.

Note: It’s good practice to remove event listeners when they aren’t needed to free up memory and device resources.

Now that you have most of the important elements on screen, the next section will get things moving around!

Working Hard or Hardly Working?

Take a moment and think about what the requirements of how the bullet will interact inside the game. The bullet needs to move around the screen, bounce off walls, and kill zombies.

Paste the following above “main();” in your main.lua file and save:

-- Bullet properties
function updatebullet()

	-- Movement
	bullet.x = bullet.x + velocityX;
	bullet.y = bullet.y + velocityY;
	
	-- If bullet hits the ceiling or left or right wall, bounce off of it
	if bullet.x < 0 or bullet.x + bullet.width > display.contentWidth then  
		velocityX = -velocityX;
	end
	
	if bullet.y < 0  then 
		velocityY = -velocityY;
	end
	
	-- If the bullet hits the bottom wall, the player has lost the game
	if bullet.y + bullet.height > player.y + player.height then 
		textBoxScreen("MY BRAINS!!", "Try Again") gameEvent = "lose";
	end
end

The local variables velocityX and velocityY will control the direction of the bullet. velocityX starts out at 3, so the bullet will move to the right; velocityY starts at -3 so it will move up the screen. Both of these velocities together means the bullet will move diagonally up and to the right.

However, the bullet shouldn’t go flying off of the screen! :] You’ll need to constrain it to the display width and height. If the bullet hits the top, left, or right sides of the screen it should ricochet. If the bullet hits the bottom of the screen, that means the player didn’t successfully bounce the ball off the paddle — and the player loses the game.

The updateBullet function looks great — now you just need to call it somewhere. But where?

Listen Up, Buster

Since the bullet needs to move around continuously (at least until the player wins or loses), you want the updateBullet function to be called over and over.

You can do this by asking Corona to call the updateBullet every time it redraws the frame. Our Zombie game runs at 60 frames per second, so Corona would call updateBullet for us automatically 60 times per second.

Paste the following code into main.lua above “main(); and save:

-- Listen for bullet and player collisions and user dragging player
function gameListeners(event)
	if event == "add" then
		Runtime:addEventListener("enterFrame", updatebullet);
		-- Bookmark A: You'll be adding some code here later
	-- Remove listeners when not needed to free up memory
	elseif event == "remove" then
		Runtime:removeEventListener("enterFrame", updatebullet);
		-- Bookmark B: You'll be adding some code here later too
	end
end

Runtime is a special top-level object in Corona. Just as you added an event listener to buttons for when the user taps on them, you can add an event listener to the runtime when a frame is about to be drawn.

Note the two spots in the code above marked “Bookmark A” and “Bookmark B”; you’ll be adding elements to the gameListeners function as you go along, so keep an eye out.

Relaunch the app in the simulator! :]

After you tap on the “Play” button, tap on the paddle, and the bullet will go bouncing around the screen. You’ve added quite a bit of complicated physics here, without adding a lot of code!

Looks like you’re fully armed — now you just need something to shoot at! :]

Where Are All The Zombies?!

You came to Atlanta looking to participate in the zombie apocalypse — but where are the zombies? What a bust!

Time to add the zombies! First, here’s a quick checklist of how the zombies should behave — besides die when you shoot them, of course! :]

  1. Add zombies to level 1.
  2. Place them on top of the background image.
  3. Place them in rows and columns to make a wall of zombies.
  4. Enable physics on them so when they are hit, they make the bullet bounce off of them.

Paste the following into main.lua above the “main();” line and save:

function gameLevel1()
	
	currentLevel = 1;

	-- Place the zombies on the top layer
	zombies:toFront();
	
	-- Number of zombies on level 1
	local numOfRows = 2;
	local numOfColumns = 2;
	
	-- Zombie position on screen
	local zombiePlacement = {x = (_W) - (zombieWidth * numOfColumns ) / 2  + 20, y = 70};
	
	-- Create zombies based on the number of columns and rows we declared
	for row = 0, numOfRows - 1 do
		for column = 0, numOfColumns - 1 do
			local zombie = display.newImage("images/zombie.png");
			zombie.name = "zombie";
			zombie.x = zombiePlacement.x + (column * zombieWidth);
			zombie.y = zombiePlacement.y + (row * zombieHeight);
			
			-- Add physics properties to zombies
			physics.addBody(zombie, "static", {density = 1, friction = 0, bounce = 0});
			zombies.insert(zombies, zombie);
		end
	end
end

Most of the code above is just positioning the zombies on the screen. After you’ve set how many rows and columns you want, there’s a loop to make each zombie appear. You don’t want the zombies overlapping each other though, so the zombieWidth and zombieHeight variables from the beginning are used to space them out.

Reload the game in the simulator, and you should see some hordes of zombies descend on Atlanta!

Hooray, there are zombies to kill! If you’d like more or fewer zombies to appear on level one, simply change the number of rows and columns from 2 to whatever you’d like.

If you’re like most people, you won’t want to stand around in the face of a zombie apocalypse — you’ll want to move around a little! :] Move on to the next section to add some player movement!