I'm new to Python and am trying a bunch of different projects to learn. I want to use Turtle to create a game and I found this guy on YouTube who walks through re-creating Space Invaders.
I'm using IDLE and Python 3. The screen and player are created, but nothing happens when I press a key. I have looked up this issue and tried a number of things, but I'm not sure what I'm doing wrong.
The other unusual thing is that each function is run once. I included a print statement in each function to discover this. Why is it running each key press event once, but not binding to my actual keyboard?
import turtle
#Screen setup
screen = turtle.Screen()
screen.bgcolor('black')
screen.title("Space Invaders")
#Create player
player = turtle.Turtle()
player.color('blue')
player.shape('triangle')
player.penup()
player.speed(0)
player.setposition(0, -250)
player.setheading(90)
playerspeed = 15
#Move the player left and right
def move_left():
x = player.xcor()
x -= playerspeed
player.setx(x)
screen.listen()
print("Move left.") #for debugging
def move_right():
x = player.xcor()
x += playerspeed
player.setx(x)
screen.listen()
print("Move right.") #for debugging
#Create keyboard binding
screen.onkey(move_left(), 'Left')
screen.onkey(move_right(), 'Right')
screen.listen()
#Play game
screen.mainloop()
The problem is with these two lines of code:
screen.onkey(move_left(), 'Left')
screen.onkey(move_right(), 'Right')
You don't want to call move_left(), you want to pass move_left to be called by the event handler when the key is pressed:
screen.onkey(move_left, 'Left')
screen.onkey(move_right, 'Right')
By including the parentheses, you pass the return value of move_left() which is None, effectively disabling the event instead of enabling it!
Here's a rework of your code with the above fix plus another trick: space invader type games are perfect for taking advantage of the rarely used turtle.settiltangle() method. This method allows us to make the turtle appear to point vertically, while actually oriented horizontally. So we can simply used forward() and backward() to move it across the screen:
from turtle import Screen, Turtle
PLAYER_SPEED = 15
# Move the player left and right
def move_left():
player.backward(PLAYER_SPEED)
def move_right():
player.forward(PLAYER_SPEED)
# Screen setup
screen = Screen()
screen.bgcolor('black')
screen.title("Space Invaders")
# Create player
player = Turtle('triangle')
player.speed('fastest')
player.color('blue')
player.penup()
player.sety(-250)
player.settiltangle(90)
# Create keyboard binding
screen.onkey(move_left, 'Left')
screen.onkey(move_right, 'Right')
screen.listen()
# Play game
screen.mainloop()
Of course, you have to remember when you fire a projectile that your turtle is pointing right and redirect it accordingly!
I think the guy you found on YouTube might have been using python 2.7 rather than python 3 which would change the keypress commands.
Instead of
screen.onkey(move_left(), 'Left')
screen.onkey(move_right(), 'Right')
screen.listen()
You should use
screen.listen()
screen.onkeypress(move_left, 'Left')
screen.onkeypress(move_right, 'Right')
Related
I have to import a turtle and make it draw a square. I have that step done but the next step is to make that square move around the screen using the arrow keys. I already added the code which should allow that to happen but the turtle is still not moving. It just appears on the screen and I'm pressing the arrow keys but nothing moves. I'm not sure what the error in my code is.
import turtle
t = turtle.Turtle
screen = turtle.Screen()
screen.setup(300,300)
screen.tracer(0)
def square():
for i in range(4):
turtle.forward(100)
turtle.left(90)
def move_up():
turtle.setheading(90) #pass an argument to set the heading of our turtle arrow
turtle.forward(15)
def move_right():
turtle.setheading(0) #the direction is east
turtle.forward(15)
def move_down():
turtle.setheading(270) #the direction is south
turtle.forward(15)
def move_left():
turtle.setheading(180) #the direction is west
turtle.forward(15)
while True :
turtle.clear()
square() #call function
screen.update() # only now show the screen, as one of the frames
screen.onkey(move_up, "Up")
screen.onkey(move_right, "Right")
screen.onkey(move_down, "Down")
screen.onkey(move_left, "Left")
screen.listen()
Your main problem is that you tried to write the entire program at once: you didn't bother to test the pieces, and now you're in a situation where you have to fix several errors in order to get any useful output. Back up, program one part at a time, and test each part before proceeding.
Your immediate problem is that you have not bound keys to actions when you need them:
while True :
turtle.clear()
square() #call function
screen.update() # only now show the screen, as one of the frames
screen.onkey(move_up, "Up")
screen.onkey(move_right, "Right")
screen.onkey(move_down, "Down")
screen.onkey(move_left, "Left")
screen.listen()
You have an infinite loop in front of your bindings: you never get to this code, so there's no attention to the arrow keys, and your screen isn't listening. You have to do these things before your loop.
You also seem to be confused about which methods apply to an object, and which you call as class invocations. You have not instantiated a Turtle object to take movement commands.
I recommend that you return to your class materials and work more slowly through each technique. Add each to your program as you learn it ... and test before moving on.
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")
My Python turtle game obstacle freezes when the player receives input and continues afterward:
# Written in Python 3
# By
# February 4th, 2019
# Purpose: Mimic the no-wifi Google Chrome dinosaur game
# Bonus 6
import turtle # Used for graphics
from turtle import Screen # Used for inputs
import random# Used to generate a random number
import time
# Creates a turtle with the proper size and color
player = turtle.Turtle()
player.shape("square")
player.color("#cc0000")
player.turtlesize(1.5, 1.5)
player.penup()
player.goto(-50, 0)
# Creates the ground
ground = turtle.Turtle()
ground.shape("square")
ground.turtlesize(0.25, 300)
ground.penup()
ground.goto(0, -18)
# This function makes the square jump, unbinds 'Up', return to the ground, then rebinds 'Up'
def jump():
Screen().onkey(null, 'Up')
player.speed(2)
if player.ycor() == 0:
player.goto((player.xcor()), (player.ycor()+100))
print("G")
player.speed(1.5)
player.goto(-50, 0)
Screen().onkey(jump, 'Up')
# Blank function
def null():
n =1
Screen().onkey(jump, 'Up')
Screen().listen()
# Ignore this
x = 3 * random.sample(range(4), 4)
print (x)
print (x[1])
# Creating obstacles (not finished, just moves)
obst1 = turtle.Turtle()
obst1.shape("square")
obst1.turtlesize(3, 2)
obst1.penup()
obst1.goto(300,0)
obst1.speed(1)
obst1.setx(-300)
I want the obstacle to continue moving while I jump. I only have Python 3 and its standard modules. I cannot download PIP or anything else like it, for some reason. I'm trying to mimic the dinosaur game from Google Chrome. I'm new to this sort of thing so please explain any suggestions in as much detail as possible. Thanks a lot!
The way you wrote your code, you can only move one turtle at a time. Below is a rework of your code where the user controls the player, but the obstacle is controlled by a timer so they can move at the same time:
from turtle import Screen, Turtle
# This function unbinds 'Up', makes the square jump, return to the ground, then rebinds 'Up'
def jump():
screen.onkey(None, 'Up')
if player.ycor() == 0:
player.forward(150)
player.backward(150)
screen.onkey(jump, 'Up')
def move():
obstacle.forward(6)
if obstacle.xcor() > -400:
screen.ontimer(move, 100)
# Creates the ground
ground = Turtle('square')
ground.turtlesize(0.25, 45)
ground.penup()
ground.sety(-15)
# Creates a turtle with the proper size and color
player = Turtle('square')
player.color('red')
player.turtlesize(1.5)
player.speed('slowest')
player.penup()
player.setx(-100)
player.setheading(90)
screen = Screen()
screen.onkey(jump, 'Up')
screen.listen()
# Creating obstacles (not finished, just moves)
obstacle = Turtle('square')
obstacle.turtlesize(3, 1.5)
obstacle.speed('fastest')
obstacle.penup()
obstacle.setposition(400, 15)
obstacle.setheading(180)
move()
screen.mainloop()
This should more closely simulate the type of motion you're trying to achieve.
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'm very new to Python and have made a couple small games during a Python Learning course but never at home. So recently I began making a game, but after just 10 minutes I stumbled upon a problem:
Nothing happened when I pressed "W" although I had writen onkeypress in the code.
See for your self:
(It's designed for full screen)
import turtle
s = turtle.Screen()
g = turtle.Turtle()
t = turtle.Turtle()
#Ground
t.speed(0)
t.up()
t.goto(-1000,-200)
t.down()
t.goto(1000,-200)
#Player
g.speed(0)
PlayerX = -600
def moveX():
g.clear()
global PlayerX
g.up()
g.goto(PlayerX,-99)
g.down()
g.color("Slate Gray")
g.begin_fill()
g.circle(-50)
g.end_fill()
PlayerX = PlayerX - 1
turtle.onkeypress(moveX, "w")
moveX()
I'm fully aware I haven't made a go backwards button.
Along with #doctorlove's spot on correction (+1) of adding listen() to allow the window to receive keyboard events, a couple of comments:
First, click on the window with your mouse to make it active otherwise it won't respond to the keyboard. Second, it can be helpful to deactivate the event handler while in the event hander, and reactivate it on the way out, to avoid problems if someone repeatedly presses the key very fast.
Here's the second comment along with some other code suggestions:
from turtle import Turtle, Screen
screen = Screen()
screen.setup(1200, 500)
# Ground
ground = Turtle()
ground.speed('fastest')
ground.penup()
ground.goto(-1000, -200)
ground.pendown()
ground.forward(2000)
# Player
player = Turtle()
player.speed('fastest')
PlayerX = -600
def moveX():
global PlayerX
screen.onkeypress(None, "w") # disable handler in handler
player.clear()
player.penup()
player.goto(PlayerX, -99)
player.pendown()
player.color("Slate Gray")
player.begin_fill()
player.circle(-50)
player.end_fill()
PlayerX -= 1
screen.onkeypress(moveX, "w") # reenable handler
screen.listen()
moveX()
screen.mainloop() # change import & use turtle.mainloop() if Python 2
mainloop() isn't required to run but the program will exit after your initial moveX() call without it. mainloop() turns control over to the Tk event handler so some events may not fire without it.
You'll need to change onkeypress() to onkey() if this is Python 2 as well as change the way that mainloop() is invoked.
I think it's called onkey not onkeypress.
Also I think you need to listen (and add a mainloop if you want it to run):
turtle.onkey(moveX, "w")
turtle.listen()
moveX() # draw things first
turtle.mainloop()
You may need to revisit the numbers you are using to make sure the shape is on the window.
with my version of python none of the others are actually correct, here is the modified code that works for me:
from turtle import Turtle, Screen, setpos, hideturtle
screen = Screen()
screen.setup(500, 500)
#Ground
t = Turtle()
t.speed(0)
t.up()
t.goto(-1000,-200)
t.down()
t.goto(1000,-200)
#Player
player = Turtle()
hideturtle()
player.speed(0)
setpos(0,0)
PlayerX = 0
def moveX():
player.clear()
global PlayerX
player.up()
player.goto(PlayerX,0)
player.down()
player.color("Slate Gray")
player.begin_fill()
player.circle(-50)
player.end_fill()
PlayerX = PlayerX - 1
screen.onkey(moveX, "w")
screen.listen()
(this can definitely be improved on)
Not sure if the change is with Python3. But onkey function seems to be dragged under Screen().
turtle.Screen().onkey(movex, "w")
#This is a short code I made using space as down and w as up, feel free to
#extract from it what you can.
import turtle
player = turtle.Turtle()
y = 0
wn = turtle.Screen()
def p_up():
global y,up
up = True
while(up==True):
y += 10
player.sety(y)
def p_down():
global y,down
down = True
while(down==True):
y -= 10
player.sety(y)
def up_stop():
global up
up = False
def down_stop():
global down
down = False
wn.listen()
wn.onkeypress(p_up,"w")
wn.onkeypress(p_down,"space")
wn.onkeyrelease(up_stop,"w")
wn.onkeyrelease(down_stop,"space")
wn.mainloop()