I am a new Python programmer, and I am learning how to use the turtle import. I am making some projects, and now I am trying to do a Pong game using turtle.
It is working but not really well; the hitbox and the collisions can be improved. Can you please look at my code and tell me how I can improve it?
Code:
import turtle
import os
import random
import math
#screen
wn = turtle.Screen()
wn.title("PingPangPong")
wn.bgcolor("black")
wn.setup(width = 1.0, height = 1.0)
#Shapes
turtle.register_shape("pong.gif")
#bordure
bordure = turtle.Turtle()
bordure.penup()
bordure.color("white")
bordure.pensize(3)
bordure.ht()
bordure.setposition(-500, 300)
bordure.speed(5)
def bordure1():
bordure.pendown()
bordure.fd(1000)
bordure.pu()
bordure.setposition(-500,-300)
bordure.pd()
bordure.fd(1000)
def filet():
bordure.pensize(1)
bordure.setposition(0, -300)
bordure.setheading(90)
for i in range (12):
bordure.fd(26)
bordure.penup()
bordure.fd(26)
bordure.pendown()
bordure1()
filet()
#Ball
ball = turtle.Turtle()
ball.shape("circle")
ball.color("white")
ballspeed = 8
ballheading = random.randint(1,360)
ball.penup()
ball.setheading(ballheading)
ball.speed(0)
#Player 1
player1 = turtle.Turtle()
player1.shape("pong.gif")
player1.turtlesize(2,2)
player1.color("white")
player1.penup()
player1.setposition(-520, 0)
player1.speed(0)
playerspeed = 50
#Player 2
player2 = turtle.Turtle()
player2.shape("pong.gif")
player2.shapesize(5,5)
player2.color("white")
player2.penup()
player2.setposition(520, 0)
player2.speed(0)
playerspeed = 50
#Player 1 Movement
def up():
y = player1.ycor()
y += playerspeed
if y < 270:
player1.sety(y)
def down():
y = player1.ycor()
y -= playerspeed
if y > -270:
player1.sety(y)
#Player 2 movement
def up1():
y = player2.ycor()
y += playerspeed
if y < 280:
player2.sety(y)
def down1():
y = player2.ycor()
y -= playerspeed
if y > -280:
player2.sety(y)
#Speed hack
def hack():
global ballspeed
if ballspeed == 8:
ballspeed = 20
elif ballspeed == 20:
ballspeed = 8
def start():
ballheading = random.randint(1,360)
ball.setposition(0, 0)
ball.setheading(ballheading)
def distance(t1,t2):
distance = math.sqrt(math.pow(t1.xcor()-t2.xcor(),2)+math.pow(t1.ycor()-t2.ycor(),2))
if distance < 45:
t2.right(91)
def angle():
print(ball.heading())
#We assign z/s to move the player 1
turtle.listen()
turtle.onkey(up, "z")
turtle.onkey(down,"s")
#We assign up and down arrow to move the player 2
turtle.onkey(up1, "Up")
turtle.onkey(down1,"Down")
#SpeedHack
turtle.onkey(hack, "m")
#Restart
turtle.onkey(start,"p")
#Print the Ball heading
turtle.onkey(angle, "l")
#Player 2 score's
Score1 = 0
s1 = turtle.Turtle()
s1.speed(0)
s1.ht()
s1.color("white")
s1.pu()
s1.setposition(-250, 250)
s1.write(Score1, font=("Arial", 44, "normal"))
#Player 2 score's
Score2 = 0
s2 = turtle.Turtle()
s2.speed(0)
s2.ht()
s2.color("white")
s2.pu()
s2.setposition(250, 250)
s2.write(Score1, font=("Arial", 44, "normal"))
#Mainloop
while True:
ball.fd(ballspeed)
degree = ball.heading()
y = ball.ycor()
x = ball.xcor()
#We define the border colision
if y > 279 or y < -279:
ball.right(91)
#We define Loose
if x > 520:
ballheading = random.randint(1,360)
Score1 += 1
s1.clear()
s1.write(Score1, font=("Arial", 44, "normal"))
start()
if x < -520:
ballheading = random.randint(1,360)
Score2 += 1
s2.clear()
s2.write(Score2, font=("Arial", 44, "normal"))
start()
#Colision beetween players and ball
distance(player1,ball)
distance(player2,ball)
turtle.mainloop()
1 Answer 1
The major issues I see with your code are:
Use of
while True:
in an event driven environment. We need to put the ball on a timer event instead.The angle of bounce off the sides of the court is unrealistic. You can't simply
ball.right(91)
as which way you turns depends on your original direction. We can reflect the heading instead.Ditto for the bouncing off the players. Also, the initial ball angle is too broad and leads to unplayable scenarios.
My rework of your code attempts to address these issues as well as clean up the code style-wise:
from turtle import Turtle, Screen
from random import randint, choice
ballspeed = 8
playerspeed = 50
cursor_size = 20
player_height = 60
player_width = 20
court_width = 1000
court_height = 600
FONT = ("Arial", 44, "normal")
def draw_border():
border.pensize(3)
border.penup()
border.setposition(-court_width/2, court_height/2)
border.pendown()
border.forward(court_width)
border.penup()
border.sety(-court_height/2)
border.pendown()
border.backward(court_width)
def filet():
border.penup()
border.pensize(1)
border.setposition(0, -court_height/2)
border.setheading(90)
border.pendown()
for _ in range(court_height // 50):
border.forward(50 / 2 + 1)
border.penup()
border.forward(50 / 2 + 1)
border.pendown()
# Player 1 Movement
def up1():
y = player1.ycor()
y += playerspeed
if y < court_height/2 - player_height/2:
player1.sety(y)
def down1():
y = player1.ycor()
y -= playerspeed
if y > player_height/2 - court_height/2:
player1.sety(y)
# Player 2 movement
def up2():
y = player2.ycor()
y += playerspeed
if y < court_height/2 - player_height/2:
player2.sety(y)
def down2():
y = player2.ycor()
y -= playerspeed
if y > player_height/2 - court_height/2:
player2.sety(y)
def reset_ball():
ball.setposition(0, 0)
ball.setheading(choice([0, 180]) + randint(-60, 60))
def distance(t1, t2):
my_distance = t1.distance(t2)
if my_distance < player_height/2:
t2.setheading(180 - t2.heading())
t2.forward(ballspeed)
# Mainloop
def move():
global score1, score2
ball.forward(ballspeed)
x, y = ball.position()
if x > court_width/2 + cursor_size: # We define scoring
score1 += 1
s1.undo()
s1.write(score1, font=FONT)
reset_ball()
elif x < cursor_size - court_width/2:
score2 += 1
s2.undo()
s2.write(score2, font=FONT)
reset_ball()
elif y > court_height/2 - cursor_size or y < cursor_size - court_height/2:
# We define the border collision
ball.setheading(-ball.heading())
else:
# Check collision between players and ball
distance(player1, ball)
distance(player2, ball)
screen.ontimer(move, 20)
# screen
screen = Screen()
screen.title("Pong")
screen.bgcolor("black")
screen.setup(width=1.0, height=1.0)
# border
border = Turtle(visible=False)
border.speed('fastest')
border.color("white")
draw_border()
filet()
# Ball
ball = Turtle("circle")
ball.color("white")
ball.penup()
ball.speed("fastest")
reset_ball()
# Player 1
player1 = Turtle("square")
player1.turtlesize(player_height / cursor_size, player_width / cursor_size)
player1.color("white")
player1.penup()
player1.setx(cursor_size - court_width/2)
player1.speed("fastest")
# Player 2
player2 = Turtle("square")
player2.shapesize(player_height / cursor_size, player_width / cursor_size)
player2.color("white")
player2.penup()
player2.setx(court_width/2 + cursor_size)
player2.speed("fastest")
# Player 1 score
score1 = 0
s1 = Turtle(visible=False)
s1.speed("fastest")
s1.color("white")
s1.penup()
s1.setposition(-court_width/4, court_height/3)
s1.write(score1, font=FONT)
# Player 2 score"s
score2 = 0
s2 = Turtle(visible=False)
s2.speed("fastest")
s2.color("white")
s2.penup()
s2.setposition(court_width/4, court_height/3)
s2.write(score2, font=FONT)
# We assign s/z to move the player 1
screen.onkey(up1, "s")
screen.onkey(down1, "z")
# We assign up and down arrow to move the player 2
screen.onkey(up2, "Up")
screen.onkey(down2, "Down")
# Restart
screen.onkey(reset_ball, "p")
screen.listen()
move()
screen.mainloop()
Not perfect, but playable. I've tossed some of your original details to simplify my example. You should be able to add them back as desired.