class Shield(Entity): """Shield which is placed between the user and the alien horde. Arguments: position (tuple {int, int}): The position to place the shield. groups (pygame.sprite.Group): All the groups this entity will be in. Attributes: image (pygame.Surface): The current image which represents the sprite. rect (pygame.Rect): The rect used for placing the sprite. mask (pygame.mask.Mask): The mast for the image. """ shield = SpriteSheet.sprite(SHIELD) def __init__(self, position, *groups): super().__init__(*groups) self.image = copy(self.shield).convert_alpha() self.rect = self.image.get_rect() self.mask = pygame.mask.from_surface(self.image) self.rect.topleft = position def take_damage(self, bullets): """Take damage from the bullets on the display. Arguments: bullets (pygame.sprite.Group): The groups which contains bullets. """ for bullet in bullets: try: pos_x, pos_y = pygame.sprite.collide_mask(self, bullet) bullet.kill() self.dirty = 1 except TypeError: continue destroy_rect = pygame.Rect((pos_x - 4, pos_y, 8, 8)) self.image.fill((0, 0, 0, 0), destroy_rect) for _ in range(10): destroy_x = randint(pos_x - 4, pos_x + 4) destroy_y = randint(pos_y - 4, pos_y + 4) destroy_rect = (destroy_x - 2, destroy_y, 4, 4) self.image.fill((0, 0, 0, 0), destroy_rect) for _ in range(20): destroy_x = randint(pos_x - 8, pos_x + 8) destroy_y = randint(pos_y - 8, pos_y + 8) destroy_rect = (destroy_x - 1, destroy_y, 2, 2) self.image.fill((0, 0, 0, 0), destroy_rect) for _ in range(30): destroy_x = randint(pos_x - 12, pos_x + 12) destroy_y = randint(pos_y - 12, pos_y + 12) destroy_rect = pygame.Rect((destroy_x - 0.5, destroy_y, 1, 1)) self.image.fill((0, 0, 0, 0), destroy_rect) self.mask = pygame.mask.from_surface(self.image)
class Tank(Entity): """The tank which the user controls to destroy the oncoming alien horde. Arguments: groups (pygame.sprite.Group): All the groups this entity will be in. Attributes: tank (pygame.Surface): The default sprite for the tank. bullet (pygame.Surface): The tanks bullet sprite. explosion (pygame.Surface): The tanks explosion animation. image (pygame.Surface): The current image which represents the sprite. rect (pygame.Rect): The rect used for placing the sprite. mask (pygame.mask.Mask): The mast for the image. _velocity (pygame.math.Vector2): The x, y velocities for the sprite. _last_shot (float): The last time that the tank fired a shot. _reload_speed (float): The amount of time it takes to reload. _current_time (float): Time in seconds. (Used for time based actions) """ tank = SpriteSheet.sprite(TANK) bullet = SpriteSheet.sprite(TANK_BULLET) explosion = Animation(SpriteSheet.animation(TANK_EXPLOSION, 1), 0.3) bullet_explosion = Animation( SpriteSheet.animation(TANK_BULLET_EXPLOSION, 1), 0.3) def __init__(self, position, *groups): super().__init__(*groups) self.image = copy(self.tank).convert_alpha() self.rect = self.image.get_rect() self.mask = pygame.mask.from_surface(self.image) self._velocity = pygame.math.Vector2(250, 0) self._last_shot = 0 self._reload_speed = 0.5 self._current_time = self._reload_speed self.rect.topleft = position def move(self, direction): """Move the tank according the users input. Arguments: The direction to move the tank. left < 0 > right. """ velocity = int(self._seconds_elapsed * self._velocity.x) if direction != 0: self.dirty = 1 if direction < 0 and self.rect.left > velocity: self.rect.x -= velocity elif direction > 0 and self.rect.right < DISPLAY.height - velocity: self.rect.x += velocity def shoot(self, *groups): """If the tank isn't reloading then fire a shot. Arguments: groups (pygame.sprite.Group): The groups the bullet will be in. """ if abs(self._last_shot - self._current_time) >= self._reload_speed: TankBullet(self, *groups) self._last_shot = self._current_time def take_damage(self, bullets, *groups): """Tank damage from any of the bullets on the display. Arguments: bullets (pygame.sprite.Group): The bullet group. groups (pygame.sprite.Group): The groups the explosion will be in. """ for bullet in bullets: if pygame.sprite.collide_mask(self, bullet): Explosion(copy(self.explosion), (self.rect.x - 4, self.rect.y), *groups) bullet.kill() self.kill()
class Mystery(Entity): """The mystery ship which flys accross the screen. Arguments: direction (int): The direction the ship will move across the screen. groups (pygame.sprite.Group): All the groups this entity will be in. Attributes: ship (Ship): The default image for the ship. explosion (Animation): The explosion animation. dirty (int): Wether or not to draw the entity. image (pygame.Surface): The sprites image. rect (pygame.Rect): The rect used to place the sprite. _explosion (Animation): The explosion animation. """ ship = SpriteSheet.sprite(MYSTERY) explosion = Animation(SpriteSheet.animation(MYSTERY_EXPLOSION, 1), 0.3) def __init__(self, direction, *groups): super().__init__(*groups) self.dirty = 2 self.image = copy(self.ship).convert_alpha() self.rect = self.image.get_rect() self.mask = pygame.mask.from_surface(self.image) self._explosion = copy(self.explosion) self.rect.y = 0 + self.rect.height if direction: self._velocity = pygame.math.Vector2(250, 0) self.rect.x = 0 else: self._velocity = pygame.math.Vector2(-250, 0) self.rect.x = DISPLAY.width def update(self, seconds_elapsed): """Update the entities time based variables and update the sprites position. Arguments: seconds_elapsed (float): The time since the last frame was drawn. """ super().update(seconds_elapsed) self.rect.x += int(self._seconds_elapsed * self._velocity.x) if not self.rect.colliderect(DISPLAY): self.kill() def take_damage(self, bullets, *groups): """Take any damage from the bullets on the screen. Create an explosion animation when the entities died. bullets (pygame.sprite.Group): The group containing the bullet sprites. groups (pygame.sprite.Group): The groups the explosion will be in. """ for bullet in bullets: if pygame.sprite.collide_mask(self, bullet): Explosion(self._explosion, (self.rect.x + 6, self.rect.y), *groups) bullet.kill() self.kill()