Glue Bonus - noooway/love2d_arkanoid_tutorial GitHub Wiki

In this part I want to implement a "glue" bonus: when it's on, the ball doesn't rebound from the platform, but sticks to it until the player presses a launch button.

First it is necessary to add recognition of the "glue" bonus type in the collision detection code.

function bonuses.bonus_collected( i, bonus, ball, platform )
   .....
   elseif bonuses.is_glue( bonus ) then
      platform.react_on_glue_bonus()
   end
   .....
end

function bonuses.is_glue( single_bonus )
   local col = single_bonus.bonustype % 10
   return ( col == 2 )
end

When a "glue" bonus is caught, platform.glued flag is raised and the platform tile is changed to indicate the change visually.

function platform.react_on_glue_bonus()
   platform.glued = true
   if platform.size == "small" then
      platform.quad = love.graphics.newQuad(
         platform.small_tile_x_pos + platfrom.glued_x_pos_shift,
         platform.small_tile_y_pos,
         platform.small_tile_width,
         platform.small_tile_height,
         platform.tileset_width,
         platform.tileset_height )
   elseif platform.size == "norm" then
      platform.quad = love.graphics.newQuad(
         platform.norm_tile_x_pos + platfrom.glued_x_pos_shift,
         platform.norm_tile_y_pos,
         platform.norm_tile_width,
         platform.norm_tile_height,
         platform.tileset_width,
         platform.tileset_height )
   elseif platform.size == "large" then
      platform.quad = love.graphics.newQuad(
         platform.large_tile_x_pos + platfrom.glued_x_pos_shift,
         platform.large_tile_y_pos,
         platform.large_tile_width,
         platform.large_tile_height,
         platform.tileset_width,
         platform.tileset_height )
   end   
end

Ball-platform collision depends on the value of the glued flag.

function ball.platform_rebound( shift_ball, platform )
   ball.increase_collision_counter()
   ball.increase_speed_after_collision()
   if not platform.glued then
      ball.bounce_from_sphere( shift_ball, platform )
   else
      ball.stuck_to_platform = true
      local actual_shift = ball.determine_actual_shift( shift_ball )
      ball.position = ball.position + actual_shift
      ball.platform_launch_speed_magnitude = ball.speed:len()            --(*1)
      ball.compute_ball_platform_separation( platform )
   end
end

function ball.compute_ball_platform_separation( platform )
   local platform_center = vector(
      platform.position.x + platform.width / 2,
      platform.position.y + platform.height / 2 )
   local ball_center = ball.position:clone()           
   ball.separation_from_platform_center =
      ball_center - platform_center
   print( ball.separation_from_platform_center )   
end

(*1): On ball collision with the "glued" platform, ball speed magnitude is memorized and used later, when the ball is launched from the platform.

The ball.launch_from_platform procedure is changed. Launch speed magnitude equals to the speed magnitude before the collision and launch angle is determined from the distance between the ball and platform centers.

function ball.launch_from_platform()
   if ball.stuck_to_platform then
      ball.stuck_to_platform = false      
      local platform_halfwidth = 70       --(*1)
      local launch_direction = vector(
         ball.separation_from_platform_center.x / platform_halfwidth, -1 )
      ball.speed = launch_direction / launch_direction:len() *
         ball.platform_launch_speed_magnitude
   end
end

(*1): Half-width of the big platform is used, since it provides more diverse angles.

For ball.launch_from_platform to be applicable on the start of the level (i.e. when the ball is stuck to the platform, but the platform is not "glued"), it is necessary to initialize ball.platform_launch_speed_magnitude and ball.separation_from_platform_center with some initial values.

local initial_launch_speed_magnitude = 300
ball.platform_launch_speed_magnitude = initial_launch_speed_magnitude
local ball_platform_initial_separation = vector(
   ball_x_shift, -1 * platform_height / 2 - ball.radius - 1 )
ball.separation_from_platform_center = ball_platform_initial_separation 

The glued effect is removed if any other bonus (except another "glue" bonus) is caught.

function bonuses.bonus_collected( i, bonus, ball, platform )
   if not bonuses.is_glue( bonus ) then
      platform.remove_glued_effect()
      ball.launch_from_platform()
   end
   .....
   table.remove( bonuses.current_level_bonuses, i )
end

function platform.remove_glued_effect()
   if platform.glued then
      platform.glued = false
      if platform.size == "small" then
         platform.quad = love.graphics.newQuad(
            platform.small_tile_x_pos,
            platform.small_tile_y_pos,
            platform.small_tile_width,
            platform.small_tile_height,
            platform.tileset_width,
            platform.tileset_height )
      elseif platform.size == "norm" then
         platform.quad = love.graphics.newQuad(
            platform.norm_tile_x_pos,
            platform.norm_tile_y_pos,
            platform.norm_tile_width,
            platform.norm_tile_height,
            platform.tileset_width,
            platform.tileset_height )
      elseif platform.size == "large" then
         platform.quad = love.graphics.newQuad(
            platform.large_tile_x_pos,
            platform.large_tile_y_pos,
            platform.large_tile_width,
            platform.large_tile_height,
            platform.tileset_width,
            platform.tileset_height )
      end
   end
end

The effect is also removed if the ball is lost, or the next level is reached.

function game.enter( prev_state, ... )
   .....
   if args and args.current_level then
      .....
      ball.reposition()
      platform.remove_bonuses_effects()
   end      
end

function game.check_no_more_balls( ball, lives_display )
   if ball.escaped_screen then
         .....
         ball.reposition()
         platform.remove_bonuses_effects()
         .....
   end
end

function platform.remove_bonuses_effects()
   platform.remove_glued_effect()
   platform.reset_size_to_norm()
end

function ball.reposition()
   ball.escaped_screen = false
   ball.collision_counter = 0
   ball.stuck_to_platform = true
   ball.platform_launch_speed_magnitude = initial_launch_speed_magnitude
   ball.separation_from_platform_center = ball_platform_initial_separation 
end