I watched https://www.youtube.com/watch?v=F86edI_EF3s.
I believe the following code is the complete code
https://github.com/games50/breakout/tree/master/breakout13
And
https://github.com/games50/breakout/blob/master/breakout13/src/states/PlayState.lua is the code in play.
relevant code:
-- detect collision across all bricks with the ball
for k, brick in pairs(self.bricks) do
-- only check collision if we're in play
if brick.inPlay and self.ball:collides(brick) then
-- add to score
self.score = self.score + (brick.tier * 200 + brick.color * 25)
-- trigger the brick's hit function, which removes it from play
brick:hit()
-- if we have enough points, recover a point of health
if self.score > self.recoverPoints then
-- can't go above 3 health
self.health = math.min(3, self.health + 1)
-- multiply recover points by 2
self.recoverPoints = math.min(100000, self.recoverPoints * 2)
-- play recover sound effect
gSounds['recover']:play()
end
-- go to our victory screen if there are no more bricks left
if self:checkVictory() then
gSounds['victory']:play()
gStateMachine:change('victory', {
level = self.level,
paddle = self.paddle,
health = self.health,
score = self.score,
highScores = self.highScores,
ball = self.ball,
recoverPoints = self.recoverPoints
})
end
--
-- collision code for bricks
--
-- we check to see if the opposite side of our velocity is outside of the brick;
-- if it is, we trigger a collision on that side. else we're within the X + width of
-- the brick and should check to see if the top or bottom edge is outside of the brick,
-- colliding on the top or bottom accordingly
--
-- left edge; only check if we're moving right, and offset the check by a couple of pixels
-- so that flush corner hits register as Y flips, not X flips
if self.ball.x + 2 < brick.x and self.ball.dx > 0 then
-- flip x velocity and reset position outside of brick
self.ball.dx = -self.ball.dx
self.ball.x = brick.x - 8
-- right edge; only check if we're moving left, , and offset the check by a couple of pixels
-- so that flush corner hits register as Y flips, not X flips
elseif self.ball.x + 6 > brick.x + brick.width and self.ball.dx < 0 then
-- flip x velocity and reset position outside of brick
self.ball.dx = -self.ball.dx
self.ball.x = brick.x + 32
-- top edge if no X collisions, always check
elseif self.ball.y < brick.y then
-- flip y velocity and reset position outside of brick
self.ball.dy = -self.ball.dy
self.ball.y = brick.y - 8
-- bottom edge if no X collisions or top collision, last possibility
else
-- flip y velocity and reset position outside of brick
self.ball.dy = -self.ball.dy
self.ball.y = brick.y + 16
end
-- slightly scale the y velocity to speed up the game, capping at +- 150
if math.abs(self.ball.dy) < 150 then
self.ball.dy = self.ball.dy * 1.02
end
-- only allow colliding with one brick, for corners
break
end
end
Question
Why does the above code check if self.ball.x + 2 < brick.x and self.ball.dx > 0 then
?
I am especially confused because the code already did the collision check with if brick.inPlay and self.ball:collides(brick) then
, but now the code adds a +2.
The same goes for the other similar sections
self.ball.x + 6 > brick.x + brick.width and self.ball.dx < 0
I don't know why +6 is also checked.
I also do not understand why ball velocity (dx
) is also used for checking.
According to the comments in the source code, it seems to be a process at the edge, but I don't really understand it. Is this a common process (or patterns) in game programs (especially in 2D collision)?
I thought it was to solve the following problem(tunneling), but I felt it was something different and could not understand the code myself.
In games physics engines, what is "tunneling", also known as the "bullet through paper problem"?
In writing this question, I think I am getting a little more organized.
the ball needs to bounce at a leftward velocity if it is on the left edge, and the ball needs to bounce at a rightward velocity if it is on the right edge, so I think (not sure exactly) this is what is being handled here.
I assume the +2 and +6 are arbitrary by the author. I just don't know why those values should be added instead of the current position.
By using the algorithm above code, is it possible to determine which side (top, bottom, left, or right) the collision occurred with?
I am having a hard time imagining it clearly.