Desarrollo con Python
  • Conceptos básicos
    • 🐍Introducción a Python
      • 🐍Variables
      • 🐍Strings
      • 🐍Números
      • 🐍Comentarios
      • 🐍Funciones
      • 🐍Funciones Propias
      • 🐍Zen of Python
    • 💿Primer programa
  • Operadores en python
    • ❎Operadores
      • ❎Operadores Aritméticos
      • ❎Operadores de asignación
      • ❎Booleanos
      • ❎Operadores de comparación
      • ❎Operadores lógicos
      • ❎Operadores de identidad
      • ❎Operadores de pertenencia
  • Datos Complejos
    • ▶️Datos complejos
      • ▶️Listas
      • ▶️Tuplas
      • ▶️Diccionarios
      • ▶️Bytes y Bytearrays
      • ▶️Sets
      • ▶️NoneType
    • 💿Caso práctico: Agenda
  • Control de flujo
    • 🛑Estructuras de control de flujo
      • 🛑Sentencias if/elif/else
      • 🛑Sentencia for
      • 🛑Sentencia while
      • 🛑break/continue/pass
    • ⚠️Excepciones en Python3
    • 🎯Caso práctico: 4 in Row
  • Orientacion a objetos
    • 💾Scope y Namespaces
    • 💾Clases en Python 3
    • 💾Métodos y atributos
    • 💾Clases y Objetos
    • 💾Decorators
  • Trabajando con objetos
    • 🔢Trabajando con Objetos
      • 🔢Trabajando con Números
      • 🔢Trabajando con Strings
      • 🔢Trabajando con Listas
      • 🔢Trabajando con Tuplas
      • 🔢Trabajando con Sets
      • 🔢Trabajando con Diccionarios
  • Programación Modular
    • 🧩Programación modular
      • 🧩Paquetes
      • 🧩PIP y paquetes externos
      • 🧩Pandas
      • 🧩NumPy
      • 🧩Matplotlib
      • 📄Caso Práctico
  • Proyectos finales
    • 🐍Videojuego Snake
    • 📥Detección de Spam con Machine Learning
Con tecnología de GitBook
En esta página
  • Introducción
  • 1. Explorando el paquete por defecto de Python Turtle
  • 2. Clase Snake
  • 3. Implementando los movimientos de la serpiente
  • 4. Implementando los movimientos de la serpiente utilizando las teclas
  • 5. Implementando las colisiones con los bordes
  • 6. Implementando la comida de la serpiente
  • 7. Implementando el aumento del tamaño de la serpiente
  • 8. Implementando las colisiones con el cuerpo de la serpiente
  • Código completo del programa:
  1. Proyectos finales

Videojuego Snake

AnteriorCaso PrácticoSiguienteDetección de Spam con Machine Learning

Última actualización hace 1 año

Introducción

¡En este ejercicio práctico vamos a implementar nuestro segundo videojuego en Python!

Concretamente el juego que vamos a programar es el Snake, uno de los juegos más populares de todos los tiempos al que seguro que muchos de nosotros hemos jugado alguna vez. Este juego consiste en mover una serpiente dentro de un rectángulo comiendo puntos que hacen que el cuerpo de la serpiente aumente de tamaño. Si nos chocamos con alguno de los bordes o el propio cuerpo de la serpiente perderemos la partida. A continuación se muestra una imagen del juego.

1. Explorando el paquete por defecto de Python Turtle

Esta vez vamos a intentar que nuestro juego tenga una interfaz gráfica una poco más visual que la que implementamos en el juego del cuatro en raya. Para implementar estos gráficos en Python, vamos a utilizar un paquete muy sencillo denominado Turtle.

Turtle es un paquete de Python preinstalado que permite a los usuarios crear imágenes y formas proporcionándoles un lienzo virtual. El lápiz en pantalla que se utiliza para dibujar se llama turtle y esto es lo que da nombre a la biblioteca.

Explora el paquete de Python Turtle y familiarízate con sus estructuras más populares.

Pista: Presta especial atención a las siguientes clases Screen() y a los siguientes métodos que exponen los objetos de esta clase: title(), bgcolor(), setup() y tracer().

import turtle
screen = turtle.Screen()
screen.title('Videojuego Snake')     # Título de la ventana
screen.bgcolor('red')                # Color de fondo
screen.setup(width=800, height=800)  # Tamaño de la ventana

Pista: Presta especial atención a las siguientes clases Turtle() y a los siguientes métodos que exponen los objetos de esta clase: goto(), speed(), shape(), color() penup(), write()

t = turtle.Turtle()

t.goto(150, 5)     # Establecer una dirección
t.goto(-100, -30)  # Establecer otra dirección
t.speed(0)         # Establecer velocidad de movimiento
t.shape('square')  # Cambiar la forma del puntero
t.color('white')   # Cambiar el color del puntero
t.penup()          # Que los elementos se superpongan
t.write('Videojuego Snake', align='center', font=("Courier", 24, 'normal'))
t2 = turtle.Turtle() # Crear un nuevo objeto en el tablero
t2.sety(t2.ycor() + 100) # Editar coordenada Y del nuevo elemento
t.forward(20)     # Mover elemento 20 posiciones hacia alante

Pista: Regresa de nuevo al objeto generados partir de la clase Screen() e intenta mover el objeto turtle utilizando los métodos listen() y onkeypress()

# Definimos una función que va a mover el objeto t2
def move():
    t2.sety(t2.ycor() - 20)
    
# Instanciamos el objeto
move()

# Hacer que el puntero se mueva hacia abajo cuando pulsemos la s
screen.listen()
screen.onkeypress(move, 's')

# Bucle infinito que cada 0.1 segundos actualiza la pantalla
import time
while True:
    screen.update() # Actualizar estado del lienzo
    time.sleep(0.1)
screen.mainloop() # Hace que la librería se quede en bucle

2. Clase Snake

Vamos a comenzar creando la pantalla en la que vamos a jugar al juego y la serpiente. Cuando comienza el juego, la serpiente es únicamente un cuadrado en la pantalla.

Implementa una clase que inicialice la pantalla en la que vamos a jugar al juego, la serpiente y el texto que vamos a mostrar por pantalla.

import turtle

class SnakeGame:
    def __init__(self, width=800, height=800, color="#CEFF00"):
        '''Inicializa los componentes del juego.'''
        
        # Inicializa el lienzo
        self.screen = turtle.Screen()                 
        self.screen.title('Videojuego Snake')
        self.screen.bgcolor(color)
        self.screen.setup(width=width, height=height)
        
        # inicializa la serpiente
        self.snake = turtle.Turtle()
        self.snake.speed(0)
        self.snake.shape('square')
        self.snake.color('black')
        self.snake.penup()
        self.snake.goto(0,0)
        
        # Inicializa el texto que se muestra en pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.penup()
        self.texto.color('black')
        self.texto.hideturtle() # Método que oculta el puntero
        self.texto.goto(0, (height / 2) - 40) # Posición arriba del todo
        self.texto.write('Puntos: 0 Record:0', align='center', font=('Courier', 24, 'normal'))
        
snake_game = SnakeGame()

3. Implementando los movimientos de la serpiente

Ya tenemos nuestra pantalla implementada y la serpiente representada como un cuadrado negro. En este punto debemos comenzar a implementar los movimientos de la serpiente por la pantalla.

Añade a la clase Snake los métodos que consideres necesarios para habilitar el movimiento de serpiente por la pantalla. Ten en cuenta que estos métodos tendrán que invocarse más adelante mediante la pulsación de una tecla.In [9]:

import turtle
class SnakeGame:
    def __init__(self, width=800, height=800, color="#CEFF00"):
        '''Inicializa los componentes del juego.'''
        
        # Inicializa el lienzo
        self.screen = turtle.Screen()                 
        self.screen.title('Videojuego Snake')
        self.screen.bgcolor(color)
        self.screen.setup(width=width, height=height)
        
        # inicializa la serpiente
        self.snake = turtle.Turtle()
        self.snake.speed(0)
        self.snake.shape('square')
        self.snake.color('black')
        self.snake.penup()
        self.snake.goto(0,0)
        
        # Inicializa el texto que se muestra en pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.penup()
        self.texto.color('black')
        self.texto.hideturtle() # Método que oculta el puntero
        self.texto.goto(0, (height / 2) - 40) # Posición arriba del todo
        self.texto.write('Puntos: 0   Record: 0', align='center', font=('Courier', 24, 'normal'))
        
        # Atributos de la clase
        self._direccion = None
        
        # Hace que la librería se quede en bucle
        self.screen.mainloop()
        
    def arriba(self):
        '''Este método define el movimiento hacia arriba de la serpiente'''
        if self._direccion != 'abajo':
            self._direccion = 'arriba'
            
    def abajo(self):
        '''Este método define el movimiento hacia abajo de la serpiente'''
        if self._direccion != 'arriba':
            self._direccion = 'abajo'
            
    def izquierda(self):
        '''Este método define el movimiento hacia la izquierda de la serpiente'''
        if self._direccion != 'derecha':
            self._direccion = 'izquierda'
            
    def derecha(self):
        '''Este método define el movimiento hacia la derecha de la serpiente'''
        if self._direccion != 'izquierda':
            self._direccion = 'derecha'
            
    def move(self):
        if self._direccion == 'arriba':
            y = self.snake.ycor()
            self.snake.sety(y + 20)
        elif self._direccion == 'abajo':
            y = self.snake.ycor()
            self.snake.sety(y - 20)
        elif self._direccion == 'izquierda':
            x = self.snake.xcor()
            self.snake.setx(x - 20)
        elif self._direccion == 'derecha':
            x = self.snake.xcor()
            self.snake.setx(x + 20)
snake_game = SnakeGame()
snake_game.arriba()
snake_game.move()

4. Implementando los movimientos de la serpiente utilizando las teclas

Si has llegado hasta este apartado, ya tienes una parte importante de tu videojuego implementada. Una vez que has conseguido mover la serpiente por la pantalla, ahora debes permitir que estos movimientos se realicen mediante la pulsación de una tecla.

Implementan el código dentro de la clase Snake y fuera de ella que consideres necesarios para mover la serpiente por la pantalla pulsando una tecla.

import turtle
import time

class SnakeGame:
    def __init__(self, width=800, height=800, color="#CEFF00"):
        '''Inicializa los componentes del juego.'''
        # Inicializa el lienzo
        self.screen = turtle.Screen()                 
        self.screen.title('Videojuego Snake')
        self.screen.bgcolor(color)
        self.screen.setup(width=width, height=height)
        
        # inicializa la serpiente
        self.snake = turtle.Turtle()
        self.snake.speed(0)
        self.snake.shape('square')
        self.snake.color('black')
        self.snake.penup()
        self.snake.goto(0,0)
        
        # Inicializa el texto que se muestra en pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.penup()
        self.texto.color('black')
        self.texto.hideturtle() # Método que oculta el puntero
        self.texto.goto(0, (height / 2) - 40) # Posición arriba del todo
        self.texto.write('Puntos: 0   Record: 0', align='center', font=('Courier', 24, 'normal'))
        
        # Atributos de la clase
        self._direccion = None
        self._delay = 0.1
        
        # Asociar movimientos a las teclas
        self.screen.listen()
        self.screen.onkeypress(self.arriba, 'w')
        self.screen.onkeypress(self.abajo, 's')
        self.screen.onkeypress(self.izquierda, 'a')
        self.screen.onkeypress(self.derecha, 'd')
        
    def arriba(self):
        '''Este método define el movimiento hacia arriba de la serpiente'''
        if self._direccion != 'abajo':
            self._direccion = 'arriba'
                
    def abajo(self):
        '''Este método define el movimiento hacia abajo de la serpiente'''
        if self._direccion != 'arriba':
            self._direccion = 'abajo'
                
    def izquierda(self):
        '''Este método define el movimiento hacia la izquierda de la serpiente'''
        if self._direccion != 'derecha':
            self._direccion = 'izquierda'
                
    def derecha(self):
        '''Este método define el movimiento hacia la derecha de la serpiente'''
        if self._direccion != 'izquierda':
            self._direccion = 'derecha'
                
    def move(self):
        '''Este método mueve y actualiza las coordenadas la serpiente'''
        if self._direccion == 'arriba':
            y = self.snake.ycor()
            self.snake.sety(y + 20)
        elif self._direccion == 'abajo':
            y = self.snake.ycor()
            self.snake.sety(y - 20)
        elif self._direccion == 'izquierda':
            x = self.snake.xcor()
            self.snake.setx(x - 20)
        elif self._direccion == 'derecha':
            x = self.snake.xcor()
            self.snake.setx(x + 20)
            
    def play(self):
        '''Este método hace que la serpiente avance constantemente'''
        while True:
            self.screen.update()
            time.sleep(self._delay)
            self.move()
        self.screen.mainloop()
snake_game.play()

5. Implementando las colisiones con los bordes

Ya tenemos implementado uno de los comportamientos más importantes de nuestro videojuego como es el movimiento de la serpiente. Sin embargo, podemos observar como la serpiente no respeta los bordes y puede traspasarlos. Implementa las colisiones con los bordes de la pantalla para que se mantenga siempre en el recuadro.

Implementa los métodos que consideres necesarios para limitar el movimiento de la serpiente a la pantalla que se está mostrando. Si la serpiente choca con un borde, debe volver al centro de la pantalla.

import turtle
import time

class SnakeGame:
    def __init__(self, width=800, height=800, color="#CEFF00"):
        '''Inicializa los componentes del juego.'''
        self._ancho = width
        self._alto = height
        # Inicializa el lienzo
        self.screen = turtle.Screen()                 
        self.screen.title('Videojuego Snake')
        self.screen.bgcolor(color)
        self.screen.setup(width=width, height=height)
        self.screen.tracer(0)
        
        # inicializa la serpiente
        self.snake = turtle.Turtle()
        self.snake.speed(0)
        self.snake.shape('square')
        self.snake.color('black')
        self.snake.penup()
        self.snake.goto(0,0)
        
        # Inicializa el texto que se muestra en pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.penup()
        self.texto.color('black')
        self.texto.hideturtle() # Método que oculta el puntero
        self.texto.goto(0, (height / 2) - 40) # Posición arriba del todo
        self.texto.write('Puntos: 0   Record: 0', align='center', font=('Courier', 24, 'normal'))
        
        # Atributos de la clase
        self._direccion = None
        self._delay = 0.1
        
        # Asociar movimientos a las teclas
        self.screen.listen()
        self.screen.onkeypress(self.arriba, 'w')
        self.screen.onkeypress(self.abajo, 's')
        self.screen.onkeypress(self.izquierda, 'a')
        self.screen.onkeypress(self.derecha, 'd')
        
    def arriba(self):
        '''Este método define el movimiento hacia arriba de la serpiente'''
        if self._direccion != 'abajo':
            self._direccion = 'arriba'
                
    def abajo(self):
        '''Este método define el movimiento hacia abajo de la serpiente'''
        if self._direccion != 'arriba':
            self._direccion = 'abajo'
                
    def izquierda(self):
        '''Este método define el movimiento hacia la izquierda de la serpiente'''
        if self._direccion != 'derecha':
            self._direccion = 'izquierda'
                
    def derecha(self):
        '''Este método define el movimiento hacia la derecha de la serpiente'''
        if self._direccion != 'izquierda':
            self._direccion = 'derecha'
                
    def move(self):
        '''Este método mueve y actualiza las coordenadas la serpiente'''
        if self._direccion == 'arriba':
            y = self.snake.ycor()
            self.snake.sety(y + 20)
        elif self._direccion == 'abajo':
            y = self.snake.ycor()
            self.snake.sety(y - 20)
        elif self._direccion == 'izquierda':
            x = self.snake.xcor()
            self.snake.setx(x - 20)
        elif self._direccion == 'derecha':
            x = self.snake.xcor()
            self.snake.setx(x + 20)
            
    def play(self):
        '''Este método hace que la serpiente avance constantemente'''
        while True:
            self.screen.update()
            self.colision_borde() # Llamamos a la función colision en el play
            time.sleep(self._delay)
            self.move()
        self.screen.mainloop()
        
    def colision_borde(self):
        # Definimos los bordes del tablero
        bxcor = (self._ancho // 2) - 20
        bycor = (self._alto // 2) - 20
        
        if self.snake.xcor() > bxcor or self.snake.xcor() < -bxcor or self.snake.ycor() > bycor or self.snake.ycor() < -bycor:
            time.sleep(1)
            self.snake.goto(0,0)
            self._direccion = None
            self.texto.clear()
            self.texto.write('Puntos: 0   Record: 0', align='center', font=('Courier', 24, 'normal'))
snake_game = SnakeGame()
snake_game.play()

6. Implementando la comida de la serpiente

Lo siguiente importante que debemos implementar en nuestro juego es la comida de la serpiente. Esto es lo que nos permite aumentar los puntos y que la serpiente aumente de tamaño. La comida debe aparecer aleatoriamente por la pantalla.

Implementa los métodos que consideres necesarios para generar la comida de manera aleatoria en la pantalla. La comida debe ser un circulo del mismo tamaño que la serpiente.

import turtle
import time
import random

class SnakeGame:
    def __init__(self, width=800, height=800, color="#CEFF00"):
        '''Inicializa los componentes del juego.'''
        
        self._ancho = width
        self._alto = height
        
        # Inicializa el lienzo
        self.screen = turtle.Screen()                 
        self.screen.title('Videojuego Snake')
        self.screen.bgcolor(color)
        self.screen.setup(width=width, height=height)
        self.screen.tracer(0)
        
        # Inicializa la serpiente
        self.snake = turtle.Turtle()
        self.snake.speed(0)
        self.snake.shape('square')
        self.snake.color('black')
        self.snake.penup()
        self.snake.goto(0,0)
        
        # Inicializa la comida de la serpiente
        self.comida = turtle.Turtle()
        self.comida.speed(0)
        self.comida.shape('circle')
        self.comida.color('white')
        self.comida.penup()
        self.comida.goto(0, 100)
        
        # Inicializa el texto que se muestra en pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.penup()
        self.texto.color('black')
        self.texto.hideturtle() # Método que oculta el puntero
        self.texto.goto(0, (height / 2) - 40) # Posición arriba del todo
        
        # Atributos de la clase
        self._direccion = None
        self._delay = 0.1
        self._score = 0
        self._high_score = 0
        
        # Asociar movimientos a las teclas
        self.screen.listen()
        self.screen.onkeypress(self.arriba, 'w')
        self.screen.onkeypress(self.abajo, 's')
        self.screen.onkeypress(self.izquierda, 'a')
        self.screen.onkeypress(self.derecha, 'd')
        
        # Inicializar score
        self._print_score()
        
    def arriba(self):
        '''Este método define el movimiento hacia arriba de la serpiente'''
        if self._direccion != 'abajo':
            self._direccion = 'arriba'
                
    def abajo(self):
        '''Este método define el movimiento hacia abajo de la serpiente'''
        if self._direccion != 'arriba':
            self._direccion = 'abajo'
                
    def izquierda(self):
        '''Este método define el movimiento hacia la izquierda de la serpiente'''
        if self._direccion != 'derecha':
            self._direccion = 'izquierda'
                
    def derecha(self):
        '''Este método define el movimiento hacia la derecha de la serpiente'''
        if self._direccion != 'izquierda':
            self._direccion = 'derecha'
                
    def move(self):
        '''Este método mueve y actualiza las coordenadas la serpiente'''
        if self._direccion == 'arriba':
            y = self.snake.ycor()
            self.snake.sety(y + 20)
        elif self._direccion == 'abajo':
            y = self.snake.ycor()
            self.snake.sety(y - 20)
        elif self._direccion == 'izquierda':
            x = self.snake.xcor()
            self.snake.setx(x - 20)
        elif self._direccion == 'derecha':
            x = self.snake.xcor()
            self.snake.setx(x + 20)
            
    def play(self):
        '''Este método hace que la serpiente avance constantemente y evalua las colisiones'''
        while True:
            self.screen.update()
            self.colision_borde()
            self.colision_comida()
            time.sleep(self._delay)
            self.move()
        self.screen.mainloop()
        
    def colision_borde(self):
        # Definimos los bordes del tablero
        bxcor = (self._ancho // 2) - 20
        bycor = (self._alto // 2) - 20
        
        if self.snake.xcor() > bxcor or self.snake.xcor() < -bxcor or self.snake.ycor() > bycor or self.snake.ycor() < -bycor:
            time.sleep(1)
            self.snake.goto(0,0)
            self._direccion = None
            # Reiniciar el delay
            self._delay = 0.1
            # Actualizar puntuación máxima
            if self._score > self._high_score:
                self._high_score = self._score
            self._score = 0
            self._print_score()
            
    def colision_comida(self):
        if self.snake.distance(self.comida) < 20:
            # Mover la comida a un lugar aleatorio
            bxcor = (self._ancho // 2) - 20
            bycor = (self._alto // 2) - 20
            x = random.randint(-bxcor, bxcor)
            y = random.randint(-bycor, bycor)
            self.comida.goto(x, y)
            
            # Reducir el delay cada vez que come
            self._delay -= 0.001
            
            # Aumentar el score
            self._score += 10
            self._print_score()
            
    def _print_score(self):
        self.texto.clear()
        self.texto.write('Puntos: {}   Record: {}'.format(self._score, self._high_score), align='center', font=('Courier', 24, 'normal'))
snake_game = SnakeGame()
snake_game.play()

7. Implementando el aumento del tamaño de la serpiente

La siguiente funcionalidad que debemos implementar es el aumento de puntuación y tamaño de la serpiente como cuando come la comida que hemos implementado anteriormente.

Implementa los métodos que consideres necesarios para aumentar la puntuación y el tamaño de la serpiente cuando come la comida implementada en el apartado anterior.

import turtle
import time
import random

class SnakeGame:
    def __init__(self, width=800, height=800, color="#CEFF00"):
        '''Inicializa los componentes del juego.'''
        
        self._ancho = width
        self._alto = height
        
        # Inicializa el lienzo
        self.screen = turtle.Screen()                 
        self.screen.title('Videojuego Snake')
        self.screen.bgcolor(color)
        self.screen.setup(width=width, height=height)
        self.screen.tracer(0)
        
        # Inicializa la serpiente
        self.snake = turtle.Turtle()
        self.snake.speed(0)
        self.snake.shape('square')
        self.snake.color('black')
        self.snake.penup()
        self.snake.goto(0, 0)

        # Inicializa los segmentos de la serpiente
        self._segmentos = []
        self._segmentos.append(turtle.Turtle())
        self._segmentos[0].speed(0)
        self._segmentos[0].shape('square')
        self._segmentos[0].color('black')
        self._segmentos[0].penup()
        self._segmentos[0].goto(0, 0)
        
        # Inicializa la comida de la serpiente
        self.comida = turtle.Turtle()
        self.comida.speed(0)
        self.comida.shape('circle')
        self.comida.color('white')
        self.comida.penup()
        self.comida.goto(0, 100)
        
        # Inicializa el texto que se muestra en pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.penup()
        self.texto.color('black')
        self.texto.hideturtle() # Método que oculta el puntero
        self.texto.goto(0, (height / 2) - 40) # Posición arriba del todo
        
        # Atributos de la clase
        self._direccion = None
        self._delay = 0.1
        self._score = 0
        self._high_score = 0
        
        # Asociar movimientos a las teclas
        self.screen.listen()
        self.screen.onkeypress(self.arriba, 'w')
        self.screen.onkeypress(self.abajo, 's')
        self.screen.onkeypress(self.izquierda, 'a')
        self.screen.onkeypress(self.derecha, 'd')
        
        # Inicializar score
        self._print_score()
        
    def arriba(self):
        '''Este método define el movimiento hacia arriba de la serpiente'''
        if self._direccion != 'abajo':
            self._direccion = 'arriba'
                
    def abajo(self):
        '''Este método define el movimiento hacia abajo de la serpiente'''
        if self._direccion != 'arriba':
            self._direccion = 'abajo'
                
    def izquierda(self):
        '''Este método define el movimiento hacia la izquierda de la serpiente'''
        if self._direccion != 'derecha':
            self._direccion = 'izquierda'
                
    def derecha(self):
        '''Este método define el movimiento hacia la derecha de la serpiente'''
        if self._direccion != 'izquierda':
            self._direccion = 'derecha'
                
    def move(self):
        '''Este método mueve y actualiza las coordenadas la serpiente'''
        if self._direccion == 'arriba':
            y = self.snake.ycor()
            self.snake.sety(y + 20)
        elif self._direccion == 'abajo':
            y = self.snake.ycor()
            self.snake.sety(y - 20)
        elif self._direccion == 'izquierda':
            x = self.snake.xcor()
            self.snake.setx(x - 20)
        elif self._direccion == 'derecha':
            x = self.snake.xcor()
            self.snake.setx(x + 20)

        # Mover los segmentos en reversa
        for i in range(len(self._segmentos) - 1, 0, -1):
            x = self._segmentos[i - 1].xcor()
            y = self._segmentos[i - 1].ycor()
            self._segmentos[i].goto(x, y)

        # Mover el primer segmento a la cabeza de la serpiente
        if len(self._segmentos) > 0:
            x = self.snake.xcor()
            y = self.snake.ycor()
            self._segmentos[0].goto(x, y)
            
    def play(self):
        '''Este método hace que la serpiente avance constantemente y evalúa las colisiones'''
        while True:
            self.screen.update()
            self.colision_borde()
            self.colision_comida()
            time.sleep(self._delay)
            self.move()
        self.screen.mainloop()
        
    def colision_borde(self):
        # Definimos los bordes del tablero
        bxcor = (self._ancho // 2) - 20
        bycor = (self._alto // 2) - 20

        if (
            self.snake.xcor() > bxcor
            or self.snake.xcor() < -bxcor
            or self.snake.ycor() > bycor
            or self.snake.ycor() < -bycor
        ):
            time.sleep(1)
            self.snake.goto(0, 0)
            self._direccion = None
            # Reiniciar el delay
            self._delay = 0.1
            # Actualizar puntuación máxima
            if self._score > self._high_score:
                self._high_score = self._score
            self._score = 0
            self._print_score()

            # Reiniciar el cuerpo de la serpiente con solo un segmento
            for segmento in self._segmentos:
                segmento.hideturtle()
            self._segmentos.clear()
            self._segmentos.append(turtle.Turtle())
            self._segmentos[0].speed(0)
            self._segmentos[0].shape('square')
            self._segmentos[0].color('black')
            self._segmentos[0].penup()
            self._segmentos[0].goto(0, 0)

            
    def colision_comida(self):
        if self.snake.distance(self.comida) < 20:
            # Mover la comida a un lugar aleatorio
            bxcor = (self._ancho // 2) - 20
            bycor = (self._alto // 2) - 20
            x = random.randint(-bxcor, bxcor)
            y = random.randint(-bycor, bycor)
            self.comida.goto(x, y)
            
            # Reducir el delay cada vez que come
            self._delay -= 0.001
            
            # Aumentar el score
            self._score += 10
            self._print_score()
            
            # Agregar un nuevo segmento
            self._agregar_segmento()
            
    def _agregar_segmento(self):
        segmento = turtle.Turtle()
        segmento.speed(0)
        segmento.shape('square')
        segmento.color('black')
        segmento.penup()
        self._segmentos.append(segmento)
            
    def _print_score(self):
        self.texto.clear()
        self.texto.write('Puntos: {}   Record: {}'.format(self._score, self._high_score), align='center', font=('Courier', 24, 'normal'))
        
snake_game = SnakeGame()
snake_game.play()

8. Implementando las colisiones con el cuerpo de la serpiente

¡Enhorabuena! Ya casi has completado la implementación de tu videojuego. Lo único que te queda por añadir son las colisiones con el propio cuerpo de la serpiente.

Implementa los métodos que consideres necesarios para introducir colisiones con el propio cuerpo de la serpiente.

import turtle
import time
import random

class SnakeGame:
    def __init__(self, width=800, height=800, color="#CEFF00"):
        '''Inicializa los componentes del juego.'''
        
        self._ancho = width
        self._alto = height
        
        # Inicializa el lienzo
        self.screen = turtle.Screen()                 
        self.screen.title('Videojuego Snake')
        self.screen.bgcolor(color)
        self.screen.setup(width=width, height=height)
        self.screen.tracer(0)
        
        # Inicializa la serpiente
        self.snake = turtle.Turtle()
        self.snake.speed(0)
        self.snake.shape('square')
        self.snake.color('black')
        self.snake.penup()
        self.snake.goto(0, 0)

        # Inicializa los segmentos de la serpiente
        self._segmentos = []
        self._segmentos.append(turtle.Turtle())
        self._segmentos[0].speed(0)
        self._segmentos[0].shape('square')
        self._segmentos[0].color('black')
        self._segmentos[0].penup()
        self._segmentos[0].goto(0, 0)
        
        # Inicializa la comida de la serpiente
        self.comida = turtle.Turtle()
        self.comida.speed(0)
        self.comida.shape('circle')
        self.comida.color('white')
        self.comida.penup()
        self.comida.goto(0, 100)
        
        # Inicializa el texto que se muestra en pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.penup()
        self.texto.color('black')
        self.texto.hideturtle() # Método que oculta el puntero
        self.texto.goto(0, (height / 2) - 40) # Posición arriba del todo
        
        # Atributos de la clase
        self._direccion = None
        self._delay = 0.1
        self._score = 0
        self._high_score = 0
        
        # Asociar movimientos a las teclas
        self.screen.listen()
        self.screen.onkeypress(self.arriba, 'w')
        self.screen.onkeypress(self.abajo, 's')
        self.screen.onkeypress(self.izquierda, 'a')
        self.screen.onkeypress(self.derecha, 'd')
        
        # Inicializar score
        self._print_score()
        
    def arriba(self):
        '''Este método define el movimiento hacia arriba de la serpiente'''
        if self._direccion != 'abajo':
            self._direccion = 'arriba'
                
    def abajo(self):
        '''Este método define el movimiento hacia abajo de la serpiente'''
        if self._direccion != 'arriba':
            self._direccion = 'abajo'
                
    def izquierda(self):
        '''Este método define el movimiento hacia la izquierda de la serpiente'''
        if self._direccion != 'derecha':
            self._direccion = 'izquierda'
                
    def derecha(self):
        '''Este método define el movimiento hacia la derecha de la serpiente'''
        if self._direccion != 'izquierda':
            self._direccion = 'derecha'
                
    def move(self):
        '''Este método mueve y actualiza las coordenadas la serpiente'''
        if self._direccion == 'arriba':
            y = self.snake.ycor()
            self.snake.sety(y + 20)
        elif self._direccion == 'abajo':
            y = self.snake.ycor()
            self.snake.sety(y - 20)
        elif self._direccion == 'izquierda':
            x = self.snake.xcor()
            self.snake.setx(x - 20)
        elif self._direccion == 'derecha':
            x = self.snake.xcor()
            self.snake.setx(x + 20)

        # Verificar colisiones con el cuerpo de la serpiente
        for segmento in self._segmentos:
            if self.snake.distance(segmento) < 20:
                self.colision_cuerpo()

        # Mover los segmentos en reversa
        for i in range(len(self._segmentos) - 1, 0, -1):
            x = self._segmentos[i - 1].xcor()
            y = self._segmentos[i - 1].ycor()
            self._segmentos[i].goto(x, y)

        # Mover el primer segmento a la cabeza de la serpiente
        if len(self._segmentos) > 0:
            x = self.snake.xcor()
            y = self.snake.ycor()
            self._segmentos[0].goto(x, y)
            
    def play(self):
        '''Este método hace que la serpiente avance constantemente y evalúa las colisiones'''
        while True:
            self.screen.update()
            self.colision_borde()
            self.colision_comida()
            time.sleep(self._delay)
            self.move()
        self.screen.mainloop()
        
    def colision_borde(self):
        # Definimos los bordes del tablero
        bxcor = (self._ancho // 2) - 20
        bycor = (self._alto // 2) - 20
        
        if (
            self.snake.xcor() > bxcor
            or self.snake.xcor() < -bxcor
            or self.snake.ycor() > bycor
            or self.snake.ycor() < -bycor
        ):
            time.sleep(1)
            self.snake.goto(0, 0)
            self._direccion = None
            # Reiniciar el delay
            self._delay = 0.1
            # Actualizar puntuación máxima
            if self._score > self._high_score:
                self._high_score = self._score
            self._score = 0
            self._print_score()

            # Reiniciar el cuerpo de la serpiente con solo un segmento
            for segmento in self._segmentos:
                segmento.hideturtle()
            self._segmentos.clear()
            self._segmentos.append(turtle.Turtle())
            self._segmentos[0].speed(0)
            self._segmentos[0].shape('square')
            self._segmentos[0].color('black')
            self._segmentos[0].penup()
            self._segmentos[0].goto(0, 0)
            
    def colision_comida(self):
        if self.snake.distance(self.comida) < 20:
            # Mover la comida a un lugar aleatorio
            bxcor = (self._ancho // 2) - 20
            bycor = (self._alto // 2) - 20
            x = random.randint(-bxcor, bxcor)
            y = random.randint(-bycor, bycor)
            self.comida.goto(x, y)
            
            # Reducir el delay cada vez que come
            self._delay -= 0.001
            
            # Aumentar el score
            self._score += 10
            self._print_score()
            
            # Agregar un nuevo segmento
            self._agregar_segmento()
            
    def colision_cuerpo(self):
        time.sleep(1)
        self.snake.goto(0, 0)
        self._direccion = None
        
        # Reiniciar el delay
        self._delay = 0.1
        
        # Actualizar puntuación máxima
        if self._score > self._high_score:
            self._high_score = self._score
        self._score = 0
        self._print_score()

        # Reiniciar el cuerpo de la serpiente con solo un segmento
        for segmento in self._segmentos:
            segmento.hideturtle()
        self._segmentos.clear()
        self._segmentos.append(turtle.Turtle())
        self._segmentos[0].speed(0)
        self._segmentos[0].shape('square')
        self._segmentos[0].color('black')
        self._segmentos[0].penup()
        self._segmentos[0].goto(0, 0)
            
    def _agregar_segmento(self):
        segmento = turtle.Turtle()
        segmento.speed(0)
        segmento.shape('square')
        segmento.color('grey')
        segmento.penup()
        self._segmentos.append(segmento)
            
    def _print_score(self):
        self.texto.clear()
        self.texto.write('Puntos: {}   Record: {}'.format(self._score, self._high_score), align='center', font=('Courier', 24, 'normal'))

Código completo del programa:

Y ya tendríamos implementado nuestro videojuego Snake. Aquí os dejo un enlace a mi repositorio de GitHub donde podéis verlo en detalle y ejecutarlo:

Más información:

https://docs.python.org/3/library/turtle.html
🐍
GitHub - afsh4ck/pysnake: Videojuego Snake en PythonGitHub
Logo
Page cover image