Code for How to Create a Space Invaders Game in Python Tutorial


View on Github

alien.py

import pygame

from settings import BULLET_SIZE
from bullet import Bullet

class Alien(pygame.sprite.Sprite):
	def __init__(self, pos, size, row_num):
		super().__init__()
		self.x = pos[0]
		self.y = pos[1]

		# alien info
		img_path = f'assets/aliens/{row_num}.png'
		self.image = pygame.image.load(img_path)
		self.image = pygame.transform.scale(self.image, (size, size))
		self.rect = self.image.get_rect(topleft = pos)
		self.mask = pygame.mask.from_surface(self.image)
		self.move_speed = 5
		self.to_direction = "right"

		# alien status
		self.bullets = pygame.sprite.GroupSingle()


	def move_left(self):
		self.rect.x -= self.move_speed

	def move_right(self):
		self.rect.x += self.move_speed

	def move_bottom(self):
		self.rect.y += self.move_speed

	def _shoot(self):
		specific_pos = (self.rect.centerx - (BULLET_SIZE // 2), self.rect.centery)
		self.bullets.add(Bullet(specific_pos, BULLET_SIZE, "enemy"))

	def update(self):
		self.rect = self.image.get_rect(topleft=(self.rect.x, self.rect.y))

bullet.py

import pygame
from settings import BULLET_SPEED, HEIGHT

class Bullet(pygame.sprite.Sprite):
	def __init__(self, pos, size, side):
		super().__init__()
		self.x = pos[0]
		self.y = pos[1]

		# bullet info
		img_path = f'assets/bullet/{side}-bullet.png'
		self.image = pygame.image.load(img_path)
		self.image = pygame.transform.scale(self.image, (size, size))
		self.rect = self.image.get_rect(topleft = pos)
		self.mask = pygame.mask.from_surface(self.image)

		# different bullet movement direction for both player and enemy (alien)
		if side == "enemy":
			self.move_speed = BULLET_SPEED
		elif side == "player":
			self.move_speed = (- BULLET_SPEED)


	def _move_bullet(self):
		self.rect.y += self.move_speed


	def update(self):
		self._move_bullet()
		self.rect = self.image.get_rect(topleft=(self.rect.x, self.rect.y))

		# delete the bullet if it get through out of the screen
		if self.rect.bottom <= 0 or self.rect.top >= HEIGHT:
			self.kill()

display.py

import pygame
from settings import WIDTH, HEIGHT, SPACE, FONT_SIZE, EVENT_FONT_SIZE

pygame.font.init()

class Display:
	def __init__(self, screen):
		self.screen = screen
		self.score_font = pygame.font.SysFont("monospace", FONT_SIZE)
		self.level_font = pygame.font.SysFont("impact", FONT_SIZE)
		self.event_font = pygame.font.SysFont("impact", EVENT_FONT_SIZE)
		self.text_color = pygame.Color("blue")
		self.event_color = pygame.Color("red")


	def show_life(self, life):
		life_size = 30
		img_path = "assets/life/life.png"
		life_image = pygame.image.load(img_path)
		life_image = pygame.transform.scale(life_image, (life_size, life_size))
		life_x = SPACE // 2

		if life != 0:
			for life in range(life):
				self.screen.blit(life_image, (life_x, HEIGHT + (SPACE // 2)))
				life_x += life_size


	def show_score(self, score):
		score_x = WIDTH // 3
		score = self.score_font.render(f'score: {score}', True, self.text_color)
		self.screen.blit(score, (score_x, (HEIGHT + (SPACE // 2))))


	def show_level(self, level):
		level_x = WIDTH // 3
		level = self.level_font.render(f'Level {level}', True, self.text_color)
		self.screen.blit(level, (level_x * 2, (HEIGHT + (SPACE // 2))))


	def game_over_message(self):
		message = self.event_font.render('GAME OVER!!', True, self.event_color)
		self.screen.blit(message, ((WIDTH // 3) - (EVENT_FONT_SIZE // 2), (HEIGHT // 2) - (EVENT_FONT_SIZE // 2)))

main.py

import pygame, sys
from settings import WIDTH, HEIGHT, NAV_THICKNESS
from world import World

pygame.init()

screen = pygame.display.set_mode((WIDTH, HEIGHT + NAV_THICKNESS))
pygame.display.set_caption("Space Invader")

class Main:
	def __init__(self, screen):
		self.screen = screen
		self.FPS = pygame.time.Clock()

	def main(self):
		world = World(self.screen)
		while True:
			self.screen.fill("black")

			for event in pygame.event.get():
				if event.type == pygame.QUIT:
					pygame.quit()
					sys.exit()
				if event.type == pygame.KEYDOWN:
					if event.key == pygame.K_SPACE:
						world.player_move(attack = True)

			world.player_move()
			world.update()
			pygame.display.update()
			self.FPS.tick(30)


if __name__ == "__main__":
	play = Main(screen)
	play.main()

settings.py

WIDTH, HEIGHT = 720, 450

SPACE = 30
FONT_SIZE = 20
EVENT_FONT_SIZE = 60
NAV_THICKNESS = 50
CHARACTER_SIZE  = 30
PLAYER_SPEED = 10
ENEMY_SPEED = 1
BULLET_SPEED = 15 # for both sides
BULLET_SIZE = 10

ship.py

import pygame

from settings import PLAYER_SPEED, BULLET_SIZE
from bullet import Bullet

class Ship(pygame.sprite.Sprite):
	def __init__(self, pos, size):
		super().__init__()
		self.x = pos[0]
		self.y = pos[1]

		# ship info 
		img_path = 'assets/ship/ship.png'
		self.image = pygame.image.load(img_path)
		self.image = pygame.transform.scale(self.image, (size, size))
		self.rect = self.image.get_rect(topleft = pos)
		self.mask = pygame.mask.from_surface(self.image)
		self.ship_speed = PLAYER_SPEED

		# ship status
		self.life = 3
		self.player_bullets = pygame.sprite.Group()


	def move_left(self):
		self.rect.x -= self.ship_speed

	def move_up(self):
		self.rect.y -= self.ship_speed

	def move_right(self):
		self.rect.x += self.ship_speed

	def move_bottom(self):
		self.rect.y += self.ship_speed

	def _shoot(self):
		specific_pos = (self.rect.centerx - (BULLET_SIZE // 2), self.rect.y)
		self.player_bullets.add(Bullet(specific_pos, BULLET_SIZE, "player"))

	def update(self):
		self.rect = self.image.get_rect(topleft=(self.rect.x, self.rect.y))

world.py

import pygame
from ship import Ship
from alien import Alien
from settings import HEIGHT, WIDTH, ENEMY_SPEED, CHARACTER_SIZE, BULLET_SIZE, NAV_THICKNESS
from bullet import Bullet
from display import Display

class World:
	def __init__(self, screen):
		self.screen = screen

		self.player = pygame.sprite.GroupSingle()
		self.aliens = pygame.sprite.Group()
		self.display = Display(self.screen)

		self.game_over = False
		self.player_score = 0
		self.game_level = 1

		self._generate_world()


	def _generate_aliens(self):
		# generate opponents
		alien_cols = (WIDTH // CHARACTER_SIZE) // 2
		alien_rows = 3
		for y in range(alien_rows):
			for x in range(alien_cols):
				my_x = CHARACTER_SIZE * x
				my_y = CHARACTER_SIZE * y
				specific_pos = (my_x, my_y)
				self.aliens.add(Alien(specific_pos, CHARACTER_SIZE, y))
		
	# create and add player to the screen
	def _generate_world(self):
		# create the player's ship
		player_x, player_y = WIDTH // 2, HEIGHT - CHARACTER_SIZE
		center_size = CHARACTER_SIZE // 2
		player_pos = (player_x - center_size, player_y)
		self.player.add(Ship(player_pos, CHARACTER_SIZE))

		self._generate_aliens()


	def add_additionals(self):
		# add nav bar
		nav = pygame.Rect(0, HEIGHT, WIDTH, NAV_THICKNESS)
		pygame.draw.rect(self.screen, pygame.Color("gray"), nav)

		# render player's life, score and game level
		self.display.show_life(self.player.sprite.life)
		self.display.show_score(self.player_score)
		self.display.show_level(self.game_level)


	def player_move(self, attack = False):
		keys = pygame.key.get_pressed()

		if keys[pygame.K_a] and not self.game_over or keys[pygame.K_LEFT] and not self.game_over:
			if self.player.sprite.rect.left > 0:
				self.player.sprite.move_left()
		if keys[pygame.K_d] and not self.game_over or keys[pygame.K_RIGHT] and not self.game_over:
			if self.player.sprite.rect.right < WIDTH:
				self.player.sprite.move_right()
		if keys[pygame.K_w] and not self.game_over or keys[pygame.K_UP] and not self.game_over:
			if self.player.sprite.rect.top > 0:
				self.player.sprite.move_up()		
		if keys[pygame.K_s] and not self.game_over or keys[pygame.K_DOWN] and not self.game_over:
			if self.player.sprite.rect.bottom < HEIGHT:
				self.player.sprite.move_bottom()

		# game restart button
		if keys[pygame.K_r]:
			self.game_over = False
			self.player_score = 0
			self.game_level = 1
			for alien in self.aliens.sprites():
				alien.kill()
			self._generate_world()

		if attack and not self.game_over:
			self.player.sprite._shoot()


	def _detect_collisions(self):
		# checks if player bullet hits the enemies (aliens)
		player_attack_collision = pygame.sprite.groupcollide(self.aliens, self.player.sprite.player_bullets, True, True)
		if player_attack_collision:
			self.player_score += 10

		# checks if the aliens' bullet hit the player
		for alien in self.aliens.sprites():	
			alien_attack_collision = pygame.sprite.groupcollide(alien.bullets, self.player, True, False)
			if alien_attack_collision:
				self.player.sprite.life -= 1
				break

		# checks if the aliens hit the player
		alien_to_player_collision = pygame.sprite.groupcollide(self.aliens, self.player, True, False)
		if alien_to_player_collision:
			self.player.sprite.life -= 1


	def _alien_movement(self):
		move_sideward = False
		move_forward = False

		for alien in self.aliens.sprites():
			if alien.to_direction == "right" and alien.rect.right < WIDTH or alien.to_direction == "left" and alien.rect.left > 0:
				move_sideward = True
				move_forward = False
			else:
				move_sideward = False
				move_forward = True
				alien.to_direction = "left" if alien.to_direction == "right" else "right"
				break

		for alien in self.aliens.sprites():
			if move_sideward and not move_forward:
				if alien.to_direction == "right":
					alien.move_right()
				if alien.to_direction == "left":
					alien.move_left()
			if not move_sideward and move_forward:
					alien.move_bottom()


	def _alien_shoot(self):
		for alien in self.aliens.sprites():
			if (WIDTH - alien.rect.x) // CHARACTER_SIZE == (WIDTH - self.player.sprite.rect.x) // CHARACTER_SIZE:
				alien._shoot()
				break


	def _check_game_state(self):
		# check if game over
		if self.player.sprite.life <= 0:
			self.game_over = True
			self.display.game_over_message()
		for alien in self.aliens.sprites():
			if alien.rect.top >= HEIGHT:
				self.game_over = True
				self.display.game_over_message()
				break

		# check if next level
		if len(self.aliens) == 0 and self.player.sprite.life > 0:
			self.game_level += 1
			self._generate_aliens()
			for alien in self.aliens.sprites():
				alien.move_speed += self.game_level - 1


	def update(self):
		# detecting if bullet, alien, and player group is colliding
		self._detect_collisions()

		# allows the aliens to move
		self._alien_movement()

		# allows alien to shoot the player
		self._alien_shoot()

		# bullets rendering
		self.player.sprite.player_bullets.update()
		self.player.sprite.player_bullets.draw(self.screen)

		[alien.bullets.update() for alien in self.aliens.sprites()]
		[alien.bullets.draw(self.screen) for alien in self.aliens.sprites()]

		# player ship rendering
		self.player.update()
		self.player.draw(self.screen)

		# alien rendering
		self.aliens.draw(self.screen)

		# add nav
		self.add_additionals()

		# checks game state
		self._check_game_state()


pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy