Python: How come the math operators won't work? - python

I've been following a tutorial that shows beginners how to make a "Space Invaders" game. I mostly just wanted a way to play around with the turtle graphics or something of the sort. Everything was going smoothly until I noticed that my if statement, founded where I defined my move_left function, does not work. The problem however is not the if statement itself. It is that any math operation I try to do under it just gets completely ignored by the program with no error messages or anything. I even attempted to make a print statement under the if statement just to see rather or not the actual statement was responsive and saw that indeed, the statement printed as I planned. So what gives? How come I cannot do any math equations or anything of the like under those two functions?
So, here is the code that I had followed below:
import turtle
import os
def main():
#Set up the screen
wn = turtle.Screen()
wn.bgcolor("black")
wn.title("Space Invaders")
#Draw Border
border_pen = turtle.Turtle()
border_pen.speed(0)
border_pen.color("white")
border_pen.penup()
border_pen.setposition(-300, -300)
border_pen.pendown()
border_pen.pensize(3)
for side in range (4):
border_pen.fd(600)
border_pen.lt(90)
border_pen.hideturtle()
#create the player turtle
player = turtle.Turtle()
player.color("blue")
player.shape('triangle')
player.penup()
player.speed(0)
player.setposition(0, -250)
player.setheading(90)
#Player controls
playerspeed = 15
def move_left():
x = player.xcor()
x -= playerspeed
player.setx(x)
print(x)
if x < -280:
print("Reached") #It is here I tested rather or not the if statement
#above works, which it does
x = -280 #The following code here will not take effect. I tried all
#of different signs to use. Nothing happens. Not even an
#error
def move_right(): #I did not put the if statement here since I noticed the
#problem with the left side first
x = player.xcor()
x += playerspeed
player.setx(x)
if x > 280:
x = 280
turtle.listen()
turtle.onkey(move_left, "Left")
turtle.onkey(move_right, "Right")
turtle.mainloop()
main()

The reason the code has no affect is because you modify the value of x, a local variable to the function scope, and not the player position. Call player.setx(x) to actually update the player position after updating the local variable x. If you want to bound your positions you could also use the built in min/max methods:
def move_left():
x = player.xcor()
x -= playerspeed
player.setx(max(x, -280))
def move_right():
x = player.xcor()
x += playerspeed
player.setx(min(x, 280))

Related

How can I delay the onkey event until the function has finished executing

Basically I'm making a space invaders type game in python and for some reason, it's still allowing the user to press the spacebar no matter what I do. Therefore, I would like to see what kind of ideas you guys have since I have no idea what to do to make this work.
Also I have tried creating a delay variable so that if the delay variable is true then it will execute the onkey event but unfortunately it didn't work.
I have also tried making the both the function and the onkey sleep via the time library but also didn't work
import turtle
# Making the window and its proporties
wn = turtle.Screen()
wn.title("Galaxy Wars")
wn.bgcolor("black")
# adding the images to the shape function so that it will recongize them as a shape
turtle.register_shape("Spaceship.gif")
turtle.register_shape("invader2.gif")
turtle.register_shape("Laser beam.gif")
# creating the fighter jet and then puting it down
fighter = turtle.Turtle()
fighter.shape("Spaceship.gif")
fighter.penup()
fighter.setposition(0,-270)
fighter.setheading(90)
# create the laser
laser = turtle.Turtle()
laser.speed(0)
laser.setheading(90)
laser.hideturtle()
laser.shape("Laser beam.gif")
laser.penup()
# how far the fighter teleports each time a key is pressed
fighttp = 20
# delay
delay = "F"
# creating functions that either adds or substracts the current position
def up():
y = fighter.ycor()
y += fighttp
if y > -130:
y = -130
fighter.sety(y)
def left():
x = fighter.xcor()
x -= fighttp
if x < -370:
x = -370
fighter.setx(x)
def down():
y = fighter.ycor()
y -= fighttp
if y < -300:
y = -300
fighter.sety(y)
def right():
x = fighter.xcor()
x += fighttp
if x > 360:
x = 360
fighter.setx(x)
# give the player the laser beam to perform the pew pew on the bad guys just like the original game
def shoot():
if delay == "F":
delay == "T"
laser.speed(0)
laser.setposition(fighter.xcor(), fighter.ycor() + 20)
laser.showturtle()
laser.speed(3)
laser.forward(500)
laser.hideturtle()
delay == "F"
# turtle listens for the keys and then it moves according to the function and key pressed
turtle.listen()
turtle.onkey(left, "a")
turtle.onkey(right, "d")
turtle.onkey(up, "w")
turtle.onkey(down, "s")
if delay == "F":
turtle.onkey(shoot, "space")
wn.mainloop()
Skip the delay variable. Instead we can turn on and off the key event within the key event handler:
def shoot():
turtle.onkey(None, "space") # disable handler inside handler
laser.speed(0)
laser.setposition(fighter.xcor(), fighter.ycor() + 20)
laser.showturtle()
laser.speed(3)
laser.forward(500)
laser.hideturtle()
turtle.onkey(shoot, "space")
Below is a rework of your code with various style changes and optimizations:
from turtle import Screen, Turtle
# Making the window and its properties
screen = Screen()
screen.title("Galaxy Wars")
screen.bgcolor('black')
# Adding images to the shape function so that it will recognize them as a shape
screen.register_shape("Spaceship.gif")
screen.register_shape("Laser beam.gif")
# Create the fighter jet and then put it down
fighter = Turtle()
fighter.shape("Spaceship.gif")
fighter.penup()
fighter.sety(-270)
fighter.setheading(90)
# Create the laser
laser = Turtle()
laser.hideturtle()
laser.shape("Laser beam.gif")
laser.setheading(90)
laser.penup()
# How far the fighter teleports each time a key is pressed
fighttp = 20
# creating functions that either adds or subtracts the current position
def up():
y = fighter.ycor() + fighttp
if y > -130:
y = -130
fighter.sety(y)
def left():
x = fighter.xcor() - fighttp
if x < -370:
x = -370
fighter.setx(x)
def down():
y = fighter.ycor() - fighttp
if y < -300:
y = -300
fighter.sety(y)
def right():
x = fighter.xcor() + fighttp
if x > 360:
x = 360
fighter.setx(x)
# Give player laser beam to perform the pew pew on the bad guys just like the original game
def shoot():
screen.onkey(None, 'space') # disable handler inside handler
laser.speed('fastest')
laser.setposition(fighter.xcor(), fighter.ycor() + 20)
laser.showturtle()
laser.speed('slow')
laser.forward(500)
laser.hideturtle()
screen.onkey(shoot, 'space')
# Listen for keys and move according to the function and key pressed
screen.onkey(left, 'a')
screen.onkey(right, 'd')
screen.onkey(up, 'w')
screen.onkey(down, 's')
screen.onkey(shoot, 'space')
screen.listen()
screen.mainloop()

Python Turtle race game. Ending game function does not seem to work

I have got a problem with how to end my turtle python game. The code seems to function if I place the turtles at the starting/ending point from the beginning of the code, but it does not register when the turtle reaches the endpoint in gameplay. From what I know I think my maths for the end function is right. I am new and appreciate the help. I am currently offline though.
CODE:
import time
import turtle
from turtle import *
wn = turtle.Screen()
name=textinput("Question", "what is your name")
#display
pencolor("white")
penup()
goto(0,170)
write("hello " +name,align='center',font=('Comic Sans', 20))
#wn = turtle.screen() if the code doesn't work
#diffrent turtles here
t1 = turtle.Turtle()
t2 = turtle.Turtle()
t3 = turtle.Turtle()
#starting psoition
turtle.penup()
t1.penup()
turtle.goto(-1, -230)
t1.goto(-1, -170)
#starting line postion
def f():
fd(10)
def b():
bk(10)
def l():
left(10)
def r():
right(10)
#testing
def fo():
t1.fd(10)
def ba():
t1.bk(10)
def le():
t1.left(10)
def ri():
t1.right(10)
#turtle coordinates
first=turtle.ycor()
second=turtle.xcor()
third=t1.ycor()
fourth=t1.xcor()
#when to end the game
if (turtle.ycor()>= (-160)) and (turtle.ycor()<= (-240)):
if (turtle.xcor()>= (0)) and (turtle.xcor()<= (11)):
print("Finally working")
#replaced with write who the winner is later
if (t1.ycor()>= (-160)) and (t1.ycor()<= (-240)):
if (t1.xcor()>= (0)) and (t1.xcor()<= (11)):
print("Finally")
# onkey creates the key board = turtle.onkey("function, key") You have to keep pressing keys for it to move
turtle.onkey(f, "w")
turtle.onkey(b, "s")
turtle.onkey(l, "a")
turtle.onkey(r, "d")
wn.onkey(fo, "Up")
wn.onkey(ba, "Down")
wn.onkey(le, "Left")
wn.onkey(ri, "Right")
listen()
#WINDOW SETUP
window = Screen()
window.setup(800, 800)
window.title("Turtle game")
turtle.bgcolor("forestgreen")
t3.color("black")
t3.speed(0)
t3.penup()
t3.setpos(-140, 250)
t3.write("THE TURTLE RACE", font=("Comic Sans", 30, "bold"))
t3.penup()
#turtle ask name
#add images here
#turtle controls
# def creates a function. : means opperation f means move turtle foward. fd push turtle forward
# onkey creates the key board = turtle.onkey("function, key") You have to keep pressing keys for it to move
t2.speed(0)
t2.color("grey")
t2.pensize(100)
t2.penup()
t2.goto(-200, -200)
t2.left(90)
t2.pendown()
t2.forward(300)
t2.right(90)
t2.forward(500)
t2.right(90)
t2.forward(300)
t2.right(90)
t2.forward(500)
turtle.penup()
Firstly, your maths is not quite right - a coordinate can never be both <= -240 and >= -160. It should be t.ycor() >= -240 and t.ycor() <= -160, or more briefly, -240 <= t.ycor() <= -160.
Secondly, the condition as it stands is only checked once, when the code is first run. Instead, you need to get the program to check it regularly. You can do this by adding a general onkeypress event handler which is checked every time any key is pressed.
def check_status():
for player, t in enumerate([turtle, t1]):
if 0 <= t.xcor() <= 11 and -240 <= t.ycor() <= -160:
print(f"Player {player} is at the endpoint")
...
wn.onkeypress(check_status)
listen()

having trouble registering collision

I've been having trouble with getting my bullet (named asteroid) and my zombie. more specifically, I'm having trouble getting my game to register collision between these two turtles, it gets even weirder when you reverse the lesser than symbol into a greater than symbol. I do not know what is up with my code, any help is appreciated.(I have included the entirety of my code, since I am unsure of the source of the problem, I just know which part isn't working, I would recommend starting there.)
#the bullet that doesn't hit it's target
#Turtle Graphics game
import turtle
import random
import time
#set up screen
wn = turtle.Screen()
wn.bgcolor("grey")
finish= False
def randor1():
rand=random.randint(-280,280)
def randor2():
rand=random.randint(50,280)
def check_target_pos():
#side boundary checking
if zombie.xcor() > 280 or zombie.xcor() <- 280:
zombie.right(180)
#top/bottom boundary checking
if zombie.ycor() > 280 or zombie.ycor() <- 280:
zombie.right(180)
def check_turtle_pos():
#side boundary checking
if asteroid.xcor() > 280 or asteroid.xcor() <- 280:
asteroid.right(180)
#top/bottom boundary checking
if asteroid.ycor() > 280 or asteroid.ycor() <- 280:
asteroid.right(180)
def new_asteroid():# the turtle bullet,will change the name later on
for i in range(50):
asteroid.forward(10)
asteroid.goto(0,0)
def k2():#turn turtle left
asteroid.left(45)
def k3():#turn turtle right
asteroid.right(45)
#Draw border for arena
mypen = turtle.Turtle()
mypen.penup()
mypen.setposition(-300,-300)
mypen.pendown()
mypen.pensize(3)
for side in range(4):
mypen.forward(600)
mypen.left(90)
mypen.hideturtle()
#create turtle turtle, again will change name later
asteroid = turtle.Turtle()
asteroid.color("green")
asteroid.shape("turtle")
asteroid.penup()
asteroid.speed(0)
#create turtle zombie
def zombies():
global zombie
zombie= turtle.Turtle()
zombie.hideturtle()
zombie.color("green")
zombie.shape("circle")
zombie.penup()
zombie.speed(0)
x= random.randint(-280,280)
y= random.randint(50,280)
zombie.goto(x,y)
zombie.showturtle()
zombies()
while (finish!= True):
check_target_pos()
check_turtle_pos()
zombie.forward(1)
def end():
finish==True
wn.bye()
if asteroid.distance(zombie)<40: #problem area
end()
wn.onkey(new_asteroid, "space")#shoot button.
wn.onkey(k2, "Left")#turn left button
wn.onkey(k3, "Right") #turn right button
wn.onkey(end, "e")#exit
wn.listen()#so all the on key functions above work
Your code is somewhat a mess and doesn't facilitate the event-driven nature of turtle. There is no place for while True: loops nor time.sleep() or such in this environment. You also seem to be confusing your gun with your bullet (you're flinging your gun into space to kill the zombie, not its bullet!)
I've rewritten your code below using an event-based model with ontimer(). This is a single bullet implementation (you can't fire again until your bullet hits something or disappears into the distance):
from turtle import Screen, Turtle
from random import randint
def check_bullet_position():
if bullet.distance(turtle) > 240:
bullet.hideturtle()
if bullet.distance(zombie) < 20:
bullet.hideturtle()
reset_zombie()
def shoot_bullet():
if bullet.isvisible():
return
bullet.setheading(turtle.heading())
bullet.setposition(turtle.position())
bullet.forward(15)
bullet.showturtle()
def turn_left():
turtle.left(20)
def turn_right():
turtle.right(20)
def reset_zombie():
while zombie.distance(turtle) < 240:
x = randint(-280, 280)
y = randint(-280, 280)
zombie.goto(x, y)
zombie.setheading(zombie.towards(turtle))
def move():
zombie.forward(1)
if bullet.isvisible():
bullet.forward(2)
check_bullet_position()
screen.update()
if turtle.distance(zombie) > 20:
screen.ontimer(move)
# Set up screen
screen = Screen()
screen.tracer(False)
screen.bgcolor('grey')
# Draw border for arena
pen = Turtle()
pen.hideturtle()
pen.pensize(3)
pen.penup()
pen.setposition(-300, -300)
pen.pendown()
for _ in range(4):
pen.forward(600)
pen.left(90)
# Create turtle turtle
turtle = Turtle()
turtle.shape('turtle')
turtle.color('green')
turtle.penup()
# Create turtle bullet
bullet = Turtle()
bullet.hideturtle()
bullet.shape('circle')
bullet.shapesize(0.5)
bullet.color('yellow')
bullet.penup()
# Create turtle zombie
zombie = Turtle()
zombie.shape('circle')
zombie.color('red')
zombie.penup()
reset_zombie()
screen.onkey(shoot_bullet, 'space')
screen.onkey(turn_left, 'Left')
screen.onkey(turn_right, 'Right')
screen.onkey(screen.bye, 'e') # exit
screen.listen() # enable onkey() functions above
move()
screen.mainloop()
This should give you a starting point for building the game you envision. It is possible to write a multiple bullet implementation, it just take a little more thought and design work.
Your searching for a collision outside of the loop where you shot the projectile.
The easiest way to make your code work is to add the collision detection to the new_asteroid() function. But I don't think that's the right way.
Your technique is what is referred to as blocking. while you're projectile is moving, no other code is running. hence your collision detection is not working. change Line 38 to this.
def new_asteroid():# the turtle bullet,will change the name later on
for i in range(50):
asteroid.forward(10)
if asteroid.distance(zombie) < 40: # problem area
end()
asteroid.goto(0,0)
To create a non-blocking version of this function you would have to divide the for loop up to increments called by your main loop. so that your projectile moves once per iteration, instead of all at once.
Your program also crashes on exit. May I recommend re organizing your code into functions, then execution. it makes it much more readable. Happy gaming.

After a few seconds, one turtle stops and the other goes faster

After weeks of trying, I have not come up with a solution to this issue, in which one turtle comes to a complete stop and the other goes 2x - 3x faster. How can I fix this? You must move them both around for a little bit to encounter the issue. Also this is on the site: repl.it
I have tried moving the wn.listen() command but that only switched which turtle stopped and which one didn't. I have unsuccessfully tried to switch the forward() command to goto() and I have tried to use direction specific movement (also unsuccessfully):
import turtle
import sys
player1 = turtle.Turtle()
player1.up()
player1.goto(0,350)
player1.right(90)
player1.down()
player2 = turtle.Turtle()
wn = turtle.Screen()
#preGame setup
player2.up()
player2.goto(0,-350)
player2.left(90)
player2.down()
player2.color("blue")
player1.color("red")
#main game loop
player1.speed(0)
player2.speed(0)
k = 0
def kr():
player1.left(90)
def kl():
player1.right(90)
wn.onkey(kr, "d")
wn.onkey(kl, "a")
def k1():
player2.right(90)
def k2():
player2.left(90)
wn.onkey(k1, "k")
wn.onkey(k2, "l")
wn.listen()
while True:
player1.forward(1)
player2.forward(1)
while player1.xcor() < (-350) or player1.xcor() > (350) or player1.ycor() > (350) or player1.ycor() < (-350):
player1.back(30)
while player2.xcor() < (-350) or player2.xcor() > (350) or player2.ycor() > (350) or player2.ycor() < (-350):
player2.back(30)
if player1.pos() == player2.pos():
print ("DONT CRASH INTO THE OTHER PLAYER")
sys.exit()
I expected them both to continue moving indefinitely, but one always stops, and the other is going 2x the speed.
Move the keylisteners outside your loop - having them inside the while loop will reattach them and redefine the functions all the time and confuse turtle.
You need to set them up once not every few milliseconds:
import turtle
player1 = turtle.Turtle()
player2 = turtle.Turtle()
player1.goto(350, 0)
player2.goto(-350, 0)
player1.right(180)
wn = turtle.Screen()
def kl():
player1.left(90)
def kr():
player1.right(90)
def k1():
player2.right(90)
def k2():
player2.left(90)
wn.onkey(kl, "d") # changed to lowercase
wn.onkey(kr, "a")
wn.onkey(k1, "j") # changed to other letters
wn.onkey(k2, "l")
wn.listen()
while True: # not changing k so just use while True
player1.forward(1) # changed speed
player2.forward(1)
Your nested while loop structure is working against you and isn't valid for an event-driven environment like turtle. Here's a rework of your program to fix this issue and clean up the code:
from turtle import Screen, Turtle
import sys
# preGame setup
player1 = Turtle()
player1.hideturtle()
player1.up()
player1.goto(0, 350)
player1.down()
player1.right(90)
player1.color('red')
player1.speed('fastest')
player1.showturtle()
def r1():
player1.left(90)
def l1():
player1.right(90)
player2 = Turtle()
player2.hideturtle()
player2.up()
player2.goto(0, -350)
player2.down()
player2.left(90)
player2.color('blue')
player2.speed('fastest')
player2.showturtle()
def r2():
player2.right(90)
def l2():
player2.left(90)
# main game loop
def move():
player1.forward(5)
if not (-350 < player1.xcor() < 350 and -350 < player1.ycor() < 350):
player1.backward(30)
player2.forward(5)
if not (-350 < player2.xcor() < 350 and -350 < player2.ycor() < 350):
player2.backward(30)
if player1.distance(player2) < 5:
print("DON'T CRASH INTO THE OTHER PLAYER!")
sys.exit()
screen.ontimer(move, 100)
screen = Screen()
screen.onkey(r1, 'd')
screen.onkey(l1, 'a')
screen.onkey(r2, 'k')
screen.onkey(l2, 'l')
screen.listen()
move()
screen.mainloop()
See if this behaves more like you expect/desire.

Turtle.onkeypress isn't firing

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

Categories

Resources