I'm trying to set up a simple turtle program in python where I can start moving the turtle with a press of the space bar, and he keeps moving until I hit the space bar again. I can get him to move a fixed distance with the space press but can't get it to continue.
Here is what I'm working with:
from turtle import *
# PUT YOUR CODE HERE
setup(800,600)
home()
pen_size = 2
color("blue")
title("Turtle")
speed("fastest")
drawdist= 25
current_state = penup
next_state = pendown
#Button Instructions
def move_up():
seth(90)
forward(drawdist)
def move_down():
seth(270)
forward(drawdist)
def move_left():
seth(180)
forward(drawdist)
def move_right():
seth(0)
forward(drawdist)
def space_bar():
seth(90)
forward(drawdist)
global current_state, next_state
next_state()
current_state, next_state = next_state, current_state
#Change Pen Color
def red():
color("red")
def green():
color("green")
def blue():
color("blue")
#Button Triggers
s= getscreen()
s.onkey(move_up,"Up")
s.onkey(move_down,"Down")
s.onkey(move_left,"Left")
s.onkey(move_right,"Right")
s.onkey(space_bar,"space")
s.onkey(red,"r")
s.onkey(green,"g")
s.onkey(blue,"b")
listen()
done()
I don't see that you ever got an answer to your query:
start moving the turtle with a press of the space bar, and he keeps
moving until I hit the space bar again
The suggested onkeypress() fix doesn't do this. Here's a simplified example that does what you want, starts the turtle when you hit the space bar and stops it when you hit the space bar again:
from turtle import Turtle, Screen
screen = Screen()
turtle = Turtle(shape="turtle")
turtle.speed("fastest")
def current_state():
global moving
moving = False
turtle.penup()
def next_state():
global moving
turtle.pendown()
moving = True
move()
def space_bar():
global current_state, next_state
next_state()
current_state, next_state = next_state, current_state
def move():
if moving:
turtle.circle(100, 3)
screen.ontimer(move, 50)
current_state()
screen.onkey(space_bar, "space")
screen.listen()
screen.mainloop()
I've used circular motion in this example so you can start and stop the turtle as much as you want.
Replace the function 'onkey' with the function 'onkeypress'.
The 'onkey' function fires once regardless of holding down the key while 'onkeypress' fires as you would expect when holding down the key.
The correct and easiest way is this(NOT FOR EVENT LISTENER SPACE BAR, THIS IS JUST EVENT LISTENERS):
import turtle
import random
t = turtle.Turtle()
screen = turtle.Screen(
def goForward():
t.forward(input_value)
screen.onkey(goForward, "Forward")
The word "right" in hashtags only means to press the right key.
Related
I am trying to make a code where you can press the spacebar and an object will move forwards constantly. I am hoping to be able to have multiple of these objects moving at once without having to code hundreds of them separately.
This is my current code:
Bullet:
bullet = turtle.Turtle()
bullet.speed(0)
bullet.shape("circle")
bullet.color("red")
bullet.shapesize(stretch_wid=0.5, stretch_len=0.5)
bullet.penup()
bullet.goto(-200, -200)
bullet.hideturtle()
Movement:
def shoot_bullet():
stop = False
bullet2 = bullet.clone()
bullet2.showturtle()
while stop == False:
y = bullet2.ycor()
bullet2.sety(y + 20)
wn.update()
time.sleep(0.5)
...
onkeypress(shoot_bullet, "space")
This works until I press space again and the bullet just stops as 'bullet2' has been redefined as the new bullet I create when I press space. Is there a way to create multiple clones which can run on top of each other?
Your while stop == False: loop and time.sleep(0.5) have no place in an event-driven environment like turtle. Instead, as we fire each bullet, the below code attaches a timer event that moves it along until it disappears. At which point the bullet is recycled.
This simplified example just shoots bullets in random directions from the center of the screen. You can keep hitting the space bar to generate simultaneous bullets that all move in their own direction until they get far enough away:
from turtle import Screen, Turtle
from random import randrange
def move_bullet(bullet):
bullet.forward(15)
if bullet.distance((0, 0)) > 400:
bullet.hideturtle()
bullets.append(bullet)
else:
screen.ontimer(lambda b=bullet: move_bullet(b), 50)
screen.update()
def shoot_bullet():
screen.onkey(None, 'space') # disable handler inside hander
bullet = bullets.pop() if bullets else bullet_prototype.clone()
bullet.home()
bullet.setheading(randrange(0, 360))
bullet.showturtle()
move_bullet(bullet)
screen.onkey(shoot_bullet, 'space') # reenable handler on exit
bullet_prototype = Turtle('circle')
bullet_prototype.hideturtle()
bullet_prototype.dot(10) # just for this example, not for actual code
bullet_prototype.shapesize(0.5)
bullet_prototype.color('red')
bullet_prototype.penup()
bullets = []
screen = Screen()
screen.tracer(False)
screen.onkey(shoot_bullet, 'space')
screen.listen()
screen.mainloop()
I'm trying to create a game in python turtle in which hitting space, an arrow fires in the direction the turtle is facing. However when I hit space the arrow always shoots the same direction.
I've already tried assigning the arrow and turtle to the same keybinds, but that makes the turtle incapable of movement
def left():
t.left(15)
k.left(20)
def right():
t.right(15)
k.right(20)
def shoot():
k = turtle.Turtle()
k.penup()
k.color("orange")
k.shape("arrow")
ts.onkey(shoot, "space")
I'm expecting the arrow to shoot from the direction the turtle is facing, but instead it just keeps shooting right.
To do this correctly, with unlimited arrows, takes more work. We need to have a timer event driving each active arrow. Since turtles are global entities that aren't garbage collected, we want to reuse spent arrows. We need to block the fire button while firing to prevent event overlap. The following should do what you describe:
from turtle import Screen, Turtle, mainloop
def left():
player.left(15)
def right():
player.right(15)
def shoot():
screen.onkey(None, 'space') # disable handler inside handler
if quiver:
arrow = quiver.pop(0)
else:
arrow = Turtle('arrow', visible=False)
arrow.speed('fastest')
arrow.color('orange')
arrow.penup()
arrow.setposition(player.position())
arrow.setheading(player.heading())
flight(arrow)
arrow.showturtle()
screen.onkey(shoot, 'space')
def flight(arrow):
if arrow.distance(0, 0) < 325:
arrow.forward(10)
screen.ontimer(lambda a=arrow: flight(a), 100)
else:
arrow.hideturtle()
quiver.append(arrow)
screen = Screen()
screen.setup(500, 500)
quiver = []
player = Turtle('turtle')
player.color('dark green', 'light green')
player.speed('fastest')
screen.onkey(shoot, 'space')
screen.onkey(left, 'Left')
screen.onkey(right, 'Right')
screen.listen()
mainloop()
To answer your original question, you don't need to rotate them together. You can align one with the other when you're ready to shoot using b.setposition(a.position()) and b.setheading(a.heading()).
Try this:
k = turtle.Turtle()
def left():
global t, k
t.left(15)
k.left(15)
def right():
global t, k
t.right(15)
k.right(15)
def shoot():
global k
k.penup()
k.color("orange")
k.shape("arrow")
ts.onkey(shoot, "space")
ts.onkey(left, "left")
ts.onkey(right, "right")
How do you make turtle move without using turtle.goto(x,y) but turtle.speed(speed) and turtle.heading(angle)? I need this for a game I am making. Where the mouse is, I want to make it go in that direction. But when I change it, it goes to that place then to my mouse:
import turtle
screen = turtle.Screen()
screen.title("Test")
screen.bgcolor("white")
screen.setup(width=600, height=600)
ship = turtle.Turtle()
ship.speed(1)
ship.shape("triangle")
ship.penup()
ship.goto(0,0)
ship.direction = "stop"
ship.turtlesize(3)
turtle.hideturtle()
def onmove(self, fun, add=None):
if fun is None:
self.cv.unbind('<Motion>')
else:
def eventfun(event):
fun(self.cv.canvasx(event.x) / self.xscale, -self.cv.canvasy(event.y) / self.yscale)
self.cv.bind('<Motion>', eventfun, add)
def goto_handler(x, y):
onmove(turtle.Screen(), None)
ship.setheading(ship.towards(x, y)) #this is where you use the x,y cordinates and I have seat them to got to x,y and set heading
ship.goto(x,y)
onmove(turtle.Screen(), goto_handler)
onmove(screen, goto_handler)
If you only setheading and speed it just turns that way and does not move. If you try this code it works -- it is just that I use ship.goto(x, y) which makes it go to (x, y). But when you change your mouse when it is moving, it first goes to (x, y) then to your new mouse position. I pretty much just want it to just follow the mouse but I can not do that.
I believe the code below gives you the motion you desire. It only uses onmove() to stash the target's position and uses an ontimer() to aim and move the turtle. It also stops when the target has been enveloped:
from turtle import Screen, Turtle, Vec2D
def onmove(self, fun, add=None):
if fun is None:
self.cv.unbind('<Motion>')
else:
def eventfun(event):
fun(Vec2D(self.cv.canvasx(event.x) / self.xscale, -self.cv.canvasy(event.y) / self.yscale))
self.cv.bind('<Motion>', eventfun, add)
def goto_handler(position):
global target
onmove(screen, None)
target = position
onmove(screen, goto_handler)
def move():
if ship.distance(target) > 5:
ship.setheading(ship.towards(target))
ship.forward(5)
screen.ontimer(move, 50)
screen = Screen()
screen.title("Test")
screen.setup(width=600, height=600)
ship = Turtle("triangle")
ship.turtlesize(3)
ship.speed('fast')
ship.penup()
target = (0, 0)
onmove(screen, goto_handler)
move()
screen.mainloop()
I am attempting to make a game in python with the turtle module, I have the square moving towards the player (the circle) and the aim is for the circle to jump over the square and not get hit.
The player can jump by pressing the spacebar,
but every time you hit the space bar to jump the player jumps, but the square stops moving and you are unable to jump over.
here is my code:
import turtle
import time
wn = turtle.Screen()
wn.bgcolor("white")
wn.title("dinosaur run")
wn.tracer(1,20)
floor = turtle.Turtle()
floor.fd(370)
floor.bk(370*2)
floor.ht()
player = turtle.Turtle()
player.shape("circle")
player.penup()
player.setpos(-370,14)
def jump():
player.lt(90)
player.fd(40)
time.sleep(0.5)
player.bk(40)
player.rt(90)
turtle.listen()
turtle.onkey(jump, "space")
class cactus(turtle.Turtle):
turtle.shape("square")
turtle.penup()
turtle.speed(0)
turtle.setpos(370,14)
cactusspeed = 2
while True:
x = turtle.xcor()
x -= cactusspeed
turtle.setx(x)
Thanks a lot,
all ideas welcome,
I've tried wn.update() at the end
As provided above, your code doesn't run at all as cactusspeed never gets defined. And your class cactus doesn't have a hope of working as currently laid out (reread about Python classes.) Finally, your while True: has no business in an event driven world like turtle.
Below is my rework of your code to use an ontimer() event to control the cactus independent of the player. I also eliminated the sleep() and simply made the player move slower and jump higher. I believe this should give you the dynamic you're looking for:
from turtle import Turtle, Screen
def jump():
player.forward(100)
player.backward(100)
def move():
if cactus.xcor() < -screen.window_width()/2:
cactus.hideturtle()
cactus.setx(370)
cactus.showturtle()
else:
cactus.forward(cactusspeed)
screen.ontimer(move, 40)
screen = Screen()
floor = Turtle(visible=False)
floor.speed('fastest')
floor.fd(370)
floor.bk(370 * 2)
player = Turtle("circle", visible=False)
player.penup()
player.setpos(-370, 14)
player.setheading(90)
player.speed('slowest')
player.showturtle()
cactusspeed = 4
cactus = Turtle("square", visible=False)
cactus.speed('fastest')
cactus.penup()
cactus.setpos(370, 14)
cactus.setheading(180)
cactus.showturtle()
screen.onkey(jump, "space")
screen.listen()
move()
screen.mainloop()
I have Turtle commands in my code as you see below. I would like to put a timer on these commands inside an if statement. My current code just works like so:
'# WHEN USER PRESSES SPACE, LIGHT TURNS GREEN
'# WHEN LIGHT IS GREEN ARROW MOVES 50 PIXELS
player1.pendown()
player1.forward(50)
player2.pendown()
player2.forward(50)
The arrow really only moves once every time I press the space key.
I would like to turn that into a timer so the arrow would move every 60 milliseconds until the user presses the space key again.
I tried using an wn.ontimer but I keep on messing up something. Below is how the code looks now:
def advance_state_machine():
global state_num
if state_num == 0:
tess.forward(70)
tess.fillcolor("red")
state_num = 1
else:
tess.back(70)
tess.fillcolor("green")
state_num = 0
player1.pendown()
player1.forward(50)
player2.pendown()
player2.forward(50)
wn.onkey(advance_state_machine, "space")
wn.listen()
wn.mainloop()
Your description of your problem is inconsistent and your code is out of sync with your description. Here's what I believe you stated you wanted your code to do:
The turtle moves forward 1 step every 60 milliseconds and alternates between red/forward and green/backward whenever the space bar is pressed.
I believe this code implements that, a key event is used to detect the space bar and a timer event is used to keep the turtle in motion:
from turtle import Turtle, Screen, mainloop
def advance_state_machine():
global state_num
wn.onkey(None, 'space') # avoid overlapping events
if state_num > 0:
tess.fillcolor('green')
else:
tess.fillcolor('red')
state_num = -state_num
wn.onkey(advance_state_machine, 'space')
def advance_tess():
tess.forward(state_num)
wn.ontimer(advance_tess, 60)
wn = Screen()
tess = Turtle()
tess.fillcolor('red')
state_num = 1
wn.onkey(advance_state_machine, 'space')
wn.ontimer(advance_tess, 60)
wn.listen()
mainloop()
Make sure to click on the window to make it active before trying the space bar. Left unattended, the turtle will eventually go off screen.