I think using a separate type for the bubbles in the circle is a good idea. This way, you can use Blitz's builtin list to keep track of the order of the bubbles in the circle. When you fire a bubble at the circle, you can Insert the new bubble into the correct location.
Here's a quick hack of the general idea:
I can't figure out the correct math for the correct_circle_offset() routine, which is supposed to be responsible for making the circle expand or contract equally on both sides of an insert or pop, instead of leaving the first bubble always in the same place.
Hopefully this is useful to you.
Here's a quick hack of the general idea:
const BUBBLE_RADIUS = 20 const POPPING_THRESHOLD = 3 type circle_bubble field colour_index% end type type middle_bubble field colour_index% end type global circle_bubble_count% global circle_origin_angle_offset# global middle_bubble.middle_bubble function create_circle_bubble.circle_bubble(colour_index% = -1) eb.circle_bubble = new circle_bubble if colour_index = -1 then colour_index = rand(1, 7) eb\colour_index = colour_index circle_bubble_count = circle_bubble_count + 1 return eb end function function destroy_circle_bubble(eb.circle_bubble) delete eb circle_bubble_count = circle_bubble_count - 1 end function function find_circle_bubble_at_position.circle_bubble(index%) this_bubble.circle_bubble = first circle_bubble for i = 0 to index - 1 this_bubble = after this_bubble next return this_bubble end function function find_angle_of_bubble(this_bubble.circle_bubble) ang# = circle_origin_angle_offset for b.circle_bubble = each circle_bubble if b = this_bubble then return ang ang = ang + 360.0 / circle_bubble_count next end function function create_middle_bubble() middle_bubble = new middle_bubble middle_bubble\colour_index = rand(1, 7) end function function correct_circle_offset(insertion_ang#, bubbles_added%) ; this is all wrong! ;effect# = (constrain_0_to_360(insertion_ang) - 180) / 180 ;circle_origin_angle_offset = circle_origin_angle_offset - bubbles_added*BUBBLE_RADIUS/2 * -effect end function ; init graphics 800, 600 setbuffer backbuffer() for i = 1 to 20 create_circle_bubble() next create_middle_bubble() ; game loop while not keyhit(1) update_game() draw_world() wend end function update_game() circle_origin_angle_offset = circle_origin_angle_offset + 1 if mousehit(1) then mx# = mousex() - graphicswidth() / 2 my# = mousey() - graphicsheight() / 2 local firing_angle# if my <> 0 then firing_angle = atan(mx / my) if my < 0 then firing_angle = firing_angle + 180 else if mx > 0 then firing_angle = 90 else firing_angle = 270 endif firing_angle = constrain_0_to_360(firing_angle - circle_origin_angle_offset) strike_after_index% = floor(firing_angle / (360.0 / circle_bubble_count)) + 1 bubble_before.circle_bubble = find_circle_bubble_at_position(strike_after_index) correct_circle_offset(find_angle_of_bubble(bubble_before) + 360.0 / circle_bubble_count / 2, 1) new_bubble.circle_bubble = create_circle_bubble(middle_bubble\colour_index) if bubble_before <> null then insert new_bubble before bubble_before delete middle_bubble create_middle_bubble() check_for_poppage(new_bubble) endif end function function check_for_poppage(bubble_to_check.circle_bubble) bubbles_to_pop% = 1 first_bubble_to_pop.circle_bubble = bubble_to_check last_bubble_to_pop.circle_bubble = bubble_to_check while true test_bubble.circle_bubble = before first_bubble_to_pop if test_bubble = null then test_bubble = last circle_bubble if test_bubble\colour_index <> first_bubble_to_pop\colour_index then exit if test_bubble = last_bubble_to_pop then exit first_bubble_to_pop = test_bubble bubbles_to_pop = bubbles_to_pop + 1 wend while true test_bubble.circle_bubble = after last_bubble_to_pop if test_bubble = null then test_bubble = first circle_bubble if test_bubble\colour_index <> last_bubble_to_pop\colour_index then exit if test_bubble = first_bubble_to_pop then exit last_bubble_to_pop = test_bubble bubbles_to_pop = bubbles_to_pop + 1 wend if bubbles_to_pop >= POPPING_THRESHOLD then popping_angle# = (find_angle_of_bubble(first_bubble_to_pop) + find_angle_of_bubble(last_bubble_to_pop)) / 2 correct_circle_offset(popping_angle, -bubbles_to_pop) doomed_bubble.circle_bubble = first_bubble_to_pop repeat next_bubble.circle_bubble = after doomed_bubble if next_bubble = null then next_bubble = first circle_bubble destroy_circle_bubble(doomed_bubble) doomed_bubble = next_bubble until last_bubble_to_pop = null ; check if we just closed a gap on more bubbles to pop if doomed_bubble <> null then check_for_poppage(doomed_bubble) endif end function function draw_world() cls circle_circumference = circle_bubble_count * BUBBLE_RADIUS * 2 circle_radius# = circle_circumference / PI / 2 eb_index% = 0 for eb.circle_bubble = each circle_bubble ang# = eb_index * 360.0 / circle_bubble_count + circle_origin_angle_offset x = sin(ang) * circle_radius + graphicswidth() / 2 y = cos(ang) * circle_radius + graphicsheight() / 2 set_colour_by_index(eb\colour_index) oval(x-BUBBLE_RADIUS, y-BUBBLE_RADIUS, BUBBLE_RADIUS*2, BUBBLE_RADIUS*2) eb_index = eb_index + 1 next x = graphicswidth() / 2 y = graphicsheight() / 2 set_colour_by_index(middle_bubble\colour_index) oval(x-BUBBLE_RADIUS, y-BUBBLE_RADIUS, BUBBLE_RADIUS*2, BUBBLE_RADIUS*2) flip end function function set_colour_by_index(colour_index%) if colour_index = 1 then color(255, 0, 0) if colour_index = 2 then color( 0, 255, 0) if colour_index = 3 then color(255, 255, 0) if colour_index = 4 then color( 0, 0, 255) if colour_index = 5 then color(255, 0, 255) if colour_index = 6 then color( 0, 255, 255) if colour_index = 7 then color(255, 255, 255) end function function constrain_0_to_360#(ang#) while ang < 0 : ang = ang + 360 : wend ang = ang mod 360 return ang end function
I can't figure out the correct math for the correct_circle_offset() routine, which is supposed to be responsible for making the circle expand or contract equally on both sides of an insert or pop, instead of leaving the first bubble always in the same place.
Hopefully this is useful to you.