Python - Keyboard Multiple Turtle Objects - python

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.

Related

Why my python kept crashing when it tried to run the turtle.tracer() method in turtle module?

I was coding a Snake Game using turtle module but when I add this line into my code the turtle screen and python crashed:
turtle.tracer(0)
can somebody help me so I can complete the game? Thanks a lot
my code:
from turtle import Turtle, Screen, colormode
screen = Screen()
screen.bgcolor("black")
screen.setup(width=600, height=600)
screen.title("My Snake Game")
screen.tracer(0)
x = 0
segments = []
for turtle in range(3):
turtle = Turtle("square")
turtle.color("white")
turtle.penup()
turtle.goto(0-x, 0)
x += 20
segments.append(turtle)
game_is_on = True
screen.update()
while game_is_on:
for segment in segments:
segment.forward(20)
screen.exitonclick()
I think we need to know more about what you mean by 'crashed'. If you mean everything froze, that's the code you wrote. Once you introduce tracer() you need to provide an update() for every change you want the user to see. But you don't have any update() calls in your loop so everything visually remains as it was before the loop. If you want to see the segments move, you need to do something like:
from turtle import Turtle, Screen
screen = Screen()
screen.bgcolor('black')
screen.setup(width=600, height=600)
screen.title("My Snake Game")
screen.tracer(0)
x = 0
segments = []
for turtle in range(3):
turtle = Turtle('square')
turtle.color('white')
turtle.penup()
turtle.setx(x)
x -= 20
segments.append(turtle)
screen.update()
game_is_on = True
while game_is_on:
for segment in segments:
segment.forward(20)
screen.update()
screen.exitonclick() # never reached
If you mean by 'crashed' that Python quit back to the operating system, then you need to describe the environment under which you're running this code.

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.

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

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

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.

Categories