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

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.

Related

How to stop turtle movement when two turtles are in proximity of each other?

I'm making a game when the user has to move the car to dodge obstacles, Everything working except I can't get the game to and end. My goal is to end the game when the block hits the turtle.
The issue is I can't get the game to detect the turtles to detect their proximity and the exit or quit command doesn't work. Also I don't think the code pasted properly so adjust the indents if it doesn't work.
import turtle as trtl
import random as rand
import sys
#initialize turtles
turtle = trtl.Turtle(shape = "turtle")
block = trtl.Turtle(shape = "square")
drawer = trtl.Turtle()
blockList = []
wn = trtl.Screen()
#game configuration
turtle.pu()
turtle.goto(0,-150)
drawer.pu()
drawer.goto(0,-160)
drawer.pd()
drawer.pensize(10)
drawer.pencolor("blue")
drawer.forward(180)
drawer.left(90)
drawer.forward(300)
drawer.left(90)
drawer.forward(350)
drawer.left(90)
drawer.forward(300)
drawer.left(90)
drawer.forward(180)
drawer.hideturtle()
def turtleRight():
turtle.setheading(0)
turtle.pu()
turtle.forward(15)
def turtleLeft():
turtle.setheading(180)
turtle.pu()
turtle.forward(15)
#actions
wn.onkeypress(turtleRight, 'Right')
wn.onkeypress(turtleLeft, 'Left')
wn.listen()
for i in range(5):
app = block
blockList.append(app)
#functions
def draw_blocks(index):
blockList[index].penup()
blockList[index].shape("square")
wn.tracer(False)
blockList[index].setx(rand.randint(-150,150))
blockList[index].sety(rand.randint(0,125))
blockList[index].showturtle()
wn.tracer(True)
wn.update()
def drop_block(index):
blockList[index].penup()
blockList[index].clear()
blockList[index].speed(2)
blockList[index].sety(-150)
blockList[index].hideturtle()
draw_blocks(index)
xDistance = abs(turtle.xcor()-block.xcor())
yDistance = abs(turtle.ycor()-block.ycor())
if (xDistance < 20 and yDistance < 20):
sys.exit()
else:
drop_block(i)
for i in range(5):
drop_block(i)
wn.mainloop()
trtl.done()
Can anyone help..!?
The problem is that you're re-drawing the block and thus resetting its position before you're testing the distance.
Alter the function like so:
def drop_block(index):
blockList[index].penup()
blockList[index].clear()
blockList[index].speed(2)
blockList[index].sety(-150)
blockList[index].hideturtle()
xDistance = abs(turtle.xcor()-block.xcor())
yDistance = abs(turtle.ycor()-block.ycor())
print(xDistance, yDistance)
if (xDistance < 20 and yDistance < 20):
sys.exit()
else: # redraw blocks _after_ calculating distance
draw_blocks(index)
drop_block(i)

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()

Python turtle not moving on arrow press

I am trying to make my turtle (main_ship) move across the bottom of my screen according to when the user presses the left and right arrow keys but the turtle is not moving. I have used the same code before when making Pong so I'm not sure why it's not working.
import turtle
wn = turtle.Screen()
wn.title("Game")
wn.bgcolor("black")
wn.setup(width=800, height=600)
wn.tracer(0)
main_ship = turtle.Turtle()
main_ship.speed(0)
main_ship.shape("turtle")
main_ship.color("green")
main_ship.shapesize(stretch_wid=2, stretch_len=4)
main_ship.penup()
main_ship.goto(0, -290)
main_ship.left(90)
def main_ship_right():
x = main_ship.xcor()
x += 20
main_ship.setx(x)
def main_ship_left():
x = main_ship.xcor()
x -= 20
main_ship.setx(x)
while True:
wn.update()
wn.mainloop()
wn.listen()
wn.onkeypress(main_ship_right, "Right")
wn.onkeypress(main_ship_left, "Left")
When I press the arrow keys, nothing happens but the code still runs and there are no error messages.
You have to assign keys before mainloop() which runs all time till you close window.
You don't need while True because mainloop() already runs internal loop.
You may have to remove wm.tracer(0) or you will have to run wn.update() to refresh elements in window.
import turtle
# --- functions ---
def main_ship_right():
x = main_ship.xcor()
x += 20
main_ship.setx(x)
wn.update()
def main_ship_left():
x = main_ship.xcor()
x -= 20
main_ship.setx(x)
wn.update()
# --- main ---
wn = turtle.Screen()
wn.title("Game")
wn.bgcolor("black")
wn.setup(width=800, height=600)
wn.tracer(0)
main_ship = turtle.Turtle()
main_ship.speed(0)
main_ship.shape("turtle")
main_ship.color("green")
main_ship.shapesize(stretch_wid=2, stretch_len=4)
main_ship.penup()
main_ship.goto(0, -290)
main_ship.left(90)
wn.update()
wn.listen()
wn.onkeypress(main_ship_right, "Right")
wn.onkeypress(main_ship_left, "Left")
wn.mainloop()
For this style of motion, there's another way to implement it. The idea is to leave the cursor moving in it's original orientation, but use settiltangle() to make it look like it's facing upward.
This lets us use forward(20) and backward(20) to move our cursor, and not have to write:
x = main_ship.xcor()
x += 20
main_ship.setx(x)
Works great for Space Invader style games, where the player faces upwards but moves sideways:
from turtle import Screen, Turtle
from functools import partial
screen = Screen()
screen.title("Game")
screen.bgcolor('black')
screen.setup(width=800, height=600)
main_ship = Turtle('turtle')
main_ship.speed('fastest')
main_ship.color('green')
main_ship.shapesize(stretch_wid=2, stretch_len=4)
main_ship.settiltangle(90)
main_ship.penup()
main_ship.sety(-290)
screen.onkeypress(partial(main_ship.forward, 20), 'Right')
screen.onkeypress(partial(main_ship.backward, 20), 'Left')
screen.listen()
screen.mainloop()
Only works in the turtle library that comes with Python -- online Python development sites usually provide limited turtle implementations that don't include methods like settiltangle().

making an endpoint in turtle graphics

I'm making a maze with turtle graphics for a class project and I have one more main thing to complete before I'm finished...
I've created a second "turtle" to make a box at the endpoint. So the objective is to finish the maze and get the turtle in the box. But I am unsure how to make the box an actual endpoint and have a message pop up.
Here is my code:
from turtle import Turtle, Screen
screen = Screen()
screen.setup(650, 850)
screen.title("Turtle Keys")
screen.bgpic('scooby_doo_maze.gif')
move = Turtle(shape="triangle")
move.penup()
move.setx(-150)
move.sety(200)
move.pendown()
move.pensize(5)
box = Turtle(shape="square")
box.hideturtle()
box.speed(0)
box.penup()
box.setx(150)
box.sety(-190)
box.pendown()
box.right(90)
box.forward(100)
box.right(90)
box.forward(100)
box.right(90)
box.forward(100)
box.right(90)
box.forward(100)
def keyUp():
move.forward(12)
def keyLeft():
move.left(90)
def keyRight():
move.right(90)
def keyDown():
move.backward(12)
def keyReset():
move.reset()
move.penup()
move.setx(-150)
move.sety(200)
move.pendown()
move.pensize(5)
screen.onkey(keyUp, "Up")
screen.onkey(keyLeft, "Left")
screen.onkey(keyRight, "Right")
screen.onkey(keyDown, "Down")
screen.onkey(keyReset, "r")
screen.listen()
screen.exitonclick()
We just need to add few features. First, instead of drawing the end point with turtle box, we make turtle box the endpoint by expanding the turtle itself via box.shapesize(). This way, we can use move.distance(box) to determine if move is near the center of box.
Second, we need a function called by all the movement functions to test if above distance is close enough and then invoke the following:
Third, we introduce screen.textinput() to let the play know they've succeeded and offer then the option to play again, or quit. I've reworked your code below to introduce these additions and tweak it a bit for style:
from turtle import Turtle, Screen
screen = Screen()
screen.setup(650, 850)
screen.title("Turtle Keys")
screen.bgpic('scooby_doo_maze.gif')
def insideBox():
if move.distance(box) < 60:
play_again = screen.textinput("Success!", "Play again?")
if play_again and play_again.lower().startswith('y'):
keyReset()
else:
screen.bye()
def keyUp():
move.forward(12)
insideBox()
def keyLeft():
move.left(90)
def keyRight():
move.right(90)
def keyDown():
move.backward(12)
insideBox()
def keyReset():
move.reset()
move.penup()
move.goto(-150, 200)
move.pendown()
move.pensize(5)
screen.listen() # it's here because screen.textinput() unsets it
screen.onkey(keyUp, "Up")
screen.onkey(keyLeft, "Left")
screen.onkey(keyRight, "Right")
screen.onkey(keyDown, "Down")
screen.onkey(keyReset, "r")
move = Turtle(shape="triangle")
keyReset()
box = Turtle(shape="square")
box.color("black", "white")
box.shapesize(5, 5, 5)
box.penup()
box.goto(150, -190)
screen.mainloop()
This is a situation where I would avoid screen.exitonclick() as you need to click the window to get it to listen and easily end up closing it! Using screen.mainloop() should be sufficient and let the user close the window by not choosing to play again or using the window controls.

while True: not working with turtle

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.

Categories