Crear un juego Pong en Python es un proyecto excelente para practicar movimiento, coordenadas, eventos del teclado, colisiones, funciones y organización del código. Utilizaremos el módulo turtle, incluido con Python, para dibujar la pantalla, las paletas, la pelota y el marcador.
El objetivo es construir una versión funcional y comprensible. Después podrás añadir dificultad progresiva, efectos de sonido, menús o una inteligencia artificial sencilla.
Qué necesitas
Instala una versión reciente de Python con soporte para Tk. No necesitas paquetes externos. Crea una carpeta con un archivo llamado pong.py.
La documentación oficial de Turtle describe la ventana, los objetos, eventos y métodos de movimiento.
Antes de continuar, la guía de Turtle para principiantes ayuda a comprender coordenadas, colores y eventos.
Crear la ventana
import turtle
screen = turtle.Screen()
screen.title("Pong en Python")
screen.bgcolor("black")
screen.setup(width=900, height=600)
screen.tracer(0)tracer(0) desactiva el refresco automático. El bucle principal llamará a screen.update(), lo que evita parpadeos y permite controlar la animación.
Crear una función para las paletas
def create_paddle(x_position):
paddle = turtle.Turtle()
paddle.speed(0)
paddle.shape("square")
paddle.color("white")
paddle.shapesize(stretch_wid=5, stretch_len=1)
paddle.penup()
paddle.goto(x_position, 0)
return paddle
left_paddle = create_paddle(-400)
right_paddle = create_paddle(400)La forma cuadrada se estira verticalmente. penup() evita que la paleta dibuje líneas al moverse.
La guía de funciones en Python explica cómo reducir duplicaciones y diseñar parámetros claros.
Crear la pelota
ball = turtle.Turtle()
ball.speed(0)
ball.shape("circle")
ball.color("white")
ball.penup()
ball.goto(0, 0)
ball.dx = 4
ball.dy = 4Los atributos dx y dy representan el desplazamiento horizontal y vertical aplicado en cada ciclo. Valores mayores producen una pelota más rápida.
Mover las paletas
PADDLE_STEP = 30
TOP_LIMIT = 250
BOTTOM_LIMIT = -250
def move_up(paddle):
new_y = min(
paddle.ycor() + PADDLE_STEP,
TOP_LIMIT,
)
paddle.sety(new_y)
def move_down(paddle):
new_y = max(
paddle.ycor() - PADDLE_STEP,
BOTTOM_LIMIT,
)
paddle.sety(new_y)min() y max() mantienen las paletas dentro de la pantalla.
Conectar el teclado
screen.listen()
screen.onkeypress(
lambda: move_up(left_paddle),
"w",
)
screen.onkeypress(
lambda: move_down(left_paddle),
"s",
)
screen.onkeypress(
lambda: move_up(right_paddle),
"Up",
)
screen.onkeypress(
lambda: move_down(right_paddle),
"Down",
)La ventana debe tener el foco para recibir las teclas. La sección oficial sobre eventos de pantalla de Turtle documenta listen(), onkeypress() y eventos del ratón.
Crear el marcador
left_score = 0
right_score = 0
scoreboard = turtle.Turtle()
scoreboard.speed(0)
scoreboard.color("white")
scoreboard.penup()
scoreboard.hideturtle()
scoreboard.goto(0, 250)
def update_scoreboard():
scoreboard.clear()
scoreboard.write(
f"{left_score} {right_score}",
align="center",
font=("Arial", 24, "normal"),
)
update_scoreboard()Las variables del marcador viven fuera de la función. En un proyecto mayor, una clase o un diccionario puede organizar mejor el estado.
Reiniciar la pelota
def reset_ball(direction):
ball.goto(0, 0)
ball.dx = abs(ball.dx) * direction
ball.dy = 4direction será 1 para moverse a la derecha y -1 para moverse a la izquierda.
Crear el bucle principal
while True:
screen.update()
ball.setx(ball.xcor() + ball.dx)
ball.sety(ball.ycor() + ball.dy)El bucle se ejecuta continuamente. La guía de bucles en Python ayuda a comprender repetición, condiciones y control del flujo, aunque aquí se utiliza while.
Detectar las paredes superior e inferior
if ball.ycor() > 285:
ball.sety(285)
ball.dy *= -1
if ball.ycor() < -285:
ball.sety(-285)
ball.dy *= -1Primero reposicionamos la pelota dentro del límite y después invertimos su dirección vertical. Esto evita que quede fuera de la pantalla.
Detectar goles
if ball.xcor() > 440:
left_score += 1
update_scoreboard()
reset_ball(-1)
if ball.xcor() < -440:
right_score += 1
update_scoreboard()
reset_ball(1)Cuando la pelota cruza un borde lateral, el jugador contrario obtiene un punto.
Detectar colisiones con las paletas
hit_right = (
380 < ball.xcor() < 410
and right_paddle.ycor() - 60
< ball.ycor()
< right_paddle.ycor() + 60
)
hit_left = (
-410 < ball.xcor() < -380
and left_paddle.ycor() - 60
< ball.ycor()
< left_paddle.ycor() + 60
)
if hit_right:
ball.setx(380)
ball.dx *= -1
if hit_left:
ball.setx(-380)
ball.dx *= -1La comprobación combina la posición horizontal con el rango vertical de la paleta. Ajustar la posición antes de invertir evita colisiones repetidas en varios ciclos.
Código completo
import turtle
WIDTH = 900
HEIGHT = 600
PADDLE_STEP = 30
screen = turtle.Screen()
screen.title("Pong en Python")
screen.bgcolor("black")
screen.setup(width=WIDTH, height=HEIGHT)
screen.tracer(0)
def create_paddle(x_position):
paddle = turtle.Turtle()
paddle.speed(0)
paddle.shape("square")
paddle.color("white")
paddle.shapesize(stretch_wid=5, stretch_len=1)
paddle.penup()
paddle.goto(x_position, 0)
return paddle
left_paddle = create_paddle(-400)
right_paddle = create_paddle(400)
ball = turtle.Turtle()
ball.speed(0)
ball.shape("circle")
ball.color("white")
ball.penup()
ball.dx = 4
ball.dy = 4
scoreboard = turtle.Turtle()
scoreboard.color("white")
scoreboard.penup()
scoreboard.hideturtle()
scoreboard.goto(0, 250)
left_score = 0
right_score = 0
def update_scoreboard():
scoreboard.clear()
scoreboard.write(
f"{left_score} {right_score}",
align="center",
font=("Arial", 24, "normal"),
)
def move_up(paddle):
paddle.sety(min(paddle.ycor() + PADDLE_STEP, 250))
def move_down(paddle):
paddle.sety(max(paddle.ycor() - PADDLE_STEP, -250))
def reset_ball(direction):
ball.goto(0, 0)
ball.dx = abs(ball.dx) * direction
ball.dy = 4
screen.listen()
screen.onkeypress(lambda: move_up(left_paddle), "w")
screen.onkeypress(lambda: move_down(left_paddle), "s")
screen.onkeypress(lambda: move_up(right_paddle), "Up")
screen.onkeypress(lambda: move_down(right_paddle), "Down")
update_scoreboard()
while True:
screen.update()
ball.setx(ball.xcor() + ball.dx)
ball.sety(ball.ycor() + ball.dy)
if ball.ycor() > 285:
ball.sety(285)
ball.dy *= -1
elif ball.ycor() < -285:
ball.sety(-285)
ball.dy *= -1
if ball.xcor() > 440:
left_score += 1
update_scoreboard()
reset_ball(-1)
elif ball.xcor() < -440:
right_score += 1
update_scoreboard()
reset_ball(1)
hit_right = (
380 < ball.xcor() < 410
and abs(ball.ycor() - right_paddle.ycor()) < 60
)
hit_left = (
-410 < ball.xcor() < -380
and abs(ball.ycor() - left_paddle.ycor()) < 60
)
if hit_right:
ball.setx(380)
ball.dx *= -1
elif hit_left:
ball.setx(-380)
ball.dx *= -1Añadir dificultad progresiva
if hit_right or hit_left:
ball.dx *= -1.05
ball.dy *= 1.05Limita la velocidad máxima para que el juego siga siendo controlable:
MAX_SPEED = 12
ball.dx = max(-MAX_SPEED, min(ball.dx, MAX_SPEED))
ball.dy = max(-MAX_SPEED, min(ball.dy, MAX_SPEED))Evitar que el bucle consuma demasiados recursos
Turtle utiliza Tkinter y el bucle puede ejecutarse muy rápido. Una alternativa más avanzada es programar cada fotograma con screen.ontimer(). Para este proyecto inicial, tracer(0) y update() ofrecen una implementación sencilla.
Organizar el proyecto
Cuando añadas más funciones, separa responsabilidades:
pong/
├── main.py
├── paddle.py
├── ball.py
└── scoreboard.pyLa guía de módulos y paquetes explica cómo distribuir clases y funciones.
Ideas para ampliar el juego
- Añadir una línea central.
- Definir una puntuación máxima.
- Crear una pantalla de inicio.
- Pausar con una tecla.
- Añadir efectos de sonido.
- Guardar el récord en un archivo.
- Crear un oponente automático.
- Permitir elegir la velocidad.
La guía de listas en Python puede ayudar a almacenar configuraciones, resultados o posiciones.
Errores frecuentes
- Olvidar
screen.listen(). - No llamar a
screen.update()contracer(0). - Invertir la velocidad sin reposicionar la pelota.
- Permitir que las paletas salgan de la ventana.
- Crear varios bucles principales.
- Usar coordenadas sin considerar el tamaño real de los objetos.
- Aumentar la velocidad sin un límite.
Conclusión
Este juego Pong combina eventos, coordenadas, colisiones, estado y animación. Empieza ejecutando el código completo y después cambia una sola característica cada vez. Añadir una puntuación máxima, una pausa o un oponente automático es una buena forma de consolidar lo aprendido.






