Trouble with detetcting where a player clicks - python

So I made a simple tracking game as a project, everything about the base works (clicking green squares for +1 point) but when I added a blue square that only sometimes appears it doesnt want to detect it when a player clicks on it.
import tkinter
canvas = tkinter.Canvas(width=500,height=500)
from random import *
canvas.pack()
def timer1():
canvas.delete("all")
global cx,cy,rn
rn = randrange(3)
cx = randrange(50,300)
cy = randrange(20,250)
cw = randrange(50,300)
cz = randrange(20,250)
canvas.create_rectangle(cx,cy,cx-size,cy+size,fill="green")
canvas.create_text(100,10,text="Score: ")
canvas.create_text(200,10,text=score)
if rn == 2:
canvas.create_rectangle(cw,cz,cw-size,cz+size,fill="blue")
if score < 100 and score > -10:
canvas.after(1000,timer1)
elif score == -10:
canvas.delete("all")
canvas.create_text(200,100,text="Wow you suck :/")
else:
canvas.delete("all")
canvas.create_text(200,100,text="Good job")
def click(cor):
global score
x = cor.x
y = cor.y
if cx > x > cx-size and cy < y < cy+size:
score = score + 1
else:
score = score -1
if cw > x > cw-size and cz < y < cz+size:
score = score + 5
canvas.bind("<Button-1>",click)
score = 0
cx = 0
cy = 0
cz = 0
cw = 0
rn = 0
size = 50
timer1()

You need to declare cw and cz as global variables inside timer1() as well.

Related

I can't find a method to prevent my program slowing down as it loads more sprites python

I have created a simple simulation to show evolution. It works through a simuple window that contains many squares representing single-celled organisms. The screen looks like this:
The single-celled organisms (dubbed amoebae for conciseness) move around randomly. If they collide with another amoebae they produce an offspring. However, to prevent them reproducing infinitely I introduced an age measure. Amoebae must attain a certain age before they reproduce and once they do their age is reset to 1.
Now for the evolution part. As you can see, the amoebae are different colours. This represents the 'gene' that is passed down to offspring through reproduction (there is a chance of mutation controlled by a constant called maturingSpeed, which I set very high to increase the speed of evolution). It's called maturingSpeed and it controls the speed at which the amoebae age, which means that amoebae that have a higher maturingSpeed with reproduce faster and pass on their gene. In this way, they should gradually evolve through natural selection so all of the amoebae have a very high maturingSpeed. A high maturingSpeed translates to a brighter colour on the screen.
There is one other thing I should mention, which is the life countdown on each amoeba. It starts out at 10000 and ticks down by one each time the amoeba is updated. This is to gradually kill off the old amoebae, also increasing the rate of evolution and making it more lifelike.
My problem is that before the amoebae all evolve to get a high maturingSpeed (the highest I've had is around 65%), they become too numerous and the simulation starts slowing down as it struggles to load them all. I need a method to make the amoebae die off faster as more of them are produced. I have tried to cull them if they are above a certain number, or increase their countdown rate based on the number of amoebae however all of these methods cause them to eventually stop reproducing and die off for some reason. I have deleted these sections from my code now because they didn't work but I could add them again if needed.
My source code:
import pygame
import random
import time
import itertools
from pygame.locals import (
QUIT
)
pygame.init()
SCREEN_WIDTH = 500
SCREEN_HEIGHT = 500
screen = pygame.display.set_mode([500, 500])
amoebas = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
idList = []
mutationConstant = 254
class Amoeba(pygame.sprite.Sprite):
id_iter = itertools.count()
def __init__(self, maturingSpeed, x, y):
super(Amoeba, self).__init__()
self.id = 'amoeba' + str(next(Amoeba.id_iter))
idList.append(self.id)
self.surf = pygame.Surface((10,10))
if maturingSpeed <= 0:
maturingSpeed = 1
elif maturingSpeed >= 255:
maturingSpeed = 254
print(maturingSpeed)
self.surf.fill((maturingSpeed, 0, 0))
self.rect = self.surf.get_rect(
center=(
x,
y,
)
)
self.speed = 2
self.age = 1
self.maturingSpeed = int(maturingSpeed)
self.life = 9999
def update(self):
if self.rect.left <= 0:
direction = 1
elif self.rect.right >= SCREEN_WIDTH:
direction = 2
elif self.rect.top <= 0:
direction = 3
elif self.rect.bottom >= SCREEN_HEIGHT:
direction = 4
else:
direction = random.randint(1, 4)
if direction == 1:
self.rect.move_ip(self.speed, 0)
elif direction == 2:
self.rect.move_ip(-self.speed, 0)
elif direction == 3:
self.rect.move_ip(0, self.speed)
elif direction == 4:
self.rect.move_ip(0, -self.speed)
self.life = self.life - 1
if self.life <= 0:
self.kill()
modMaturingSpeed = self.maturingSpeed / 1240
self.age = self.age + (1 * modMaturingSpeed)
#classmethod
def collide(cls):
global collisionSuccess
collisionSuccess = False
global posList
posList = [[amoeba.rect.left, amoeba.rect.bottom] for amoeba in amoebas]
length = len(posList)
for i in range(length):
for amoeba in amoebas:
if amoeba.id == str(idList[i]):
ageOne = getattr(amoeba, 'age')
for h in range(i+1, length):
for amoeba in amoebas:
if amoeba.id == str(idList[h]):
ageTwo = getattr(amoeba, 'age')
OneX = int(posList[i][0])
OneY = int(posList[i][1])
TwoX = int(posList[h][0])
TwoY = int(posList[h][1])
if ageOne >= 100 and ageTwo >= 100:
if (OneX < TwoX + 10 and OneX + 10 > TwoX
and OneY < TwoY + 10 and 10 + OneY > TwoY):
for amoeba in amoebas:
if amoeba.id == str(idList[i]):
setattr(amoeba, 'age', 1)
pOMSinitial = int(getattr(amoeba, 'maturingSpeed'))
for amoeba in amoebas:
if amoeba.id == str(idList[h]):
setattr(amoeba, 'age', 1)
pTMSinitial = int(getattr(amoeba, 'maturingSpeed'))
locationX = OneX + random.randint(-10, 10)
locationY = OneY + random.randint(-10, 10)
if pOMSinitial >= pTMSinitial:
pOMSfinal = pOMSinitial + mutationConstant
pTMSfinal = pTMSinitial - mutationConstant
newMaturingSpeed = random.randint(pTMSfinal, pOMSfinal)
else:
pOMSfinal = pOMSinitial - mutationConstant
pTMSfinal = pTMSinitial + mutationConstant
newMaturingSpeed = random.randint(pOMSfinal, pTMSfinal)
collisionSuccess = True
return cls(newMaturingSpeed, locationX, locationY)
screen.fill((255, 255, 255))
for i in range(15):
amoebaname = Amoeba(random.randint(100, 150), random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
amoebas.add(amoebaname)
all_sprites.add(amoebaname)
p = 0
while True:
ageArray = [amoeba.age for amoeba in amoebas]
if p == 1000:
print(amoebas)
five = 0
four = 0
three = 0
two = 0
one = 0
for amoeba in amoebas:
if amoeba.maturingSpeed >= 200:
five = five + 1
elif amoeba.maturingSpeed >=150:
four = four + 1
elif amoeba.maturingSpeed >= 100:
three = three + 1
elif amoeba.maturingSpeed >= 50:
two = two + 1
else:
one = one + 1
total = one + two + three + four + five
DivFive = five / total
DivFour = four / total
DivThree = three / total
DivTwo = two / total
DivOne = one / total
print(DivFive, DivFour, DivThree, DivTwo, DivOne)
p = 0
else:
p = p + 1
time.sleep(0.0000001)
screen.fill((255, 255, 255))
for event in pygame.event.get():
if event.type == QUIT:
break
amoebas.update()
amoebaname = Amoeba.collide()
if collisionSuccess == True:
amoebas.add(amoebaname)
all_sprites.add(amoebaname)
for entity in all_sprites:
screen.blit(entity.surf, entity.rect)
pygame.display.flip()
pygame.quit()
Too many nested loops and unneeded data structures. I did some cleanup and it's faster now. And it seems that the mutation constant was far to high. I changed the value from 254 to 25.
import pygame
import random
import time
import itertools
from pygame.locals import (
QUIT
)
SCREEN_WIDTH = 500
SCREEN_HEIGHT = 500
MUTATION_CONSTANT = 25
pygame.init()
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
amoebas = pygame.sprite.Group()
class Amoeba(pygame.sprite.Sprite):
id_iter = itertools.count()
def __init__(self, maturing_speed, x, y):
super().__init__()
self.id = 'amoeba' + str(next(Amoeba.id_iter))
self.surf = pygame.Surface((10, 10))
self.maturing_speed = min(max(maturing_speed, 1), 254)
self.surf.fill((self.maturing_speed, 0, 0))
self.rect = self.surf.get_rect(center=(x, y,))
self.speed = 2
self.age = 1
self.life = 9999
def update(self):
if self.rect.left <= 0:
direction = 1
elif self.rect.right >= SCREEN_WIDTH:
direction = 2
elif self.rect.top <= 0:
direction = 3
elif self.rect.bottom >= SCREEN_HEIGHT:
direction = 4
else:
direction = random.randint(1, 4)
if direction == 1:
self.rect.move_ip(self.speed, 0)
elif direction == 2:
self.rect.move_ip(-self.speed, 0)
elif direction == 3:
self.rect.move_ip(0, self.speed)
elif direction == 4:
self.rect.move_ip(0, -self.speed)
self.life = self.life - 1
if self.life <= 0:
self.kill()
self.age = self.age + (1 * self.maturing_speed / 1240)
#classmethod
def collide(cls):
for amoeba_1, amoeba_2 in itertools.combinations(amoebas, 2):
if amoeba_1.age >= 100 and amoeba_2.age >= 100 and (
pygame.sprite.collide_rect(amoeba_1, amoeba_2)
):
amoeba_1.age = 1
amoeba_2.age = 1
location_x = amoeba_1.rect.left + random.randint(-10, 10)
location_y = amoeba_1.rect.bottom + random.randint(-10, 10)
speed_low = min(amoeba_1.maturing_speed, amoeba_2.maturing_speed) - MUTATION_CONSTANT
speed_high = max(amoeba_1.maturing_speed, amoeba_2.maturing_speed) + MUTATION_CONSTANT
new_maturing_speed = random.randint(speed_low, speed_high)
return cls(new_maturing_speed, location_x, location_y)
return None
def main():
screen.fill((255, 255, 255))
for i in range(25):
amoeba = Amoeba(random.randint(100, 150), random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
amoebas.add(amoeba)
step_counter = 0
while True:
step_counter += 1
if step_counter % 100 == 0:
print(step_counter, amoebas)
five = 0
four = 0
three = 0
two = 0
one = 0
for amoeba in amoebas:
if amoeba.maturing_speed >= 200:
five = five + 1
elif amoeba.maturing_speed >= 150:
four = four + 1
elif amoeba.maturing_speed >= 100:
three = three + 1
elif amoeba.maturing_speed >= 50:
two = two + 1
else:
one = one + 1
total = one + two + three + four + five
print(f'{five/total:.4f} {four/total:.4f} {three/total:.4f} {two/total:.4f} {one/total:.4f}')
time.sleep(0.0000001)
screen.fill((255, 255, 255))
for event in pygame.event.get():
if event.type == QUIT:
break
amoebas.update()
amoeba = Amoeba.collide()
if amoeba:
amoebas.add(amoeba)
for amoeba in amoebas:
screen.blit(amoeba.surf, amoeba.rect)
pygame.display.flip()
pygame.quit()
if __name__ == '__main__':
main()

How to set random movement direction of koning(ghost in pacman) and how to make the coins to disappear in pacman game using tKinter?

We are creating pacman in Python- tKinter(not in pygame) and the coins are not disappearing. I am not able to finish the program of random movement of koning(ghost).
It is supposed to change direction every 10 steps and not go out of the canvas. The coins are supposed to disappear after the pacman goes through the coin, it would disappear. The coins are supposed to be counted and be shown in the corner. After the 3 times the pacman meets the ghost, it would print ;Game over;.
sirka = 0
vyska = 0
koning_x = 0
koning_y = 0
```pome=coins
pome_x = 0
pome_y = 0
random_direction = random.randint(0,3)
counter = 10
def platne_pole (y, x) :
global sirka
global vyska
if (x > 0 and x < sirka - 1) and (y > 0 and y < vyska - 1):
return True
return False
def kmove (event):
global koning_x
global koning_y
global mapa
target_x = koning_x *cell_size
target_y = koning_y *cell_size
def posun (target_x, target_y, koning_smer):
if koning_smer == 0:
target_y -= 1
elif koning_smer == 1:
target_x += 1
elif koning_smer == 2:
target_y += 1
elif koning_smer == 3:
target_x == 1
return target_x, target_y
target_x, target_y = kmove(koning_x, koning_y, koning_smer)

Keeping the turtle inside a square, no output and no errors

I wanted turtle not to go out of square
the window comes out and no error but loading keeps and if I click the window, it shuts down.
x, y is turtle's location.
D is to show weather or not turtle is inside square and on line(?).
a is nothing
direction changes
speed changes
location check and change
if turtle's in line, it go along boundary.
import turtle
import msvcrt
turtle.setup(100, 100, 0, 0)
t = turtle.Turtle()
D = 0
a = 1
while True:
if msvcrt.kbhit():
c = msvcrt.getch().decode('UTF - 8')
if c == 'j': # turn left
t.left(10)
if c == 'k':
t.right(10)
if c == 'a':# speed change
a += 1
if a > 10: # speed limitation
a = 10
if c == 'z':
a += -1
if a < 0:
a = 0
#---------------------------------------
x = t.xcor() # turtle's location
y = t.ycor()
if x > 100: # if go out of square, go back to the square
t.setx(100)
if x < -100:
t.setx(-100)
if y > 100:
t.sety(100)
if y < -100:
t.sety(-100)
#---------------------------------------
x = t.xcor() # turtle's location
y = t.ycor()
h = t.heading() # turtle's direction
#---------------------------------------
if - 100 < x < 100 and -100 < y < 100:
D = 0 # if it's in the square, D = 0
elif x == 100 and -100 < y < 100: # if it's in ~
if 0 <= d <= 90: # direction changes
t.setheading(90) # direction change to 90 degrees
D = 1 # D = 1
elif 270 <= d < 360:
t.setheading(270)
D = 2
elif x == -100 and -100 < y < 100:
if 90 <= d < 180:
t.setheading(90)
D = 2
elif 180 <= d <= 270:
t.setheading(270)
D = 1
elif y == 100 and -100 < x < 100:
if 0 <= d < 90:
t.setheading(0)
D = 2
elif 90 <= d <= 180:
t.setheading(180)
D = 1
elif y == -100 and -100 < x < 100:
if 180 <= d < 270:
t.setheading(180)
D = 2
elif 270 <= d < 360:
t.setheading(0)
D = 1
elif D == 1:
t.left(90)
elif D == 2:
t.right(90)
This code is a mess. First, by setting your window size to 100 x 100 and then moving your turtle between -100 and 100 in both dimensions, only 1/4 of your field of play is visible! Why use the msvcrt module when turtle has perfectly good keyboard events built in? As far as I can tell, your code checks and corrects the turtle's position but never actually moves it! And you have a while True: loop which has no place in an event-driven environment like turtle.
Let's start over with a simple example of motion within a square which can be manipulated via the keyboard:
from turtle import Screen, Turtle
def turn_left():
turtle.left(10)
def turn_right():
turtle.right(10)
def speed_up():
speed = turtle.speed() + 1
if speed > 10: # speed limitation
speed = 10
turtle.speed(speed)
def slow_down():
speed = turtle.speed() - 1
if speed < 1: # speed limitation
speed = 1
turtle.speed(speed)
def move():
# there are two different senses of 'speed' in play, we'll exploit
# both! I.e. as we move faster, we'll draw faster and vice versa
turtle.forward(turtle.speed())
# if we go out of square, go back into the square
if not -100 < turtle.xcor() < 100:
turtle.undo()
turtle.setheading(180 - turtle.heading())
elif not -100 < turtle.ycor() < 100:
turtle.undo()
turtle.setheading(360 - turtle.heading())
screen.ontimer(move, 100)
screen = Screen()
screen.setup(300, 300)
# show turtle's boundary
boundary = Turtle('square', visible=False)
boundary.color('pink')
boundary.shapesize(10)
boundary.stamp()
turtle = Turtle()
move()
screen.onkey(turn_left, 'j')
screen.onkey(turn_right, 'k')
screen.onkey(speed_up, 'a')
screen.onkey(slow_down, 'z')
screen.listen()
screen.mainloop()

Snake segments that "flow" rather than "snap" to the snake's head position

I am trying to make a snake game in python and I would like the segments of the snake to flow when the user presses the WASD keys rather than the segments snapping to the user's desired direction
import pygame
import random
import time
pygame.init()
win = pygame.display.set_mode((800,600))
pygame.display.set_caption("Pygame")
clock = pygame.time.Clock()
x = 30
y = 30
x2 = x
y2 = random.randrange(1,601-30)
vel = 2
run = True
facing = 0
direction = 0
text = pygame.font.SysFont('Times New Roman',30)
score = 0
segments = []
green = ((0,128,0))
white = ((255,255,255))
counting = 0
segmentTime = time.time()
class segmentClass():
def __init__(self,x,y,pos,color):
self.x = x
self.y = y
self.pos = pos
self.color = color
def draw(self,win):
pygame.draw.rect(win,(self.color),(self.x,self.y,30,30))
def gameOver():
global run
run = False
def segmentGrowth():
global x2
global y2
global score
global vel
global ammount
segments.append(segmentClass(x,y,len(segments)+1,green))
ammount = 0
x2 = random.randrange(1,801-30)
y2 = random.randrange(1,601-30)
score += 1
print(vel)
while run:
currentTime = time.time()
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
vel += (score*0.0001)
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
if direction != 1:
direction = 1
facing = -1
if keys[pygame.K_s]:
if direction != 1:
direction = 1
facing = 1
if keys[pygame.K_a]:
if direction != 0:
direction = 0
facing = -1
if keys[pygame.K_d]:
if direction != 0:
direction = 0
facing = 1
if direction == 1:
y += (vel*facing)
else:
x += (vel*facing)
if x > x2 and x < x2 + 30 or x + 30 > x2 and x + 30 < x2 + 30:
if y == y2:
segmentGrowth()
if y > y2 and y < y2 + 30 or y + 30 > y2 and y + 30 < y2 + 30:
segmentGrowth()
if y > y2 and y < y2 + 30 or y + 30 > y2 and y + 30 < y2 + 30:
if x == x2:
segmentGrowth()
if x > x2 and x < x2 + 30 or x + 30 > x2 and x + 30 < x2 + 30:
segmentGrowth()
if x > 800-30 or y > 600-30 or x < 0 or y < 0:
gameOver()
win.fill((0,0,0))
for segment in segments:
if direction == 0: #X value
if facing == 1: #Right
segment.x = x - (35 * segment.pos)
segment.y = y
else: #Left
segment.x = x + (35 * segment.pos)
segment.y = y
else: #Y value
if facing == -1: #Up
segment.y = y + (35 * segment.pos)
segment.x = x
else:#Down
segment.y = y - (35 * segment.pos)
segment.x = x
for segment in segments:
segment.draw(win)
scoreDisplay = text.render(str(score),1,(255,255,255))
win.blit(scoreDisplay,(760,0))
pygame.draw.rect(win,(0,128,0),(x,y,30,30))
pygame.draw.rect(win,(255,0,0),(x2,y2,30,30))
pygame.display.update()
pygame.quit()
How it works is there is a list of segments and a class for information of each segment (ie x, y, etc). I append to that list an instance of the segment class whenever the user has collided with the red cube. I have this code:
for segment in segments:
if direction == 0: #X value
if facing == 1: #Right
segment.x = x - (35 * segment.pos)
segment.y = y
else: #Left
segment.x = x + (35 * segment.pos)
segment.y = y
else: #Y value
if facing == -1: #Up
segment.y = y + (35 * segment.pos)
segment.x = x
else:#Down
segment.y = y - (35 * segment.pos)
segment.x = x
That will move all segments of the snake all at once when the player decides what direction they want the snake to move. However, the segments are snapping immediately to the x position of the head rather than moving one at a time, smoothly. If someone could help me out with this that would be great. Thanks!
Nice game. I recommend to create a list of points, which is a list of tuples of the snakes head positions ((x, y)). Add every position to the list:
pts = []
while run:
# [...]
pts.append((x, y))
Create a function which calculates the position of a part of the snake by its index (i) counted to the head of the snake. The distance to the head has to be lenToI = i * 35.
The distance between to points can be calculated by the Euclidean distance (math.sqrt((px-pnx)*(px-pnx) + (py-pny)*(py-pny)), where the points are (px, py) and (pnx, pny). If the sum of the distances between the points (lenAct) exceeds the length to point (lenToI), then the position of part i is found:
def getPos(i):
global pts
lenToI = i * 35
lenAct = 0
px, py = pts[-1]
for j in reversed(range(len(pts)-1)):
px, py = pts[j]
pnx, pny = pts[j+1]
lenAct += math.sqrt((px-pnx)*(px-pnx) + (py-pny)*(py-pny))
if lenAct >= lenToI:
break
return (px, py)
Write another function cutPts, which deletes the points from the list, which ar not further required:
def cutPts(i):
global pts
lenToI = i * 35
lenAct = 0
cut_i = 0
px, py = pts[0]
for j in reversed(range(len(pts)-1)):
px, py = pts[j]
pnx, pny = pts[j+1]
lenAct += math.sqrt((px-pnx)*(px-pnx) + (py-pny)*(py-pny))
if lenAct >= lenToI:
break
cut_i = j
del pts[:cut_i]
Update the positions of the segments in a loop:
pts.append((x, y))
for i in range(len(segments)):
segments[i].x, segments[i].y = getPos(len(segments)-i)
cutPts(len(segments)+1)
Regarding the comment:
how would I go about calling the gameOver() function if the head of the snake touches any of its segments? I tried using an if statement to check for collision (the same way I did for the apple) using segment.x and segment.y but this won't work since the second segment of the snake always overlaps the head when the snake moves.
Note, the head can never "touch" the first segment, except the direction is changed to the reverse direction, but this case can be handled by an extra test, with ease.
It is sufficient to check if the head "hits" any segment except the fist one which connects to the head.
Use pygame.Rect.colliderect to check for the intersection of rectangular segments:
def selfCollide():
for i in range(len(segments)-1):
s = segments[i]
if pygame.Rect(x, y, 30, 30).colliderect(pygame.Rect(s.x, s.y, 30, 30)):
return True
return False
if selfCollide():
gameOver()

How to get rid of 'Unable to free colormap, pallette is still selected' error?

I have been working bugs out of a python script for color gradients, but I get this obscure error when closing out of the python console that says:
Unable to free colormap, pallette is still selected
Then, I get a popup saying "Python has stopped responding". I think this means it crashed, but i have no clue. I have no idea why it happens, but it seems random so far.
I have tried many different versions of if statements, math, and execution in the past, but nothing has worked to fix it.
import turtle, random, os
turtle.colormode(255)
turtle.bgcolor(0, 0, 0)
curX = 0
curY = 0
curZ = 0
while True:
x = random.randint(0, 255)
y = random.randint(0, 255)
z = random.randint(0, 255)
success = False
XD = 0
YD = 0
ZD = 0
while success == False:
if curX < x:
curX = curX + 1
elif curX > x:
curX = curX - 1
if curY < y:
curY = curY + 1
elif curY > y:
curY = curY - 1
if curZ < z:
curZ = curZ + 1
elif curZ > z:
curZ = curZ - 1
turtle.bgcolor(curX, curY, curZ)
os.system("cls")
print(x),
print(y),
print(z)
print(curX),
print(curY),
print(curZ)
if curX == x:
print("X")
XD = 1
if curY == y:
print("Y")
YD = 1
if curZ == z:
print("Z")
ZD = 1
if XD + YD + ZD == 3:
success = True
When I close out of the program, I expect it to just close out with no errors whatsoever, 100% of the time, but every now and then, it will throw up that "Unable to free colormap, pallette is still selected" error.
In an event-driven environment, we can't simply do while True: and expect things to work. Doing such effectively blocks some events from firing. The window closing event can be tricky -- more so that than turtle is sometimes able to handle, so we may need to drop down to the tkinter level to do it properly.
Below is my rework of your code to use a timer event to replace the infinite loop, and a window closing handler to catch the window closing event. The handler tries to stop your inner loop and timer event cleanly, then finishes closing out the window. Plus some other changes for style:
from turtle import Screen
from random import randint
from os import system
screen = Screen()
screen.colormode(255)
screen.bgcolor(0, 0, 0)
curR = 0
curG = 0
curB = 0
running = True
def window_closing():
global running
running = False
screen.ontimer(screen.bye, 500)
def switch_color_target():
global curR, curG, curB
r = randint(0, 255)
g = randint(0, 255)
b = randint(0, 255)
success = False
RD = False
GD = False
BD = False
while running and not success:
if curR < r:
curR += 1
elif curR > r:
curR -= 1
else:
RD = True
if curG < g:
curG += 1
elif curG > g:
curG -= 1
else:
GD = True
if curB < b:
curB += 1
elif curB > b:
curB -= 1
else:
BD = True
screen.bgcolor(curR, curG, curB)
system("cls")
print(r)
print(g)
print(b)
success = RD and GD and BD
if success:
print("R")
print("B")
print("G")
else:
print(curR)
print(curG)
print(curB)
if running:
screen.ontimer(switch_color_target, 250)
switch_color_target()
canvas = screen.getcanvas()
root = canvas.winfo_toplevel()
root.protocol("WM_DELETE_WINDOW", window_closing)
screen.mainloop()
I am not using the same operating system as you so I can't throughly test this -- give it a try to see if it solves your issues.

Categories