Python executable (pyinstaller) throws an error when I close it - python

I created a basic Pong game with Turtle on Windows, which works pretty well, but every time I close it, it throws an error: 'Fatal error detected: Failed to execute script pong'. I have been looking for a solution prior to ask for help, but I couldn't find a proper answer.
In order to create the .exe file I used 'pyinstaller'. This was the exact command I wrote:
pyinstaller --onefile --windowed --add-data "bounce.wav;." --add-data "collision.wav;." --add-data "score.wav;." pong.py
This is my code:
"""
Basic pong game
"""
import turtle
import winsound
import os
import sys
win = turtle.Screen()
win.title("Pong")
win.bgcolor("black")
win.setup(width=800, height=600)
win.tracer(0)
# Score
score_a = 0
score_b = 0
# Paddle A
paddle_a = turtle.Turtle()
name_a = "Verde"
paddle_a.speed(0)
paddle_a.shape("square")
paddle_a.color("green")
paddle_a.shapesize(stretch_wid=5, stretch_len=1)
paddle_a.penup()
paddle_a.goto(-350, 0)
# Paddle B
paddle_b = turtle.Turtle()
name_b = "Amarillo"
paddle_b.speed(0)
paddle_b.shape("square")
paddle_b.color("yellow")
paddle_b.shapesize(stretch_wid=5, stretch_len=1)
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 = 0.15
ball.dy = -0.15
# Pen
pen = turtle.Turtle()
pen.speed(0)
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0, 260)
pen.write("{} 0 | 0 {}".format(name_a, name_b), align="center", font=("Courier", 24, "normal"))
# Functions
def resource_path(relative_path):
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath('.'), relative_path)
def paddle_a_up():
if paddle_a.ycor() < 240:
y = paddle_a.ycor()
y += 20
paddle_a.sety(y)
def paddle_a_down():
if paddle_a.ycor() > -240:
y = paddle_a.ycor()
y -= 20
paddle_a.sety(y)
def paddle_b_up():
if paddle_b.ycor() < 240:
y = paddle_b.ycor()
y += 20
paddle_b.sety(y)
def paddle_b_down():
if paddle_b.ycor() > -240:
y = paddle_b.ycor()
y -= 20
paddle_b.sety(y)
# Keyboard binding
win.listen()
win.onkeypress(paddle_a_up, "w")
win.onkeypress(paddle_a_down, "s")
win.onkeypress(paddle_b_up, "Up")
win.onkeypress(paddle_b_down, "Down")
# Main game loop
while True:
win.update()
# Move the ball
ball.setx(ball.xcor() + ball.dx)
ball.sety(ball.ycor() + ball.dy)
# Border checking
if ball.ycor() > 290:
winsound.PlaySound(resource_path("bounce.wav"), winsound.SND_ASYNC)
ball.sety(290)
ball.dy *= -1
if ball.ycor() < -290:
winsound.PlaySound(resource_path("bounce.wav"), winsound.SND_ASYNC)
ball.sety(-290)
ball.dy *= -1
if ball.xcor() > 390:
winsound.PlaySound(resource_path("score.wav"), winsound.SND_ASYNC)
ball.goto(0, 0)
ball.dx *= -1
score_a += 1
pen.clear()
pen.write("{} {} | {} {}".format(name_a, score_a, score_b, name_b), align="center", font=("Courier", 24, "normal"))
if ball.xcor() < -390:
winsound.PlaySound(resource_path("score.wav"), winsound.SND_ASYNC)
ball.goto(0, 0)
ball.dx *= -1
score_b += 1
pen.clear()
pen.write("{} {} | {} {}".format(name_a, score_a, score_b, name_b), align="center", font=("Courier", 24, "normal"))
# Paddle and ball collisions
if (ball.xcor() > 340 and ball.xcor() < 350) and (ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() - 50):
winsound.PlaySound(resource_path("collision.wav"), winsound.SND_ASYNC)
ball.setx(340)
ball.dx *= -1
if (ball.xcor() < -340 and ball.xcor() > -350) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() - 50):
winsound.PlaySound(resource_path("collision.wav"), winsound.SND_ASYNC)
ball.setx(-340)
ball.dx *= -1
"""
End code
"""
I have no clue what may cause that error, since the program runs fine and all the sound effects work correctly.
Thank you all for your answers!

Hey not sure if you still need help on this but line 103 seems to be causing issues:
ball.setx(ball.xcor() + ball.dx)
It only occurs when closing the application, like you said.
I'm not sure if there is a proper solution but a bandaid solution you can use to avoid pyinstaller from throwing errors is to wrap the entire while loop in a try/catch.
# Main game loop
try:
while True:
win.update()
# Move the ball
ball.setx(ball.xcor() + ball.dx)
ball.sety(ball.ycor() + ball.dy)
# Border checking
if ball.ycor() > 290:
winsound.PlaySound(resource_path("bounce.wav"), winsound.SND_ASYNC)
ball.sety(290)
ball.dy *= -1
if ball.ycor() < -290:
winsound.PlaySound(resource_path("bounce.wav"), winsound.SND_ASYNC)
ball.sety(-290)
ball.dy *= -1
if ball.xcor() > 390:
winsound.PlaySound(resource_path("score.wav"), winsound.SND_ASYNC)
ball.goto(0, 0)
ball.dx *= -1
score_a += 1
pen.clear()
pen.write("{} {} | {} {}".format(name_a, score_a, score_b, name_b), align="center", font=("Courier", 24, "normal"))
if ball.xcor() < -390:
winsound.PlaySound(resource_path("score.wav"), winsound.SND_ASYNC)
ball.goto(0, 0)
ball.dx *= -1
score_b += 1
pen.clear()
pen.write("{} {} | {} {}".format(name_a, score_a, score_b, name_b), align="center", font=("Courier", 24, "normal"))
# Paddle and ball collisions
if (ball.xcor() > 340 and ball.xcor() < 350) and (ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() - 50):
winsound.PlaySound(resource_path("collision.wav"), winsound.SND_ASYNC)
ball.setx(340)
ball.dx *= -1
if (ball.xcor() < -340 and ball.xcor() > -350) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() - 50):
winsound.PlaySound(resource_path("collision.wav"), winsound.SND_ASYNC)
ball.setx(-340)
ball.dx *= -1
except Exception:
sys.exit(0)
It's not the best solution I admit, but I hope this helps!

Related

Pong via Python Turtle issues

I've been looking at this for hours and can't figure out why it won't run properly. Any ideas? I've tried messing with different x and y coords to see if that was the problem but nothing works.
The program just runs twitches and ends, when it should be playing through a game of pong until the user exits out.
code: you can ignore the comments
import turtle
# screen
screen = turtle.Screen()
screen.title('Pong')
screen.bgcolor('black')
screen.setup(width=1000, height=500)
# ball
ball = turtle.Turtle()
ball.shape('circle')
ball.color('white')
ball.speed(0)
ball.penup() #solves line issue
ball.goto(0, 0)
ball.dx = 5
ball.dy = -5
# right paddle____add speed___
r_pad = turtle.Turtle()
r_pad.speed(0.5)
r_pad.shape('square')
r_pad.color('white')
r_pad.shapesize(stretch_wid=5, stretch_len=2)
r_pad.penup()
r_pad.goto(450, 0)
# left paddle
l_pad = turtle.Turtle()
l_pad.speed(0.5)
l_pad.shape('square')
l_pad.color('white')
l_pad.shapesize(stretch_wid=5, stretch_len=2)
l_pad.penup()
l_pad.goto(-450, 0)
# Score
score = turtle.Turtle()
score.speed(0)
score.color('white')
score.penup()
score.hideturtle()
score.goto(0, 200)
score.write("Left_player : 0 Right_player: 0",
align="center", font=("arial", 24, "normal"))
#solving that score error
left_player = 0
right_player = 0
# movement
def paddler_up():
y = r_pad.ycor()
y += 20
r_pad.sety(y)
def paddler_down():
y = r_pad.ycor()
y -= 20
r_pad.sety(y)
def paddlel_up():
y = l_pad.ycor()
y += 20
l_pad.sety(y)
def paddlel_down():
y = l_pad.ycor()
y -= 20
l_pad.sety(y)
#main game
screen.listen()
screen.onkeypress(paddler_up, "w")
screen.onkeypress(paddler_down, "s")
screen.onkeypress(paddlel_up, "up")
screen.onkeypress(paddlel_down, "down")
while True:
screen.update()
ball.setx(ball.xcor() + ball.dx)
ball.sety(ball.ycor() + ball.dy)
# Checking borders
if ball.ycor() > 230:
ball.sety(230)
ball.dy *= -1
if ball.ycor() < -230:
ball.sety(-230)
ball.dy *= -1
if ball.xcor() > 600:
ball.goto(0, 0)
ball.dy *= -1
left_player += 1
score.clear()
score.write("Left_player : {} Right_player: {}".format(
left_player, right_player), align="center",
font=("Courier", 24, "normal"))
if ball.xcor() < -600:
ball.goto(0, 0)
ball.dy *= -1
right_player += 1
score.clear()
score.write("Left_player : {} Right_player: {}".format(
left_player, right_player), align="center",
font=("Courier", 24, "normal"))
# Paddle ball collision
if (ball.xcor() > 360 and ball.xcor() < 370) \
and (ball.ycor() < r_pad.ycor() + 40 and ball.ycor() > r_pad.ycor() - 40):
ball.setx(360)
ball.dx *= -1
if (ball.xcor() < -360 and ball.xcor() > -370) \
and (ball.ycor() < l_pad.ycor() + 40 and ball.ycor() > l_pad.ycor() - 40):
ball.setx(-360)
ball.dx *= -1
Your onkeypress calls for up and down keys should be capitalized (Up and Down instead of up and down) for it to work
screen.onkeypress(paddlel_up, "Up")
screen.onkeypress(paddlel_down, "Down")

turtle graphics goto() not working correctly

there are two paddles and a ball in a pong game the ball doesn't go back to 0, 0 after hitting right border in this game the whole script isnt finished yet only a bit I assume it has something to do with the goto() command but i do not know as i am new to python please help me figure this out here is the script of the game:
import turtle
wn = turtle.Screen()
wn.title('Pong by me')
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.color('white')
paddle_a.shapesize(stretch_wid=5, stretch_len=1)
paddle_a.penup()
paddle_a.goto(-350, 0)
# Paddle B
paddle_b = turtle.Turtle()
paddle_b.speed(0)
paddle_b.shape('square')
paddle_b.color('white')
paddle_b.shapesize(stretch_wid=5, stretch_len=1)
paddle_b.penup()
paddle_b.goto(350, 0)
# Ball
ball = turtle.Turtle()
ball.speed(0)
ball.shape('square')
ball.color('white')
ball.penup()
ball.goto(0, 0)
ball.dx = 2
ball.dy = -2
# Function
def paddle_a_up():
y = paddle_a.ycor()
y +=20
paddle_a.sety(y)
def paddle_a_down():
y = paddle_a.ycor()
y -=20
paddle_a.sety(y)
def paddle_b_up():
y = paddle_b.ycor()
y +=20
paddle_b.sety(y)
def paddle_b_down():
y = paddle_b.ycor()
y -=20
paddle_b.sety(y)
# keyboard binding
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 game loop
while True:
wn.update()
# Move the ball
ball.setx(ball.xcor() + ball.dx)
ball.sety(ball.ycor() + ball.dy)
# Border checking
if ball.ycor() > 290:
ball.sety(290)
ball.dy *= -1
if ball.ycor() < -290:
ball.sety(-290)
ball.dy *= -1
if ball.xcor() > 390:
ball.goto(0, 0)
ball.dx += -1
I guess your border checking should look like this
# Border checking
if ball.ycor() > 290:
ball.sety(290)
ball.dy *= -1
if ball.ycor() < -290:
ball.sety(-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
Then it works as expected

After taking turtle to other turtle's y coordinate, the program crashes. Any fixes?

Here's the full code
import os
wn = turtle.Screen()
wn.title("Pong")
wn.bgcolor("black")
wn.setup(width=800, height=600)
wn.tracer(0)
# Score
score_a = 0
score_b = 0
# Paddle A
paddle_a = turtle.Turtle()
paddle_a.speed(0)
paddle_a.shape("square")
paddle_a.color("white")
paddle_a.shapesize(stretch_wid=5,stretch_len=1)
paddle_a.penup()
paddle_a.goto(-350, 0)
# Paddle B
paddle_b = turtle.Turtle()
paddle_b.speed(0)
paddle_b.shape("square")
paddle_b.color("white")
paddle_b.shapesize(stretch_wid=5,stretch_len=1)
paddle_b.penup()
paddle_b.goto(350, 0)
# Ball
ball = turtle.Turtle()
ball.speed(0)
ball.shape("square")
ball.color("white")
ball.penup()
ball.goto(0, 0)
ball.dx = 0.5
ball.dy = 0.5
# Pen
pen = turtle.Turtle()
pen.speed(0)
pen.shape("square")
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0, 260)
pen.write("Player 1: 0 Player 2: 0", align="center", font=("Impact", 24, "normal"))
# Functions
def paddle_a_up():
y = paddle_a.ycor()
y += 20
paddle_a.sety(y)
def paddle_a_down():
y = paddle_a.ycor()
y -= 20
paddle_a.sety(y)
def paddle_b_up():
y = paddle_b.ycor()
y += 20
paddle_b.sety(y)
def paddle_b_down():
y = paddle_b.ycor()
y -= 20
paddle_b.sety(y)
# Keyboard bindings
wn.listen()
wn.onkeypress(paddle_a_up, "w")
wn.onkeypress(paddle_a_down, "s")
# Main game loop
while True:
wn.update()
# Computer player
if ball.xcor() > 250:
paddle_b.goto (ball.ycor())
# Move the ball
ball.setx(ball.xcor() + ball.dx)
ball.sety(ball.ycor() + ball.dy)
# Border checking
# Top and bottom
if ball.ycor() > 290:
ball.sety(290)
ball.dy *= -1
os.system("afplay bounce.wav&")
elif ball.ycor() < -290:
ball.sety(-290)
ball.dy *= -1
os.system("afplay bounce.wav&")
# Left and right
if ball.xcor() > 350:
score_a += 1
pen.clear()
pen.write("Player 1: {} Player 2: {}".format(score_a, score_b), align="center", font=("Impact", 24, "normal"))
ball.goto(0, 0)
ball.dx *= -1
elif ball.xcor() < -350:
score_b += 1
pen.clear()
pen.write("Player 1: {} Player 2: {}".format(score_a, score_b), align="center", font=("Impact", 24, "normal"))
ball.goto(0, 0)
ball.dx *= -1
# Paddle and ball collisions
if ball.xcor() < -340 and ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() - 50:
ball.dx *= -1
os.system("afplay bounce.wav&")
elif ball.xcor() > 340 and ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() - 50:
ball.dx *= -1
os.system("afplay bounce.wav&")
I'm trying to make a computer player with # Computer player
if ball.xcor() > 250:
paddle_b.goto (ball.ycor())
Each time the ball's xcor gets passed 250, the program crashes. Any fixes?
It wont let me post till I have more text ignore this please
It wont let me post till I have more text ignore this please
It wont let me post till I have more text ignore this please
I always feel like
Somebodys watching meee
And I got no privacy
Oh Oh Oh
So, your main problem is that paddle_b.goto uses an x/y point, not just the y-coordinate which you're inputting from the ball.
This should be giving you the error:
Traceback (most recent call last):
File "<Path>", line 85, in <module>
paddle_b.goto(ball.ycor())
File "<Path>\turtle.py", line 1774, in goto
self._goto(Vec2D(*x))
TypeError: type object argument after * must be an iterable, not float
From the documentation of goto ( https://docs.python.org/3.3/library/turtle.html?highlight=turtle#turtle.goto ):
If y is None, x must be a pair of coordinates or a Vec2D (e.g. as returned by pos()).
You should be able to do: paddle_b.sety(ball.ycor()) instead, which only needs the y-coordinate and you use already. Alternatively, another way to solve this is to keep the X-coordinate of the paddle the same through: paddle_b.goto(paddle_b.xcor(), ball.ycor()).

Python returns an error when i try to quit the application window

I was following a video for this little project but i encountered this error
Traceback (most recent call last):
File "C:/Users/Dell/Desktop/Pygame/games/pong.py", line 92, in <module>
ball.setx(ball.xcor()+ball.dx)
File "C:\Users\Dell\AppData\Local\Programs\Python\Python37-32\lib\turtle.py", line 1808, in setx
self._goto(Vec2D(x, self._position[1]))
File "C:\Users\Dell\AppData\Local\Programs\Python\Python37-32\lib\turtle.py", line 3158, in _goto
screen._pointlist(self.currentLineItem),
File "C:\Users\Dell\AppData\Local\Programs\Python\Python37-32\lib\turtle.py", line 755, in _pointlist
cl = self.cv.coords(item)
File "<string>", line 1, in coords
File "C:\Users\Dell\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 2469, in coords
self.tk.call((self._w, 'coords') + args))]
_tkinter.TclError: invalid command name ".!canvas"
This happens when I press the exit button to close the window.
How to solve this?
Here's the code:
import turtle
wn = turtle.Screen()
wn.title("Pong")
wn.bgcolor('black')
wn.setup(width=800, height=600)
wn.tracer(0)
#Score
score_a = 0
score_b = 0
#paddle A
paddle_a = turtle.Turtle()
paddle_a.speed(0)
paddle_a.shape("square")
paddle_a.color("white")
paddle_a.shapesize(stretch_wid=5, stretch_len = 1)
paddle_a.penup()
paddle_a.goto(-350,0)
#paddle B
paddle_b = turtle.Turtle()
paddle_b.speed(0)
paddle_b.shape("square")
paddle_b.color("white")
paddle_b.shapesize(stretch_wid=5, stretch_len = 1)
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 = 0.5
ball.dy = 0.5
#pen
pen = turtle.Turtle()
pen.speed(0)
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0,260)
pen.write("Player A: 0 Player B: 0", align="center", font=('Courier', 24, "normal"))
#Function
def paddle_a_up():
y = paddle_a.ycor()
y+=20
paddle_a.sety(y)
def paddle_a_down():
y = paddle_a.ycor()
y-=20
paddle_a.sety(y)
def paddle_b_up():
y = paddle_b.ycor()
y+=20
paddle_b.sety(y)
def paddle_b_down():
y = paddle_b.ycor()
y-=20
paddle_b.sety(y)
#Keyboard binding
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")
running = True
#main game loop
while running:
wn.update()
#move the ball
ball.setx(ball.xcor()+ball.dx)
ball.sety(ball.ycor()+ball.dy)
#border
if ball.ycor() > 280:
ball.sety(280)
ball.dy*=-1
if ball.ycor() < -280:
ball.sety(-280)
ball.dy*=-1
if ball.xcor() > 380:
ball.goto(0,0)
ball.dx*=-1
score_a+=1
pen.clear()
pen.write(f"Player A: {score_a} Player B: {score_b}", align="center", font=('Courier', 24, "normal"))
if ball.xcor() < -380:
ball.goto(0,0)
ball.dx*=-1
score_b += 1
pen.clear()
pen.write(f"Player A: {score_a} Player B: {score_b}", align="center", font=('Courier', 24, "normal"))
#colliosion
if (ball.xcor() > 330 and ball.xcor() < 340) and (ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() -50):
ball.setx(330)
ball.dx*=-1
if (ball.xcor() < -330 and ball.xcor() > -340) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() -50):
ball.setx(-330)
ball.dx*=-1
i read about putting the .mainloop() method but i couldn't figure out where do i put it. I understand this much that the while loop runs forever and has no condition to stop here so how do i make the loop stop? How do i tell python to stop the loop and quit the window after pressing the exit button?
It looks like turtle uses tkinter. In Tk there's a method named protocol which you can use to control what happens when certain events happen, one of those being hitting the red 'X'.
In order to invoke that we need to get the root level window.
Placing
canvas = wn.getcanvas()
root = canvas.winfo_toplevel()
will set root as your root window.
From here you can use root.protocol("WM_DELETE_WINDOW", on_close) to invoke a function named on_close or whatever you want to name it.
Your function will probably look something like this.
def on_close():
global running
running = False
This will break you out of your loop and close your program.
Full Code.
import turtle
wn = turtle.Screen()
canvas = wn.getcanvas()
root = canvas.winfo_toplevel()
wn.title("Pong")
wn.bgcolor('black')
wn.setup(width=800, height=600)
wn.tracer(0)
#Score
score_a = 0
score_b = 0
#paddle A
paddle_a = turtle.Turtle()
paddle_a.speed(0)
paddle_a.shape("square")
paddle_a.color("white")
paddle_a.shapesize(stretch_wid=5, stretch_len = 1)
paddle_a.penup()
paddle_a.goto(-350,0)
#paddle B
paddle_b = turtle.Turtle()
paddle_b.speed(0)
paddle_b.shape("square")
paddle_b.color("white")
paddle_b.shapesize(stretch_wid=5, stretch_len = 1)
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 = 0.5
ball.dy = 0.5
#pen
pen = turtle.Turtle()
pen.speed(0)
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0,260)
pen.write("Player A: 0 Player B: 0", align="center", font=('Courier', 24, "normal"))
#Function
def paddle_a_up():
y = paddle_a.ycor()
y+=20
paddle_a.sety(y)
def paddle_a_down():
y = paddle_a.ycor()
y-=20
paddle_a.sety(y)
def paddle_b_up():
y = paddle_b.ycor()
y+=20
paddle_b.sety(y)
def paddle_b_down():
y = paddle_b.ycor()
y-=20
paddle_b.sety(y)
#Keyboard binding
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")
def on_close():
global running
running = False
root.protocol("WM_DELETE_WINDOW", on_close)
running = True
#main game loop
while running:
wn.update()
#move the ball
ball.setx(ball.xcor()+ball.dx)
ball.sety(ball.ycor()+ball.dy)
#border
if ball.ycor() > 280:
ball.sety(280)
ball.dy*=-1
if ball.ycor() < -280:
ball.sety(-280)
ball.dy*=-1
if ball.xcor() > 380:
ball.goto(0,0)
ball.dx*=-1
score_a+=1
pen.clear()
pen.write(f"Player A: {score_a} Player B: {score_b}", align="center", font=('Courier', 24, "normal"))
if ball.xcor() < -380:
ball.goto(0,0)
ball.dx*=-1
score_b += 1
pen.clear()
pen.write(f"Player A: {score_a} Player B: {score_b}", align="center", font=('Courier', 24, "normal"))
#colliosion
if (ball.xcor() > 330 and ball.xcor() < 340) and (ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() -50):
ball.setx(330)
ball.dx*=-1
if (ball.xcor() < -330 and ball.xcor() > -340) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() -50):
ball.setx(-330)
ball.dx*=-1
We can solve this problem from within turtle, no need to drop down to tkinter underpinnings. Generally, you need to play by the rules. Specifically, no while running: aka while True:. Turtle is an event-based environment and you're not letting events get handled properly and thus the error messages.
Instead of the while loop, we need an ontimer() event:
from turtle import Screen, Turtle
FONT = ('Courier', 24, 'normal')
# Score
score_a = 0
score_b = 0
# Function
def paddle_a_up():
paddle_a.sety(paddle_a.ycor() + 20)
def paddle_a_down():
paddle_a.sety(paddle_a.ycor() - 20)
def paddle_b_up():
paddle_b.sety(paddle_b.ycor() + 20)
def paddle_b_down():
paddle_b.sety(paddle_b.ycor() - 20)
def single_step():
global score_a, score_b
# move the ball
ball.setposition(ball.xcor() + ball.dx, ball.ycor() + ball.dy)
# border
if ball.ycor() > 280:
ball.sety(280)
ball.dy *= -1
elif ball.ycor() < -280:
ball.sety(-280)
ball.dy *= -1
if ball.xcor() > 380:
ball.goto(0, 0)
ball.dx *= -1
score_a += 1
pen.clear()
pen.write(f"Player A: {score_a} Player B: {score_b}", align='center', font=FONT)
if ball.xcor() < -380:
ball.goto(0, 0)
ball.dx *= -1
score_b += 1
pen.clear()
pen.write(f"Player A: {score_a} Player B: {score_b}", align='center', font=FONT)
# collision
if 330 < ball.xcor() < 340 and paddle_b.ycor() - 50 < ball.ycor() < paddle_b.ycor() + 50:
ball.setx(330)
ball.dx *= -1
elif -340 < ball.xcor() < -330 and paddle_a.ycor() - 50 < ball.ycor() < paddle_a.ycor() + 50:
ball.setx(-330)
ball.dx *= -1
screen.update()
screen.ontimer(single_step)
screen = Screen()
screen.title('Pong')
screen.bgcolor('black')
screen.setup(width=800, height=600)
screen.tracer(0)
# paddle A
paddle_a = Turtle()
paddle_a.shape('square')
paddle_a.color('white')
paddle_a.shapesize(stretch_wid=5, stretch_len=1)
paddle_a.penup()
paddle_a.setx(-350)
# paddle B
paddle_b = Turtle()
paddle_b.shape('square')
paddle_b.color('white')
paddle_b.shapesize(stretch_wid=5, stretch_len=1)
paddle_b.penup()
paddle_b.setx(350)
# Ball
ball = Turtle()
ball.shape('circle')
ball.color('white')
ball.penup()
ball.dx = 1
ball.dy = 1
# pen
pen = Turtle()
pen.hideturtle()
pen.color('white')
pen.penup()
pen.sety(260)
pen.write("Player A: 0 Player B: 0", align='center', font=FONT)
# Keyboard binding
screen.onkeypress(paddle_a_up, 'w')
screen.onkeypress(paddle_a_down, 's')
screen.onkeypress(paddle_b_up, 'Up')
screen.onkeypress(paddle_b_down, 'Down')
screen.listen()
single_step()
screen.mainloop()
Now when you close the window, that event will be handled by the same mainloop event handler that's running your game.

Python ping-pong game, speeding up the ball after paddle hit

I'm new here and I'm the beginner. I've been learning programming since 5 months and as the main language I've decided to stick to python. I wrote my first simple game which is ping-pong (based on yt tutorials) and I want to improve it a bit by speeding up the ball after each paddle hit and comes back to normal speed when scored. I know that I put ball.dx +=1 in wrong place. It speeds up tho, but only when ball goes up. When it goes down, it comes back to normal speed and of course the speed is looped and even if scored, it still speeds up. Appreciate for any help.
import turtle
wn = turtle.Screen()
wn.title("gra by mati")
wn.bgcolor("black")
wn.setup(width=800, height=600)
wn.tracer(0)
# Paddle A
paddle_a = turtle.Turtle()
paddle_a.shape("square")
paddle_a.shapesize(stretch_wid=5, stretch_len=1)
paddle_a.speed(0)
paddle_a.color("white")
paddle_a.penup()
paddle_a.goto(-350, 0)
# Paddle B
paddle_b = turtle.Turtle()
paddle_b.shape("square")
paddle_b.shapesize(stretch_wid=5, stretch_len=1)
paddle_b.speed(0)
paddle_b.color("white")
paddle_b.penup()
paddle_b.goto(350, 0)
# ball
ball = turtle.Turtle()
ball.shape("square")
ball.speed(0)
ball.color("white")
ball.penup()
ball.goto(0, 0)
ball.dx = 1/5
ball.dy = 1/5
# Pen
pen = turtle.Turtle()
pen.speed(0)
pen.color("white")
pen.penup()
pen.hideturtle()
pen.goto(0, 260)
pen.write("Player A: 0 Player B: 0", align="center", font=("Courier", 24, "normal"))
# Score
score_a = 0
score_b = 0
# Function
def paddle_a_up():
y = paddle_a.ycor()
y += 20
paddle_a.sety(y)
def paddle_a_down():
y = paddle_a.ycor()
y -= 20
paddle_a.sety(y)
def paddle_b_up():
y = paddle_b.ycor()
y += 20
paddle_b.sety(y)
def paddle_b_down():
y = paddle_b.ycor()
y -= 20
paddle_b.sety(y)
#keyboard biding
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 game loop
while True:
wn.update()
# move the ball
ball.setx(ball.xcor() + ball.dx)
ball.sety(ball.ycor() + ball.dy)
# border checking
if ball.ycor() > 290:
ball.sety(290)
ball.dy *= -1
if ball.ycor() < -290:
ball.sety(-290)
ball.dy *= -1
if ball.xcor() > 390:
ball.goto(0, 0)
ball.dx *= -1
score_a += 1
pen.clear()
pen.write("Player A: {} Player B: {}".format(score_a, score_b), align="center", font=("Courier", 24, "normal"))
if ball.xcor() < -390:
ball.goto(0, 0)
ball.dx *= -1
score_b += 1
pen.clear()
pen.write("Player A: {} Player B: {}".format(score_a, score_b), align="center", font=("Courier", 24, "normal"))
# paddle and ball collision
if (ball.xcor() > 340 and ball.xcor() < 350) and (ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() -40):
ball.setx(340)
ball.dx +=1
ball.dx *= -1
if (ball.xcor() < -340 and ball.xcor() > -350) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() -40):
ball.setx(-340)
ball.dx +=1
ball.dx *= -1
So after reviewing your game a bit I found an error that the ball would "stick" to the paddle on the left side, and like you said the speed did not reset each score. I've adjusted it in a few places and it seems much improved.
Firstly I reset the speed every time there was a score:
if ball.xcor() > 390:
ball.goto(0, 0)
ball.dx = 1 / 5 # reset to initial speed
score_a += 1
pen.clear()
pen.write("Player A: {} Player B: {}".format(score_a, score_b), align="center", font=("Courier", 24, "normal"))
if ball.xcor() < -390:
ball.goto(0, 0)
ball.dx = 1 / 5 # reset to initial speed
ball.dx *= -1
score_b += 1
pen.clear()
pen.write("Player A: {} Player B: {}".format(score_a, score_b), align="center", font=("Courier", 24, "normal"))
I think this could be improved by having a variable at the top like initial_speed = 1/5 and then you can put ball.dx = initial_speed everywhere it resets. This allows you to only change one number at the top of your program and it will adjust the speed everywhere, preventing you to have to hunt down everywhere you reset it every time!
Secondly I fixed the paddle collision a little bit
if (ball.xcor() > 340 and ball.xcor() < 350) and (ball.ycor() < paddle_b.ycor() + 50 and ball.ycor() > paddle_b.ycor() -40):
ball.setx(340)
ball.dx *= -1 # flip direction first
ball.dx -=1 # speed it up
if (ball.xcor() < -340 and ball.xcor() > -350) and (ball.ycor() < paddle_a.ycor() + 50 and ball.ycor() > paddle_a.ycor() -40):
ball.setx(-340)
ball.dx *= -1
ball.dx +=1
Again this could be improved by making a variable speed_up_by = 1 and then using ball.dx += speed_up_by to easily adjust it. I think that 1 is far too large of a number and you won't be able to get more than 5 hits in (if you're lucky). To answer your comment about why one is ball.dx +=1 and the other is ball.dx -=1 I urge you to think about it in numbers. The initial speed is .2 (or 1/5), and then after it hits on the right side you should reverse it (to -.2 and now it is traveling left) and then increase its speed (by minusing 1 -> -1.2). Now when it gets to the other side you reverse it again (to 1.2) and then increase its speed (by adding 1 -> 2.2). You can see that even though we are subtracting from the speed it actually increases the magnitude of the speed!! I think this also shows you that increasing the speed by 1 each hit is insanely large. After the first hit the ball is going 6 times as fast as the initial speed!!! After 2 hits it is going 11 times the initial speed!!! You probably want to increase the magnitude of speed by .1 each time. That makes it so after 1 hit the speed is only 1.5 times initial speed. After 2 hits, the speed is twice the initial speed...and so on.

Categories

Resources