I'm trying to build a game similar to snake with the turtle library. I was able to make the turtle continually move forward with a while True loop, and also make turns without breaking the while loop.
Now I'm trying to figure out a way to exit the while loop that makes the turtle go forward in order to end the game. My aim is to allow the player to exit the loop by entering 'e' on their keyboard.
This code currently results in: AttributeError: 'Turtle' object has no attribute 'done'
def forward():
while True:
snake.forward(0.8)
if window.onkey(exit,"e"):
exit()
def left():
snake.left(90)
def right():
snake.right(90)
def back():
snake.back(0.8)
def exit():
snake.done()
#the function that actually moves the snake
def movesnake():
while True:
window.listen()
window.onkey(forward, "w")
window.onkey(left, "a")
window.onkey(right, "d")
window.onkey(back, "s")
window.mainloop()
movesnake()
If you just want the snake to stop moving, snake.done() should be turtle.done(). done is a turtle module function, not a turtle.Turtle method, so you can call it as a function, but not on the Turtle object.
Related
I'm new to python and decided to practice by building a game similar to snake with the turtle library. I was able to initiate the turtle to continually move forward with a while True loop, but now I'm having trouble with getting the turtle to break this loop to make turns.
I have tried various different ways of writing my conditionals but I can't seem to figure out where the issue is. Thanks in advance!
import turtle
window = turtle.Screen()
snake = turtle.Turtle()
snake.speed(1)
snake.penup()
#Functions that move the snake:
def forward():
while True:
snake.forward(.7)
def left():
snake.left(90)
def right():
snake.right(90)
#Movement functions all put together:
def movesnake():
while True:
entry = input()
if entry == 'w':
forward()
if entry == 'a':
left()
if entry == 'd':
right()
movesnake()
Try this approach to move:
def forward():
turtle.forward(how-many-pixels-forward)
turtle.onkey(forward,'what-key-you-want-to-listen-to') #when key pressed call forward function
https://www.geeksforgeeks.org/turtle-onkey-function-in-python/
The turtle module provides turtle graphics primitives, in both object-oriented and procedure-oriented ways. Because it uses Tkinter for the underlying graphics, it needs a version of Python installed with Tk support.
turtle.onkey()
This function is used to bind fun to the key-release event of the key. In order to be able to register key-events, TurtleScreen must have focus.
You can try increasing the value of the forward function:
def forward():
while True:
snake.forward(5)
Take a look at this book
https://argentinaenpython.com/quiero-aprender-python/doma-de-serpientes-para-ninos_swfk-es-linux-0.0.4.pdf
In the snake program (Python), the line my_screen.onkey(my_snake.turn_up(), 'Up') is always executing. It triggers this 'Up' keystroke event irrespective of the my_screen.listen() statement or if i have pressed any keys ! Can someone help please as I am unable to get this to run properly, ie it was always run the onkey event 'Up'.
from turtle import Turtle
from turtle import Screen
from snake import Snake
import time
my_screen = Screen()
my_screen.setup(width=600, height=600)
my_screen.bgcolor("black")
my_screen.title("My Snake Game")
'''this causes the screen to stop updating, until it gets the 'Update' function call'''
my_screen.tracer(0)
'''create turtle objects'''
my_snake = Snake()
print(my_snake.segments)
my_screen.listen()
my_screen.onkey(my_snake.turn_up(), 'Up')
game_is_on = True
while game_is_on:
my_screen.update()
time.sleep(.1)
my_snake.move()
my_screen.exitonclick()
Actually, the onkey() command must have a function without braces (). So you could have written as
my_screen.onkey(my_snake.turn_up, 'Up')
instead of
my_screen.onkey(my_snake.turn_up(), 'Up')
I am writing a script to read my keystrokes and draw simple shapes in turtle.
To record keystrokes, I am using the keyboard module and I am using turtle for drawing.
I am getting struck due to the use of threading in the keyboard module.
What I am currently doing is-
I added hotkeys using keyboard.add_hotkey method.
If I am pressing a certain key, that letter is added to a list (named data) for later use.
When I press the combination of Ctrl+Shift+S, the save function is called. In the save function, a turtle window is instantiated, and the list data is popped one letter at a time. The shape is drawn according to the letter popped.
When the list gets empty, I save the drawing and close the turtle window.
The problem that I am facing is that once the save function is called, the program stops listening to other calls. It is perhaps due to the use of threads in keyboard module.
The code is attached here-
def start():
#turtle.mainloop()
s=turtle.Screen().setup( width = WIDTH, height = HEIGHT, startx = 0, starty = 0)
global t
t=turtle.Turtle()
turtle.ht()
t.ht()
def save():
start()
global t
global data
t.speed(0)
while data:
fun = data.pop()
if fun=='c':
draw_circle()
elif fun=='r':
draw_rectangle()
elif fun=='p':
draw_polygon()
elif fun=='h':
draw_hexagon()
elif fun=='t':
draw_triangle()
elif fun=='m':
draw_pentagon()
ts = turtle.getscreen()
ts.getcanvas().postscript(file="drawing.eps")
img = Image.open('drawing.eps')
img.save('drawing.png')
turtle.bye()
def push_fun(fun):
data.append(fun)
if __name__=='__main__':
keyboard.add_hotkey('ctrl+shift+s', save)
keyboard.add_hotkey('ctrl+shift+e', exit)
keyboard.add_hotkey('ctrl+shift+p', send_to_server)
# keyboard.add_hotkey('ctrl+shift+s', save, args=(data))
keyboard.add_hotkey('c', push_fun, args=('c',))
keyboard.add_hotkey('s', push_fun, args=('t',))
keyboard.add_hotkey('h', push_fun, args=('h',))
keyboard.add_hotkey('p', push_fun, args=('p',))
keyboard.add_hotkey('r', push_fun, args=('r',))
keyboard.wait()
After the save function is called, the program remains in the keyboard.wait() part but does not listen to any other key press.
you can end the wait by setting a key to press like:
keyboard.wait('space')
but keyboard.wait() without any keys given blocks all keystrokes forever
I'm not sure why you even put it there, I'm not even sure why it picks anything up at all, but I think you can do this:
if __name__=='__main__':
'''your keystrokes'''
while True: #or set a timer or something
pass
you didn't give me the whole code so I can't make sure it works
you also need to global the list data in the push_fun function
I hope it helps :)
I've added a function definition to tell my turtle to jump when you press the space bar. There is also a while True loop in my code, and whenever the space button is pressed, the while True loop freezes momentarily until the jump is finished and then carries on.
I've tried adding the function definition in the while True loop and outside. I can only put the function definition before the while True loop, because if I put it after the while True, the code will never reach it.
#making the player jump
def jump():
player.fd(100)
player.rt(180)
player.fd(100)
player.lt(180)
turtle.listen()
turtle.onkey(jump, "space")
I'm expecting the while True loop to not freeze, but wherever I've tried putting the def, it doesn't seem to work.
I also saw another answer to something similar to this, but didn't understand how I could apply that to my code.
Any other suggestions would be great.
Until you get that async stuff to work, here's a minimalist implementation using turtle's own timer event to keep an obstacle moving forward, even when jumping:
from turtle import Screen, Turtle
def jump():
screen.onkey(None, 'space') # disable handler inside handler
if jumper.ycor() == 0: # if jumper isn't in the air
jumper.forward(150)
jumper.backward(150)
screen.onkey(jump, 'space')
def move():
hurdle.forward(6)
if hurdle.xcor() > -400:
screen.ontimer(move, 100)
jumper = Turtle('turtle')
jumper.speed('slowest')
jumper.penup()
jumper.setheading(90)
hurdle = Turtle('turtle')
hurdle.speed('fastest')
hurdle.penup()
hurdle.setheading(180)
hurdle.setx(400)
screen = Screen()
screen.onkey(jump, 'space')
screen.listen()
move()
screen.mainloop()
You can find several, more fleshed out versions of this on SO by searching for '[turtle-graphics] jump'
Avoid using a while True: loop in turtle's event-based environment.
I expected that it can be hard to do it with async but I built example which works.
Inside jump I use asyncio.sleep so this way when one turtle is sleeping then other turtle can walk. Without asyncio.sleep first turtle walk all the time.
import asyncio
import turtle
t1 = turtle.Turtle()
t2 = turtle.Turtle()
async def jump1():
while True:
t1.fd(100)
await asyncio.sleep(0.01)
t1.left(90)
async def jump2():
while True:
t2.fd(100)
await asyncio.sleep(0.01)
t2.right(90)
tasks = [jump1(), jump2()]
# Python 3.6.7
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
# Python 3.7
#asyncio.run(asyncio.wait(tasks))
But building something more complex can be more difficult.
I also found aioturtle - turtle which use async. Maybe it will be easier to use aioturtle.
The problem is the following:
the code for the jump event is called synchronously. That means, everything has to wait for jump() to finish before continuing. this can maybe be fixed by declaring / calling the jump() method asynchronously. This website does a good job of explaining what asynchronous python means and how to implement it: https://hackernoon.com/asynchronous-python-45df84b82434
in short, here's how it would be implemented(in python 3.3 or higher):
async def jump():
#your code here
this just makes the jump() function run asynchronously.
now, whenever you call it, you have to call it like this:
await jump()
this might not work, depending on your exact setup.
i hope this helps.
please, ask me if you have any further questions.
EDIT: example
I'm making this project for school that involves displaying data to a raspberry pi. The code I'm using refreshes (and needs to refresh) incredibly quickly, but I need a way for the user to stop the output, which I believe requires some kind of key event. The thing is, I'm new to Python and I can't figure out how to exit a while loop with turtle.onkey(). I found this code:
import turtle
def quit():
global more
more = False
turtle.onkey(quit, "Up")
turtle.listen()
more = True
while more:
print("something")
Which doesn't work. I've tested it. How do I make this work, or is there another way to get user input without interrupting the flow of the program?
while loop run on thread
check this code
import threading
def something():
while more:
print("something")
th = threading.Thread(something)
th.start()
Avoid infinite loops in a Python turtle graphics program:
more = True
while more:
print("something")
You can effectively block events from firing, including the one intended to stop the loop. Instead, use timer events to run your code and allow other events to fire:
from turtle import Screen
more = True
counter = 0
def stop():
global more
more = False
def start():
global more
more = True
screen.ontimer(do_something, 100)
def do_something():
global counter
print("something", counter)
counter += 1
if more:
screen.ontimer(do_something, 100)
screen = Screen()
screen.onkey(stop, "Up")
screen.onkey(start, "Down")
screen.listen()
start()
screen.mainloop()
I've added a counter to your program just so you can more easily see when the 'something' statements stop and I've added a restart on the down key so you can start them up again. Control should always reach mainloop() (or done() or exitonclick()) to give all the event handlers a chance to execute. Some infinite loops allow events to fire but they typically have calls into the turtle methods that allow it to have control some of the time but are still the wrong approach.
Chances are that you are trying to run your code in an interactive IPython shell. That does not work. The bare Python repl shell works, though.
Here I found a project that tries to bring turtle to IPython: https://github.com/Andrewkind/Turtle-Ipython. I did not test it, and I'm not exactly sure that this is a better solution than simply using the unsugared shell.
You could have you loop check a file like this:
def check_for_value_in_file():
with open('file.txt') as f:
value = f.read()
return value
while check_for_value_in_file() == 'the right value':
do_stuff()