1

I programmed Pong using the Turtle Module in Python 3 and the ball does not stay a consistent speed. It will randomly slow down, then speed up, then slow down. It can't be my laptop because if I can run Far Cry 5 perfectly with no issue, then I don't see how an itty bitty Pong game won't work smoothly. It runs a little smoother when I have my laptop running on a charger, but still has some speed up, slow down, speed up issues.

import turtle 

# Window Set Up
wn = turtle.Screen()
wn.title("Pong")
wn.bgcolor("black")
wn.setup(width=800, height=600)
wn.tracer(0)

# Paddle A 
paddle_a = turtle.Turtle()
paddle_a.speed(0)
paddle_a.shape("square")
paddle_a.shapesize(stretch_len=1, stretch_wid=5)
paddle_a.color("white")
paddle_a.penup()
paddle_a.goto(-350, 0)

# Paddle B
paddle_b = turtle.Turtle()
paddle_b.speed(0)
paddle_b.shape("square")
paddle_b.shapesize(stretch_len=1, stretch_wid=5)
paddle_b.color("white")
paddle_b.penup()
paddle_b.goto(350, 0)

# Ball
ball = turtle.Turtle()
ball.speed(0)
ball.shape("circle")
ball.color("white")
ball.penup()
ball.goto(0, 0)
ball_dx = .2
ball_dy = .2

# Paddle A Up
def paddle_a_up():
    y = paddle_a.ycor()
    y += 35
    paddle_a.sety(y)

# Paddle A Down
def paddle_a_down():
    y = paddle_a.ycor()
    y -= 35
    paddle_a.sety(y)

# Paddle B Up
def paddle_b_up():
    y = paddle_b.ycor()
    y += 35
    paddle_b.sety(y)

# Paddle B Down
def paddle_b_down():
    y = paddle_b.ycor()
    y -= 35
    paddle_b.sety(y)

# Keyboard Bindings
wn.listen()
wn.onkeypress(paddle_a_up, "w")
wn.onkeypress(paddle_a_down, "s")
wn.onkeypress(paddle_b_up, "Up")
wn.onkeypress(paddle_b_down, "Down")





# Main Loop
while True:
    wn.update()

    # Make The Ball Move
    ball.setx(ball.xcor() + ball_dx)
    ball.sety(ball.ycor() + ball_dy)

    # Border Collisions 
    if ball.ycor() > 290:
        ball_dy *= -1
    if ball.ycor() < -290:
        ball_dy *= -1
    if ball.xcor() > 390:
        ball.goto(0, 0)
        ball_dx *= -1
    if ball.xcor() < -390:
        ball.goto(0, 0)
        ball_dx *= -1

    # Paddle Collisions 
    if (ball.xcor() < 350 and ball.xcor() > 340) and (ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() - 50):
        ball.setx(340)
        ball_dx *= -1
    if (ball.xcor() > -350 and ball.xcor() < -340) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() - 50):
        ball.setx(-340)
        ball_dx *= -1

Pastebin Link

ggorlen
  • 44,755
  • 7
  • 76
  • 106
  • Does this answer your question? [How to fix inconsistent frame rate (speed) in python turtle](https://stackoverflow.com/questions/55495581/how-to-fix-inconsistent-frame-rate-speed-in-python-turtle) – ggorlen Aug 21 '22 at 15:52

1 Answers1

3

From what I can observe, the problem is that when you call the window update function, it doesn't wait until the next frame is shown and therefore, after updating the window, the next step in the while loop is immediately executed before the last screen is shown. This will mean that for every single frame of your screen not only single screen is drawn, but in fact, your program will draw as many as possible. Since your logic is tied to the frames, and since the amount of steps in your while loop your computer can process will depend on external factors (e.g. CPU usage by other programs), the amount of steps processed for every frame shown won't be consistent and results in the behavior you observe. Also this is very inefficient because you are drawing many frames you won't even show!

To get a more consistent behavior you could add a long enough pause into your loop to offset the variability of the computing times and to avoid drawing useless frames. You can do this using time

import time

# Initialization
...

while True:
   time.sleep(1 / 60)

   # The rest of your game logic
   ...

You could also tie your logic to elapsed time instead of moving the ball a constant amount each step

last_time = time.perf_counter()
ball_xspeed = 10

while True:
   current_time = time.perf_counter()
   elapsed_time = current_time - last_time
   last_time = current_time

   ball.setx(ball.xcor() + ball_xspeed * elapsed_time)
   ... # Update the rest of the variables
Hans Lehnert
  • 444
  • 3
  • 10