#!/usr/bin/env python import random, os.path #import basic pygame modules import pygame from pygame.locals import * #see if we can load more than standard BMP if not pygame.image.get_extended(): raise SystemExit("Sorry, extended image module required") #game constants MAX_SHOTS = 2 #most player bullets onscreen ALIEN_ODDS = 22 #chances a new alien appears BOMB_ODDS = 60 #chances a new bomb will drop ALIEN_RELOAD = 12 #frames between new aliens SCREENRECT = Rect(0, 0, 640, 480) SCORE = 0 main_dir = os.path.split(os.path.abspath(__file__))[0] def load_image(file): "loads an image, prepares it for play" file = os.path.join(main_dir, 'data', file) try: surface = pygame.image.load(file) except pygame.error: raise SystemExit('Could not load image "%s" %s'%(file, pygame.get_error())) return surface.convert() def load_images(*files): imgs = [] for file in files: imgs.append(load_image(file)) return imgs class dummysound: def play(self): pass def load_sound(file): if not pygame.mixer: return dummysound() file = os.path.join(main_dir, 'data', file) try: sound = pygame.mixer.Sound(file) return sound except pygame.error: print ('Warning, unable to load, %s' % file) return dummysound() # each type of game object gets an init and an # update function. the update function is called # once per frame, and it is when each object should # change it's current position and state. the Player # object actually gets a "move" function instead of # update, since it is passed extra information about # the keyboard class Player(pygame.sprite.Sprite): speed = 10 bounce = 24 gun_offset = -11 images = [] def __init__(self): pygame.sprite.Sprite.__init__(self, self.containers) self.image = self.images[0] self.rect = self.image.get_rect(midbottom=SCREENRECT.midbottom) self.reloading = 0 self.origtop = self.rect.top self.facing = -1 def move(self, direction): if direction: self.facing = direction self.rect.move_ip(direction*self.speed, 0) self.rect = self.rect.clamp(SCREENRECT) if direction < 0: self.image = self.images[0] elif direction > 0: self.image = self.images[1] self.rect.top = self.origtop - (self.rect.left//self.bounce%2) def gunpos(self): pos = self.facing*self.gun_offset + self.rect.centerx return pos, self.rect.top class Alien(pygame.sprite.Sprite): speed = 13 animcycle = 12 images = [] def __init__(self): pygame.sprite.Sprite.__init__(self, self.containers) self.image = self.images[0] self.rect = self.image.get_rect() self.facing = random.choice((-1,1)) * Alien.speed self.frame = 0 if self.facing < 0: self.rect.right = SCREENRECT.right def update(self): self.rect.move_ip(self.facing, 0) if not SCREENRECT.contains(self.rect): self.facing = -self.facing; self.rect.top = self.rect.bottom + 1 self.rect = self.rect.clamp(SCREENRECT) self.frame = self.frame + 1 self.image = self.images[self.frame//self.animcycle%3] class Explosion(pygame.sprite.Sprite): defaultlife = 12 animcycle = 3 images = [] def __init__(self, actor): pygame.sprite.Sprite.__init__(self, self.containers) self.image = self.images[0] self.rect = self.image.get_rect(center=actor.rect.center) self.life = self.defaultlife def update(self): self.life = self.life - 1 self.image = self.images[self.life//self.animcycle%2] if self.life <= 0: self.kill() class Shot(pygame.sprite.Sprite): speed = -11 images = [] def __init__(self, pos): pygame.sprite.Sprite.__init__(self, self.containers) self.image = self.images[0] self.rect = self.image.get_rect(midbottom=pos) def update(self): self.rect.move_ip(0, self.speed) if self.rect.top <= 0: self.kill() class Bomb(pygame.sprite.Sprite): speed = 9 images = [] def __init__(self, alien): pygame.sprite.Sprite.__init__(self, self.containers) self.image = self.images[0] self.rect = self.image.get_rect(midbottom= alien.rect.move(0,5).midbottom) def update(self): self.rect.move_ip(0, self.speed) if self.rect.bottom >= 470: Explosion(self) self.kill() class Score(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.font = pygame.font.Font(None, 20) self.font.set_italic(1) self.color = Color('white') self.lastscore = -1 self.update() self.rect = self.image.get_rect().move(10, 450) def update(self): if SCORE != self.lastscore: self.lastscore = SCORE msg = "Score: %d" % SCORE self.image = self.font.render(msg, 0, self.color) def main(winstyle = 0): # Initialize pygame if pygame.get_sdl_version()[0] == 2: pygame.mixer.pre_init(44100, 32, 2, 1024) pygame.init() if pygame.mixer and not pygame.mixer.get_init(): print ('Warning, no sound') pygame.mixer = None fullscreen = False # Set the display mode winstyle = 0 # |FULLSCREEN bestdepth = pygame.display.mode_ok(SCREENRECT.size, winstyle, 32) screen = pygame.display.set_mode(SCREENRECT.size, winstyle, bestdepth) #Load images, assign to sprite classes #(do this before the classes are used, after screen setup) img = load_image('player1.gif') Player.images = [img, pygame.transform.flip(img, 1, 0)] img = load_image('explosion1.gif') Explosion.images = [img, pygame.transform.flip(img, 1, 1)] Alien.images = load_images('alien1.gif', 'alien2.gif', 'alien3.gif') Bomb.images = [load_image('bomb.gif')] Shot.images = [load_image('shot.gif')] #decorate the game window icon = pygame.transform.scale(Alien.images[0], (32, 32)) pygame.display.set_icon(icon) pygame.display.set_caption('Pygame Aliens') pygame.mouse.set_visible(0) #create the background, tile the bgd image bgdtile = load_image('background.gif') background = pygame.Surface(SCREENRECT.size) for x in range(0, SCREENRECT.width, bgdtile.get_width()): background.blit(bgdtile, (x, 0)) screen.blit(background, (0,0)) pygame.display.flip() #load the sound effects boom_sound = load_sound('boom.wav') shoot_sound = load_sound('car_door.wav') if pygame.mixer: music = os.path.join(main_dir, 'data', 'house_lo.wav') pygame.mixer.music.load(music) pygame.mixer.music.play(-1) # Initialize Game Groups aliens = pygame.sprite.Group() shots = pygame.sprite.Group() bombs = pygame.sprite.Group() all = pygame.sprite.RenderUpdates() lastalien = pygame.sprite.GroupSingle() #assign default groups to each sprite class Player.containers = all Alien.containers = aliens, all, lastalien Shot.containers = shots, all Bomb.containers = bombs, all Explosion.containers = all Score.containers = all #Create Some Starting Values global score alienreload = ALIEN_RELOAD kills = 0 clock = pygame.time.Clock() #initialize our starting sprites global SCORE player = Player() Alien() #note, this 'lives' because it goes into a sprite group if pygame.font: all.add(Score()) while player.alive(): #get input for event in pygame.event.get(): if event.type == QUIT or \ (event.type == KEYDOWN and event.key == K_ESCAPE): return elif event.type == KEYDOWN: if event.key == pygame.K_f: if not fullscreen: print("Changing to FULLSCREEN") screen_backup = screen.copy() screen = pygame.display.set_mode( SCREENRECT.size, winstyle | FULLSCREEN, bestdepth ) screen.blit(screen_backup, (0, 0)) else: print("Changing to windowed mode") screen_backup = screen.copy() screen = pygame.display.set_mode( SCREENRECT.size, winstyle, bestdepth ) screen.blit(screen_backup, (0, 0)) # screen.fill((255, 0, 0)) pygame.display.flip() fullscreen = not fullscreen keystate = pygame.key.get_pressed() # clear/erase the last drawn sprites all.clear(screen, background) #update all the sprites all.update() #handle player input direction = keystate[K_RIGHT] - keystate[K_LEFT] player.move(direction) firing = keystate[K_SPACE] if not player.reloading and firing and len(shots) < MAX_SHOTS: Shot(player.gunpos()) shoot_sound.play() player.reloading = firing # Create new alien if alienreload: alienreload = alienreload - 1 elif not int(random.random() * ALIEN_ODDS): Alien() alienreload = ALIEN_RELOAD # Drop bombs if lastalien and not int(random.random() * BOMB_ODDS): Bomb(lastalien.sprite) # Detect collisions for alien in pygame.sprite.spritecollide(player, aliens, 1): boom_sound.play() Explosion(alien) Explosion(player) SCORE = SCORE + 1 player.kill() for alien in pygame.sprite.groupcollide(shots, aliens, 1, 1).keys(): boom_sound.play() Explosion(alien) SCORE = SCORE + 1 for bomb in pygame.sprite.spritecollide(player, bombs, 1): boom_sound.play() Explosion(player) Explosion(bomb) player.kill() #draw the scene dirty = all.draw(screen) pygame.display.update(dirty) #cap the framerate clock.tick(40) if pygame.mixer: pygame.mixer.music.fadeout(1000) pygame.time.wait(1000) pygame.quit() #call the "main" function if running this script if __name__ == '__main__': main()