while True: not working with turtle - python

When I import turtle, then try to use a while True: loop with it it doesn't work. Here's the code:
import turtle
import time
stage = turtle.Turtle()
width = 900
height = 500
def up():
turtle.setheading(90)
turtle.forward(10)
def down():
turtle.setheading(270)
turtle.forward(10)
def char():
turtle.listen()
turtle.onkey(up, 'w')
turtle.onkey(up, 's')
turtle.setup(width, height)
turtle.goto(390, 0)
char()
while True:
if (turtle.ycor() >= 250):
turtle.goto(460, 0)
stage.goto(350, 0)
turtle.done()
I have no idea why it isn't working, it just freezes (not responding) then, no error messages. It's really annoying, as the same thing has happened with other programs where I had turtle and while true loops.
If while True is the issue, is there any other way to 'forever check if', thanks!

Rather than your infinite loop, you can have any routine that moves the turtle check if the turtle has reached the boundary of interest:
import turtle
WIDTH = 900
HEIGHT = 500
def up():
turtle.setheading(90)
turtle.forward(10)
check()
def down():
turtle.setheading(270)
turtle.forward(10)
check()
def check():
if turtle.ycor() >= HEIGHT/2:
turtle.goto(400, 0)
turtle.setup(WIDTH, HEIGHT)
turtle.goto(350, 0)
turtle.listen()
turtle.onkey(up, 'w')
turtle.onkey(down, 's')
turtle.done()
Also note that your original code had two turtles, the default one and one called stage -- make sure to keep track of the turtle you're manipulating! Also, get on top of your coordinate system, you were moving the turtle off screen (unless that's what you wanted) with no way to move it back on screen.

I donĀ“t know exactly what you need to accomplish, but you could probably just put the
if (turtle.ycor() >= 250):
turtle.goto(460, 0)
inside up() and down().
Although if you need to have the function run forever, as you mentioned in your comment, you can put your while True: thing inside a second thread, which should keep your window from freezing.

Related

Why won't Python Turtle respond to my movement inputs?

I'm taking a coding course this semester and for one of the projects it requires us to make a game of any kind. I chose to make a game contained within a box where enemies move on screen travel completely across then appear again at a different x or y coordinate to add some variety. The issue I'm dealing with is following adding the code needed to create "enemies" the keys I set for the movement of the player turtle no longer work, another strange thing is that the player turtle will spin in place right as the program is run. I am at a total loss as to how to make the turtle respond to the code as it worked correctly prior to writing the code for the enemies. I don't believe the code for the enemies is the issue as when it is commented out it still acts the same way. I didn't include the enemies code for the sake of brevity. this code is done in Python 3. Please help if you can!
EDIT: I removed the parenthesis following the window.onkeypress(mov_x,"x") and after adding the code back in for the enemies it won"t respond, it works without the code for the enemies but that kinda removes the point of the game. Thank you for the help!
import turtle
import random
#screen
window = turtle.Screen()
window.title("Final Project Game")
window.bgcolor("gray")
window.setup(width=600,height=600)
#player
t= turtle.Turtle()
t.speed(5)
t.shape("triangle")
t.color("blue")
t.penup()
#player movement
def mov_rt():
t.seth(0)
t.fd(20)
def mov_lt():
t.seth(180)
t.fd(20)
def mov_up():
t.seth(90)
t.fd(20)
def mov_dw():
t.seth(270)
t.fd(20)
window.onkeypress(mov_rt,"d")
window.onkeypress(mov_lt,"a")
window.onkeypress(mov_up,"w")
window.onkeypress(mov_dw,"s")
window.listen()
#enemies
enemies = []
turt_num = turtle.numinput("Final","Number of Enemies", default=5, minval=1,maxval=10)
e_dir= [0,90,180,270]
if turt_num == 1:
e1= turtle.Turtle("square",visible=False)
e1.speed(5)
e1.color("red")
e1.penup()
e1.setpos(random.randint(-290,290),random.randint(-290,290))
e1.seth(random.choice(e_dir))
enemies.append(e1)
e1.st()
elif turt_num == 2:
e1= turtle.Turtle("square",visible=False)
e1.speed(5)
e1.color("red")
e1.penup()
e1.setpos(random.randint(-290,290),random.randint(-290,290))
e1.seth(random.choice(e_dir))
enemies.append(e1)
e2= turtle.Turtle("square",visible=False)
e2.speed(5)
e2.color("red")
e2.penup()
e2.setpos(random.randint(-290,290),random.randint(-290,290))
e2.seth(random.choice(e_dir))
enemies.append(e2)
e1.st()
e2.st()
elif turt_num ==3:
e1= turtle.Turtle("square",visible=False)
e1.speed(5)
e1.color("red")
e1.penup()
e1.setpos(random.randint(-290,290),random.randint(-290,290))
e1.seth(random.choice(e_dir))
enemies.append(e1)
e2= turtle.Turtle("square",visible=False)
e2.speed(5)
e2.color("red")
e2.penup()
e2.setpos(random.randint(-290,290),random.randint(-290,290))
e2.seth(random.choice(e_dir))
enemies.append(e2)
e3= turtle.Turtle("square",visible=False)
e3.speed(5)
e3.color("red")
e3.penup()
e3.setpos(random.randint(-290,290),random.randint(-290,290))
e3.seth(random.choice(e_dir))
enemies.append(e3)
e1.st()
e2.st()
e3.st()
#borders
def border(): #if you hold down the button it wont reappear bc youre still moving while the turtle is trying to move to the desired target
tx, ty= t.pos()
if t.xcor() >295:
t.ht()
t.setpos(-295,ty)
t.st()
if t.xcor() <-295:
t.ht()
t.setpos(295,ty)
t.st()
if t.ycor() >295:
t.ht()
t.setpos(tx,-295)
t.st()
if t.ycor() <-295:
t.ht()
t.setpos(tx,295)
t.st()
#main game loop
while True:
window.update()
border()
turtle.mainloop()
Try to use
window.onkey()
That is a different way to listen and it does the exact same thing.
Also, remember at the end of that code you need
window.listen()
Common beginner's error. Instead of:
window.onkeypress(mov_rt(),"d")
window.onkeypress(mov_lt(),"a")
window.onkeypress(mov_up(),"w")
window.onkeypress(mov_dw(),"s")
Do:
window.onkeypress(mov_rt, "d")
window.onkeypress(mov_lt, "a")
window.onkeypress(mov_up, "w")
window.onkeypress(mov_dw, "s")
That is, you don't want to call your event handler function, you instead want to pass the name of your event hanlder function for the system to call later, when something actually happens.
Below is a rework of your code to address this as well as some other turtle and Python issues:
from turtle import Screen, Turtle
def border():
x, y = turtle.position()
if x > 295:
turtle.hideturtle()
turtle.setx(-295)
turtle.showturtle()
elif x < -295:
turtle.hideturtle()
turtle.setx(295)
turtle.showturtle()
if y > 295:
turtle.hideturtle()
turtle.sety(-295)
turtle.showturtle()
elif y < -295:
turtle.hideturtle()
turtle.sety(295)
turtle.showturtle()
# player movement
def mov_rt():
turtle.setheading(0)
turtle.forward(20)
border()
def mov_lt():
turtle.setheading(180)
turtle.forward(20)
border()
def mov_up():
turtle.setheading(90)
turtle.forward(20)
border()
def mov_dw():
turtle.setheading(270)
turtle.forward(20)
border()
screen = Screen()
screen.title("Final Project Game")
screen.bgcolor('gray')
screen.setup(width=600, height=600)
# player
turtle = Turtle()
turtle.speed('normal')
turtle.shape('triangle')
turtle.color('blue')
turtle.penup()
screen.onkeypress(mov_rt, 'd')
screen.onkeypress(mov_lt, 'a')
screen.onkeypress(mov_up, 'w')
screen.onkeypress(mov_dw, 's')
screen.listen()
screen.mainloop()
Note removal of while True: loop as it has no place in an event-driven environment like turtle -- it potentially blocks events from being processed.

Why do I need the time.sleep(x) function in this code for it to work?

from turtle import Screen, Turtle
import time
import snake
MOVE_DISTANCE = 20
UP = 90
DOWN = 270
LEFT = 180
RIGHT = 0
class InitialSnake:
def __init__(self):
self.number_x = 0
self.snake_first = []
self.create_snake()
self.actual_snake = self.snake_first[0]
def create_snake(self):
for number in range(3):
snake = Turtle(shape="square")
snake.penup()
snake.color("white")
snake.goto(self.number_x, 0)
self.number_x -= 20
self.snake_first.append(snake)
def move(self):
for segments_num in range(len(self.snake_first) - 1, 0, -1):
self.snake_first[segments_num].goto(self.snake_first[segments_num - 1].xcor(),
self.snake_first[segments_num - 1].ycor())
self.snake_first[0].forward(MOVE_DISTANCE)
def up(self):
if self.actual_snake.heading() != DOWN:
self.snake_first[0].setheading(UP)
def down(self):
if self.actual_snake.heading() != UP:
self.snake_first[0].setheading(DOWN)
def left(self):
if self.actual_snake.heading() != RIGHT:
self.snake_first[0].setheading(LEFT)
def right(self):
if self.actual_snake.heading() != LEFT:
self.snake_first[0].setheading(RIGHT)
my_screen = Screen()
my_screen.setup(width=600, height=600)
my_screen.bgcolor("black")
my_screen.title("Snake Game")
my_screen.tracer(0)
snake_1 = snake.InitialSnake()
#snake_here.create_snake()
game_is_on = True
my_screen.listen()
my_screen.onkey(snake_1.up, "Up")
my_screen.onkey(snake_1.down,"Down")
my_screen.onkey(snake_1.left,"Left")
my_screen.onkey(snake_1.right,"Right")
while game_is_on:
my_screen.update()
time.sleep(0.1)
snake_1.move()
my_screen.exitonclick()
I did not really understand the concept of the tracer and the update and how this is linked to the sleep function. I understand that when the tracer is called and turned off, it will not refresh the screen until you call the update() function. But shouldn't it still work without time.sleep(0.1) since this is just creating a short delay before the next functions get called. Can someone help me please to understand this? Thanks in advance (:
If you use print() to see snake position
while game_is_on:
my_screen.update()
snake_1.move()
print(snake_1.snake_first[0].ycor(), snake_1.snake_first[0].xcor())
then you will see it moves very, very fast and it left screen - and you simply can't see it.
On my very old computer after few milliseconds its positon was (0, 125700). Probably on the newest computer it would be much bigger value.
So this code use sleep() to slow down snake and to move it with the same speed on all computers.
BTW:
I would use turtle method to repeate code
def game_loop():
snake_1.move()
my_screen.update()
my_screen.ontimer(game_loop, 100) # repeate after 100ms (0.1s)
# start loop
game_loop()
because sleep may blocks some code and ontimer was created for non-blocking delay.

Couldn't get rid of (_tkinter.TclError: bad event type or keysym "UP") problem

I am running a Linux mint for the first time . I tried coding a python problem but for two days I am continiously facing problems due to Linux interface please
This is my code:-
import turtle
import time
boxsize=200
caught=False
score=0
#function that are called in keypress
def up():
mouse.forward(10)
checkbound()
def left():
move.left(45)
def right():
move.right(45)
def back():
mouse.backward(10)
checkbound()
def quitTurtles():
window.bye()
#stop the mouse from leaving the square set size
def checkbound():
global boxsize
if mouse.xcor()>boxsize:
mouse.goto(boxsize, mouse.ycor())
if mouse.xcor()<-boxsize:
mouse.goto(-boxsize, mouse.ycor())
if mouse.ycor()>boxsize:
mouse.goto(mouse.xcor(),boxsize)
if mouse.ycor()<-boxsize:
mouse.goto(mouse.xcor(),-boxsize)
#set up screen
window=turtle.Screen()
mouse=turtle.Turtle()
cat=turtle.Turtle()
mouse.penup()
mouse.penup()
mouse.goto(100,100)
#add key listeners
window.onkeypress(up ,'UP')
window.onkeypress(right ,'left')
window.onkeypress(left ,'Right')
window.onkeypress(back ,'DOWN')
window.onkeypress(quitTurtles, "Escape")
difficulty=window.numinput("difficulty","Enter a difficulty from 1 to 5",minval=1,maxval=5)
window.listen()
#main loop
#note how it changes with difficulty
while not caught:
cat.setheading(cat.towards(mouse))
cat.forward(8+diffficulty)
score=score+1
if cat.distance(mouse)<5:
caught=true
time.sleep(0.2-(0.1*difficulty))
window.textinput("GAME OVER","WELL DONE YOU SCORED:"+str(score*difficulty))
window.bye()
This code has several problems, many of which will keep it from running correctly:
Substituted move for mouse:
def up():
mouse.forward(10)
checkbound()
def left():
move.left(45)
Unnecessary global declaration as boxsize is not assigned:
def checkbound():
global boxsize
In code copy-and-paste, didn't change mouse to cat:
mouse=turtle.Turtle()
cat=turtle.Turtle()
mouse.penup()
mouse.penup()
The difficulty variable not spelled consistently:
cat.forward(8+diffficulty)
time.sleep(0.2-(0.1*difficulty))
Incorrect case for boolean:
caught=true
As noted in comments, total inconsistency in key naming case:
window.onkeypress(right ,'left')
window.onkeypress(left ,'Right')
window.onkeypress(back ,'DOWN')
Bigger picture issues are use of sleep() in an event-driven environment and lack of drawn boundaries so player knows the limits. Rather than address these issues one by one in SO questions, let's rework this code to work within the turtle event environment and be playable as a game:
from turtle import Screen, Turtle
BOX_SIZE = 600
# functions that are called in keypress
def up():
mouse.forward(15)
checkbound()
def left():
mouse.left(45)
def right():
mouse.right(45)
def back():
mouse.backward(15)
checkbound()
def checkbound():
''' stop the mouse from leaving the square set size '''
if mouse.xcor() > BOX_SIZE/2:
mouse.goto(BOX_SIZE/2, mouse.ycor())
elif mouse.xcor() < -BOX_SIZE/2:
mouse.goto(-BOX_SIZE/2, mouse.ycor())
if mouse.ycor() > BOX_SIZE/2:
mouse.goto(mouse.xcor(), BOX_SIZE/2)
elif mouse.ycor() < -BOX_SIZE/2:
mouse.goto(mouse.xcor(), -BOX_SIZE/2)
def move():
global score
cat.setheading(cat.towards(mouse))
cat.forward(2 * difficulty)
score += 1
if cat.distance(mouse) < 5:
screen.textinput("GAME OVER", "WELL DONE YOU SCORED: {}".format(score * difficulty))
screen.bye()
else:
screen.ontimer(move, 200 - 100 * difficulty)
score = 0
# set up screen
screen = Screen()
marker = Turtle()
marker.hideturtle()
marker.penup()
marker.goto(-BOX_SIZE/2, -BOX_SIZE/2)
marker.pendown()
for _ in range(4):
marker.forward(BOX_SIZE)
marker.left(90)
difficulty = int(screen.numinput("difficulty", "Enter a difficulty from 1 to 5", minval=1, maxval=5))
cat = Turtle()
cat.shapesize(2)
cat.penup()
mouse = Turtle()
mouse.penup()
mouse.goto(200, 200)
# add key listeners
screen.onkeypress(up, 'Up')
screen.onkeypress(right, 'Left')
screen.onkeypress(left, 'Right')
screen.onkeypress(back, 'Down')
screen.onkeypress(screen.bye, 'Escape')
screen.listen()
screen.ontimer(move, 1000) # give player a chance to move hand from keyboard to mouse
screen.mainloop()

Use onkey() to do multiple functions with Python turtle

I'm trying to write a basic turtle drawing game/program and I've been using onkey(function, "key") to have the user input keystrokes. Well I wanted the user to be able to change the width of the pen by either hitting the up key to increase the width by one, or the down key to decrease the width by one. I know I need some kind of loop, but I don't really know where to implement it.
Here's a simple example that will make the turtle walk in a continuous circle while you press up and down arrows to change the pen width:
from turtle import Turtle, Screen
def larger():
size = turtle.pensize()
if size < 10:
turtle.pensize(size + 1)
def smaller():
size = turtle.pensize()
if size > 1:
turtle.pensize(size - 1)
def move():
turtle.circle(150, extent=3)
screen.ontimer(move, 100)
turtle = Turtle()
screen = Screen()
screen.onkey(larger, "Up")
screen.onkey(smaller, "Down")
screen.listen()
move()
screen.mainloop()
Make sure you click on the window first to make it the key listener.
I think you can't, but you can call the function insde the function you bind to the key:
from turtle import *
def function1():
do_that = "do that"
print(do_that)
def function2():
do_this = "do this"
print(do_this)
function1()
onkey(function2, "space")
do this
do that
It worked for me ;)

Python - Keyboard Multiple Turtle Objects

I would like to create a program in which a Turtle object responds to key presses. I can do this, but I can't seem to understand how to move a second Turtle object, which is controlled by the computer, while the first one is moving. Any help would be appreciated.
Here is my code:
from turtle import *
from Tkinter import Tk
root = Tk()
root.withdraw()
turtle = Turtle()
def h1():turtle.forward(10)
def h2():turtle.left(45)
def h3():turtle.right(45)
def h4():turtle.back(10)
def h5(root=root):root.quit()
onkey(h1,"Up")
onkey(h2,"Left")
onkey(h3,"Right")
onkey(h4,"Down")
onkey(h5,"q")
listen()
root.mainloop()
Insert a second turtle before listen() that moves with keys w,a,s,d:
turtle2 = Turtle()
def h11():turtle2.forward(10)
def h21():turtle2.left(45)
def h31():turtle2.right(45)
def h41():turtle2.back(10)
onkey(h11,"w")
onkey(h21,"a")
onkey(h31,"d")
onkey(h41,"s")
I can't seem to understand how to move a second Turtle object, which
is controlled by the computer, while the first one is moving.
Below is some minimal code that does as you describe. Green turtle Pokey is computer controlled while red turtle Hokey is user controlled (click on the window first so your keystrokes are heard):
from turtle import Turtle, Screen
def move_pokey():
pokey.forward(10)
x, y = pokey.position()
if not (-width/2 < x < width/2 and -height/2 < y < height/2):
pokey.undo()
pokey.left(90)
screen.ontimer(move_pokey, 100)
hokey = Turtle(shape="turtle")
hokey.color("red")
hokey.penup()
pokey = Turtle(shape="turtle")
pokey.setheading(30)
pokey.color("green")
pokey.penup()
screen = Screen()
width = screen.window_width()
height = screen.window_height()
screen.onkey(lambda: hokey.forward(10), "Up")
screen.onkey(lambda: hokey.left(45), "Left")
screen.onkey(lambda: hokey.right(45), "Right")
screen.onkey(lambda: hokey.back(10), "Down")
screen.onkey(screen.bye, "q")
screen.listen()
screen.ontimer(move_pokey, 100)
screen.mainloop()
This is not finished code (shutdown of the timer event should be cleaner, Hokey's handlers should lock out additional events while running, etc.) but should give you a basic idea of how to go about it.

Categories