Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pygame circle not changing

I finally got the collision down so that when my mouse is hovering over the circles and you click the left mouse button, It fills in. It changes going up, but going down it doesn't.

Here's my code:

# Imports a library of functions!
import pygame
import random
# Initializes the game engine
pygame.init()
# Defines the colors
BLACK = (  0,   0,   0)
GREEN = (  3, 255,   3)
# Controls the width of the circle
width_1 = 2
width_2 = 2
width_3 = 2
width_4 = 2
# Un-fills circles
filled_1 = False
filled_2 = False
filled_3 = False
filled_4 = False
# Sets the height and width of the screen
size = [720, 575] 
screen = pygame.display.set_mode(size)
# Loops until the user clicks the close button
done = False
clock = pygame.time.Clock()
# While loop
while not done:
    # Leaves the fps at 30
    clock.tick(30)
    for event in pygame.event.get(): # If user did something
        if event.type == pygame.QUIT: # If user clicked close
             done = True
        elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            # Finds where you clicked            
            x, y = event.pos
            # Check if mouse was over it
            if circle_1.collidepoint(x, y):
                # Lets the circle draw
                filled_1 = True
                width_1 = 0
                if filled_1 == True:
                    circle_1 = pygame.draw.circle(screen, BLACK, [250, 230], 7, width_1)
            elif circle_2.collidepoint(x, y):
                # Lets the circle draw
                filled_2 = True
                width_2 = 0
                if filled_2 == True:
                    circle_2 = pygame.draw.circle(screen, BLACK, [250, 260], 7, width_2)               
            elif circle_3.collidepoint(x, y):
                # Lets the circle draw
                filled_3 = True
                width_3 = 0
                if filled_3 == True:
                    circle_3 = pygame.draw.circle(screen, BLACK, [250, 260], 7, width_3)
            elif circle_4.collidepoint(x, y):
                # Lets the circle draw
                filled_4 = True
                width_4 = 0
                if filled_4 == True:
                    circle_4 = pygame.draw.circle(screen, BLACK, [250, 260], 7, width_4)
    # Cleans the screen and sets the screen background
    screen.fill(GREEN)
    # Circles
    circle_1 = pygame.draw.circle(screen, BLACK, [250, 230], 7, width_1)
    circle_2 = pygame.draw.circle(screen, BLACK, [250, 260], 7, width_2)
    circle_3 = pygame.draw.circle(screen, BLACK, [250, 290], 7, width_3)
    circle_4 = pygame.draw.circle(screen, BLACK, [250, 320], 7, width_4)
    if filled_1 == True:
        filled_2 = False
        filled_3 = False
        filled_4 = False
        width_2 = 2
        width_3 = 2
        width_4 = 2
    elif filled_2 == True:
        filled_1 = False
        filled_3 = False
        filled_4 = False
        width_1 = 2
        width_3 = 2
        width_4 = 2
    elif filled_3 == True:
        filled_1 = False
        filled_2 = False
        filled_4 = False
        width_1 = 2
        width_2 = 2
        width_4 = 2
    elif filled_4 == True:
        filled_1 = False
        filled_2 = False
        filled_3 = False
        width_1 = 2
        width_2 = 2
        width_3 = 2
    # Update the screen
    pygame.display.flip()

Just run this code and see what happens, its pretty hard to explain.

like image 340
jason97931 Avatar asked Nov 27 '22 23:11

jason97931


1 Answers

Let's assume that the second one is clicked, so

filled_1 = False
filled_2 = True
filled_3 = False
filled_4 = False

Then you click the third. Thus,

filled_1 = False
filled_2 = True
filled_3 = True
filled_4 = False

You then have:

screen.fill(GREEN)

circle_1 = pygame.draw.circle(screen, BLACK, [250, 230], 7, width_1)
circle_2 = pygame.draw.circle(screen, BLACK, [250, 260], 7, width_2)
circle_3 = pygame.draw.circle(screen, BLACK, [250, 290], 7, width_3)
circle_4 = pygame.draw.circle(screen, BLACK, [250, 320], 7, width_4)

which will (tempoarily) draw two black circles.

You then do:

if filled_1 == True:
    # Not run

and then

elif filled_2 == True:
    filled_1 = False
    filled_3 = False
    filled_4 = False
    width_1 = 2
    width_3 = 2
    width_4 = 2

so now

filled_1 = False
filled_2 = True
filled_3 = False
filled_4 = False

This isn't wanted! Now

elif filled_3 == True:
    # Not run
elif filled_4 == True:
    # Not run

So clicking the third didn't work! This is because you don't store the order, which is needed.

I suggest moving this setting-to-false into the part inside the click handler:

if circle_1.collidepoint(x, y):
    # Lets the circle draw
    filled_1 = True
    width_1 = 0

    filled_2 = False
    filled_3 = False
    filled_4 = False
    width_2 = 2
    width_3 = 2
    width_4 = 2

    if filled_1 == True:
        circle_1 = pygame.draw.circle(screen, BLACK, [250, 230], 7, width_1)

# ... etc ...

That works beautifully.

Now, there is still a problem. If on the first iteration there was an event, circle_1 would not be defined. This would crash the program. You should define the circles first.


Some code advice.

Instead of

BLACK = (  0,   0,   0)
GREEN = (  3, 255,   3)

use

pygame.Color("black")
pygame.Color(3, 255, 3)

They exist for you!

Instead of having

thing_1 = ...
thing_2 = ...
...

other_thing_1 = ...
other_thing_2 = ...
...

have a list of dictionaries:

circles = [
    {
        "thing": ...,
        "other_thing": ...
    }, {
        "thing": ...,
        "other_thing": ...
    },
    ...
]

where you use circles[1]["thing"] instead of thing_1.

This allows you to "simplify" to:

import pygame
import random
pygame.init()

circles = [
    {
        "width": 2,
        "filled": False,
        "position": [250, 230]
    }, {
        "width": 2,
        "filled": False,
        "position": [250, 260]
    }, {
        "width": 2,
        "filled": False,
        "position": [250, 290]
    }, {
        "width": 2,
        "filled": False,
        "position": [250, 320]
    },
]

size = [720, 575] 
screen = pygame.display.set_mode(size)

    done = False
    clock = pygame.time.Clock()
    while not done:
        clock.tick(30)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                 done = True

            elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                x, y = event.pos

                # Check if mouse was over it
                if circles[1]["bounding box"].collidepoint(x, y):
                    # Lets the circle draw
                    circles[1]["filled"] = True
                    circles[1]["width"] = 0

                    circles[2]["filled"] = False
                    circles[3]["filled"] = False
                    circles[4]["filled"] = False
                    circles[2]["width"] = 2
                    circles[3]["width"] = 2
                    circles[4]["width"] = 2

                    if circles[1]["filled"] == True:
                        circles[1]["bounding box"] = pygame.draw.circle(screen, pygame.Color("black"), [250, 230], 7, circles[1]["width"])

                ...
    # Cleans the screen and sets the screen background
    screen.fill(pygame.Color(3, 255, 3))
    # Circles
    circles[1]["bounding box"] = pygame.draw.circle(screen, pygame.Color("black"), circles[1]["position"], 7, circles[1]["width"])
    circles[2]["bounding box"] = pygame.draw.circle(screen, pygame.Color("black"), circles[2]["position"], 7, circles[2]["width"])
    circles[3]["bounding box"] = pygame.draw.circle(screen, pygame.Color("black"), circles[3]["position"], 7, circles[3]["width"])
    circles[4]["bounding box"] = pygame.draw.circle(screen, pygame.Color("black"), circles[4]["position"], 7, circles[4]["width"])
    # Update the screen
    pygame.display.flip()

That might not look simpler, but it allows you to use loops instead of specifying things over and over:

import pygame
import random
pygame.init()

circles = [
    {
        "width": 2,
        "filled": False,
        "position": [250, 230]
    }, {
        "width": 2,
        "filled": False,
        "position": [250, 260]
    }, {
        "width": 2,
        "filled": False,
        "position": [250, 290]
    }, {
        "width": 2,
        "filled": False,
        "position": [250, 320]
    },
]

size = [720, 575] 
screen = pygame.display.set_mode(size)

done = False
clock = pygame.time.Clock()
while not done:
    clock.tick(30)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
             done = True

        elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            x, y = event.pos

            for circle in circles:
                # Check if mouse was over it
                if circle["bounding box"].collidepoint(x, y):
                    # Lets the circle draw
                    circle["filled"] = True
                    circle["width"] = 0

                    for othercircle in circles:
                        if othercircle is not circle:
                            othercircle["filled"] = False
                            othercircle["width"] = 2

                    if circle["filled"] == True:
                        circle["bounding box"] = pygame.draw.circle(screen, pygame.Color("black"), circle["position"], 7, circle["width"])

    # Cleans the screen and sets the screen background
    screen.fill(pygame.Color(3, 255, 3))
    # Circles
    for circle in circles:
        circle["bounding box"] = pygame.draw.circle(screen, pygame.Color("black"), circle["position"], 7, circle["width"])
    # Update the screen
    pygame.display.flip()

With this design:

Q: What do you do to add another circle?
A: You add it to circles.

Q: What do you do to make a circle larger?
A: You increase its size property.

Q: What do you do to change the way collisions are checked for?
A: You change the one place collisions are checked.


See the benefit? :)

like image 141
Veedrac Avatar answered Dec 05 '22 04:12

Veedrac