Construyendo Space Invaders usando PyGame – Python

En este artículo, vamos a construir invasores del espacio usando PyGame en Python. 

El archivo utilizado se puede descargar desde aquí .

Acercarse:

  • Importe el módulo requerido.
  • Inicialice el pygame.
  • Crea tres funciones:
    • isCollision(): ¿Qué nos dice si la colisión ha ocurrido o no?
    • game_over(): Que devuelve Verdadero o Falso en base a lo cual el código decidió si el juego ha terminado.
    • show_score(x, y): Esto muestra el puntaje en la pantalla
  • Crea un bucle infinito para ejecutar el código continuamente.

esColisión():

Es muy simple en realidad. Antes de explicar esto, queremos que eches un vistazo a la parte de colisión del código dentro del bucle del juego primero a continuación:

Python3

# Collision
collision = isCollision(bullet_X, invader_X[i], bullet_Y, invader_Y[i])
if collision:
        score_val += 1
        bullet_Y = 600
        bullet_state = "rest"
        invader_X[i] = random.randint(64, 736)
        invader_Y[i] = random.randint(30, 200)
        invader_Xchange[i] *= -1

El valor devuelto por la función «isCollision()» se almacena dentro de la variable «colisión». El valor devuelto por la función es Verdadero o Falso según los criterios establecidos para la colisión dentro de la función. Echemos un vistazo a lo que hay dentro de la función isCollision():

Python3

def isCollision(x1, x2, y1, y2):
    distance = math.sqrt((math.pow(x1 - x2, 2)) + (math.pow(y1 - y2, 2)))
    if distance <= 50:
        return True
    else:
        return False

El criterio de colisión establecido dentro de la función es tan simple como la distancia entre la bala y el invasor (nuestro enemigo). Como puede ver, la fórmula utilizada para calcular la distancia es algo que todos los estudiantes estudian en su clase de matemáticas de la escuela secundaria. Es la fórmula de la distancia entre dos puntos que tienen coordenadas (x1, y1) y (x2, y2) que se pasan como parámetros de la función isCollision(). 

Aquí, hemos establecido el criterio de que si el valor de la distancia es menor o igual a 50, significa que se ha producido una colisión. El valor se elige en función de la altura y el ancho de la imagen png utilizada para la bala y el invasor. El valor se puede modificar según sus propios requisitos mediante el método de prueba y error. 

Por lo tanto, siempre que cambie la posición de la bala y el invasor, la función isCollision() comprueba si se ha producido una colisión o no. Esa es la razón por la que se llama dentro del ciclo del juego. 

juego terminado():

Que devuelve Verdadero o Falso en base a lo cual el código decidió si el juego ha terminado. Para comprender la función game_over(), echemos un vistazo al siguiente fragmento de código que está presente dentro del ciclo del juego:

Python3

# movement of the invader
for i in range(no_of_invaders):
 
        if invader_Y[i] >= 450:
            if abs(player_X-invader_X[i]) < 80:
                for j in range(no_of_invaders):
                    invader_Y[j] = 2000
                    explosion_sound = mixer.Sound('data/explosion.wav')
                    explosion_sound.play()
                game_over()
                break

Antes de entrar en la explicación del código, se recomienda conocer el sistema de coordenadas seguido en pygame. Hecha un vistazo a la imagen de abajo:

Entonces, el criterio para el fin del juego también es la colisión. Cuando la coordenada y del invasor es mayor que la nave espacial, es decir, 450 (coordenada y de la nave espacial), y la distancia entre el invasor y la nave espacial es inferior a 80, se produce una colisión y se llama a la función game_over() seguido por el sonido de la explosión. 

Las siguientes líneas lo harán más claro:

Python3

# y-coordinate of invader more than 450
if invader_Y[i] >= 450:
   
        # distance between the x-coordinate of invader
        # and spaceship
        if abs(player_X-invader_X[i]) < 80:
            #....... rest code .....#

Lo anterior se comprueba para todos los invasores presentes en el juego, lo que se asegura mediante un bucle for al inicio.

mostrar_puntaje(x, y):

Muestra la puntuación en la pantalla.

Python3

def show_score(x, y):
    score = font.render("Points: " + str(score_val),
                        True, (255, 255, 255))
    screen.blit(score, (x, y))

Lo único que hace la función show_score() es mostrar la puntuación en la pantalla en una fuente adecuada seleccionada por el usuario.  

Cada vez que ocurre una colisión entre la bala y los invasores, se incrementa una variable » score_val «. Luego, esta variable se muestra en la pantalla mediante la función show_score(), como se puede ver en el fragmento de código anterior.  

A continuación se muestra la implementación:

Python3

import pygame
import random
import math
from pygame import mixer
 
# initializing pygame
pygame.init()
 
# creating screen
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width,
                                  screen_height))
 
# caption and icon
pygame.display.set_caption("Welcome to Space\
Invaders Game by:- styles")
 
 
# Score
score_val = 0
scoreX = 5
scoreY = 5
font = pygame.font.Font('freesansbold.ttf', 20)
 
# Game Over
game_over_font = pygame.font.Font('freesansbold.ttf', 64)
 
 
def show_score(x, y):
    score = font.render("Points: " + str(score_val),
                        True, (255,255,255))
    screen.blit(score, (x , y ))
 
def game_over():
    game_over_text = game_over_font.render("GAME OVER",
                                           True, (255,255,255))
    screen.blit(game_over_text, (190, 250))
 
# Background Sound
mixer.music.load('data/background.wav')
mixer.music.play(-1)
 
# player
playerImage = pygame.image.load('data/spaceship.png')
player_X = 370
player_Y = 523
player_Xchange = 0
 
# Invader
invaderImage = []
invader_X = []
invader_Y = []
invader_Xchange = []
invader_Ychange = []
no_of_invaders = 8
 
for num in range(no_of_invaders):
    invaderImage.append(pygame.image.load('data/alien.png'))
    invader_X.append(random.randint(64, 737))
    invader_Y.append(random.randint(30, 180))
    invader_Xchange.append(1.2)
    invader_Ychange.append(50)
 
# Bullet
# rest - bullet is not moving
# fire - bullet is moving
bulletImage = pygame.image.load('data/bullet.png')
bullet_X = 0
bullet_Y = 500
bullet_Xchange = 0
bullet_Ychange = 3
bullet_state = "rest"
 
# Collision Concept
def isCollision(x1, x2, y1, y2):
    distance = math.sqrt((math.pow(x1 - x2,2)) +
                         (math.pow(y1 - y2,2)))
    if distance <= 50:
        return True
    else:
        return False
 
def player(x, y):
    screen.blit(playerImage, (x - 16, y + 10))
 
def invader(x, y, i):
    screen.blit(invaderImage[i], (x, y))
 
def bullet(x, y):
    global bullet_state
    screen.blit(bulletImage, (x, y))
    bullet_state = "fire"
 
# game loop
running = True
while running:
 
    # RGB
    screen.fill((0, 0, 0))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
 
        # Controlling the player movement
        # from the arrow keys
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                player_Xchange = -1.7
            if event.key == pygame.K_RIGHT:
                player_Xchange = 1.7
            if event.key == pygame.K_SPACE:
               
                # Fixing the change of direction of bullet
                if bullet_state is "rest":
                    bullet_X = player_X
                    bullet(bullet_X, bullet_Y)
                    bullet_sound = mixer.Sound('data/bullet.wav')
                    bullet_sound.play()
        if event.type == pygame.KEYUP:
            player_Xchange = 0
 
    # adding the change in the player position
    player_X += player_Xchange
    for i in range(no_of_invaders):
        invader_X[i] += invader_Xchange[i]
 
    # bullet movement
    if bullet_Y <= 0:
        bullet_Y = 600
        bullet_state = "rest"
    if bullet_state is "fire":
        bullet(bullet_X, bullet_Y)
        bullet_Y -= bullet_Ychange
 
    # movement of the invader
    for i in range(no_of_invaders):
         
        if invader_Y[i] >= 450:
            if abs(player_X-invader_X[i]) < 80:
                for j in range(no_of_invaders):
                    invader_Y[j] = 2000
                    explosion_sound = mixer.Sound('data/explosion.wav')
                    explosion_sound.play()
                game_over()
                break
 
        if invader_X[i] >= 735 or invader_X[i] <= 0:
            invader_Xchange[i] *= -1
            invader_Y[i] += invader_Ychange[i]
        # Collision
        collision = isCollision(bullet_X, invader_X[i],
                                bullet_Y, invader_Y[i])
        if collision:
            score_val += 1
            bullet_Y = 600
            bullet_state = "rest"
            invader_X[i] = random.randint(64, 736)
            invader_Y[i] = random.randint(30, 200)
            invader_Xchange[i] *= -1
 
        invader(invader_X[i], invader_Y[i], i)
 
 
    # restricting the spaceship so that
    # it doesn't go out of screen
    if player_X <= 16:
        player_X = 16;
    elif player_X >= 750:
        player_X = 750
 
 
    player(player_X, player_Y)
    show_score(scoreX, scoreY)
    pygame.display.update()

Producción:

Publicación traducida automáticamente

Artículo escrito por pk2222001 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *