How do I speed up on key press in python turtle - python

I am trying to speed up my turtle whenever I press the space bar.
I have a code that looks something like this
import turtle
instructions = [20,30,40,20,50,5,20,30,40,200,5]
speed = 0
wn = turtle.Screen()
drone = turtle.Turtle()
speed = 1
def sped():
global speed
speed += 1
for instruction in instructions:
drone.forward(instruction)
drone.left(45)
wn.onkey(sped, "space")
drone.speed(speed)
print(speed)
However, the speed is always 1. I've tried scouring the internet but nothing comes up. How do I fix this?

Related

Turtle control the rate of refresh using sleep does not refresh properly

I'm controlling turtle animation by using tracer(0, 0) and stamping the turtle cursor itself.
However, it refreshes strangely, it's suppose to be 1 second between any animation (with sleep) but it seems to sometimes hang for two second, then a couple of second later zaps into position:
The code is:
import turtle
import time
screen = turtle.Screen()
screen.listen()
screen.tracer(0, 0)
pen = turtle.Turtle()
pen.speed('fastest')
pen.shape("circle")
pen.penup()
pen.hideturtle()
next = [0, 8]
time.sleep(10)
while True:
pen.goto(next[0]*20, next[1]*20)
screen.clear()
pen.stamp()
screen.update()
time.sleep(1)
next = [next[0], next[1]-1]
Seems like simply sleeping is not a good idea. I seem to also have trouble getting it to work with threading. How do I it works with a predefined time like 1 second in this case?
Depending on the efficiency of your computer, time.sleep(1) would have different durations.
Instead of relying on the efficiency of your computer to adjust the sleep duration, you can use the perf_counter method to detect how long your program has been running from one part to another.
Basically, once you run the program, the time tracking starts. Where ever you call time.perf_counter(), it will return the amount of time for the start of the program to reach the place you called time.perf_counter().
import turtle
import time
screen = turtle.Screen()
screen.listen()
screen.tracer(0, 0)
pen = turtle.Turtle()
pen.speed('fastest')
pen.shape("circle")
pen.penup()
pen.hideturtle()
nxt = [0, 8]
time.sleep(10)
while True:
start = time.perf_counter() # Find the total performance time from the start of the program to here
pen.goto(nxt[0]*20, nxt[1]*20)
screen.clear()
pen.stamp()
screen.update()
while time.perf_counter() - start < 1: # Keep looping until the amount of performance time from right under "while True" to this line reaches 1 second
pass
nxt = [nxt[0], nxt[1]-1]
Using sleep and while True: loops in an event-driven world like turtle is a bad idea. We can instead use a timer event to produce the effect you describe. While we're at it, we're going to toss stamping as that's not adding anything, and neither are clear() and listen():
from turtle import Screen, Turtle
CURSOR_SIZE = 20
def drop():
screen.update()
turtle.sety(turtle.ycor() - CURSOR_SIZE)
screen.ontimer(drop, 1000) # 1 second
screen = Screen()
screen.tracer(False)
turtle = Turtle()
turtle.shape('circle')
turtle.penup()
turtle.sety(160)
screen.ontimer(drop, 10_000) # 10 seconds
screen.mainloop()
Of course, you need to add some logic to avoid restarting the timer event if/when the circle falls off the bottom of the screen. By using while True: loops, and sleep() you potentially block events, like user keystrokes or window closing, from reaching turtle.
One minor inaccuracy here is the drop() method takes some minimal time to run -- to factor that out, if needed/desired, you need to adjust the timing based on clock time or something like time.perf_counter() as #AnnZen demonstrates, but not in a pass loop!
EDIT:

Having trouble timing turtle movement

I wrote the following code, which creates expanding squares at two random locations. I would like to write a function f(squares, seconds) so that if the user inputs f(5,10), a new square would begin forming every 10 seconds, until 5 had formed.
I can't seem to find anything which lets me start a new square while one is still forming. I can either make two form at the same time, as in the code below, or have one be completed, and then for another to start forming. Help?
import sys
sys.setExecutionLimit(1000000)
import turtle
import random
wn = turtle.Screen()
#Creates alex the turtle
alex = turtle.Turtle()
alex.color('blue')
alex.pensize(3)
alex.ht()
alex.penup()
#creates bob the turtle
bob = turtle.Turtle()
bob.color('blue')
bob.pensize(3)
bob.ht()
bob.penup()
#Sets variables so that alex starts in a random location
a=random.randrange(360)
b=random.randrange(360)
x=random.randrange(50,150)
y=random.randrange(50,150)
#Sets variables so that bob starts in a random location
l=random.randrange(360)
m=random.randrange(360)
n=random.randrange(50,150)
o=random.randrange(50,150)
#Moves alex to his random starting location
alex.speed(100)
alex.left(a)
alex.forward(x)
alex.left(b)
alex.forward(y)
alex.pendown()
#Moves bob to his random starting location
bob.speed(100)
bob.left(l)
bob.forward(n)
bob.left(m)
bob.forward(o)
bob.pendown()
#Draws the 2 squares
for i in range(1,500):
alex.forward(i)
alex.left(90)
bob.forward(i)
bob.left(90)
The functionality you want requires independent execution threads. You need to work with the multi-threading package and tutorial
You will want logic such as this:
import time
import threading
def draw_square():
# Draw a square in a random place
length = random.randrange(360)
width = random.randrange(360)
x_pos = random.randrange(50,150)
y_pos = random.randrange(50,150)
# Continue with your square-drawing logic;
# you already know how to do this.
while True:
threading.thread(draw_square)
time.sleep(10)

ways of using midi events to make a player move in pygame

I have made some little games with the pygame module and it had been fun. However, right now i´m trying to move the character with a piano via midi using pygame.midi. there´s the problem. I did it but not in the way i wanted to because
the character moves sometimes and other it doesn´t. I think i know where is the problem: If i understand correctly, the pygame.event.get() function "catch" the events always, it does not matter when (inside the main loop of the game), so i think that with my code this is not happening, i mean, i believe that the player not always do what is supposed to do because the midi input has to be in a specific "time" not as pygame.event.get(). I looked into the pygame documentation and there seems to be a function that does the trick: pygame.midi.midis2events(), but i don´t know how to use it.The question is just:
How can i move the character through the piano via midi with pygame in order that the character moves everytime?
import pygame as pg, pygame.midi
WIDTH = 800
HEIGHT = 600
FPS = 60
BLACK = (0,0,0)
BLUE = (0,0,255)
pg.init()
pg.midi.init()
screen = pg.display.set_mode((WIDTH,HEIGHT))
pg.display.set_caption('STACKOVERFLOW_EXAMPLE_MIDI')
clock = pg.time.Clock()
running = True
inp = pg.midi.Input(1)
x = WIDTH//2
y = HEIGHT//2
speedx = 0
midi_list = []
while running:
clock.tick(FPS)
if inp.poll():
midi_value = inp.read(1000)[0][0][1]
if midi_value==57:
midi_list.append(midi_value)
if len(midi_list)==1:
speedx = -1
else:
speedx = 0
midi_list = []
if midi_value == 63:
running = False
x = x+speedx
screen.fill(BLUE)
pg.draw.rect(screen,BLACK,[x,y,50,60])
pg.display.update()
pg.display.flip()
pg.quit()
I need that the player moves to the left (or to the right) when the piano´s key A3 (a specific note) is being pressed and that the player stops moving when
the key has been released. In this particular fragment of the code, but also to do things like press a piano´s key an shoot one bullet regardless of whether is being pressed or not, in short, to do the same things i can do with the keyboard events.
ok! i found and answer that works well for the time being:
if inp.poll():
s(0.1)
midi_values = inp.read(1000)
for midi in midi_values:
midi_value = midi[0][1]
#Movement to the left
if midi_value==57:
midi_list.append(midi_value)
if len(midi_list)==1:
speedx = -50
Modifying the code in order to iterate the list midi_values gives me the correct input-output response without the inestability which i experienced. Also i did introduce a sleep(0.1) delay and works well without to much cpu use. I found the answer here:
https://www.reddit.com/r/learnpython/comments/36dxu9/python_whileloop_cpu_demanding/
The only problem which i find now is that the pygame window stops with the message no responde (doesn´t respond or something similar) and it stops working.
For example the cube which i´m moving with the keys of the piano doesn´t do anything but the key to close the program does work fine!!

In Python, how can I execute two Turtle commands simultaneously?

As in having two Turtles moving at once. For example, I import two turtles, then try to have both of them move forward alongside each other. How can I do this?
bob = turtle.Turtle()
john = turtle.Turtle()
def move_turtles(ammount):
for i in range(ammount // 10):
bob.forward(10)
john.forward(10)
move_turtles(100)
There's no way to move them at the same time, although you can use something like that. It moves the turtles by 10 points each, so it gives the impression that they are moving together, but they are actually moving separately by little ammounts. It repeats the operation (ammount //10) times, and moves 10 in each iteration, so if you were to give 50 as an input, it would move 5 times 10 points, resulting in 50. You can then customize the function to move by a little a turtle so they don't overlap and so on.
You can move multiple turtles independently at the same time using timer events -- you can even have them move at different rates, both in time and space:
import turtle
turtle.setworldcoordinates(0, -100, 100, 100)
bob = turtle.Turtle(shape="turtle")
bob.penup()
bob.sety(20)
john = turtle.Turtle(shape="turtle")
john.penup()
john.sety(-20)
def move_bob():
bob.forward(1)
if bob.xcor() < 90:
turtle.ontimer(move_bob, 75)
def move_john():
john.forward(2)
if john.xcor() < 90:
turtle.ontimer(move_john, 100)
move_bob()
move_john()
turtle.exitonclick()
Other folks also use threads to achieve this but timer events are built into the turtle module.
There is a way to control frames using the Turtle module - you need to change the screen attributes.
screen = turtle.Screen()
screen.tracer(0)
This method makes all turtle movement invisible until you run screen.update(), and then every turtle will be visually updated at the same time on the screen. In your case, you can write screen.update() after the movement of both turtles, and they will appear to move at the same time.

I'm trying to time how long a key is held down using vPython

I'm writing a program for my physics final. Throughout the semester we have used vPython to model situations and get exact answers, etc. Our final project is to create a game using vPython that includes some type of physics.
I chose to remake Bowman except with tanks. So you have a tank on the right hand of the screen and left hand of the screen with a wall in the middle. The object is to aim your cannon and shoot the right velocity to hit your opponent's tank. I have the a good chunk of the program complete however I am stuck on a few different things.
First, how can I time a keystroke? I have it so I shoot from the each cannon however I want to be able to hold down a key and dependent on how long it's held down for the faster the initial velocity will be.
Second, where would I incorporate gravity into the program? I have a general idea of how to but I just don't know which function to put it into.
Lastly, I have a wall height being generated randomly each time the program is run. However sometimes the wall is so small you can't see it. Is there a way I can set a range of values for this?
Here is my code:
from visual import*
from random import*
scene.autoscale=False
scene.width = 1500
scene.height = 800
scene.title='Tanks'
def moveaup(gun):
theta=arctan(gun.axis.y/gun.axis.x)
dtheta=.1
if (theta<pi/2):
theta=theta+dtheta
if not (theta>pi/2):
gun.axis=(cos(theta),sin(theta),0)
else:
gun.axis=vector(0,1,0)
def moveadown(gun):
theta=arctan(gun.axis.y/gun.axis.x)
dtheta=.1
if (theta>0):
theta=theta-dtheta
gun.axis=(cos(theta),sin(theta),0)
def movebup(gun):
theta=arctan(gun.axis.y/gun.axis.x)+pi
dtheta=.1
if (theta>pi/2):
theta=theta-dtheta
if not (theta<pi/2):
gun.axis=(cos(theta),sin(theta),0)
else:
gun.axis=vector(0,1,0)
def movebdown(gun):
theta=arctan(gun.axis.y/gun.axis.x)+pi
dtheta=.1
if (theta<pi):
theta=theta+dtheta
gun.axis=(cos(theta),sin(theta),0)
def shoota(gun):
vel = vector(1,1,0)
bullet = sphere(pos=(gun.pos.x+gun.axis.x,gun.pos.y+gun.axis.y,0),radius=(.0785),color=color.yellow)
bullet.v = vector(0,0,0)
bullet.v = bullet.v+vel
bulletlist.append(bullet)
def shootb(gun):
vel = vector(-1,1,0)
bullet = sphere(pos=(gun.pos.x+gun.axis.x,gun.pos.y+gun.axis.y,0),radius=(.0785),color=color.green)
bullet.v = vector(0,0,0)
bullet.v = bullet.v+vel
bulletlist.append(bullet)
def bulletlistupdate(bulletlist):
dt=.01
for a in bulletlist:
a.pos=a.pos+a.v*dt
def checks(agun,bgun):
if scene.kb.keys:
key=scene.kb.getkey()
if key=='a':
moveaup(agun)
if key=='s':
moveadown(agun)
if key=='l':
movebup(bgun)
if key=='k':
movebdown(bgun)
if key=='d':
shoota(agun)
if key=='j':
shootb(bgun)
#enviroment
ground = box(pos=(0,-8,0),size=(50,5,0),color=color.red)
wall = box(pos=(0,-8,0),size=(.25,20*random(),0),color=color.red)
#playerA
abody = box(pos=(-11,-5.25,0),size=(.5,.5,0),color=color.blue)
agun = cylinder(pos=(-11,-5.1,0),axis=(.8,.8,0),radius=(.08),color=color.blue)
#playerB
bbody= box(pos=(11,-5.25,0),size=(.5,.5,0),color=color.yellow)
bgun = cylinder(pos=(11,-5.1,0),axis=(-.8,.8,0),radius=(.08),color=color.yellow)
bulletlist = []
while True:
rate(1000)
checks(agun,bgun)
bulletlistupdate(bulletlist)
Any and all help is welcome!
Thanks much!
You can time things in python using the time module
import time
start = time.time()
finish = time.time()
print start # 1386269106.18
print finish # 1386269111.11
print (finish - start) # 4.9276599884
So when the player first starts pressing the button, save the time. Then save the time again when the player stops pressing the button. The difference between these two times is the number of seconds the player held the button.
[Edit] If all you can do is check if the key is pressed down, you can get the time inside the main loop and calculate dt (the amount of time that has passed):
t = time.time()
while True:
new_t = time.time()
dt = new_t - t
t = new_t
rate(1000)
checks(agun,bgun, dt)
bulletlistupdate(bulletlist)
Then pass dt to checks, and if the key is pressed down, you know the key has been held down for another dt seconds, and you can add it to your running total of time that it has been held down.
For the random you would need to enter a command similar to this:
random.randrange(5,31) #this would give you a random range between the numbers 4-30
I don't want to do your homework for you as I don't think you are asking for that. I hope this helps you.
I'm sorry this should be the correct code for you:
random.randint(7,40) # this would get you a random integer of 7-40
I apologize for the misinformation.

Categories

Resources