Project Type: Unversity/Group Project
Software Used: VScode, Aseprite
Language Used: Pygame, Python
Primary Role: Asset design and Gameplay Programming
Github link: https://github.com/SugarCow/SkullInvader
Skull Invader is a game I was a part of during my Intro to game development course. It was one of my first game project developed in python and pygame and my first game developed ever. The project had two members I was in charge of creating
Demo:
Sprite and animation creation in Aseprite: I created all of the in game assets except the background for the game. Here are some of the assets created in Aseprite.
Code Snippet- game.py
The following code is the implementation of the game.py file which is initial entry point for the game:
import pygame as pg
from settings import Settings
import game_functions as gf

from laser import Lasers, LaserType
from alien import Aliens
from ship import Ship
from sound import Sound
from scoreboard import Scoreboard
from barrier import Barriers
import sys

from start_screen import Start_screen

class Game:
    def __init__(self):
        pg.init()
        self.settings = Settings()
        size = self.settings.screen_width, self.settings.screen_height   # tuple
        self.screen = pg.display.set_mode(size=size)
        pg.display.set_caption("Alien Invasion")

        self.sound = Sound(bg_music='sounds/undetale_spider_dance.wav')
        self.scoreboard = Scoreboard(game=self)  

        self.ship_lasers = Lasers(settings=self.settings, type=LaserType.SHIP)
        self.alien_lasers = Lasers(settings=self.settings, type=LaserType.ALIEN)
       
        self.barriers = Barriers(game=self)
        self.ship = Ship(game=self, scoreboard = self.scoreboard)
        self.aliens = Aliens(game=self)
        self.settings.initialize_speed_settings()

    def reset(self):
        print('Resetting game...')
        # self.lasers.reset()
        self.barriers.reset()
        self.ship.reset()
        self.aliens.reset()
        # self.scoreboard.reset()

    def game_over(self):
        print('All ships gone: game over!')
        self.sound.gameover()
        pg.quit()
        sys.exit()
   
    def draw(self):
        background = pg.image.load(f'images/desert2alt.png').convert()
        self.screen.blit(background, (0,0))

    def play(self):
        self.sound.play_bg()
        while True:     # at the moment, only exits in gf.check_events if Ctrl/Cmd-Q pressed
            gf.check_events(settings=self.settings, ship=self.ship)
            # self.screen.fill(self.settings.bg_color)
            self.draw()
            self.ship.update()
            self.aliens.update()
            self.barriers.update()
            # self.lasers.update()
            self.scoreboard.update()
            pg.display.flip()

def main():
   
    g = Game()
    s =Start_screen(g)
    s.draw()
    g.play()

if __name__ == '__main__':
    main()

Code Snippet - alien.py
The following code is the the implementation of the alien enemies:
from ast import Or
from email.headerregistry import HeaderRegistry
from random import randint
import pygame as pg
from pygame.sprite import Sprite, Group
from laser import Lasers
from timer import Timer

class Alien(Sprite):
    # alien_images = []
    # for n in range(2):
    #     alien_images.append(pg.image.load(f'images/alien{n}.bmp'))

    # alien_images = [pg.image.load(f'images/alien{n}.bmp') for n in range(2)]

    # alien_images0 = [pg.image.load(f'images/alien0{n}.bmp') for n in range(2)]
    # alien_images1 = [pg.image.load(f'images/alien1{n}.bmp') for n in range(2)]
    # alien_images2 = [pg.image.load(f'images/alien2{n}.bmp') for n in range(2)]

    alien_images0 = [pg.transform.rotozoom(pg.image.load(f'images/Cow_skull{n+1}.png'), 0, 0.7)for n in range(8)]
    alien_images1 = [pg.transform.rotozoom(pg.image.load(f'images/Orc_skull{n+1}.png'), 0, 0.7) for n in range(6)]
    alien_images2 = [pg.transform.rotozoom(pg.image.load(f'images/Cyclop_skull{n+1}.png'), 0, 0.7) for n in range(8)]
    alien_images2 = [pg.transform.rotozoom(pg.image.load(f'images/Enemy_skull{n+1}.png'), 0, 0.7) for n in range(7)]
    # alien_images3 = [pg.image.load(f'images/alien3{n}.bmp') for n in range(2)]

    # alien_types = {0: alien_images0, 1 : alien_images1, 2: alien_images2, 3: alien_images3}    
    alien_timers = {0 : Timer(image_list=alien_images0),
                   1 : Timer(image_list=alien_images1),
                   2 : Timer(image_list=alien_images2)}
                #    3 : Timer(image_list=alien_images3)}    

    alien_explosion_images = [pg.image.load(f'images/Skull_Dead{n+1}.png') for n in range(7)]

    def __init__(self, game, type):
        super().__init__()
        self.screen = game.screen
        self.settings = game.settings
        self.image = pg.image.load('images/alien0.bmp')
        self.rect = self.image.get_rect()
        self.rect.y = self.rect.height
        self.x = float(self.rect.x)
        self.type = type
        self.sb = game.scoreboard
       
        self.dying = self.dead = False
       
        # self.timer_normal = Timer(image_list=self.alien_images)  
        # self.timer_normal = Timer(image_list=self.alien_types[type])
                     
        self.timer_normal = Alien.alien_timers[type]              
        self.timer_explosion = Timer(image_list=Alien.alien_explosion_images, is_loop=False)  
        self.timer = self.timer_normal                                    

    def check_edges(self):
        screen_rect = self.screen.get_rect()
        return self.rect.right >= screen_rect.right or self.rect.left <= 0
    def check_bottom_or_ship(self, ship):
        screen_rect = self.screen.get_rect()
        return self.rect.bottom >= screen_rect.bottom or self.rect.colliderect(ship.rect)
    def hit(self):
        if not self.dying:
            self.dying = True
            self.timer = self.timer_explosion
            self.sb.increment_score()
    def update(self):
        if self.timer == self.timer_explosion and self.timer.is_expired():
            self.kill()
        settings = self.settings
        self.x += (settings.alien_speed_factor * settings.fleet_direction)
        self.rect.x = self.x
        self.draw()
    def draw(self):
        image = self.timer.image()
        rect = image.get_rect()
        rect.left, rect.top = self.rect.left, self.rect.top
        self.screen.blit(image, rect)
        # self.screen.blit(self.image, self.rect)

class ufo(Alien):
    ufo_image = [pg.transform.rotozoom(pg.image.load(f'images/Cyclop_skull{n+1}.png'), 0, 0.7) for n in range(8)]
    alien_explosion_images = [pg.image.load(f'images/Skull_Dead{n+1}.png') for n in range(7)]

    def __init__(self, game):
        super().__init__()
        self.screen = game.screen
        self.settings = game.settings
        self.image = pg.image.load('images/alien0.bmp')
        self.rect = self.image.get_rect()
        self.rect.y = self.rect.height
        self.x = float(self.rect.x)
        self.type = type
        self.sb = game.scoreboard
       
        self.dying = self.dead = False
       
        # self.timer_normal = Timer(image_list=self.alien_images)  
        # self.timer_normal = Timer(image_list=self.alien_types[type])
                     
        self.timer_normal = Alien.alien_timers[type]              
        self.timer_explosion = Timer(image_list=Alien.alien_explosion_images, is_loop=False)  
        self.timer = self.timer_normal

class Aliens:
    def __init__(self, game):
        self.model_alien = Alien(game=game, type=1)
        self.game = game
        self.sb = game.scoreboard
        self.aliens = Group()

        # self.ship_lasers = game.ship.lasers.lasers    # a laser Group
        # self.aliens_lasers = Lasers(settings=game.settings)

        self.ship_lasers = game.ship_lasers.lasers    # a laser Group
        self.aliens_lasers = game.alien_lasers

        self.screen = game.screen
        self.settings = game.settings
        self.shoot_requests = 0
        self.ship = game.ship
        self.create_fleet()
    def get_number_aliens_x(self, alien_width):
        available_space_x = self.settings.screen_width - (6 * alien_width)
        number_aliens_x = int(available_space_x / (1.2 * alien_width))
        return number_aliens_x
    def get_number_rows(self, ship_height, alien_height):
        available_space_y = (self.settings.screen_height - (3 * alien_height) - ship_height)
        number_rows = int(available_space_y / (1 * alien_height))
        number_rows = 6
        return number_rows        
    def reset(self):
        self.aliens.empty()
        self.create_fleet()
        self.aliens_lasers.reset()
    def create_alien(self, alien_number, row_number):
        # if row_number > 5: raise ValueError('row number must be less than 6')
        type = row_number // 2    
        alien = Alien(game=self.game, type=type)
        alien_width = alien.rect.width

        alien.x = alien_width + 1.5 * alien_width * alien_number
        alien.rect.x = alien.x
        alien.rect.y = alien.rect.height + 1.2 * alien.rect.height * row_number
        self.aliens.add(alien)    
    def create_fleet(self):
        number_aliens_x = self.get_number_aliens_x(self.model_alien.rect.width)
        number_rows = self.get_number_rows(self.ship.rect.height, self.model_alien.rect.height)
        for row_number in range(number_rows):
            for alien_number in range(number_aliens_x):
                   self.create_alien(alien_number, row_number)
    def check_fleet_edges(self):
        for alien in self.aliens.sprites():
            if alien.check_edges():
                self.change_fleet_direction()
                break
    def check_fleet_bottom(self):
        for alien in self.aliens.sprites():
            if alien.check_bottom_or_ship(self.ship):
                self.ship.hit()
                break
    def check_fleet_empty(self):
        if len(self.aliens.sprites()) == 0:
            print('Aliens all gone!')
            self.game.reset()
    def change_fleet_direction(self):
        for alien in self.aliens.sprites():
            alien.rect.y += self.settings.fleet_drop_speed
        self.settings.fleet_direction *= -1
    def shoot_from_random_alien(self):
        self.shoot_requests += 1
        if self.shoot_requests % self.settings.aliens_shoot_every != 0:
            return
       
        num_aliens = len(self.aliens.sprites())
        alien_num = randint(0, num_aliens)
        i = 0
        for alien in self.aliens.sprites():
            if i == alien_num:
                self.aliens_lasers.shoot(game=self.game, x=alien.rect.centerx, y=alien.rect.bottom)
            i += 1

    # alien_lasers hitting the ship Or
    # alien_lasers hitting a barrier or
    # alien_lasers hitting a ship_lasers

    # ship_lasers hitting an alien or
    # ship_lasers hitting a barrier or
    # ship_lasers hitting an aliens_lasers

    def check_collisions(self):  
        collisions = pg.sprite.groupcollide(self.aliens, self.ship_lasers, False, True)  
        if collisions:
            for alien in collisions:
                alien.hit()

        collisions = pg.sprite.spritecollide(self.ship, self.aliens_lasers.lasers, True)
        if collisions:
            self.ship.hit()

        # aliens_lasers collide with barrier?

        # ship_lasers collide with barrier?

        # aliens_lasers collide with ship_lasers ?

    def update(self):
        self.check_fleet_edges()
        self.check_fleet_bottom()
        self.check_collisions()
        self.check_fleet_empty()
        self.shoot_from_random_alien()
        for alien in self.aliens.sprites():
            if alien.dead:      # set True once the explosion animation has completed
                alien.remove()
            alien.update()
        self.aliens_lasers.update()
    def draw(self):
        for alien in self.aliens.sprites():
            alien.draw()
Back to Top