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 5 of 6 of this article. Click here to view the first page.

Rubber Bullets

Paste the following function under the movePlayer function in main.lua and save:

-- Determines bullet movement by where it hits the player
function bounce()
	velocityY = -3
	if((bullet.x + bullet.width * 0.5) < player.x) then
		velocityX = -velocityX;
	elseif((bullet.x + bullet.width * 0.5) >= player.x) then
		velocityX = velocityX;
	end
end

This is another instance where the velocityX and velocityY variables come into play. The bullet needs to change its Y direction to move up towards the zombies. However, the X direction (side to side) will depend on whether the bullet hits the left or right side of the paddle.

Time to add our event listener! :] Paste this line above Bookmark A in the gameListeners function:

		player:addEventListener("collision", bounce);

And paste this line above Bookmark B in the gameListeners function:

		player:removeEventListener("collision", bounce);

Relaunch the app in the simulator and start the game! :]

You should now be able to drag the paddle back and forth across the screen, and the bullet should bounce off. Those pesky zombies are still invincible though!

Enough with the rubber bullets — time to get some real firepower behind that bullet!

Killing Zombies and Padding Stats

Remember how you used the velocityX and velocityY variables for the bullet and paddle collisions? You’ll need to do that for the zombies as well!

Add the following code to main.lua before “main();”.

-- Zombies are exterminated, remove them from screen
function zombieDestroyed(event)
	
	-- Where did the bullet hit the zombie?
	if event.other.name == "zombie" and bullet.x + bullet.width * 0.5 < event.other.x + event.other.width * 0.5 then
		velocityX = -velocityX;
	elseif event.other.name == "zombie" and bullet.x + bullet.width * 0.5 >= event.other.x + event.other.width * 0.5 then
		velocityX = velocityX;
	end
	
	-- Ricochet the bullet off the zombie and remove him from the screen
	if event.other.name == "zombie" then
		-- Bounce the bullet
		velocityY = velocityY * -1;
		-- Zombie says "ow" when hit by a bullet
		audio.play(zombieKill);
		-- Remove zombie instance
		event.other:removeSelf();
		event.other = nil;
		-- One less zombie
		zombies.numChildren = zombies.numChildren - 1;
		
		-- Score
		score = score + 1;
		zombieKillNum.text = score;
		zombieKillNum:setReferencePoint(display.CenterLeftReferencePoint);
		zombieKillNum.x = 150;
	end
	
	-- Check if all zombies are destroyed
	if zombies.numChildren < 0 then
		textBoxScreen("City: Zombie Free", "Next City");
		gameEvent = "win";
	end
end

In the code above, when a Zombie-bullet collision occurs, the bullet needs to bounce off properly by modifying the velocityY variable.

If zombies could talk while being shot, they'd probably say "Ow!", so add that sound effect in with the collision.

The zombie should then disappear forever by removing itself from the collection of zombies, never to be heard from again.

As well, when the bullet hits a zombie, add 1 to the zombies killed score; if all the zombies are gone, show text saying the city is now zombie free!

You're almost done — you just need to add this function to the listener events! Paste this line above Bookmark A in the gameListeners function:

		bullet:addEventListener("collision", zombieDestroyed);

And paste this line above Bookmark B in the gameListeners function:

		bullet:removeEventListener("collision", zombieDestroyed);

That's it! Just for completeness, here's what the final gameListeners function should look like:

-- Listen for bullet and player collisions and user dragging player
function gameListeners(event)
	if event == "add" then
		Runtime:addEventListener("enterFrame", updatebullet);
		player:addEventListener("touch", movePlayer);
		player:addEventListener("collision", bounce);
		bullet:addEventListener("collision", zombieDestroyed);
	-- Remove listeners when not needed to free up memory
	elseif event == "remove" then
		Runtime:removeEventListener("enterFrame", updatebullet);
		player:removeEventListener("touch", movePlayer);
		player:removeEventListener("collision", bounce);
		bullet:removeEventListener("collision", zombieDestroyed);
	end
end

Note:The order of the four event listeners doesn't matter, so don't worry if you pasted them in a different order.

Relaunch the game in the simluator and give it a try!

Now when you click on the player paddle, the bullet shoots outwards and upwards, you can drag the paddle back and forth, the bullet bounces off the walls, it kills the zombies and you get a high score! All of your hard work has paid off!

Uh...wait a second. When you win nothing happens — and when you lose nothing happens! Somewhat less than gratifying, isn't it? :]

Why did this happen? You're calling the textBoxScreen function to display a message when you win or lose, so where is it?

Right — you never actually created that function yet, you just referred to it in the code! Tapping on the resulting text box should also take you to the next level. You'll fix that in the next section!

I'm Back in the New York Groove

Before you create the text box that will take you to New York City after you kill all of Atlanta's zombies, first create the New York City level.

Paste the following into main.lua above the "main();" line:

-- Level 2 zombies
function gameLevel2()

	currentLevel = 2;
	bg1.isVisible = false;
	
	-- This code is the same to gameLevel1(), but you can change the number of zombies on screen.
	zombies:toFront();
	local numOfRows = 2;
	local numOfColumns = 8;
	
	-- Zombie position on screen
	local zombiePlacement = {x = (_W) - (zombieWidth * numOfColumns ) / 2  + 20, y = 100};
	
	-- 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

The gameLevel2() function is almost identical to gameLevel1(). The currentLevel is now 2 rather than 1, and the Atlanta city background needs to be hidden away. In true Breakout fashion, this level is slightly more difficult, with 2 rows and 8 columns' worth of zombies.

Before advancing to level 2, you'll need to clean up the screen and reset the bullet and paddle.

Paste the following into main.lua above the "main();" line and save.

function cleanupLevel()
	-- Clear old zombies 
	zombies:removeSelf();
	zombies.numChildren = 0;
	zombies = display.newGroup();

	-- Remove text Box
	textBox:removeEventListener("tap", restart);
	textBoxGroup:removeSelf();
	textBoxGroup = nil;
	
	-- Reset bullet and player position 
	bullet.x = _W;
	bullet.y = player.y - 30;
	player.x = _W;

	score = 0;
	zombieKillNum.text = "0";
end

This function cleans up everything you created so far - it removes all the zombies, removes the text box and listener, and resets the bullet position, player position, and score.

Now you'll need the code to advance the player to level 2.

In level 2, you'll display a background image of New York City, which will be centered on the screen. In the event that the player was on level 2, lost, and reset the level to try again, you'll need to remove any left over zombies from memory. Finally, place the player and bullet on the screen in their original starting point.

Does this sound really similar to the level 1 init code? It sure does! :]

Paste the following into main.lua above the "main();" line and save.

-- New York City (Level 2)
function changeLevel2()
	
	-- Display background image and move it to the back
	bg2 = display.newImage("images/nyc.png", 0, 0, true);
	bg2.x = _W;
	bg2.y = _H;
	bg2:toBack();

	-- Reset zombies 
	gameLevel2();
	
	-- Start
	player:addEventListener("tap", startGame)
end

New York City is waiting for you to solve their zombie problem; you just need a way to get there. Maybe you can fly there on a magic text box! :]