Turtle onscreenclick not behaving as expected - python

I am trying to create a basic Turtle Race. My only requirement is that the turtles must move with each click on the screen. I am trying to use onscreenclick to call a function that moves the turtles forward a random amount and then checks their x-coordinates to determine if someone has won.
import turtle
import random
import time
def raceRound():
firstRacer.forward(random.randint(1, 10))
secondRacer.forward(random.randint(1, 10))
checkWinner()
def firstRacerSetup():
# setup turtle
def secondRacerSetup():
# set up second turtle
def screenSetup():
# create screen
def checkWinner():
if firstRacer.xcor() >= 80:
announcer.write("Congratualtions! You won!")
if secondRacer.xcor() >= 80:
announcer.write("Sorry... You lost")
wn = turtle.Screen()
racerName = wn.textinput("Name Entry", "What would you like your turtle's name to be?")
screenSetup()
announcer = turtle.Turtle()
announcer.hideturtle()
announcer.penup()
announcer.goto(0, -140)
announcer.write("Welcome to the race!", align='center')
time.sleep(3)
firstRacerSetup()
secondRacerSetup()
announcer.write("Click to start the race!", align='center')
wn.onscreenclick(raceRound)
turtle.done()
I'm just not sure where I am going wrong and some assistance would be greatly appreciated

Related

How to make multiple turtles move in a line at the same time

My goal is to be able to make a snake(three turtles next to each other) move at the same time and also make the snake turn using arrow keys. I have tried the ontimer method/function but it does not work as expected. Here is my code:
import make_snake
from turtle import Turtle, Screen
game_is_on = True
screen = Screen()
screen.setup(600, 600)
screen.bgcolor("black")
screen.title("Snake Game")
snake_seg1 = make_snake.snake_segments[0]
snake_seg2 = make_snake.snake_segments[1]
snake_seg2.setheading(snake_seg1.heading())
snake_seg3 = make_snake.snake_segments[2]
snake_seg3.setheading(snake_seg2.heading())
def move_forward():
snake_seg1.forward(20)
def move_backward():
snake_seg1.backward(20)
def turn_left():
snake_seg1.left(90)
def turn_right():
snake_seg1.right(90)
screen.onkey(move_forward, "Up")
screen.onkey(move_backward, "Down")
screen.onkey(turn_left, "Left")
screen.onkey(turn_right, "Right")
while game_is_on:
for seg in make_snake.snake_segments:
seg.forward(20)
# def follow_head():
# snake_seg1.forward(20)
# snake_seg2.setheading(snake_seg1.heading())
# snake_seg2.forward(20)
# snake_seg3.setheading(snake_seg2.heading())
# snake_seg3.forward(20)
# screen.ontimer(follow_head, 0)
screen.exitonclick()
File make_snake:
from turtle import Turtle
start_positions = [0, 20, 40]
snake_segments = []
for position in start_positions:
snake_part = Turtle(shape="square")
snake_part.color("white")
snake_part.penup()
snake_part.backward(position)
snake_segments.append(snake_part)
What can I fix in my code to make it stop moving one turtle at a time?
Your program has at least one problem: you use onkey() but forgot to call listen() to allow key events.
Here's a minimalist rework of your code to get basic snake movement working, it just supports right and left turns:
from turtle import Turtle, Screen
SEGMENT_SIZE = 20
START_COORDINATES = [-SEGMENT_SIZE * count for count in range(5)]
def turn_left():
snake_segments[0].left(90)
screen.update()
def turn_right():
snake_segments[0].right(90)
screen.update()
def move_forward():
for index in range(len(snake_segments) - 1, 0, -1):
snake_segments[index].goto(snake_segments[index - 1].position())
snake_segments[0].forward(SEGMENT_SIZE)
screen.update()
screen.ontimer(move_forward, 250)
screen = Screen()
screen.setup(600, 600)
screen.title("Snake Game")
screen.tracer(False)
snake_segments = []
for position in START_COORDINATES:
snake_segment = Turtle(shape='circle', visible=False)
snake_segment.penup()
snake_segment.setx(position)
snake_segment.showturtle()
snake_segments.append(snake_segment)
snake_segments[0].color('red')
screen.onkey(turn_left, 'Left')
screen.onkey(turn_right, 'Right')
screen.listen()
screen.update()
move_forward()
screen.exitonclick()
Be careful, it's easy to lose the snake off the edge of the window and not be able to get it back again!
The thing you might be looking for here is called multiprocessing. There is an eponymous library to execute lines of code simultaneously in Python. For reference look at the following thread:
Python: Executing multiple functions simultaneously

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.

Update the score when two turtles collide

I'm doing an assignment where I have to write a small game. When a turtle collides with a dot (bug) on the screen, it will add one point to the score value in the top left and teleport the bug to another random spot. I'm having trouble getting the score to update when they collide.
I tried to put the score update within the game loop but that did not work as it kept telling me that the value is not defined. I tried solving that with a global value, but that didn't do anything:
import turtle
import math
import random
#Set up the constants for the game.
WINDOW_HEIGHT = 300
WINDOW_WIDTH = 300
FORWARD_STEP = 10 #how much does the turtle move forward
TURN_STEP = 30 #how much does the turtle turn (in degrees)
SHRINK_FACTOR = 0.95 #how much does the turtle shrink when it moves
DEATH_WIDTH = 0.05 #the size at which you stop the game because the user lost
COLLISION_THRESHOLD = 10;#we say that two turtles collided if they are this much away
#from each other
#Define functions
def game_setup():
'''set up the window for the game, a bug and the player turtle '''
#create the screen
wn = turtle.Screen()
wn.screensize(WINDOW_HEIGHT,WINDOW_WIDTH)
wn.bgcolor("light green")
#Create player turtle
player = turtle.Turtle()
player.color("blue")
player.shape("turtle")
player.penup()
player.setpos (random.randrange(1,301), random.randrange(1,301))
#create a bug
bug1 = turtle.Turtle()
bug1.color("black")
bug1.shape("circle")
bug1.shapesize(stretch_wid=0.2, stretch_len=0.2)
bug1.penup()
bug1.speed(0) #the bug is not moving
bug1.setposition(-200, 200)
#create score turtle
score_keeper = turtle.Turtle()
score_keeper.hideturtle()
score_keeper.penup()
score_keeper.setposition (-400,360)
score = 0
scorestring = "Score: %s" %score
score_keeper.write(scorestring, False, align="left", font=("Arial",14, "normal"))
return (wn,player,bug1,score_keeper)
def is_collision (player, bug1):
distance = (math.sqrt((player.xcor()-bug1.xcor())**2 + (player.ycor() - bug1.ycor())**2))
if distance < COLLISION_THRESHOLD:
return True
else:
return False
def main():
#set up the window, player turtle and the bug
(wn,player,bug1,score_keeper) = game_setup()
#make the arrow keys move the player turtle
bindKeyboard(player)
#Set this veriableto True inside the loop below if you want the game to end.
game_over = False
player_width = get_width(player)
#This is the main game loop - while the game is not over and the turtle is large enough print the width of the turtle
#on the screen.
while not game_over and player_width > DEATH_WIDTH:
#your collision detection should go here
if is_collision (player, bug1):
bug1.setpos (random.randrange(1,301), random.randrange(1,301))
player.shapesize(stretch_wid=1, stretch_len=1)
player_width = get_width(player)
player.showturtle()
print(player_width)
print("Done")
wn.exitonclick()
main()
This is most of the code. All I want it to do is when the is_collision() function happens, it adds 1 to the value of score and the score_keeper turtle then prints that value in the window.
Im havign trouble getting the score to update when they collide.
I've done a stripped down rework of your code below (substuting for methods you left out) to show how to update the score on the screen. Code like this shouldn't have an explicit main loop as it's all event driven and should instead call turtle's main event loop:
from turtle import Screen, Turtle
from random import randrange
from functools import partial
# Set up the constants for the game.
WINDOW_WIDTH, WINDOW_HEIGHT = 500, 500
FORWARD_STEP = 10 # how much does the turtle move forward
TURN_STEP = 30 # how much does the turtle turn (in degrees)
COLLISION_THRESHOLD = 10 # we say that two turtles collided if they are this much away from each other
CURSOR_SIZE = 20
FONT = ('Arial', 14, 'normal')
# Define functions
def is_collision(player, bug):
return player.distance(bug) < COLLISION_THRESHOLD
def random_position(turtle):
scale, _, _ = turtle.shapesize()
radius = CURSOR_SIZE * scale
return randrange(radius - WINDOW_WIDTH/2, WINDOW_WIDTH/2 - radius), randrange(radius - WINDOW_HEIGHT/2, WINDOW_HEIGHT/2 - radius)
def forward():
global score
player.forward(FORWARD_STEP)
if is_collision(player, bug):
bug.setposition(random_position(bug))
score += 1
score_keeper.clear()
score_keeper.write(f"Score: {score}", font=FONT)
# Set up the window for the game, a bug and the player turtle.
# Create the screen
screen = Screen()
screen.setup(WINDOW_WIDTH, WINDOW_HEIGHT)
screen.bgcolor('light green')
# Create score turtle
score_keeper = Turtle(visible=False)
score_keeper.penup()
score_keeper.setposition(-230, 230)
score = 0
score_keeper.write(f"Score: {score}", font=FONT)
# Create a bug
bug = Turtle('circle', visible=False)
bug.shapesize(4 / CURSOR_SIZE)
bug.penup()
bug.setposition(random_position(bug))
bug.showturtle()
# Create player turtle
player = Turtle('turtle', visible=False)
player.color('blue')
player.speed('fastest')
player.penup()
player.setposition(random_position(player))
player.showturtle()
# make the arrow keys move the player turtle
screen.onkey(partial(player.left, TURN_STEP), 'Left')
screen.onkey(partial(player.right, TURN_STEP), 'Right')
screen.onkey(forward, 'Up')
screen.listen()
screen.mainloop()

players not moving simultaneously

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

Categories

Resources