local tau = math.pi * 2 local game = {} local function load_level(level, bubble_diameter, row_gap) local slots = {} local bubble_radius = bubble_diameter / 2 -- set prev_num_cols to size of 2nd row so x_offset is correct when row == 1 local prev_num_cols = #level[2] for row = 1, #level do local num_cols = #level[row] local x_offset = num_cols < prev_num_cols and bubble_radius or 0 for col = 1, num_cols do slots[#slots+1] = { x = x_offset + bubble_radius + (col - 1) * bubble_diameter, y = bubble_radius + (row - 1) * row_gap, bubble_type = level[row][col] } end prev_num_cols = num_cols end return slots end -- ex. remaining_bubble_types = {1,4,5,8} -- should only be regular, not special local function get_next_bubble_type(index, remaining_bubble_types) return remaining_bubble_types[love.math.random(#remaining_bubble_types)] end function love.load(arg) game.window_width, game.window_height = love.graphics.getDimensions() game.bubble_diameter = 60 game.bubble_radius = game.bubble_diameter / 2 game.bubble_speed = 900 -- px/s -- vertical distance between bubble center points game.row_gap = math.ceil(math.sqrt( (game.bubble_diameter * game.bubble_diameter) - (game.bubble_radius * game.bubble_radius) )) game.background_image = love.graphics.newImage('images/background.png') game.background_width = game.background_image:getWidth() game.bubble_images = { love.graphics.newImage('images/red.png'), -- 1 love.graphics.newImage('images/orange.png'), -- 2 love.graphics.newImage('images/yellow.png'), -- 3 love.graphics.newImage('images/green.png'), -- 4 love.graphics.newImage('images/blue.png'), -- 5 love.graphics.newImage('images/purple.png'), -- 6 love.graphics.newImage('images/pink.png'), -- 7 love.graphics.newImage('images/white.png') -- 8 } game.levels = {} game.levels[1] = { {1,1,1,3,3,2,2,2}, { 1,1,3,3,3,2,2 }, {4,4,7,8,8,6,5,5}, { 4,7,7,8,6,6,5 }, {0,0,0,0,0,0,0,0}, { 0,0,0,0,0,0,0 }, {0,0,0,0,0,0,0,0}, { 0,0,0,0,0,0,0 }, {0,0,0,0,0,0,0,0}, { 0,0,0,0,0,0,0 }, {0,0,0,0,0,0,0,0}, { 0,0,0,0,0,0,0 }, {0,0,0,0,0,0,0,0}, { 0,0,0,0,0,0,0 } } game.current_level = 1 game.bubble_slots = load_level( game.levels[game.current_level], game.bubble_diameter, game.row_gap ) local bubbles_wide = math.max( #game.levels[game.current_level][1], #game.levels[game.current_level][2] ) local bubbles_high = #game.levels[game.current_level] game.level_width = bubbles_wide * game.bubble_diameter game.level_height = (bubbles_high - 1) * game.row_gap + game.bubble_diameter game.level_x = (game.window_width - game.level_width) / 2 game.level_y = game.bubble_radius game.launcher_image = love.graphics.newImage('images/launcher.png') game.launcher_height = game.launcher_image:getHeight() game.launcher_width = game.launcher_image:getWidth() game.launcher_x = game.window_width / 2 game.launcher_y = game.level_y + game.level_height + game.bubble_diameter game.launcher_offset_x = 90 -- rotation point in launcher image game.launcher_offset_y = game.launcher_height / 2 game.launcher_rotation = -tau / 4 -- up game.bubble_type_counts = {} local bubble_types = {} for i = 1, #game.bubble_slots do local bubble_type = game.bubble_slots[i].bubble_type if game.bubble_type_counts[bubble_type] == nil then game.bubble_type_counts[bubble_type] = 0 if bubble_type >= 1 and bubble_type <= 8 then bubble_types[#bubble_types+1] = bubble_type end end game.bubble_type_counts[bubble_type] = game.bubble_type_counts[bubble_type] + 1 end game.next_bubble_index = 1 game.next_bubble = { x = game.launcher_x, y = game.launcher_y, bubble_type = get_next_bubble_type(game.next_bubble_index, bubble_types), velocity_x = 0, velocity_y = 0 } end function love.update(dt) if game.next_bubble.velocity_x ~= 0 or game.next_bubble.velocity_y ~= 0 then game.next_bubble.x = game.next_bubble.x + game.next_bubble.velocity_x * dt game.next_bubble.y = game.next_bubble.y + game.next_bubble.velocity_y * dt end end function love.draw() -- draw background love.graphics.setColor(1, 1, 1, 1) love.graphics.draw(game.background_image, 0, 0) love.graphics.draw(game.background_image, game.background_width, 0) -- draw stationary bubbles for i = 1, #game.bubble_slots do local slot = game.bubble_slots[i] if slot.bubble_type >= 1 and slot.bubble_type <= #game.bubble_images then love.graphics.draw( game.bubble_images[slot.bubble_type], -- image game.level_x + slot.x, -- x game.level_y + slot.y, -- y 0, -- rotation 1, -- x scale 1, -- y scale game.bubble_radius, -- x offset game.bubble_radius -- y offset ) else love.graphics.circle( 'line', game.level_x + slot.x, game.level_y + slot.y, game.bubble_radius ) end end -- draw level border love.graphics.setColor(0, 0, 0, 1) love.graphics.rectangle( 'line', game.level_x, game.level_y, game.level_width, game.level_height ) -- draw launcher love.graphics.setColor(1, 1, 1, 1) love.graphics.draw( game.launcher_image, game.launcher_x, game.launcher_y, game.launcher_rotation, 1, 1, game.launcher_offset_x, game.launcher_offset_y ) -- draw next bubble love.graphics.setColor(1, 1, 1, 1) love.graphics.draw( game.bubble_images[game.next_bubble.bubble_type], game.next_bubble.x, game.next_bubble.y, 0, 1, 1, game.bubble_radius, game.bubble_radius ) end function love.mousepressed(x, y, button, is_touch, presses) if button == 1 then local diff_x = x - game.launcher_x local diff_y = y - game.launcher_y local dist = math.sqrt(diff_x * diff_x + diff_y * diff_y) game.next_bubble.velocity_x = diff_x / dist * game.bubble_speed game.next_bubble.velocity_y = diff_y / dist * game.bubble_speed end end function love.mousemoved(x, y, dx, dy, is_touch) local diff_x = x - game.launcher_x local diff_y = y - game.launcher_y game.launcher_rotation = math.atan2(diff_y, diff_x) end function love.keypressed(key, scan_code, is_repeat) if key == 'escape' then love.event.quit() end end