Create a Brick Breaker Game with the Corona SDK: Collision Detection

Create a Brick Breaker Game with the Corona SDK: Collision Detection

Tutorial Details
  • Technology: Corona SDK
  • Difficulty: Intermediate
  • Estimated Completion Time: 45 Minutes
This entry is part 3 of 3 in the series Create a Brick Breaker Game with the Corona SDK

Welcome to the final tutorial in our Brick Breaker game series! In this tutorial, we’ll handle the logic for the remaining collisions, check for win and loss states, change levels, and more.


Where We Left Off. . .

Be sure to read part 1 and part 2 of this series to fully understand the code presented in this tutorial.

Step 35: Detect Brick Collisions

When the ball collides with a brick, we will use the same technique applied to the paddle to determine the side the ball will follow:

function removeBrick(e)
    -- Check the which side of the brick the ball hits, left, right
    if(e.other.name == 'brick' and (ball.x + ball.width * 0.5) < (e.other.x + e.other.width * 0.5)) then
        xSpeed = -5
    elseif(e.other.name == 'brick' and (ball.x + ball.width * 0.5) >= (e.other.x + e.other.width * 0.5)) then
        xSpeed = 5
    end
end

Step 37: Remove Brick

When a brick is hit, we use the other parameter of the collision event to find out exactly which brick was hit, and then remove it from both the stage and the bricks group:

-- Bounce, Remove
if(e.other.name == 'brick') then
    ySpeed = ySpeed * -1
    e.other:removeSelf()
    e.other = nil
    bricks.numChildren = bricks.numChildren - 1

Step 38: Add Score

Each brick hit will add 100 points to the score. The score will be taken from the score constant and added to the current score as text.

    score = score + 1<br />		scoreNum.text = score * SCORE_CONST<br />		scoreNum:setReferencePoint(display.CenterLeftReferencePoint)<br />		scoreNum.x = 54 <br />	end

Step 39: Check Bricks

This code checks if there are anymore bricks left on stage and displays a “you won” message if not:

    if(bricks.numChildren < 0) then
        alert('  You Win!', '  Next Level ›')
        gameEvent = 'win'
    end
end

Step 40: Ball Movement

The ball speed is determined by the xSpeed and ySpeed variables. When the update function is executed, the ball starts moving using these values for placement on every frame.

function update(e)
    -- Ball Movement
    ball.x = ball.x + xSpeed
    ball.y = ball.y + ySpeed

Step 41: Wall Collision

This code checks for wall collisions with the ball, and responds by sending the ball in the opposite direction when necessary:

if(ball.x < 0) then ball.x = ball.x + 3 xSpeed = -xSpeed end--Left
if((ball.x + ball.width) > display.contentWidth) then ball.x = ball.x - 3 xSpeed = -xSpeed end--Right
if(ball.y < 0) then ySpeed = -ySpeed end--Up

Step 42: Loss Condition

An if statement is used to check if the paddle misses the ball. If true, an alert is displayed asking the user if they would like to try again.

if(ball.y + ball.height > paddle.y + paddle.height) then alert('  You Lose', '  Play Again ›') gameEvent = 'lose' end--down/lose

Step 43: Game Status Message

The Alert Screen shows the player information about the status of the game. It is shown when a win/loss event is reached.

Two parameters are used in this function:

  • t: The alert title
  • m: A short message
function alert(t, m)
    gameListeners('remove')
    alertBg = display.newImage('alertBg.png')
    box = display.newImage('alertBox.png', 90, 202)
    transition.from(box, {time = 300, xScale = 0.5, yScale = 0.5, transition = easing.outExpo})
    titleTF = display.newText(t, 0, 0, 'akashi', 19)
    titleTF:setTextColor(254,203,50)
    titleTF:setReferencePoint(display.CenterReferencePoint)
    titleTF.x = display.contentCenterX
    titleTF.y = display.contentCenterY - 15
    msgTF = display.newText(m, 0, 0, 'akashi', 12)
    msgTF:setTextColor(254,203,50)
    msgTF:setReferencePoint(display.CenterReferencePoint)
    msgTF.x = display.contentCenterX
    msgTF.y = display.contentCenterY + 15
    box:addEventListener('tap', restart)
    alertScreen = display.newGroup()
    alertScreen:insert(alertBg)
    alertScreen:insert(box)
    alertScreen:insert(titleTF)
    alertScreen:insert(msgTF)
end

Step 44: Restart

The next function checks the game status (win, lose, finished) and performs the corresponding action:

function restart(e)
    if(gameEvent == 'win' and table.maxn(levels) > currentLevel) then
        currentLevel = currentLevel + 1
        changeLevel(levels[currentLevel])--next level
        levelNum.text = tostring(currentLevel)
    elseif(gameEvent == 'win' and table.maxn(levels) &lt;= currentLevel) then
        box:removeEventListener('tap', restart)
        alertScreen:removeSelf()
        alertScreen = nil
        alert('  Game Over', '  Congratulations!')
        gameEvent = 'finished'
    elseif(gameEvent == 'lose') then
        changeLevel(levels[currentLevel])--same level
    elseif(gameEvent == 'finished') then
        addMenuScreen()
        transition.from(menuScreen, {time = 300, y = -menuScreen.height, transition = easing.outExpo})
        box:removeEventListener('tap', restart)
        alertScreen:removeSelf()
        alertScreen = nil
        currentLevel =
        scoreText:removeSelf()
        scoreText = nil
        scoreNum:removeSelf()
        scoreNum = nil
        levelText:removeSelf()
        levelText = nil
        levelNum:removeSelf()
        levelNum = nil
        ball:removeSelf()
        ball = nil
        paddle:removeSelf()
        paddle = nil
        score = 0
    end
end

Step 45: Change Level

This function changes updates the level when necessary:

function changeLevel(level)
    -- Clear Level Bricks
    bricks:removeSelf()
    bricks.numChildren = 0
    bricks = display.newGroup()
    -- Remove Alert
    box:removeEventListener('tap', restart)
    alertScreen:removeSelf()
    alertScreen = nil
    -- Reset Ball and Paddle position
    ball.x = (display.contentWidth * 0.5) - (ball.width * 0.5)
    ball.y = (paddle.y - paddle.height) - (ball.height * 0.5) -2
    paddle.x = display.contentWidth * 0.5
    -- Redraw Bricks
    buildLevel(level)
    -- Start
    background:addEventListener('tap', startGame)
end

Step 46: Call Main Function

In order to initially start the game, the Main function needs to be called. With the above code in place, we’ll do that here:

Main()

Step 47: Create the Loading Screen

The Default.png file is an image that will be displayed right when you start the application while the iOS loads the basic data to show the Main Screen. Add this image to your project source folder, it will be automatically added by the Corona compliler.


Step 48: Icon

Using the graphics you created before you can now create a nice and good looking icon. The icon size for the non-retina iPhone icon is 57x57px, but the retina version is 114x114px and the iTunes store requires a 512x512px version. I suggest creating the 512×512 version first and then scaling down for the other sizes.

It doesn’t need to have the rounded corners or the transparent glare, iTunes and the iPhone will do that for you.


Step 49: Testing in the Simulator

It is time to do the final test. Open the Corona Simulator, browse to your project folder, and then click open. If everything works as expected, you are ready for the final step!


Step 50: Build

In the Corona Simulator go to File > Build and select your target device. Fill the required data and click build. Wait a few seconds and your app will be ready for device testing and/or submission for distribution!


Conclusion

The final result is a customizable and entertaining game. Try adding your own custom graphics and levels to spice things up!

I hope you liked this tutorial series and find it helpful. Thank you for reading!

Series Navigation«Create a Brick Breaker Game with the Corona SDK: Game Controls

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • caine

    A lot of the code isnt showing, if you could fix that i’d appreciate it

  • Cron

    There are a lot of inconsistencies in the code, and also there are some HTML errors that prevent it from showing properly. I’ve yet to test the code, but you can tell from reading the code blocks.

  • ali

    Amazing efforts, I liked the game. But there is one thing, the paddle leave the stage and go beyond screen borders. I have tried to add these lines of code under the “Borders”:

    local leftWall = display.newRect(0, 0, 5, _H);
    leftWall:setReferencePoint(display.CenterReferencePoint);
    leftWall.x = 0-leftWall.width/2; leftWall.y = _H/2;

    local rightWall = display.newRect(0, 0, 5, _H);
    rightWall:setReferencePoint(display.CenterReferencePoint);
    rightWall.x = _W+rightWall.width/2; rightWall.y = _H/2;

    physics.addBody(leftWall, “static”, {friction=0.3, bounce=0.4});
    physics.addBody(rightWall, “static”, {friction=0.3, bounce=0.4});

    but unfortunately it doesn’ work also?

    if there is anyone can give a help?

  • Alan

    Great work Carlos. I tried to see if could manage to build this, but I get this error.

    What have I done wrong? Thanks :)

    Syntax error, please check consol output for details.

  • Ciprian

    Nice tutorial!
    I would like to add a function that, when two bricks are destroyed.
    A power-up should appear, where the second brick is destroyed.
    Thank you!

  • Mcgool

    Hi there,
    How can I insert a sound when the ball hits a brick?

    • http://twitter.com/edu_arana Edu_Arana

      That’s really simple, first you have to define the file (ex. 1.mp3) and then call it with the audio.play(var) command.

      • http://www.facebook.com/abbeybully Abbey Don

        hello i have been trying to create a simple brick game with corona sdk i will be happy if you can help me with it email me abbey.ade@hotmail.co.uk

  • http://twitter.com/edu_arana Edu_Arana

    Hi! like this tutorial to start my own little brick game. I have a question about the bricks. I like to change the color of the brick on each level, I made this on the code (level 1=brick.png, level 2=brick2.png) but in’t working ¿What i’m doing wrong?:

    for i = 1, len do

    for j = 1, W_LEN do

    if(level[i][j] == 1) then

    local brick = display.newImage(‘brick.png’)

    brick.name = ‘brick’

    brick.x = BRICK_W * j – OFFSET

    brick.y = BRICK_H * i

    physics.addBody(brick, {density = 1, friction = 0, bounce = 0})

    brick.bodyType = ‘static’

    bricks.insert(bricks, brick)

    end

    end

    end

    for i = 2, len do

    for j = 2, W_LEN do

    if(level[i][2] == 2) then

    local brick2 = display.newImage(‘brick2.png’)

    brick2.name = ‘brick2′

    brick2.x = BRICK_W * j – OFFSET

    brick2.y = BRICK_H * i

    physics.addBody(brick2, {density = 1, friction = 0, bounce = 0})

    brick2.bodyType = ‘static’

    bricks.insert(bricks, brick2)

    end

    end

    end

    for i = 3, len do

    for j = 3, W_LEN do

    if(level[i][3] == 3) then

    local brick3 = display.newImage(‘brick3.png’)

    brick3.name = ‘brick3′

    brick3.x = BRICK_W * j – OFFSET

    brick3.y = BRICK_H * i

    physics.addBody(brick3, {density = 1, friction = 0, bounce = 0})

    brick3.bodyType = ‘static’

    bricks.insert(bricks, brick3)

    end

    end

    end

    for i = 4, len do

    for j = 4, W_LEN do

    if(level[i][4] == 4) then

    local brick4 = display.newImage(‘brick4.png’)

    brick4.name = ‘brick4′

    brick4.x = BRICK_W * j – OFFSET

    brick4.y = BRICK_H * i

    physics.addBody(brick4, {density = 1, friction = 0, bounce = 0})

    brick4.bodyType = ‘static’

    bricks.insert(bricks, brick4)

    end

    end

    end

    end