🏓 Python Ping Pong Game

This is my Ping Pong Game made with Tkinter! Two paddles, smooth collisions, and a score system.
Controls: W/S for the left paddle and Up/Down for the right paddle.

import tkinter as tk
import random

WIDTH = 800
HEIGHT = 500
PADDLE_WIDTH = 10
PADDLE_HEIGHT = 100
BALL_SIZE = 20
PADDLE_SPEED = 8
BALL_SPEED_START = 6
SCORE_TO_WIN = 10

class Pong:
    def __init__(self, root):
        self.root = root
        root.title("Ping Pong — tkinter")
        self.canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, bg="black")
        self.canvas.pack()

        # paddles
        self.left_paddle = self.canvas.create_rectangle(
            20, (HEIGHT - PADDLE_HEIGHT)//2,
            20 + PADDLE_WIDTH, (HEIGHT + PADDLE_HEIGHT)//2,
            fill="white"
        )
        self.right_paddle = self.canvas.create_rectangle(
            WIDTH - 20 - PADDLE_WIDTH, (HEIGHT - PADDLE_HEIGHT)//2,
            WIDTH - 20, (HEIGHT + PADDLE_HEIGHT)//2,
            fill="white"
        )

        # ball
        self.ball = self.canvas.create_oval(
            (WIDTH - BALL_SIZE)//2, (HEIGHT - BALL_SIZE)//2,
            (WIDTH + BALL_SIZE)//2, (HEIGHT + BALL_SIZE)//2,
            fill="white"
        )

        self.left_score = 0
        self.right_score = 0
        self.score_text = self.canvas.create_text(
            WIDTH//2, 30, text="0 : 0", fill="white", font=("Helvetica", 24)
        )

        self.ball_dx = 0
        self.ball_dy = 0
        self.left_move = 0
        self.right_move = 0

        root.bind("", self.key_press)
        root.bind("", self.key_release)
        self.reset_ball()
        self.running = True
        self.game_loop()

    def reset_ball(self):
        self.canvas.coords(
            self.ball,
            (WIDTH - BALL_SIZE)//2, (HEIGHT - BALL_SIZE)//2,
            (WIDTH + BALL_SIZE)//2, (HEIGHT + BALL_SIZE)//2
        )
        self.ball_dx = BALL_SPEED_START * random.choice([-1, 1])
        self.ball_dy = BALL_SPEED_START * random.uniform(-0.4, 0.4)

    def key_press(self, event):
        k = event.keysym.lower()
        if k == "w": self.left_move = -PADDLE_SPEED
        elif k == "s": self.left_move = PADDLE_SPEED
        elif k == "up": self.right_move = -PADDLE_SPEED
        elif k == "down": self.right_move = PADDLE_SPEED

    def key_release(self, event):
        k = event.keysym.lower()
        if k in ("w", "s"): self.left_move = 0
        elif k in ("up", "down"): self.right_move = 0

    def move_paddles(self):
        for paddle, move in [(self.left_paddle, self.left_move), (self.right_paddle, self.right_move)]:
            x1, y1, x2, y2 = self.canvas.coords(paddle)
            y1 += move
            y2 += move
            if y1 < 0: y1, y2 = 0, PADDLE_HEIGHT
            if y2 > HEIGHT: y1, y2 = HEIGHT - PADDLE_HEIGHT, HEIGHT
            self.canvas.coords(paddle, x1, y1, x2, y2)

    def move_ball(self):
        self.canvas.move(self.ball, self.ball_dx, self.ball_dy)
        bx1, by1, bx2, by2 = self.canvas.coords(self.ball)

        if by1 <= 0 or by2 >= HEIGHT:
            self.ball_dy = -self.ball_dy

        if self.check_collision(self.left_paddle) and self.ball_dx < 0:
            self.ball_dx = abs(self.ball_dx) * 1.05
        elif self.check_collision(self.right_paddle) and self.ball_dx > 0:
            self.ball_dx = -abs(self.ball_dx) * 1.05

        if bx1 <= 0:
            self.right_score += 1
            self.update_score()
            self.reset_ball()
        elif bx2 >= WIDTH:
            self.left_score += 1
            self.update_score()
            self.reset_ball()

    def check_collision(self, paddle):
        p1, p2, p3, p4 = self.canvas.coords(paddle)
        b1, b2, b3, b4 = self.canvas.coords(self.ball)
        return not (p3 < b1 or p1 > b3 or p4 < b2 or p2 > b4)

    def update_score(self):
        self.canvas.itemconfig(self.score_text, text=f"{self.left_score} : {self.right_score}")

    def game_loop(self):
        if not self.running: return
        self.move_paddles()
        self.move_ball()
        self.root.after(16, self.game_loop)

if __name__ == "__main__":
    root = tk.Tk()
    Pong(root)
    root.mainloop()
    

💾 Copy this into a file named PingPong.py and run it with Python 3! Make sure tkinter is installed.