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: