Start the game when SPACE is pressed (Turtle module)

Question:

I’ve been trying to code the Pong minigame using Turtle Graphics. Everything seems to work perfectly except for the beginning. I want the main loop to start iterating ONLY once the space key is pressed.
Here is the part i’ve been having trouble with:

## Start the game
start = False

def start_game():
    startmessage.clear()   #This is a turtle i created to show the message "Press SPACE to start"
    start = True
    ball_start()    #This is a function i created to get the ball moving

wn.onkeypress(start_game, "space")

## Main loop    
while start == True:  

I’ve included .listen() and .mainloop(), so that’s not the problem.
The full code is below. If i run the program with that code, this is what it does:

  1. It asks for the user to enter the max points. The black window appears, the score table also appears, but for some reason the border doesn’t.
  2. When the max points value is entered in the shell, the message “Press SPACE to start” appeats in the black screen.
  3. As soon as Space is pressed, that message disappears and nothing else occurs.

Here is the full code in case I’m missing something important:

import turtle
import random
import time



## Screen setup
wn = turtle.Screen()
wn.title("Pong!")
wn.bgcolor("black")
wn.setup(width = 900, height = 700)

wn.tracer(0)


# Border
collisions = 0

border = turtle.Turtle()
border.penup()
border.color("white")
border.setposition(-400,-300)
border.pendown()
for side in range(2):
    border.forward(800)
    border.left(90) 
    border.forward(600)
    border.left(90)

border.hideturtle()


# Scores
scoreA = 0
scoreB = 0

score_marker = turtle.Turtle()
score_marker.shape("blank")
score_marker.color("yellow")
score_marker.speed(0)
score_marker.penup()
score_marker.setposition(0, 310)
score_marker.pendown()
score_marker.write("Player A : {}       Player B:  {}".format(scoreA,scoreB), align = "center", font = ("Courier", 20, "bold"))


# Select number of points
maxpoints = int(input("Enter max points: "))
print("The player who first gets to {} points wins the game!".format(maxpoints))


# Start message
startmessage = turtle.Turtle()
startmessage.speed(0)
startmessage.color("white")
startmessage.shape("blank")
startmessage.penup()
startmessage.setposition(0,75)
startmessage.pendown()
startmessage.write("Press SPACE to start", align = "center", font = ("Courier", 20, "bold"))

# End message
endmessage = turtle.Turtle()
endmessage.speed(0)
endmessage.color("green")
endmessage.shape("blank")
endmessage.penup()
endmessage.setposition(0,0)
endmessage.pendown()


## Paddles

paddleB_speed = 25
paddleA_speed = paddleB_speed

wn.listen()

# Paddle A
paddleA = turtle.Turtle()
paddleA.speed(0)
paddleA.shape("square")
paddleA.color("white")
paddleA.shapesize(3.2,0.7)

paddleA.penup()
paddleA.goto(-350,0)


# Paddle A movement
def a_up():
    y = paddleA.ycor() + paddleA_speed
    paddleA.sety(y)

def a_down():
    y = paddleA.ycor() - paddleA_speed
    paddleA.sety(y)

wn.onkeypress(a_up,"w")
wn.onkeypress(a_down,"s")


# Paddle B
paddleB = turtle.Turtle()
paddleB.speed(0)
paddleB.shape("square")
paddleB.color("white")
paddleB.shapesize(3.2,0.7)

paddleB.penup()
paddleB.goto(350,0)


# Paddle B movement
def b_up():
    y = paddleB.ycor() + paddleB_speed
    paddleB.sety(y)

def b_down():
    y = paddleB.ycor() - paddleB_speed
    paddleB.sety(y)

wn.onkeypress(b_up,"Up")
wn.onkeypress(b_down,"Down")

## Ball
ball = turtle.Turtle()
ball.speed(0)
ball.shape("circle")
ball.color("white")
ball.shapesize(0.5,0.5)

ball.penup()
ball.setposition(0,0)

ballspeed = 0.3
ballspeed_increase = 0.01


# Ball starting movement
def ball_start():
    angle_ranges = list(range(30,60)) + list(range(120,150)) + list(range(210,240)) + list(range(300,330))
    angle = random.choice(angle_ranges)
    ball.setheading(angle)

ball_start()


## Exit the game
def exit_game():
    wn.bye()


## Start the game
start = False

def start_game():
    startmessage.clear()
    start = True
    ball_start()

wn.onkeypress(start_game, "space")



## Main loop

while start == True:    

    wn.update()

    ### MOVEMENT

    ## Ball movement
    ball.forward(ballspeed)


    ### COLLISIONS

    ## Paddles and border

    # Paddle A
    if paddleA.ycor() > 268:
        paddleA.sety(268)

    if paddleA.ycor() < -268:
        paddleA.sety(-268)

    # Paddle B  
    if paddleB.ycor() > 268:
        paddleB.sety(268)

    if paddleB.ycor() < -268:
        paddleB.sety(-268)


    ## Ball and paddles
    if paddleA.distance(ball) <= 10:

        collisions += 1

        #direction = ball.heading()
        #ball.setheading(180 - random.randint(0,30) -  direction)
        ball.setheading(random.randint(110,250) + 180)
        ball.forward(ballspeed + ballspeed_increase)

    if paddleB.distance(ball) <= 10:

        collisions += 1

        #direction = ball.heading()
        #ball.setheading(180 - random.randint(0,30) -  direction)
        ball.setheading(random.randint(110,250))
        ball.forward(ballspeed + ballspeed_increase)


    ## Ball and border

    # Top and bottom borders
    if ball.ycor() < - 296 or ball.ycor() > 296:

        collisions += 1

        direction = ball.heading()
        ball.setheading(360 - direction)
        ball.forward(ballspeed + ballspeed_increase)

    # Left and right borders
    if ball.xcor() < -396:  #--> Player B wins the point
        delay = 0.1
        time.sleep(1)
        collisions += 1

        ball.setposition(0,0)

        scoreB += 1
        score_marker.clear()
        score_marker.write("Player A : {}       Player B:  {}".format(scoreA,scoreB), align = "center", font = ("Courier", 20, "bold"))
        ball_start()


    if ball.xcor() > 396:  #--> Player A wins the poin
        delay = 0.1
        time.sleep(1)
        collisions += 1

        ball.setposition(0,0)

        scoreA += 1
        score_marker.clear()
        score_marker.write("Player A : {}       Player B:  {}".format(scoreA,scoreB), align = "center", font = ("Courier", 20, "bold"))
        ball_start()


    # End of the game
    if scoreA == maxpoints or scoreB == maxpoints:
        if scoreA == maxpoints:
            print("Player A wins the game!")
            endmessage.write("Player A wins the game!nA scored {} pointsnB scored {} points".format(scoreA,scoreB), align = "center", font = ("Courier", 18, "bold"))
            time.sleep(1)
            endmessage.penup()
            endmessage.setposition(0,-100)
            endmessage.pendown()
            endmessage.color("red")
            endmessage.write("Press ESC to exit game", align = "center", font = ("Courier", 14, "normal"))
            wn.onkeypress(exit_game, "Escape")

            break

        if scoreB == maxpoints:
            print("Player B wins the game!")
            endmessage.write("Player B wins the game!nA scored {} pointsnB scored {} points".format(scoreA,scoreB), align = "center", font = ("Courier", 18, "bold"))
            time.sleep(1)
            endmessage.penup()
            endmessage.setposition(0,-100)
            endmessage.pendown()
            endmessage.color("red")
            endmessage.write("Press ESC to exit game", align = "center", font = ("Courier", 14, "normal"))
            wn.onkeypress(exit_game, "Escape")

            break


wn.mainloop()
Asked By: pypau

||

Answers:

I think it might be the way you used the space key value. You put in space instead of return.

wn.onkeypress(start_game, "return")
Answered By: Jordan Dixon

This code looks like it resets start but it doesn’t — it sets a local start and ignores the global start:

start = False

def start_game():
    startmessage.clear()
    start = True
    ball_start()

You need a global statement:

start = False

def start_game():
    global start
    startmessage.clear()
    start = True
    ball_start()

The above is necessary but not sufficient. The next problem is the way you use a top level while loop instead of a timer event. The way I’d expect this game to start up and run would be more like:

from turtle import Screen, Turtle

running = False

def start_game():
    global running

    start_message.clear()
    running = True
    ball_start()

def ball_start():
    start_message.write("We've started the game!", align="center", font=("Courier", 20, "bold"))
    # what really ball_start() really does replaces the above...

def move_one_step():

    if running:

        screen.update()

        # ...

    screen.ontimer(move_one_step, 100)

screen = Screen()

start_message = Turtle()
start_message.hideturtle()
start_message.penup()
start_message.sety(75)
start_message.write("Press SPACE to start", align="center", font=("Courier", 20, "bold"))

screen.onkeypress(start_game, 'space')
screen.listen()

move_one_step()

screen.mainloop()
Answered By: cdlane