pythonturtle-graphicspong

Pong : issue with ontimer


I am a relative new bee in Python coding and exercise myself by coding Pong game. As I had some issues with a stable speed of the ball (by using a win.update() method in a main loop while True: ) I try to use the ontimer function now to get a stable speed of the ball/screen refresh. The issue now is that the screen is shown for a split second and disappears directly. Can anybody help me to overcome that issue ? I hope I programmed the ontimer function correctly. Here is my latest code (I am using VS code as IDE)

import turtle as t
import time
import os

#Score variables
player_a = 0
player_b = 0

paddle_min_step=15

#create Pong main screen
win = t.Screen()
win.title('Ping Pong Game')
win.bgcolor('black')
win.setup(width=800,height=600)
win.tracer(0)

#create left paddle
paddle_left=t.Turtle()
paddle_left.speed(0)
paddle_left.shape('square')
paddle_left.shapesize(stretch_wid=5,stretch_len=1)
paddle_left.color('yellow')
paddle_left.penup()
paddle_left.goto(-350,0)

#create right paddle
paddle_right=t.Turtle()
paddle_right.speed(0)
paddle_right.shape('square')
paddle_right.shapesize(stretch_wid=5,stretch_len=1)
paddle_right.color('blue')
paddle_right.penup()
paddle_right.goto(350,0)

#create ball
ball=t.Turtle()
ball.speed(0)
ball.shape('circle')
ball.color('white')
ball.penup()
ball.goto(0,0)
ball_dx=1    #variabel for speed of ball in x dir
ball_dy=1     #variabel for speed of ball in y dir

#create pen for score
pen=t.Turtle()
pen.speed(0)
pen.color('skyblue')
pen.penup()
pen.hideturtle()
pen.goto(0,260)
pen.write("Player A: 0                  Player B: 0 ",align="center",font=('Monaco',24,"normal"))

#create paddle actions
def paddle_left_up():
    y=paddle_left.ycor()
    y=y+paddle_min_step
    paddle_left.sety(y)

def paddle_left_down():
    y=paddle_left.ycor()
    y=y-paddle_min_step
    paddle_left.sety(y)

def paddle_right_up():
    y=paddle_right.ycor()
    y=y+paddle_min_step
    paddle_right.sety(y)

def paddle_right_down():
    y=paddle_right.ycor()
    y=y-paddle_min_step
    paddle_right.sety(y)


win.listen()
win.onkeypress(paddle_left_up,"w")
win.onkeypress(paddle_left_down,'x')
win.onkeypress(paddle_right_up,'Up')
win.onkeypress(paddle_right_down,'Down')


def check_ballpos_score():
    global ball_dx, ball_dy

    win.update()
    ball.setx(ball.xcor()+ball_dx)
    ball.sety(ball.ycor()+ball_dy)

    #setting the borders for the ball
    #for y dir avoid ball is out of screen
    #for x dir check ball out of screen -> score
    if ball.ycor()>290:
        ball.sety(290)
        ball_dy=ball_dy * -1

    if ball.ycor()<-290:
        ball.sety(-290)
        ball_dy=ball_dy * -1

    #ball out of screen left/right check + change score 
    if ball.xcor()>390:
        ball.goto(0,0)
        player_a+=1
        pen.clear()
        pen.goto(0,260)
        pen.write("Player A: {}                  Player B: {} ".format(player_a,player_b),align="center",font=('Monaco',24,"normal"))
        
    if ball.xcor()<-390:
        ball.goto(0,0)
        player_b+=1
        pen.clear()
        pen.goto(0,260)
        pen.write("Player A: {}                  Player B: {} ".format(player_a,player_b),align="center",font=('Monaco',24,"normal"))
         

    #handling collision ball with the paddles
    if(ball.xcor() > 340) and (ball.xcor() < 350) and (ball.ycor() < paddle_right.ycor() + 40 and ball.ycor() > paddle_right.ycor() - 40):
        ball.setx(340)
        ball_dx = ball_dx * -1
       

    if(ball.xcor() < -340) and (ball.xcor() > -350) and (ball.ycor() < paddle_left.ycor() + 40 and ball.ycor() > paddle_left.ycor() - 40):
        ball.setx(-340)
        ball_dx = ball_dx * -1
    win.ontimer(check_ballpos_score, 40)

  
# Main loop 

check_ballpos_score()

I have tried different ways of keeping the screen on, but without luck till now.


Solution

  • Add the following as the last line of your code/file:

    win.mainloop()
    

    This turns control over to the turtle event handler. Otherwise, Python falls off the end of the file and returns to the operating system.

    My rework of your code including the above fix:

    from turtle import Screen, Turtle
    
    PADDLE_MIN_STEP = 30
    
    SCORE_FONT = ('Monaco', 24, 'normal')
    SCORE_FORMAT = "Player A: {}                  Player B: {}"
    
    # Paddle actions
    
    def paddle_left_up():
        y = paddle_left.ycor() + PADDLE_MIN_STEP
        paddle_left.sety(y)
    
    def paddle_left_down():
        y = paddle_left.ycor() - PADDLE_MIN_STEP
        paddle_left.sety(y)
    
    def paddle_right_up():
        y = paddle_right.ycor() + PADDLE_MIN_STEP
        paddle_right.sety(y)
    
    def paddle_right_down():
        y = paddle_right.ycor() - PADDLE_MIN_STEP
        paddle_right.sety(y)
    
    ball_dx = 1  # variable for speed of ball in x dir
    ball_dy = 1  # variable for speed of ball in y dir
    
    # Score variables
    player_a = 0
    player_b = 0
    
    def check_ballpos_score():
        global ball_dx, ball_dy, player_a, player_b
    
        ball.setx(ball.xcor() + ball_dx)
        ball.sety(ball.ycor() + ball_dy)
    
        # set the borders for the ball
        # for y dir avoid ball is out of screen
        # for x dir check ball out of screen -> score
    
        if ball.ycor() > 290:
            ball.sety(290)
            ball_dy *= -1
        elif ball.ycor() < -290:
            ball.sety(-290)
            ball_dy *= -1
    
        # ball out of screen left/right check + change score
    
        if ball.xcor() > 390:
            ball.goto(0, 0)
            player_a += 1
            pen.clear()
            pen.write(SCORE_FORMAT.format(player_a, player_b), align='center', font=SCORE_FONT)
    
        elif ball.xcor() < -390:
            ball.goto(0, 0)
            player_b += 1
            pen.clear()
            pen.write(SCORE_FORMAT.format(player_a, player_b), align='center', font=SCORE_FONT)
    
        # handle collision of ball with the paddles
        if 340 < ball.xcor() < 360 and paddle_right.ycor() - 50 < ball.ycor() < paddle_right.ycor() + 50:
            ball.setx(340)
            ball_dx *= -1
        elif -340 > ball.xcor() > -360 and paddle_left.ycor() - 50 < ball.ycor() < paddle_left.ycor() + 50:
            ball.setx(-340)
            ball_dx *= -1
    
        screen.update()
        screen.ontimer(check_ballpos_score)
    
    # Pong main screen
    screen = Screen()
    screen.title('Ping Pong Game')
    screen.bgcolor('black')
    screen.setup(width=800, height=600)
    screen.tracer(0)
    
    # Left paddle
    paddle_left = Turtle()
    paddle_left.shape('square')
    paddle_left.shapesize(stretch_wid=5, stretch_len=1)
    paddle_left.color('yellow')
    paddle_left.penup()
    paddle_left.setx(-350)
    
    # Right paddle
    paddle_right = paddle_left.clone()
    paddle_right.color('blue')
    paddle_right.setx(350)
    
    # Ball
    ball = Turtle()
    ball.shape('circle')
    ball.color('white')
    ball.penup()
    
    # Pen for score
    pen = Turtle()
    pen.hideturtle()
    pen.color('skyblue')
    pen.penup()
    pen.sety(260)
    pen.write(SCORE_FORMAT.format(player_a, player_b), align='center', font=SCORE_FONT)
    
    screen.onkeypress(paddle_left_up, 'w')
    screen.onkeypress(paddle_left_down, 'x')
    screen.onkeypress(paddle_right_up, 'Up')
    screen.onkeypress(paddle_right_down, 'Down')
    screen.listen()
    
    # Main loop
    
    check_ballpos_score()
    
    screen.mainloop()