Different Brick Types - noooway/love2d_arkanoid_tutorial GitHub Wiki
Currently different bricks respond identically to collisions with the ball - they disappears on the first hit. In this part I'm going to add bricks, that can take several hits.
To implement different reactions, it is necessary to change the brick response on collision with the ball.
The idea is simple: we know the type of each brick, and we need to check it in collision.
That is, most of the changes will concern the bricks.brick_hit_by_ball
function.
Currently, the brick type is encoded by a two-digit number. We can continue to work with that, however, it helps the code readability to define human readable types. It is possible to create a table, that maps two-digit types to human readable descriptions. Instead, I'll use a simpler approach and just define several methods that determine brick properties based on it's type number.
Brick colors are blue, green, orange, purple, red and yellow. In the first row bricks are 'simple', in the second -- 'armored', third -- 'scratched', fourth -- 'cracked'. Fifth row is 'heavyarmored'.
The appropriate methods are following:
function bricks.is_simple( single_brick )
local row = math.floor( single_brick.bricktype / 10 )
return ( row == 1 )
end
function bricks.is_armored( single_brick )
local row = math.floor( single_brick.bricktype / 10 )
return ( row == 2 )
end
function bricks.is_scratched( single_brick )
local row = math.floor( single_brick.bricktype / 10 )
return ( row == 3 )
end
function bricks.is_cracked( single_brick )
local row = math.floor( single_brick.bricktype / 10 )
return ( row == 4 )
end
function bricks.is_heavyarmored( single_brick )
local row = math.floor( single_brick.bricktype / 10 )
return ( row == 5 )
end
If the brick is 'simple', it is destroyed on the collision with the ball. If it is 'armored', after collision it's type is changed to 'scratched'. 'Scratched' becomes 'cracked'. 'Cracked' is destroyed on collision. 'Heavyarmored' bricks are unaffected by collisions.
Here is a template for case analysis in the bricks.brick_hit_by_ball
:
function bricks.brick_hit_by_ball( i, brick, shift_ball )
if bricks.is_simple( brick ) then
.....
elseif bricks.is_armored( brick ) then
.....
elseif bricks.is_scratched( brick ) then
.....
elseif bricks.is_cracked( brick ) then
.....
elseif bricks.is_heavyarmored( brick ) then
.....
end
end
If the brick should be destroyed, it is enough to simply call the table.remove
function.
To change brick type, it is convenient to have a special functions: armored_to_scratched
and scratched_to_cracked
. It is possible implement them simply by adding 10 to the brick type.
After brick type is changed it is also necessary to update it's quad; this is done by calling the
bricktype_to_quad
function.
function bricks.armored_to_scratched( single_brick )
single_brick.bricktype = single_brick.bricktype + 10
single_brick.quad = bricks.bricktype_to_quad( single_brick.bricktype )
end
function bricks.scratched_to_cracked( single_brick )
single_brick.bricktype = single_brick.bricktype + 10
single_brick.quad = bricks.bricktype_to_quad( single_brick.bricktype )
end
With these functions, the collision resolution code looks like this:
function bricks.brick_hit_by_ball( i, brick, shift_ball )
if bricks.is_simple( brick ) then
table.remove( bricks.current_level_bricks, i )
elseif bricks.is_armored( brick ) then
bricks.armored_to_scratched( brick )
elseif bricks.is_scratched( brick ) then
bricks.scratched_to_cracked( brick )
elseif bricks.is_cracked( brick ) then
table.remove( bricks.current_level_bricks, i )
elseif bricks.is_heavyarmored( brick ) then
end
end
It is also necessary not to forget to remove 'heavyarmored' bricks from the
check for next level switch and remove them from the bricks.current_level_bricks
before switching to the next level:
function bricks.update( dt )
local no_more_bricks = true
for _, brick in pairs( bricks.current_level_bricks ) do
if bricks.is_heavyarmored( brick ) then
no_more_bricks = no_more_bricks and true --(*1)
else
no_more_bricks = no_more_bricks and false
end
end
bricks.no_more_bricks = no_more_bricks
end
function game.switch_to_next_level( bricks, ball, levels )
if bricks.no_more_bricks then
bricks.clear_current_level_bricks() --(*2)
.....
end
(*1): If there is a brick, but it's type is 'heavyarmored', we ignore it.
(*2): The remaining 'heavyarmored' bricks are removed from the bricks.current_level_bricks
before switching to the next level.
Also, in the objects' draw
methods I remove the auxiliary shapes and leave only quads.