how to add a def function with a while true loop - python

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

Related

How can I make python wait for a specified amount of time before moving to the next line?

This is my code currently.
def attack(self, surface, target):
attacking_rect = pygame.Rect(self.rect.centerx - (2*self.rect.width*self.flip), self.rect.y, 2*self.rect.width, self.rect.height)
if attacking_rect.colliderect(target.rect) and self.char_type == 'Player':
time.sleep(.9) #wait for animation to finish
target.health -= random.randint(7, 15)
target.hit = True
elif attacking_rect.colliderect(target.rect) and self.char_type == 'Skeleton':
time.sleep(1.4) #wait for animation to finish
target.health -= random.randint(6, 10)
target.hit = True
Doing my first pygame project this is another issue I ran into. The issue here is that time pauses my whole program whereas I only want to pause this function from moving to the next line.
You can consider multithreading,.
Why don't you open a new thread for every time you run attack(self, surface, target), and then pause just the thread instead of making your whole program hang?
Check out the official documentation for the threading library as well as this guide for more information on how to actually use threading.
It is correct behaviour and it will freeze your whole application because there is only one main thread that is handling your code. In this case the only way will be as Ryan suggested, will be using the multithreading

Turtle Screen.tracer(0) doesn't stop all animation

I thought using Screen.tracer(0) disabled animation in Python Turtle Graphics. However in the following program, if you comment out screen.update(), there is still some animation happening - the turtle trail gets drawn although the turtle doesn't "move" (or get updated). What is happening here please? Is there way to make updating the screen completely manual?
import turtle
def move():
my_turtle.forward(1)
my_turtle.right(1)
screen.update() # Comment out this line to see issue.
screen.ontimer(move, 10)
screen = turtle.Screen()
my_turtle = turtle.Turtle()
my_turtle.shape("turtle")
screen.tracer(0)
move()
turtle.done()
No, screen.tracer(0) doesn't stop all animation. Some turtle commands like end_fill() invoke screen.update() directly, some like dot() invoke it due to other methods that they in turn invoke. You only advise the system when you call update(), not control it completely.
Put your update() calls where you believe you need them, and don't assume certain methods force an update, otherwise future updates of turtle might break your code. (I.e. someone might actually fix turtle.)
For potentially helpful details, see my tracer() rules of thumb and information about the first argument's numeric value
In turtle.py, forward() calls _go() which sets an endpoint, then calls _goto()
_goto() creates a newline if line segments get above 42
if len(self.currentLine) > 42: # 42! answer to the ultimate question
# of life, the universe and everything
self._newLine()
The value appears to be arbitrary; you could set it to something higher, but then there are pauses where nothing appears to be happening.
def _newLine(self, usePos=True):
"""Closes current line item and starts a new one.
Remark: if current line became too long, animation
performance (via _drawline) slowed down considerably.
"""

Python 3 turtle speed of drawing

I am creating a game in python using turtle but I am unable to control the speed of the turtle in the loop as the speed of the turtle is 0. It is supposed to run like flash but it is running at normal speed
import turtle
c=turtle.Screen()
a=turtle.Turtle()
a.speed(0)
b=True
def ch( a , d):
global b
b = False
while b:
a.fd(1)
c.onclick(ch)
c.mainloop()
speed(0) can only speed up the animations a bit.
Try using c.tracer(0, 0)
This fully disables all animations, and should result it a bit more of a speed up. Although, to refresh the screen you'll need to call c.update()
First, your code is structured incorrectly. You don't need to call onclick() in a loop, it simply sets a handler function so only needs to be called once. Also, mainloop() should be running the events, not called after the events are over.
I don't believe you're going get any more speed out of this code unless you increase the forward distance. Simply increading to fd(3) will make a noticeable differece. My rework of your code:
from turtle import Turtle, Screen
def click_handler(x, y):
global flag
flag = False
def turtle_forward():
if flag:
turtle.forward(3)
screen.ontimer(turtle_forward, 0)
flag = True
screen = Screen()
screen.onclick(click_handler)
turtle = Turtle()
turtle.speed('fastest')
turtle_forward()
screen.mainloop()

Mixing events in a python turtle program

I am trying to write a python turtle program that behaves similarly to a regular event-driven program that uses a game loop. The program tries to mix mouse, keyboard and timer events as is as posted below.
My problem is that python doesn't seem to be able to mix the onkey() events with the ontimer() loop. When run, the program will animate the turtle and the onclick() event will work. The key press isn't even registered until the mouse is first clicked. Then, when the key is pressed to quit, I get a large list of errors in the shell. The bye() method seems to be terminating the program in a brutish fashion and not shutting down elegantly.
I think that I have the commands in the correct order.
Any suggestions will be appreciated!
import turtle
playGround = turtle.Screen()
playGround.screensize(800, 600, 'light blue')
bob = turtle.Turtle()
bob.color('red')
bob.pencolor('red')
bob.ht()
def teleport(x,y):
bob.goto(x,y)
def quitThis():
playGround.bye()
def moveAround():
bob.fd(10)
bob.rt(15)
playGround.ontimer(moveAround,30)
playGround.onclick(teleport,btn=1)
playGround.onkey(quitThis,'q')
moveAround()
playGround.listen()
playGround.mainloop()
One problem I see with your code is you need to keep the moveAround() from happening during the teleport() otherwise you get confusing visuals. I find with turtle that it helps to disable the event handler when inside the event hander and reenable it on the way out.
I believe the following will smooth out your events and allow them all to fire at the appropriate time. I've added a state variable to help control the activity:
from turtle import Turtle, Screen
def teleport(x, y):
global state
playGround.onclick(None) # disable handler inside handler
if state == "running":
state = "teleporting"
bob.goto(x, y)
state = "running"
if state != "quitting":
playGround.onclick(teleport)
def quitThis():
global state
state == "quitting"
playGround.onkey(None, 'q')
playGround.bye()
def moveAround():
if state == "running":
bob.fd(10)
bob.rt(15)
if state != "quitting":
playGround.ontimer(moveAround, 30)
playGround = Screen()
playGround.screensize(800, 600, 'light blue')
bob = Turtle(visible=False)
bob.color('red')
playGround.onclick(teleport)
playGround.onkey(quitThis, 'q')
playGround.listen()
state = "running"
playGround.ontimer(moveAround, 100)
playGround.mainloop()
when the key is pressed to quit, I get a large list of errors in the
shell. The bye() method seems to be terminating the program in a
brutish fashion
This is typical of turtle. If it really bothers you, see my answer to the question about Turtle window exit errors for one possible solution.

How do I exit a while loop in python with an event?

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

Categories