I'm learning Lua and thought I should try my hand at making a Breakout clone. It is pretty much playable, but there seems to be odd intersection logic at some points, specifically the ball-brick collisions.

Ball inside of bricks

In case you can't tell, the ball is behind 2 bricks (left-most light blue and dark brown). Also, most of the bricks that are missing seem to have been detected correctly.

I cannot seem to figure out why this is happening. Here is the code:

for i=1,rows do
  for j=1,cols do
    if bricks[i][j].x~=nil then

      --ball is between left and right edges
      if ball.x+dirx>bricks[i][j].x-radius and ball.x+dirx<bricks[i][j].x+length+radius then

        --ball is between top and bottom edges
        if ball.y+diry>bricks[i][j].y-radius and ball.y+diry<bricks[i][j].y+8+radius then

          --Ball hit top/bottom?
          if ball.y<bricks[i][j].y or ball.y>bricks[i][j].y+8 then
            diry=-diry  -- Reverse Y velocity

          --Ball hit side?
          if ball.x<bricks[i][j].x or ball.x>bricks[i][j].x+length then
            dirx=-dirx  --Reverse X velocity

I've kind of been doing this Lua thing on-the-fly so if I am doing any bad practices I'd appreciate knowing how it should be done.

  • 2
    \$\begingroup\$ You should learn to use a debugger (they do exist for Lua). Step through the code when the ball exhibits the behavior. See which tests fail when they shouldn't and test your assumptions. \$\endgroup\$ – Sean Middleditch Nov 19 '13 at 18:39
  • \$\begingroup\$ @SeanMiddleditch Any suggestions? So far I've been doing a print when events occur but debuggers are always nice. \$\endgroup\$ – David Starkey Nov 19 '13 at 23:34

I haven't debugged your code for you, so here are some bits of general advice on how to make things more robust:

dirx = -dirx is a problematic way to implement bouncing, because if for whatever reason the ball is already inside an obstacle, or already moving the right direction, it will then be bounced the wrong direction and oscillate back and forth, and possibly zigzag its way into an even worse place. This could happen in your program if, for example, the ball hit two bricks simultaneously (the direction will be reversed twice).

Better is to set the sign appropriately. (Pseudocode:)

if collision on the left then
   dirx = abs(dirx)
else if collision on the right then
   dirx = -abs(dirx)

It also looks like your collision logic depends on the ball being just at the edge (its center being within radius but outside the brick itself) to determine collision direction. This could miss collisions. It would be more robust to, once you've decided a collision has occurred (the two outermost ifs as they are), write logic which decides which direction the collision was and always gives one answer under all circumstances (never "both horizontal and vertical" and never "neither", which are both possible with your current logic).

Since you ask about bad practices: you have massively repetitive code and magic numbers. Take out that recurring 8 and use local variables to hold relevant values:

brick = bricks[x][y]   -- do this only once in the loop!
brickLeft = brick.x
brickRight = brick.x + brick.length    -- better: use a method on the brick
brickTop = brick.y
brickBottom = brick.y + BRICK_HEIGHT

Then you should never have to write bricks[x][y].anything again inside the collision logic.


For some reason, the center of the bricks is the x value. Changing the if statement to the following seems to have worked:

if ball.x+dirx>curBrick.x-radius-length/2 and ball.x+dirx<curBrick.x+length/2+radius then
  if ball.y+diry>curBrick.y-radius-4 and ball.y+diry<curBrick.y+4+radius then

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.