Turtle colour doesn't change with variable and list - python

So this is my code right now and the problem should be somwehere between Line 18 and 37. What I want to do is that when the user clicks on the top left turtle, it changes to the next colour. The turtle in the top left is only optical and has no other function than telling the user where to click (at least that's the idea). The problem is that it doesn't do that and I don't really get why
import turtle
from turtle import *
# def on_click_handler(x,y):
# print("Clicked: " , [x,y])
# t1.goto(x,y)
sc = Screen()
sc.setup(400, 400, 10, 10)
sc.setworldcoordinates(-300, -300, 300, 300)
# sc.onscreenclick(on_click_handler)
t1 = Turtle("turtle")
t1.shape("circle")
t1.shapesize(0.25, 0.25)
t1.speed(-1)
#changing turtle colour
tcolour = Turtle("turtle")
tcolour.penup()
tcolour.shape("square")
tcolour.shapesize(1, 1.5)
tcolour.setpos(-275, 285)
colour_list = ["#000000", "#0101DF", "#04B404", "#FF0000", "#FF8000", "B40486"] #black, blue, green, red, orange, purple
n = 0
def colourchange(x, y):
if (x < -275 and x > -300 and y > 284 and y < 300):
global n
n += 1
turtle.onscreenclick(colourchange, 1)
turtle.listen()
t1.color(colour_list[0+n])
def dragging(x, y):
t1.ondrag(None)
t1.setheading(t1.towards(x, y))
t1.goto(x, y)
t1.ondrag(dragging)
def clickright(x, y):
t1.clear()
def main():
turtle.listen()
t1.ondrag(dragging)
turtle.onscreenclick(clickright, 3)
sc.mainloop()
main()
And also I don't think I'm allowed to import tkinter, atleast I think that's what our prof said

Whenever you import the same module two different ways, you're already in trouble:
import turtle
from turtle import *
You're having problems distinguishing between the turtle and the screen -- using the above facilitates those problems. I recommend instead that you only use turtle's object-oriented interface and turn off the functional interface:
from turtle import Screen, Turtle
You're trying to use a turtle as a button, which is fine, but you put the click handler on the screen and had the handler test if you clicked the turtle. Instead, put the click handler on the turtle so you needn't test. (Again, part of the problem of not being clear about what the turtle does and what the screen does.)
Though you call it twice, listen() doesn't apply here as were not dealing with keyboard input (yet).
Finally, your color change handler updated the color index but never actually changed any colors. Below is my rework and simplification of your code to address the above issues:
from turtle import Screen, Turtle
COLOUR_LIST = ['black', 'blue', 'green', 'red', 'orange', 'purple']
colour_index = 0
def colour_change(x, y):
global colour_index
colour_index = (colour_index + 1) % len(COLOUR_LIST)
t1.color(COLOUR_LIST[colour_index])
def dragging(x, y):
t1.ondrag(None)
t1.setheading(t1.towards(x, y))
t1.goto(x, y)
t1.ondrag(dragging)
def click_right(x, y):
t1.clear()
t1 = Turtle('circle')
t1.shapesize(0.5)
t1.speed('fastest')
t1.color(COLOUR_LIST[colour_index])
t1.ondrag(dragging)
# changing colour turtle
tcolour = Turtle('square')
tcolour.penup()
tcolour.shapesize(1, 1.5)
tcolour.setpos(-275, 285)
tcolour.onclick(colour_change, 1)
screen = Screen()
screen.onclick(click_right, btn=3)
screen.mainloop()

Related

Trying to create two objects at the same time but it creates one

I'm trying to develop a simple game while I'm learning python. Game is not complex, random cars (which are squares) are spawning at right of the screen and they are going to left. We are a turtle, trying to avoid them and make it to the top of the screen.
The problem is my code below doesn't spawn two objects at the same time, it spawns just one.
from turtle import Screen
from turt import Turt
from spawnpoint import SpawnPoint
from cars import Car
import random
screen = Screen()
screen.setup(1000, 700)
screen.title("Cars and Turtle")
screen.bgcolor("gray")
turt = Turt()
is_game_on = True
screen.listen()
screen.onkey(turt.move_up, "Up")
spawn_points_ycords = [300, 200, 100, 0, -100, -200]
spawn_1 = SpawnPoint(spawn_points_ycords[0])
spawn_2 = SpawnPoint(spawn_points_ycords[1])
spawn_3 = SpawnPoint(spawn_points_ycords[2])
spawn_4 = SpawnPoint(spawn_points_ycords[3])
spawn_5 = SpawnPoint(spawn_points_ycords[4])
spawn_6 = SpawnPoint(spawn_points_ycords[5])
spawn_points = [spawn_1, spawn_2, spawn_3, spawn_4, spawn_5, spawn_6]
while is_game_on:
for n in range(60):
if n == 59:
random_spawn = spawn_points[random.randint(0, len(spawn_points)-1)]
random_spawn_2 = spawn_points[random.randint(0, len(spawn_points)-1)]
while random_spawn_2 == random_spawn:
random_spawn_2 = spawn_points[random.randint(0, len(spawn_points) - 1)]
random_spawn_car = Car(random_spawn.spawn.ycor())
random_spawn_2_car = Car(random_spawn_2.spawn.ycor())
screen.exitonclick()
My spawn points class code:
from turtle import Turtle
class SpawnPoint:
def __init__(self, ycor):
self.spawn = Turtle()
self.spawn.hideturtle()
self.spawn.speed(0)
self.spawn.penup()
self.spawn.goto(600, ycor)
self.spawn.showturtle()
self.new_car = None
and my car class code:
from turtle import Turtle
import random
class Car:
def __init__(self, ycor):
self.body = Turtle()
self.body.hideturtle()
self.body.penup()
self.body.shape("square")
self.colors = ["black", "red", "orange", "blue", "green", "yellow"]
self.body.color(self.colors[random.randint(0, len(self.colors)-1)])
self.body.shapesize(1, 5, 0)
self.body.speed(2)
self.body.goto(700, ycor)
self.body.showturtle()
self.body.goto(-700, ycor)
I can't figure it out to solve this bug. I'm using Turtle module.
The two car objects are created, but the problem is that you haven't implemented real-time movement for multiple turtles, so the first turtle completes its 5-second journey across the screen before the second one is created or begins moving.
When you encounter problems like this, my suggestion is to strip the problem down to a minimal, reproducible example. This process makes the problem obvious by removing the noise. For example, if you move the spawn and destination points onto the visible screen, the problem becomes clear.
Here's an even more minimal demonstration:
from turtle import Turtle
t = Turtle()
tt = Turtle()
t.speed(2)
tt.speed(2)
t.goto(100, 100)
tt.goto(200, 100)
t.Screen().exitonclick()
When you run this, you'll see that t moves from 0, 0 to 100, 100 in about a second. Only once t arrives at the destination does tt even begin moving. Adding print statements on each line is another way to see that each goto blocks the script completely until the slow movement completes. The simultaneous movement you expect is not the default behavior of turtle.
The typical solution is to use tracer(0) to disable the internal update/rendering loop that turtle uses to smooth out gotos. Once you've done this, you can reposition turtles at will and call turtle.update() to render a frame. It's up to you to reimplement smooth movement, which is not difficult to do.
Also worth noting, your exitonclick call is never reached and the for loop with if n == 59: is pointless. Cars are never garbage collected, and probably shouldn't be doing so much work in the initializer. Kudos for using composition rather than inheritance for your classes, though.
I'd also caution against adding complexity like multiple classes and files before you've convinced yourself that the basics are operational. If something as simple as movement isn't working as you expect, all of that other stuff only gets in the way of debugging. Run your code often, building up guarantees about its behavior as you work.
Here's a quick sketch of how you might begin to redesign your project. It's based on my recommended real-time setup for turtle.
import turtle
class Car:
def __init__(self, x, y, speed):
self.x = x
self.y = y
self.speed = speed
self.body = turtle.Turtle()
self.body.shape("square")
self.body.penup()
self.body.goto(x, y)
def move(self):
self.x -= self.speed
w = turtle.screensize()[0]
if self.x < -w:
self.x = w
self.body.goto(self.x, self.y)
def tick():
for action in keys_pressed:
actions[action]()
for car in cars:
car.move()
turtle.update()
win.ontimer(tick, frame_delay_ms)
if __name__ == "__main__":
w, h = turtle.screensize()
turtle.tracer(0)
t = turtle.Turtle()
t.penup()
t.goto(0, -h + 50)
t.left(90)
cars = [
Car(w, -200, 3),
Car(w, -100, 5),
Car(w, 0, 4.5),
Car(w, 100, 4),
Car(w, 200, 6),
]
frame_delay_ms = 1000 // 30
step_speed = 10
actions = dict(
u=lambda: t.forward(step_speed),
)
win = turtle.Screen()
keys_pressed = set()
win.onkeypress(lambda: keys_pressed.add("u"), "Up")
win.onkeyrelease(lambda: keys_pressed.remove("u"), "Up")
win.listen()
tick()
win.exitonclick()

Is there a way to avoid the recursion limit in my Turtle-program?

import turtle
from turtle import Turtle
WIDTH = 1000
HEIGHT = 1000
#Screen setup
screen = turtle.Screen()
screen.setup(WIDTH, HEIGHT)
screen.title(" " *150 + "Test_GIU")
screen.bgcolor("black")
screen.setup(1000, 1000)
#Pen
pen = Turtle("circle")
pen.pensize = 5
pen.color("green")
pen.speed(-1)
def dragging(x, y): # These parameters will be the mouse position
pen.ondrag(None)
pen.setheading(pen.towards(x, y))
pen.goto(x, y)
pen.ondrag(dragging)
def click_on_c():
screen.reset()
pen = Turtle("circle")
pen.pensize = 5
pen.color("green")
pen.speed(-1)
pen.ondrag(dragging)
def main(): # This will run the program
turtle.listen()
pen.ondrag(dragging) # When we drag the turtle object call dragging
turtle.onkeypress(click_on_c, "c")
screen.mainloop() # This will continue running main()
main()
This is my code, im pretty new to it, so its not very good, but its my first real project. I´ve already tried to increase the recursin limit, but it crashes even if I set it to 10000. I also tried to catch the error with an try and exept block, but it also doesnt work.
Let's try a simpler design where instead of calling screen.reset() and recreating the turtle, we instead call pen.reset() to clear the drawing:
from turtle import Screen, Turtle
WIDTH = 1000
HEIGHT = 1000
def dragging(x, y): # Parameters are the mouse position
pen.ondrag(None)
pen.setheading(pen.towards(x, y))
pen.goto(x, y)
pen.ondrag(dragging)
def click_on_c():
pen.reset()
pen.pensize = 5
pen.color("green")
pen.speed('fastest')
# Screen setup
screen = Screen()
screen.setup(WIDTH, HEIGHT)
screen.title("Test_GUI")
screen.bgcolor("black")
# Pen
pen = Turtle("circle")
pen.pensize = 5
pen.color("green")
pen.speed('fastest')
pen.ondrag(dragging)
screen.onkeypress(click_on_c, "c")
screen.listen()
screen.mainloop()
We have to reset some aspects of the pen after calling reset() as that call clears the settings back to the defaults.

Why isn't this code working? I am new and I really need assistance

So I am trying to make it so when the lt turtle collides with the circle turtles(the ones in the list) it draws a star. But when I run it and try it the turtle does not draw a star. Please run it and see that I am trying to make it so when my turtle collides with the circles the turtle draws a star.
import turtle
import random
screen=turtle.Screen()
screen.listen()
list=[]
lt=turtle.Turtle()
lt.penup()
lt.shape("turtle")
for i in range(10):
x=random.randint(-250,250)
y=random.randint(-250,250)
st=turtle.Turtle()
list.append(st)
for z in list:
z.speed(1000)
z.shape("circle")
z.color("white")
x=random.randint(-250,250)
y=random.randint(-250,250)
z.penup()
z.goto(x,y)
z.pendown()
def left():
lt.forward(2)
lt.left(10)
screen.onkey(left,"A")
def right():
lt.forward(2)
lt.right(10)
screen.onkey(right,"D")
r=195
g=20
b=50
screen.bgcolor(r,g,b)
def StarCheck(z):
if abs(lt.xcor()-z.xcor()) <15 and abs(lt.ycor()-z.ycor()) <15:
z.clear()
lt.color("yellow")
lt.begin_fill()
for i in range(5):
lt.forward(5)
lt.right(145)
lt.forward(10)
lt.end_fill()
while True:
r=r-0.20
screen.bgcolor(r,g,b)
lt.forward(1)
for n in list:
StarCheck(z)
I would assume you have a typo in your while loop. It should be
StarCheck(n) instead of StarCheck(z)
Below is the listing of your altered code.
import turtle
import random
screen = turtle.Screen()
screen.listen()
list = []
lt = turtle.Turtle()
lt.penup()
lt.shape("turtle")
for i in range(10):
x = random.randint(-250, 250)
y = random.randint(-250, 250)
st = turtle.Turtle()
list.append(st)
for z in list:
z.speed(1000)
z.shape("circle")
z.color("white")
x = random.randint(-250, 250)
y = random.randint(-250, 250)
z.penup()
z.goto(x, y)
z.pendown()
def left():
lt.forward(2)
lt.left(10)
screen.onkey(left, "A")
def right():
lt.forward(2)
lt.right(10)
screen.onkey(right, "D")
r = 0.9
g = 0.2
b = 0.5
screen.bgcolor('red')
def StarCheck(z):
if abs(lt.xcor() - z.xcor()) < 10 and abs(lt.ycor() - z.ycor()) < 10:
z.clear()
lt.color("yellow")
lt.begin_fill()
for i in range(5):
lt.forward(10)
lt.right(120)
lt.forward(10)
lt.right(72 - 120)
lt.end_fill()
return
while True:
r = r - 0.000002
screen.bgcolor(r, g, b)
lt.forward(1)
for n in list:
StarCheck(n)
I ran this code and a yellow star is created as the turtle goes over the white circles.
You might also want to refer colormode for setting appropriate RGB values or color. I am using python 3.7.
HTH
I made the changes that #MustafaHaider suggests and implies but I couldn't get your code to work in any real sense. There's a lot broken:
As #MustafaHaider noted, if this is standard Python turtle, you'd need to call:
colormode(255)
If you're not using standard Python turtle, eg. the Repl site, you need to mention that in your question. This makes no sense:
z.speed(1000)
The numeric arguments range from 0 to 10, though I suggest a symbolic argument like "fastest". This will eventually underflow and cause an error:
r=r-0.20
#MustafaHaider switched to a smaller increment but that's the same issue -- using a multiplicative reduction and int() wouldn't have this problem. Did you really want the user to have the CAPSLOCK pressed on some systems:
screen.onkey(left,"A")
screen.onkey(right,"D")
If not, I suggest "a" and "d" instead. There's a turtle method for this:
if abs(lt.xcor()-z.xcor()) <15 and abs(lt.ycor()-z.ycor()) <15:
it's called distance(). This doesn't do what you want:
z.clear()
as z hasn't drawn anything. You want z.hideturtle() and only call StarCheck(z) if z.isvisible(). Below is my rework of your code that addresses the above issues as well as others I haven't mentioned and general style:
from turtle import Screen, Turtle
from random import randint
def left():
player.left(10)
def right():
player.right(10)
def StarCheck(enemy):
if player.distance(enemy) < 15:
enemy.hideturtle()
player.begin_fill()
for _ in range(5): # a la #MustafaHaider
player.forward(10)
player.right(120)
player.forward(10)
player.left(48)
player.end_fill()
r, g, b = 195, 20, 50
screen = Screen()
screen.colormode(255)
screen.bgcolor(r, g, b)
player = Turtle()
player.shape('turtle')
player.color('yellow')
player.speed('fastest')
player.penup()
enemies = []
for _ in range(10):
enemy = Turtle()
enemy.hideturtle()
enemy.shape('circle')
enemy.color('white')
x = randint(-250, 250)
y = randint(-250, 250)
enemy.penup()
enemy.goto(x, y)
enemy.pendown()
enemy.showturtle()
enemies.append(enemy)
screen.onkey(left, 'a')
screen.onkey(right, 'd')
screen.listen()
while True:
r *= 0.9999
screen.bgcolor(int(r), g, b)
player.forward(1)
for enemy in enemies:
if enemy.isvisible():
StarCheck(enemy)
screen.mainloop() # never reached
This should be playable now. There's more to do, e.g. replace your while True: loop with a function and timed event if this is standard Python turtle.

Enter button in Python turtle program is not responding

import turtle
import random
wn = turtle.Screen() #sets the screen
wn.setup(1000,900)
wn.screensize(2000,2000)
ad = turtle.Turtle() #names the turtle
ad.shape("circle") #changes turtles or "ad's" shape
ad.speed("fastest")
r = int(60) #CHANGES THE SIZE OF THE WRITING
x = int(-950)
y = int(200)
ad.penup()
ad.goto(x,y)
def enter():
ad.penup()
y -= 100
ad.goto(x,y)
wn.onkey(lambda: enter(), "Return")
wn.listen()
Trying to do an enter button in turtle but this wont work.
It says that there is an error with the local variable.
Although your immediate problem is the lack of a global y statement in your enter() function, there's a lot of noise in your code that we should eliminate to make it a better MVCE:
import random # not used so leave out of SO question example
r = int(60) # ditto
x = int(-950) # int() not needed for ints
y = int(200) # ditto
wn.onkey(lambda: enter(), "Return") # lambda not needed
Although we could fix this with the addition of a global y statement, I prefer to simply interrogate the turtle itself and avoid the global:
from turtle import Turtle, Screen
def enter():
ad.sety(ad.ycor() - 100)
X, Y = -950, 200
wn = Screen()
wn.setup(1000, 1000) # visible field
wn.screensize(2000, 2000) # total field
ad = Turtle("circle")
ad.speed("fastest")
ad.penup()
ad.goto(X, Y)
wn.onkey(enter, "Return")
wn.listen()
wn.mainloop()
Note, you positioned the turtle off the visible portion of the screen so you need to scroll to the left side of the window to see the turtle cursor. Once you do, you can move it down by hitting, "Return".

Trigger event when text is clicked in Python Turtle

I'm currently making a program in python's Turtle Graphics. Here is my code in case you need it
import turtle
turtle.ht()
width = 800
height = 800
turtle.screensize(width, height)
##Definitions
def text(text, size, color, pos1, pos2):
turtle.penup()
turtle.goto(pos1, pos2)
turtle.color(color)
turtle.begin_fill()
turtle.write(text, font=('Arial', size, 'normal'))
turtle.end_fill()
##Screen
turtle.bgcolor('purple')
text('This is an example', 20, 'orange', 100, 100)
turtle.done()
I want to have click events. So, where the text 'This is an example' is wrote, I want to be able to click that and it prints something to the console or changes the background. How do I do this?
I don't want to install anything like pygame, it has to be made in Turtle
Use the onscreenclick method to get the position then act on it in your mainloop (to print or whatever).
import turtle as t
def main():
t.onscreenclick(getPos)
t.mainloop()
main()
Also see : Python 3.0 using turtle.onclick
Also see : Turtle in python- Trying to get the turtle to move to the mouse click position and print its coordinates
Since your requirement is to have onscreenclick around text area, we need
to track mouse position. For that we are binding function onTextClick to the screenevent.
Within function, if we are anywere around text This is an example , a call is made to turtle.onscreenclick to change color of the background to red.
You can change lambda function and insert your own, or just create external function and call within turtle.onscreenclick as per this documentation
I tried to change your code as little as possible.
Here is a working Code:
import turtle
turtle.ht()
width = 800
height = 800
turtle.screensize(width, height)
##Definitions
def text(text, size, color, pos1, pos2):
turtle.penup()
turtle.goto(pos1, pos2)
turtle.color(color)
turtle.begin_fill()
turtle.write(text, font=('Arial', size, 'normal'))
turtle.end_fill()
def onTextClick(event):
x, y = event.x, event.y
print('x={}, y={}'.format(x, y))
if (x >= 600 and x <= 800) and ( y >= 280 and y <= 300):
turtle.onscreenclick(lambda x, y: turtle.bgcolor('red'))
##Screen
turtle.bgcolor('purple')
text('This is an example', 20, 'orange', 100, 100)
canvas = turtle.getcanvas()
canvas.bind('<Motion>', onTextClick)
turtle.done()

Categories