Proyecto Final 1: Juego Snake¶

Enunciado y contexto del ejercicio¶

¡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 rectangulo 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.

¡Completa todos los apartados que se muestran a continuación para conseguir implementar estas funciones!

1. Explora 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.

Más información: https://docs.python.org/3/library/turtle.html

Explora el paquete de Python Turtle y familiarizate 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().

In [1]:
import turtle
In [2]:
screen = turtle.Screen()
In [3]:
screen.title("Esto es el titulo de la ventana")
In [4]:
screen.bgcolor("green")
In [5]:
screen.setup(width=800, height=600)

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()

In [6]:
t = turtle.Turtle()
In [7]:
t.goto(150, 5)
In [8]:
t.goto(-100, -30)
In [9]:
t.speed(0)
In [10]:
t.goto(200, 30)
In [11]:
t.shape("circle")
In [12]:
t.shape("square")
In [13]:
t.color("red")
In [14]:
t.penup()
In [15]:
t.write("Esto es texto escrito en el lienzo", align="center", font=("Courier", 24, "normal"))
In [16]:
t2 = turtle.Turtle()
In [17]:
t2.sety(t2.ycor() + 100)
In [18]:
t2.forward(20)

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

In [19]:
def move():
    t2.sety(t2.ycor() - 20)
In [20]:
move()
In [21]:
screen.listen()
screen.onkeypress(move, "s")
In [22]:
import time

while True:
    screen.update()
    time.sleep(0.1)
---------------------------------------------------------------------------
Terminator                                Traceback (most recent call last)
Cell In[22], line 4
      1 import time
      3 while True:
----> 4     screen.update()
      5     time.sleep(0.1)

File ~\anaconda3\Lib\turtle.py:1304, in TurtleScreen.update(self)
   1302 self._tracing = True
   1303 for t in self.turtles():
-> 1304     t._update_data()
   1305     t._drawturtle()
   1306 self._tracing = tracing

File ~\anaconda3\Lib\turtle.py:2647, in RawTurtle._update_data(self)
   2646 def _update_data(self):
-> 2647     self.screen._incrementudc()
   2648     if self.screen._updatecounter != 0:
   2649         return

File ~\anaconda3\Lib\turtle.py:1293, in TurtleScreen._incrementudc(self)
   1291 if not TurtleScreen._RUNNING:
   1292     TurtleScreen._RUNNING = True
-> 1293     raise Terminator
   1294 if self._tracing > 0:
   1295     self._updatecounter += 1

Terminator: 
In [ ]:
screen.mainloop()
In [ ]:
 

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.
In [1]:
import turtle
In [2]:
class SnakeGame:
    
    def __init__(self, width=600, height=600, color="green"):
        """Inicializa los componentes del juego."""
        # Inicializa el lienzo de la pantalla
        self.screen = turtle.Screen()
        self.screen.title("Juego 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 la pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.shape("square")
        self.texto.color("white")
        self.texto.penup()
        self.texto.hideturtle()
        self.texto.goto(0, (height / 2) - 40)
        self.texto.write("Puntos: 0 Record: 0", align='center', font=("Courier", 24, "normal"))
In [3]:
juego_snake = SnakeGame()

3. Implementa 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 [ ]:
import turtle

class SnakeGame:
    
    def __init__(self, width=600, height=600, color="green"):
        """Inicializa los componentes del juego."""
        # Inicializa el lienzo de la pantalla
        self.screen = turtle.Screen()
        self.screen.title("Juego 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 la pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.shape("square")
        self.texto.color("white")
        self.texto.penup()
        self.texto.hideturtle()
        self.texto.goto(0, (height / 2) - 40)
        self.texto.write("Puntos: 0 Record: 0", align='center', font=("Courier", 24, "normal"))
        # Atributos de la clase
        self._direccion = None
        
    def arriba(self):
        """Este metodo define el movimiento hacia arriba de la serpiente."""
        if self._direccion != "abajo":
            self._direccion = "arriba"
            
    def abajo(self):
        if self._direccion != "arriba":
            self._direccion = "abajo"
            
    def izquierda(self):
        if self._direccion != "derecha":
            self._direccion = "izquierda"
            
    def derecha(self):
        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)
        
In [ ]:
snake_game = SnakeGame()
In [ ]:
snake_game.arriba()
In [ ]:
snake_game.move()
In [ ]:
snake_game.izquierda()
In [ ]:
snake_game.move()
In [ ]:
snake_game.abajo()
In [ ]:
snake_game.move()
In [ ]:
snake_game.derecha()
In [ ]:
snake_game.move()
In [ ]:
 

4. Implementa 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.
In [ ]:
import turtle
import time

class SnakeGame:
    
    def __init__(self, width=600, height=600, color="green"):
        """Inicializa los componentes del juego."""
        # Inicializa el lienzo de la pantalla
        self.screen = turtle.Screen()
        self.screen.title("Juego 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 la pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.shape("square")
        self.texto.color("white")
        self.texto.penup()
        self.texto.hideturtle()
        self.texto.goto(0, (height / 2) - 40)
        self.texto.write("Puntos: 0 Record: 0", align='center', font=("Courier", 24, "normal"))
        # Atributos de la clase
        self._direccion = None
        self._delay = 0.1
        # Asociacion de los movimiento y 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 metodo define el movimiento hacia arriba de la serpiente."""
        if self._direccion != "abajo":
            self._direccion = "arriba"
            
    def abajo(self):
        if self._direccion != "arriba":
            self._direccion = "abajo"
            
    def izquierda(self):
        if self._direccion != "derecha":
            self._direccion = "izquierda"
            
    def derecha(self):
        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)
            
    def jugar(self):
        while True:
            self.screen.update()
            time.sleep(self._delay)
            self.move()
        self.screen.mainloop()
In [ ]:
snake_game = SnakeGame()
In [ ]:
snake_game.jugar()

5. Implementa 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.
In [ ]:
import turtle
import time

class SnakeGame:
    
    def __init__(self, width=600, height=600, color="green"):
        """Inicializa los componentes del juego."""
        self._ancho = width
        self._alto = height
        # Inicializa el lienzo de la pantalla
        self.screen = turtle.Screen()
        self.screen.title("Juego 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 la pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.shape("square")
        self.texto.color("white")
        self.texto.penup()
        self.texto.hideturtle()
        self.texto.goto(0, (height / 2) - 40)
        self.texto.write("Puntos: 0 Record: 0", align='center', font=("Courier", 24, "normal"))
        # Atributos de la clase
        self._direccion = None
        self._delay = 0.1
        # Asociacion de los movimiento y 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 metodo define el movimiento hacia arriba de la serpiente."""
        if self._direccion != "abajo":
            self._direccion = "arriba"
            
    def abajo(self):
        if self._direccion != "arriba":
            self._direccion = "abajo"
            
    def izquierda(self):
        if self._direccion != "derecha":
            self._direccion = "izquierda"
            
    def derecha(self):
        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)
            
    def jugar(self):
        while True:
            self.screen.update()
            self.colision_borde()
            time.sleep(self._delay)
            self.move()
        self.screen.mainloop()
        
    def colision_borde(self):
        bxcor = (self._ancho // 2) - 10
        bycor = (self._alto // 2) - 10
        
        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"))
In [ ]:
snake_game = SnakeGame()
In [ ]:
snake_game.jugar()

6. Implementa 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.
In [ ]:
import turtle
import time
import random

class SnakeGame:
    
    def __init__(self, width=600, height=600, color="green"):
        """Inicializa los componentes del juego."""
        self._ancho = width
        self._alto = height
        # Inicializa el lienzo de la pantalla
        self.screen = turtle.Screen()
        self.screen.title("Juego 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 la pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.shape("square")
        self.texto.color("white")
        self.texto.penup()
        self.texto.hideturtle()
        self.texto.goto(0, (height / 2) - 40)
        # Inicialización de la comida de la serpiente
        self.comida = turtle.Turtle()
        self.comida.speed(0)
        self.comida.shape('circle')
        self.comida.color("red")
        self.comida.penup()
        self.comida.goto(0, 100)
        # Atributos de la clase
        self._direccion = None
        self._delay = 0.1
        self._score = 0
        self._high_score = 0
        # Asociacion de los movimiento y 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")
        # Sacamos el texto por pantalla
        self._print_score()
        
    def arriba(self):
        """Este metodo define el movimiento hacia arriba de la serpiente."""
        if self._direccion != "abajo":
            self._direccion = "arriba"
            
    def abajo(self):
        if self._direccion != "arriba":
            self._direccion = "abajo"
            
    def izquierda(self):
        if self._direccion != "derecha":
            self._direccion = "izquierda"
            
    def derecha(self):
        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)
            
    def jugar(self):
        while True:
            self.screen.update()
            self.colision_borde()
            self.colision_comida()
            time.sleep(self._delay)
            self.move()
        self.screen.mainloop()
        
    def colision_borde(self):
        bxcor = (self._ancho // 2) - 10
        bycor = (self._alto // 2) - 10
        
        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
            # Reiniciar el sore
            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) - 10
            bycor = (self._alto // 2) - 10
            x = random.randint(-bxcor, bxcor)
            y = random.randint(-bycor, bycor)
            self.comida.goto(x, y)
            # Reducir el dalay
            self._delay -= 0.001
            # Aumentar el score
            self._score += 10
            self.texto.write
            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"))
In [ ]:
snake_game = SnakeGame()
In [ ]:
snake_game.jugar()

7. Implementa 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.
In [ ]:
import turtle
import time
import random

class SnakeGame:
    
    def __init__(self, width=600, height=600, color="green"):
        """Inicializa los componentes del juego."""
        self._ancho = width
        self._alto = height
        # Inicializa el lienzo de la pantalla
        self.screen = turtle.Screen()
        self.screen.title("Juego 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 la pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.shape("square")
        self.texto.color("white")
        self.texto.penup()
        self.texto.hideturtle()
        self.texto.goto(0, (height / 2) - 40)
        # Inicialización de la comida de la serpiente
        self.comida = turtle.Turtle()
        self.comida.speed(0)
        self.comida.shape('circle')
        self.comida.color("red")
        self.comida.penup()
        self.comida.goto(0, 100)
        # Atributos de la clase
        self._direccion = None
        self._delay = 0.1
        self._score = 0
        self._high_score = 0
        self.snake_cuerpo = []
        # Asociacion de los movimiento y 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")
        # Sacamos el texto por pantalla
        self._print_score()
        
    def arriba(self):
        """Este metodo define el movimiento hacia arriba de la serpiente."""
        if self._direccion != "abajo":
            self._direccion = "arriba"
            
    def abajo(self):
        if self._direccion != "arriba":
            self._direccion = "abajo"
            
    def izquierda(self):
        if self._direccion != "derecha":
            self._direccion = "izquierda"
            
    def derecha(self):
        if self._direccion != "izquierda":
            self._direccion = "derecha"
            
    def move(self):
        
        # Obtener las coordenadas de la cabeza de la serpiente
        hx, hy = self.snake.xcor(), self.snake.ycor()
        
        # Movemos el cuerpo de la serpiente
        for i in range(len(self.snake_cuerpo)-1, 0, -1):
            x = self.snake_cuerpo[i-1].xcor()
            y = self.snake_cuerpo[i-1].ycor()
            self.snake_cuerpo[i].goto(x, y)
            
        # Mover el segmento mas cercano a la cabeza
        if len(self.snake_cuerpo) > 0:
            self.snake_cuerpo[0].goto(hx, hy)
            
        if self._direccion == "arriba":
            self.snake.sety(hy + 20)
        elif self._direccion == "abajo":
            self.snake.sety(hy - 20)
        elif self._direccion == "izquierda":
            self.snake.setx(hx - 20)
        elif self._direccion == "derecha":
            self.snake.setx(hx + 20)
            
    def jugar(self):
        while True:
            self.screen.update()
            self.colision_borde()
            self.colision_comida()
            time.sleep(self._delay)
            self.move()
        self.screen.mainloop()
        
    def colision_borde(self):
        bxcor = (self._ancho // 2) - 10
        bycor = (self._alto // 2) - 10
        
        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
            # Reiniciamos el cuerpo de la serpiente
            for s in self.snake_cuerpo:
                s.ht() # Oculta el segmento
            # Limpiar la lista de segmentos
            self.snake_cuerpo.clear()
            # Reiniciar el delay
            self._delay = 0.1
            # Reiniciar el sore
            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) - 10
            bycor = (self._alto // 2) - 10
            x = random.randint(-bxcor, bxcor)
            y = random.randint(-bycor, bycor)
            self.comida.goto(x, y)
            # Incrementar el cuerpo de la serpiente
            self.incrementar_cuerpo()
            # Reducir el dalay
            self._delay -= 0.001
            # Aumentar el score
            self._score += 10
            self.texto.write
            self._print_score()
            
    def incrementar_cuerpo(self):
        segmento = turtle.Turtle()
        segmento.speed(0)
        segmento.shape('square')
        segmento.color('grey')
        segmento.penup()
        self.snake_cuerpo.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"))
In [ ]:
snake_game = SnakeGame()
In [ ]:
snake_game.jugar()

8. Implementa 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.
In [1]:
import turtle
import time
import random

class SnakeGame:
    
    def __init__(self, width=600, height=600, color="green"):
        """Inicializa los componentes del juego."""
        self._ancho = width
        self._alto = height
        # Inicializa el lienzo de la pantalla
        self.screen = turtle.Screen()
        self.screen.title("Juego 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 la pantalla
        self.texto = turtle.Turtle()
        self.texto.speed(0)
        self.texto.shape("square")
        self.texto.color("white")
        self.texto.penup()
        self.texto.hideturtle()
        self.texto.goto(0, (height / 2) - 40)
        # Inicialización de la comida de la serpiente
        self.comida = turtle.Turtle()
        self.comida.speed(0)
        self.comida.shape('circle')
        self.comida.color("red")
        self.comida.penup()
        self.comida.goto(0, 100)
        # Atributos de la clase
        self._direccion = None
        self._delay = 0.1
        self._score = 0
        self._high_score = 0
        self.snake_cuerpo = []
        # Asociacion de los movimiento y 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")
        # Sacamos el texto por pantalla
        self._print_score()
        
    def arriba(self):
        """Este metodo define el movimiento hacia arriba de la serpiente."""
        if self._direccion != "abajo":
            self._direccion = "arriba"
            
    def abajo(self):
        if self._direccion != "arriba":
            self._direccion = "abajo"
            
    def izquierda(self):
        if self._direccion != "derecha":
            self._direccion = "izquierda"
            
    def derecha(self):
        if self._direccion != "izquierda":
            self._direccion = "derecha"
            
    def move(self):
        
        # Obtener las coordenadas de la cabeza de la serpiente
        hx, hy = self.snake.xcor(), self.snake.ycor()
        
        # Movemos el cuerpo de la serpiente
        for i in range(len(self.snake_cuerpo)-1, 0, -1):
            x = self.snake_cuerpo[i-1].xcor()
            y = self.snake_cuerpo[i-1].ycor()
            self.snake_cuerpo[i].goto(x, y)
            
        # Mover el segmento mas cercano a la cabeza
        if len(self.snake_cuerpo) > 0:
            self.snake_cuerpo[0].goto(hx, hy)
            
        if self._direccion == "arriba":
            self.snake.sety(hy + 20)
        elif self._direccion == "abajo":
            self.snake.sety(hy - 20)
        elif self._direccion == "izquierda":
            self.snake.setx(hx - 20)
        elif self._direccion == "derecha":
            self.snake.setx(hx + 20)
            
    def jugar(self):
        while True:
            self.screen.update()
            self.colision_borde()
            self.colision_comida()
            self.colision_cuerpo()
            time.sleep(self._delay)
            self.move()
        self.screen.mainloop()
        
    def colision_borde(self):
        bxcor = (self._ancho // 2) - 10
        bycor = (self._alto // 2) - 10
        
        if self.snake.xcor() > bxcor or self.snake.xcor() < -bxcor or self.snake.ycor() > bycor or self.snake.ycor() < -bycor:
            self._reset()
            
    def colision_cuerpo(self):
        for s in self.snake_cuerpo:
            if s.distance(self.snake) < 20:
                self._reset()
            
    def colision_comida(self):
        if self.snake.distance(self.comida) < 20:
            # Mover la comida a un lugar aleatorio
            bxcor = (self._ancho // 2) - 10
            bycor = (self._alto // 2) - 10
            x = random.randint(-bxcor, bxcor)
            y = random.randint(-bycor, bycor)
            self.comida.goto(x, y)
            # Incrementar el cuerpo de la serpiente
            self.incrementar_cuerpo()
            # Reducir el dalay
            self._delay -= 0.001
            # Aumentar el score
            self._score += 10
            self.texto.write
            self._print_score()
            
    def incrementar_cuerpo(self):
        segmento = turtle.Turtle()
        segmento.speed(0)
        segmento.shape('square')
        segmento.color('grey')
        segmento.penup()
        self.snake_cuerpo.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"))
        
    def _reset(self):
        time.sleep(1)
        self.snake.goto(0, 0)
        self._direccion = None
        # Reiniciamos el cuerpo de la serpiente
        for s in self.snake_cuerpo:
            s.ht() # Oculta el segmento
        # Limpiar la lista de segmentos
        self.snake_cuerpo.clear()
        # Reiniciar el delay
        self._delay = 0.1
        # Reiniciar el sore
        if self._score > self._high_score:
            self._high_score = self._score
        self._score = 0
        self._print_score()
In [2]:
snake_game = SnakeGame()
In [3]:
snake_game.jugar()
---------------------------------------------------------------------------
Terminator                                Traceback (most recent call last)
Cell In[3], line 1
----> 1 snake_game.jugar()

Cell In[1], line 97, in SnakeGame.jugar(self)
     95 def jugar(self):
     96     while True:
---> 97         self.screen.update()
     98         self.colision_borde()
     99         self.colision_comida()

File ~\anaconda3\Lib\turtle.py:1304, in TurtleScreen.update(self)
   1302 self._tracing = True
   1303 for t in self.turtles():
-> 1304     t._update_data()
   1305     t._drawturtle()
   1306 self._tracing = tracing

File ~\anaconda3\Lib\turtle.py:2647, in RawTurtle._update_data(self)
   2646 def _update_data(self):
-> 2647     self.screen._incrementudc()
   2648     if self.screen._updatecounter != 0:
   2649         return

File ~\anaconda3\Lib\turtle.py:1293, in TurtleScreen._incrementudc(self)
   1291 if not TurtleScreen._RUNNING:
   1292     TurtleScreen._RUNNING = True
-> 1293     raise Terminator
   1294 if self._tracing > 0:
   1295     self._updatecounter += 1

Terminator: 

9. Ejecuta el ejercicio en Pycharm¶

In [ ]: