# Breakout intersection logic issues

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.

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

--ball is between top and bottom edges

--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
end

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


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.

• 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. – Sean Middleditch Nov 19 '13 at 18:39
• @SeanMiddleditch Any suggestions? So far I've been doing a print when events occur but debuggers are always nice. – 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)
end


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