class Bullet(Sprite): """A class to manage bullets from the ship""" def __init__(self, ship): super(Bullet, self).__init__() # Create bullet at the correct position self.image = GFX().bullets[0] self.mask = GFX().bullets_mask[0] self.rect = self.image.get_rect() self.rect.centerx = ship.rect.centerx self.rect.bottom = ship.rect.top # Attributes self.pos_y = float(self.rect.y) self.speed = CFG().bullet_speed def update(self, dt): """Move the bullet on screen""" self.pos_y -= self.speed * dt self.rect.y = self.pos_y if self.rect.bottom <= 0: self.kill() def blitme(self, screen): """Draw the bullet""" screen.blit(self.image, self.rect)
class Asteroid(Sprite): def __init__(self, pos_x): """Init asteroid - square sprite with random image and rotation speed""" super(Asteroid, self).__init__() self.movement_speed = CFG().asteroid_small_speed # Stats self.health = 100 self.reward = 100 self.pickup = None # Select random asteroid image self.i = randint(0, len(GFX().asteroids)-1) self.image = GFX().asteroids[self.i][0] # Set starting position self.rect = self.image.get_rect() self.rect.centerx = pos_x self.rect.bottom = 0 self.size = self.rect.height self.timer = 0 self.num_frames = len(GFX().asteroids[self.i]) # Gen number of animation frames self.frame = randint(0, self.num_frames-1) # Current frame number of animation - set random one self.rotation_speed = uniform(0.08, 0.2) # time in seconds between animation frames self.direction = choice([1, -1]) self.image = GFX().asteroids[self.i][self.frame] self.mask = GFX().asteroids_mask[self.i][self.frame] def update(self, dt, enemy_bullets, ship): """Update movement and animation""" # If time between frames elapsed - set image of the sprite to the next frame if self.timer < time(): self.timer = time() + self.rotation_speed self.frame += self.direction # loop animation if self.frame == self.num_frames: self.frame = 0 if self.frame == -1: self.frame = self.num_frames-1 self.image = GFX().asteroids[self.i][self.frame] self.mask = GFX().asteroids_mask[self.i][self.frame] # move the asteroid self.rect.bottom += self.movement_speed * dt def hit(self): self.health -= 20
class Ship(): def __init__(self, screen): """Init the player ship and it's starting position""" self.screen = screen # load the ships image and get it's rect self.image = GFX().ship['c_0'] self.mask = GFX().ship_mask['c_0'] self.rect = self.image.get_rect() self.screen_rect = self.screen.get_rect() # Start the ship at the bottom center of the screen self.rect.centerx = self.screen_rect.centerx self.rect.bottom = self.screen_rect.bottom # Attributes self.pos_x = float(self.rect.centerx) self.shooting_timer = 0 # Flags self.moving_left = False self.moving_right = False self.moving_center = False # Used for resetting ship image self.shooting = False self.effects = Group() def blitme(self): """Draw the ship""" self.screen.blit(self.image, self.rect) self.effects.draw(self.screen) def update(self, dt): """Updates ship movement and graphics""" # After shooting timer runs out remove shooting flag and reset ship image if self.shooting_timer < time(): self.shooting = False self.moving_center = True # Calculating ship movement and setting correct image if self.moving_left and self.rect.left > 0: self.pos_x -= CFG().ship_speed * dt self.image = GFX().ship['l_0'] self.mask = GFX().ship_mask['l_0'] elif self.moving_right and self.rect.right < self.screen_rect.right: self.pos_x += CFG().ship_speed * dt self.image = GFX().ship['r_0'] self.mask = GFX().ship_mask['r_0'] elif self.moving_center: self.image = GFX().ship['c_0'] self.mask = GFX().ship_mask['c_0'] self.moving_center = False # if shooting use special ship image if self.shooting: if self.moving_left: self.image = GFX().ship['l_1'] elif self.moving_right: self.image = GFX().ship['r_1'] else: self.image = GFX().ship['c_1'] # Apply ship movement self.rect.centerx = self.pos_x self.effects.update(dt) def hit(self): self.effects.add(shield.PlayerShield(self))
class Story(): """ Shows story before and after level """ def __init__(self, start_story, end_story, screen): """ Init Story :param start_story: list of dict containing image name, time in seconds, and text :param end_story: list of dict containing image name, time in seconds, and text :param screen: surface to show the story on """ self.start_story = start_story self.end_story = end_story self.screen = screen self.font = Text(self.screen, CFG().font_main, 11, (255, 255, 255), True) self.story_image = None self.story_timer = 0 self.story_text = '' rect = self.screen.get_rect() self.text_x = rect.width / 2 self.text_y = rect.height - (rect.height / 16) def update(self, set='start'): """ Goes trough the story list, keeps duration for showing the story and updates current image and text :param set: string start or end - which part of story to show :return: True if showing image, False if all images have been shown """ # If it's time for next story if self.story_timer < time(): self.story_image = None self.story_text = '' if set == 'start': story = self.start_story else: story = self.end_story if len(story): page = story.pop(0) # Set next story image, duration and text self.story_image = GFX().story[page['image']] self.story_timer = time() + page['time'] if 'text' in page.keys(): self.story_text = page['text'] else: return False else: # Allow skipping of story at the start of level if set == 'start': if Events().key_pressed: self.story_timer = 0 return True def draw(self): """ Draw current story image and text""" self.screen.blit(self.story_image, self.story_image.get_rect()) if self.story_text != '': text = self.story_text.split('\n') # Set initial padding from bottom based on number of lines y = self.text_y - (16 * len(text)) for line in text: self.font.write(line, self.text_x, y, origin='center') y += 16
class EnemyBullet(Sprite): """A class to manage enemy bullets""" def __init__(self, position, speed, look=1, target=None): """ Create and aim bullet Target angle is -90 left, 0 straight down, 90 right :param position: Starting position: Sprite or [x, y] :param gfx: game graphics lib :param speed: speed of the bullet :param look: index of the bullet image :param target: Target to aim at None/int angle/[x,y] """ super(EnemyBullet, self).__init__() # Set selected image, mask and rect self.image = GFX().bullets[look] self.mask = GFX().bullets_mask[look] self.rect = self.image.get_rect() # Set starting position if isinstance(position, Sprite): self.rect.centerx = position.rect.centerx self.rect.bottom = position.rect.bottom else: self.rect.centerx = position[0] self.rect.centery = position[1] # Attributes self.pos_x = float(self.rect.x) self.pos_y = float(self.rect.y) self.speedx = 0 self.speedy = 0 self.angle = 0 if target is None: self.speedy = speed else: if isinstance(target, list): # Calculate angle to target self.angle = rt_angle(target[0] - self.rect.x, target[1] - self.rect.y) else: self.angle = target # Rotate bullet image if self.angle != 0: self.image = rotate(self.image, self.angle) self.mask = from_surface(self.image) self.rect = self.image.get_rect() # Perform vectoring based on angle self.angle += 90 self.angle = radians(self.angle) self.speedx = cos(self.angle) * speed * -1 self.speedy = sin(self.angle) * speed def update(self, dt): """Calculate position and move bullet""" if self.speedx != 0: self.pos_x += self.speedx * dt self.rect.x = self.pos_x self.pos_y += self.speedy * dt self.rect.y = self.pos_y if self.rect.top > CFG().int_screen_height: self.kill() def blitme(self, screen): """Draw the bullet""" screen.blit(self.image, self.rect)