Search code examples
pythonrandompygameoverlap

How to stop pygame circles from overlapping?


I am making a game in pygame, and I am trying to display 7 balloons (circles for now), with random colors, and a random x-axis. The colors are working, however, when trying to display the circles at a random x-axis, the circles usually overlap. How can I fix this issue?

Here's my code:

import pygame as pg
import random as r
import sys

pg.init()

def draw_balloons():
    global balloon_list
    global colors
    for i in range(7):
        balloon_x = r.randint(0, 500)
        balloon_color = (r.choice([0,255]), r.randint(0,255), r.choice([0,255]))
        balloon_list.append(balloon_x)
        colors.append(balloon_color)
        pg.draw.circle(screen, colors[i], (balloon_list[i], y), radius=30)

# Vars #
balloon_list = []
colors = []
x = 0
y = 250
velocity = 5
clock = pg.time.Clock()

screen = pg.display.set_mode((688 ,387)) # Size of the screen #
screen.fill('#ffffff')

caption = pg.display.set_caption("Remember") # Title of the window #


pg.display.flip() # Updating #

running = True # Game loop bool #

while running: # Game loop #
    clock.tick(60)
    for event in pg.event.get():
        if event.type == pg.QUIT:
            pg.quit()
            sys.exit()
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_ESCAPE:
                pg.quit()
                sys.exit()

    draw_balloons()
    pg.display.update()

enter image description here

P.S: How can I make the circles in more of a balloon shape without using an image?


Solution

  • This following brute-force approach seems to work for the relatively small number of balloons. There's now a separate function called create_ballons() which does nothing by determine their positions and colors which is called outside the game loop. Given that, all draw_ballons() does now is draw them.

    I say it's brute-force because it simply checks every new potential balloon x position against all of those already picked and ensures it's not too close to any of them.

    One bug I noted about your draw_ballons() function is that it keeps appending more values to the two lists, but is only drawing the first seven — so eventually you'll run out of memory.

    import pygame as pg
    import random as r
    import sys
    
    MAX_ATTEMPTS = 1000
    NUM_BALLOONS = 7
    WIDTH, HEIGHT = 688, 387  # Screen size.
    RADIUS = 30
    DIAMETER = 2 * RADIUS
    
    pg.init()
    
    def create_balloons():
        global balloon_list
        global colors
    
        x_min, x_max = 0+RADIUS, WIDTH-RADIUS  # Constrain to be entirely on screen.
        max_balloons = (x_max-x_min) // DIAMETER  # Maximum that would fit.
        num_balloons = min(NUM_BALLOONS, max_balloons)  # No more than what could fit.
    
        balloon_list = []
        colors = []
        for _ in range(num_balloons):
            attempts = 0
            while (attempts := attempts+1) <= MAX_ATTEMPTS:
                candidate = r.randint(x_min, x_max)
                if all(abs(candidate-x) >= DIAMETER for x in balloon_list):  # No overlaps.
                    break
            else:
                raise RuntimeError(f"No valid candiate after {attempts-1} attempts.")
            balloon_list.append(candidate)
            balloon_color = r.choice([0,255]), r.randint(0,255), r.choice([0,255])
            colors.append(balloon_color)
    
    def draw_balloons(y):
        for i, x in enumerate(balloon_list):
            pg.draw.circle(screen, colors[i], (x, y), RADIUS)
    
    
    # Vars #
    balloon_list = []
    colors = []
    x = 0
    y = 250
    velocity = 5
    clock = pg.time.Clock()
    
    screen = pg.display.set_mode((WIDTH, HEIGHT)) # Size of the screen #
    caption = pg.display.set_caption("Remember") # Title of the window #
    create_balloons()
    
    pg.display.flip() # Updating #
    
    running = True # Game loop bool #
    
    while running: # Game loop #
        clock.tick(60)
        for event in pg.event.get():
            if event.type == pg.QUIT:
                pg.quit()
                sys.exit()
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_ESCAPE:
                    pg.quit()
                    sys.exit()
    
        draw_balloons(y)
    
        pg.display.update()
    

    Here's a screenshot:

    screenshot showing non-overlapping circles