<-- Back to list of examples

""" 
 Juego tipo Breakout
 
 Sample Python/Pygame Programs
 Simpson College Computer Science
 http://programarcadegames.com/
 http://simpson.edu/computer-science/
""" 

# --- Importamos las bibliotecas que usaremos en este programa

import math
import pygame

# Definimos algunos colores
NEGRO = (0, 0, 0)
BLANCO = (255, 255, 255)
AZUL = (0, 0, 255)

# Tamaño de los bloques break-out
largo_bloque = 23
alto_bloque = 15

class Bloque(pygame.sprite.Sprite):
    """Esta clase representa a cada bloque que será golpeado por la pelota.
    Deriva de la clase "Sprite" en Pygame """

    def __init__(self, color, x, y):
        """ Constructor. Pasa el color del bloque y su 
            posición x, y. """
        
        # Llama al constructor de la clase padre (Sprite)
        super().__init__()
        
        # Crea una imagen del bloque de tamaño apropiado
        # El largo y alto son enviados como una lista al primer parámetro.
        self.image = pygame.Surface([largo_bloque, alto_bloque])
        
        # Rellenamos la imagen con el color apropiado
        self.image.fill(color)
        
        # Extraemos el objeto rectángulo que posee las dimensiones de la imagen
        self.rect = self.image.get_rect()
        
        # Movemos la esquina superior izquierda del rectángulo a las coordenadas x,y.
        # Aquí es donde aparecerá nuestro bloque.
        self.rect.x = x
        self.rect.y = y


class Pelota(pygame.sprite.Sprite):
    """ Esta clase representa la pelota       
        Deriva de la clase "Sprite" en Pygame """
    
    # Velocidad en píxeles por ciclo
    velocidad = 10.0
    
    # Representación en coma flotante de la ubicación de la pelota
    x = 0.0
    y = 180.0
    
    # Rumbo de la pelota (en grados)
    rumbo = 200

    largo = 10
    alto = 10
    
    # Constructor. Pasa el color del bloque así como su posición x e y
    def __init__(self):
        # Llama al constructor de la clase padre (Sprite)
        super().__init__()
        
        # Crea la imagen de la pelota
        self.image = pygame.Surface([self.largo, self.alto])
        
        # Color de la pelota
        self.image.fill(BLANCO)
        
        # Obtiene un objeto rectángulo que muestra dónde se encuentra nuestra imagen
        self.rect = self.image.get_rect()
        
        # Obtiene los atributos para alto/largo de la pantalla
        self.alto_pantalla = pygame.display.get_surface().get_height()
        self.largo_pantalla = pygame.display.get_surface().get_width()
    
    def botar(self, diff):
        """ Está función hará botar la pelota 
            desde una superficie horizontal (no de una vertical) """
        
        self.rumbo = (180 - self.rumbo) % 360
        self.rumbo -= diff
    
    def update(self):
        """ Actualiza la posición de la pelota. """
        # Seno y Coseno trabajan con grados, por eso debemos convertirlos a radianes
        rumbo_radianes = math.radians(self.rumbo)
        
        # Cambia la posición (x e y) según la velocidad y el rumbo
        self.x += self.velocidad * math.sin(rumbo_radianes)
        self.y -= self.velocidad * math.cos(rumbo_radianes)
        
        # Mueve la imagen hacia las coordenadas x e y
        self.rect.x = self.x
        self.rect.y = self.y
        
        # ¿Hemos botado por fuera del borde superior de la pantalla?
        if self.y <= 0:
            self.botar(0)
            self.y = 1
            
        # ¿Hemos botado por fuera de la izquierda de la pantalla?
        if self.x <= 0:
            self.rumbo = (360 - self.rumbo) % 360
            self.x = 1
            
        # ¿Hemos botado por fuera de la derecha de la pantalla?
        if self.x > self.largo_pantalla - self.largo:
            self.rumbo = (360 - self.rumbo) % 360
            self.x = self.largo_pantalla - self.largo - 1
        
        # ¿Hemos botado por fuera del borde inferior de la pantalla?
        if self.y > 600:
            return True
        else:
            return False

class Protagonista(pygame.sprite.Sprite):
    """ Esta clase representa la barra de la parte inferior que controla el protagonista. """
    
    def __init__(self):
        """ Constructor para Protagonista. """
        # Llama al constructor padre
        super().__init__()
        
        self.largo = 75
        self.alto = 15
        self.image = pygame.Surface([self.largo, self.alto])
        self.image.fill((BLANCO))
        
        # Hacemos que la esquina superior izquierda se la ubicación a pasar.
        self.rect = self.image.get_rect()
        self.alto_pantalla = pygame.display.get_surface().get_height()
        self.largo_pantalla = pygame.display.get_surface().get_width()

        self.rect.x = 0
        self.rect.y = self.alto_pantalla-self.alto
    
    def update(self):
        """ Actualiza la posición del protagonista. """
        # Obtenemos la posición del ratón
        pos = pygame.mouse.get_pos()
        # Sitúa la barra del lado izquierdo del jugador en la posición del ratón
        self.rect.x = pos[0]
        # Asegúrate de que no empujamos la pala del protagonista 
        # por fuera del borde derecho de la pantalla 
        if self.rect.x > self.largo_pantalla - self.largo:
            self.rect.x = self.largo_pantalla - self.largo

#Llamamos a esta función para que la biblioteca Pygame pueda inicializarse.
pygame.init()

#Creamos una pantalla de 800x600
pantalla = pygame.display.set_mode([800, 600])

# Establecemos el título de la ventana
pygame.display.set_caption('Breakout')

# Haz esto para que el ratón desaparezca cuando se encuentre sobre nuestra ventana
pygame.mouse.set_visible(0)

# Esta es la fuente que usaremos para dibujar texto sobre pantalla (tamaño 36)
fuente = pygame.font.Font(None, 36)

# Creamos una superficie sobre la que podamos dibujar
fondo_pantalla = pygame.Surface(pantalla.get_size())

# Listas de todos los sprites
bloques = pygame.sprite.Group()
pelotas = pygame.sprite.Group()
todos_los_sprites = pygame.sprite.Group()

# Creamos el objeto pala del protagonista
protagonista = Protagonista()
todos_los_sprites.add(protagonista)

# Creamos las pelotas
pelota = Pelota()
todos_los_sprites.add(pelota)
pelotas.add(pelota)

# La parte superior del bloque (posición y)
top = 80

# Número de bloques a crear
numero_de_bloques = 32

# --- Creamos los bloques

# Cinco filas de bloques
for fila in range(5):
    # 32 columnas de bloques
    for columna in range(0, numero_de_bloques):
        # Crea un bloque (color,x,y)
        bloque = Bloque(AZUL, columna * (largo_bloque + 2) + 1, top)
        bloques.add(bloque)
        todos_los_sprites.add(bloque)
    # Mueve  hacia abajo el borde superior de la siguiente fila
    top += alto_bloque + 2

# Reloj para limitar la velocidad
reloj = pygame.time.Clock()

# ¿Se acabó el juego?
game_over = False

# ¿Salir del programa?
salir_programa = False

# Bucle principal
while not salir_programa:

    # Limitamos a 30 fps
    reloj.tick(30)

    # Limpiamos la pantalla
    pantalla.fill(NEGRO)
    
    # Procesamos los eventos en el juego
    for evento in pygame.event.get():
        if evento.type == pygame.QUIT:
            salir_programa = True
    
    # Mientras que el juego no acabe, actualizamos las posiciones del protagonista 
    # y las pelotas.
    if not game_over:
        #actualizamos las posiciones del protagonista y las pelotas.
        protagonista.update()
        game_over = pelota.update()
    
    # Si terminamos, imprimir game over
    if game_over:
        texto = fuente.render("Game Over", True, BLANCO)
        textopos = texto.get_rect(centerx=fondo_pantalla.get_width()/2)
        textopos.top = 300
        pantalla.blit(texto, textopos)
    
    # Observamos si las pelotas chocan contra la pala del protagonista.
    if pygame.sprite.spritecollide(protagonista, pelotas, False):
        # El 'diff' te permite intentar botar las pelotas hacia la izquierda o derecha 
        # dependiendo por que parte de la pala las golpees
        diff = (protagonista.rect.x + protagonista.largo/2) - (pelota.rect.x+pelota.largo/2)
        
        # Establece la posición 'y' de la pelota en caso la golpees 
        # con el borde la pala
        pelota.rect.y = pantalla.get_height() - protagonista.rect.alto - pelota.rect.alto - 1
        pelota.botar(diff)
    
    # Comprueba las colisiones entre las pelotas y los bloques
    bloquesmuertos = pygame.sprite.spritecollide(pelota, bloques, True)
    
    # Si le damos a un bloque, botamos las pelotas
    if len(bloquesmuertos) > 0:
        pelota.botar(0)
        
        # El juego se termina si todos los bloques desaparecen.
        if len(bloques) == 0:
            game_over = True
    
    # Dibujamos Todo
    todos_los_sprites.draw(pantalla)

    # Actualizamos la pantalla para mostrar todo lo dibujado
    pygame.display.flip()

pygame.quit()