Пример #1
0
 def create_level(self):
     """ Creates a new player and restarts level sprites. """
     self._paused = False
     self._game.ui.clear()
     self._player = PlayerCtrl()
     self._level = Level('level_1.tmx', self._player, self)
     self._timer = Timer()
Пример #2
0
    def __init__(self, level_file, player, game_state):
        self._game_state = game_state
        self._score = 0
        self.image = map_loader.make_map(level_file)
        self.rect = self.image.get_rect()
        self._groups = {
            'all': pg.sprite.LayeredUpdates(),
            'tanks': pg.sprite.Group(),
            'damageable': pg.sprite.Group(),
            'bullets': pg.sprite.Group(),
            'obstacles': pg.sprite.Group(),
            'items': pg.sprite.Group(),
            'item_boxes': pg.sprite.Group()
        }
        self._ai_mobs = []
        map_loader.init_sprites(self._groups, player, self._ai_mobs)
        self._player = player

        self._camera = Camera(player, self.rect.width, self.rect.height)
        player.camera = self._camera

        # Top/Bottom boundaries.
        BoundaryWall(0, 0, self.rect.width, 1, self._groups)
        BoundaryWall(0, self.rect.height, self.rect.width, 1, self._groups)
        # Left/Right boundaries.
        BoundaryWall(0, 0, 1, self.rect.height, self._groups)
        BoundaryWall(self.rect.width, 0, 1, self.rect.height, self._groups)

        self._item_timer = Timer()
        self.level_music = None
Пример #3
0
 def __init__(self, x, y, dir, type, color, id, groups):
     self._layer = cfg.ITEM_LAYER
     SpriteW.__init__(self, x, y, _IMAGES[type][color],
                      (groups['all'], groups['bullets']))
     Movable.__init__(self, x, y)
     self.rotate_image(dir - Bullet.IMAGE_ROT)
     # Rotatable.rotate_image(self, self.image, dir - Bullet.IMAGE_ROT)
     self.hit_rect = self.rect
     self._damage = _STATS[type]["damage"]
     self.vel = cfg.Vec2(_STATS[type]["speed"], 0).rotate(-dir)
     self._lifetime = _STATS[type]["lifetime"]
     self._spawn_timer = Timer()
     self.id = id
Пример #4
0
 def __init__(self, x, y, img, groups):
     self._layer = cfg.TANK_LAYER
     SpriteW.__init__(
         self, x, y, img,
         (groups['all'], groups['tanks'], groups['damageable']))
     MovableNonlinear.__init__(self, x, y)
     Rotatable.__init__(self)
     Damageable.__init__(self, self.hit_rect)
     self.groups = groups
     self.MAX_ACCELERATION = 768
     self._barrels = []
     self._items = []
     self.hit_rect.center = self.pos
     self._track_timer = Timer()
Пример #5
0
class Bullet(SpriteW, Movable):
    IMAGE_ROT = 90

    def __init__(self, x, y, dir, type, color, id, groups):
        self._layer = cfg.ITEM_LAYER
        SpriteW.__init__(self, x, y, _IMAGES[type][color],
                         (groups['all'], groups['bullets']))
        Movable.__init__(self, x, y)
        self.rotate_image(dir - Bullet.IMAGE_ROT)
        # Rotatable.rotate_image(self, self.image, dir - Bullet.IMAGE_ROT)
        self.hit_rect = self.rect
        self._damage = _STATS[type]["damage"]
        self.vel = cfg.Vec2(_STATS[type]["speed"], 0).rotate(-dir)
        self._lifetime = _STATS[type]["lifetime"]
        self._spawn_timer = Timer()
        self.id = id

    @classmethod
    def range(self, type):
        return _STATS[type]["speed"] * (_STATS[type]["lifetime"] / 1000)

    @property
    def damage(self):
        return self._damage

    def update(self, dt):
        if self._spawn_timer.elapsed_time() > self._lifetime:
            self.kill()
        else:
            self.move(dt)
Пример #6
0
    def __init__(self, color, type, parent, offset, image, groups):
        self._layer = cfg.BARREL_LAYER
        SpriteW.__init__(self, *parent.rect.center, image, (groups['all'], ))
        Rotatable.__init__(self)
        self.groups = groups

        # Bullet parameters.
        self._type = type
        self._color = color
        self._ammo_count = _STATS[self._type]["max_ammo"]

        # Parameters used for position.
        self._parent = parent
        self._offset = offset

        self._fire_delay = _STATS[self._type]["fire_delay"]
        self._fire_timer = Timer()
        self._fire_sfx = sfx_loader.get_sfx(Barrel._FIRE_SFX)
Пример #7
0
class DurationItem(Item):
    def __init__(self, x, y, duration, image, sound, groups):
        Item.__init__(self, x, y, image, sound, groups)
        self._effect_timer = Timer()
        self._item_duration = duration
        self._tank = None

    def apply_effect(self, tank):
        self._effect_timer.restart()
        self._tank = tank
        super().kill()

    def effect_subsided(self):
        if self._effect_timer.elapsed_time() > self._item_duration:
            self._remove_effect()
            return True
        return False

    def _remove_effect(self):
        pass
Пример #8
0
 def pause(self):
     if self._paused:
         self._game.ui.pop_menu()
         Timer.unpause_timers()
     else:
         actions = [{
             'action': self.pause,
             'text': 'Resume'
         }, {
             'action': self.create_level,
             'text': 'Restart'
         }, {
             'action':
             lambda: self._game.set_state(GameNotPlayingState),
             'text':
             'Main Menu'
         }]
         self._game.ui.make_menu("Game Paused", actions, 24, cfg.WHITE)
         Timer.pause_timers()
     self._paused = not self._paused
Пример #9
0
class MuzzleFlash(SpriteW):
    IMG_ROT = -90
    FLASH_DURATION = 25
    IMAGE = 'shotLarge.png'

    def __init__(self, x, y, rot, groups):
        self._layer = cfg.EFFECTS_LAYER
        SpriteW.__init__(self, x, y, MuzzleFlash.IMAGE, groups['all'])
        self.rotate_image(rot - MuzzleFlash.IMG_ROT)
        # Rotatable.rotate_image(self, self.image, rot - MuzzleFlash.IMG_ROT)
        self._spawn_timer = Timer()

    def update(self, dt):
        if self._spawn_timer.elapsed_time() > MuzzleFlash.FLASH_DURATION:
            self.kill()
Пример #10
0
class AITankState:
    WALL_AVOID_DURATION = 1000
    WALL_TURN_ANGLE = 15
    _crash_timer = Timer()
    def __init__(self, ai):
        self._ai = ai
        # self._crash_time = -math.inf

    def check_for_walls(self):
        if self._ai.tank.collided_with_wall():
            # self._crash_time = pg.time.get_ticks()
            AITankState._crash_timer.restart()
            self._ai.rotate_to(self._ai.tank.rot + AITankState.WALL_TURN_ANGLE)

    def is_avoiding_wall(self):
        # return cfg.time_since(self._crash_time) < AITankState.WALL_AVOID_DURATION
        return AITankState._crash_timer.elapsed_time() < AITankState.WALL_AVOID_DURATION
Пример #11
0
 def __init__(self, x, y, duration, image, sound, groups):
     Item.__init__(self, x, y, image, sound, groups)
     self._effect_timer = Timer()
     self._item_duration = duration
     self._tank = None
Пример #12
0
class Level:
    MAX_ITEMS = 1
    ITEM_RESPAWN_TIME = 5000

    def __init__(self, level_file, player, game_state):
        self._game_state = game_state
        self._score = 0
        self.image = map_loader.make_map(level_file)
        self.rect = self.image.get_rect()
        self._groups = {
            'all': pg.sprite.LayeredUpdates(),
            'tanks': pg.sprite.Group(),
            'damageable': pg.sprite.Group(),
            'bullets': pg.sprite.Group(),
            'obstacles': pg.sprite.Group(),
            'items': pg.sprite.Group(),
            'item_boxes': pg.sprite.Group()
        }
        self._ai_mobs = []
        map_loader.init_sprites(self._groups, player, self._ai_mobs)
        self._player = player

        self._camera = Camera(player, self.rect.width, self.rect.height)
        player.camera = self._camera

        # Top/Bottom boundaries.
        BoundaryWall(0, 0, self.rect.width, 1, self._groups)
        BoundaryWall(0, self.rect.height, self.rect.width, 1, self._groups)
        # Left/Right boundaries.
        BoundaryWall(0, 0, 1, self.rect.height, self._groups)
        BoundaryWall(self.rect.width, 0, 1, self.rect.height, self._groups)

        self._item_timer = Timer()
        self.level_music = None

    def _can_spawn_item(self):
        return self._item_timer.elapsed_time() > Level.ITEM_RESPAWN_TIME

    def update(self, dt):
        for ai in self._ai_mobs:
            ai.update(dt)
        self._groups['all'].update(dt)
        # Update list of ai mobs.
        self._camera.update()

        # Handle damage-causing bullets.
        hits = pg.sprite.groupcollide(self._groups['damageable'],
                                      self._groups['bullets'], False, True,
                                      bullet_collide_id)

        for sprite, bullets in hits.items():
            for bullet in bullets:
                Explosion(bullet.pos.x, bullet.pos.y, self._groups)
                sprite.damage(bullet.damage)
                if sprite.health <= 0:
                    sprite.kill()
                    if not self._player.alive():
                        self._game_state.game_over()
                    else:
                        self._ai_mobs = [
                            ai for ai in self._ai_mobs if ai.alive()
                        ]
                        if len(self._ai_mobs) == 0:
                            self._game_state.game_over()
                    break

        # Handle bullets that destroy item boxes.
        for box in self._groups['item_boxes']:
            if not box.is_broken():
                for bullet in self._groups['bullets']:
                    if collide_hit_rect(box, bullet):
                        bullet.kill()
                        box.wear_out()
                        if box.is_broken():
                            self._item_timer.restart()
                            break

        # See if it's time to spawn a new item.
        if len(self._groups['item_boxes']
               ) < Level.MAX_ITEMS and self._can_spawn_item():
            spawn_box(self._groups)

        # Handle bullets that hit other obstacles.
        hits = pg.sprite.groupcollide(self._groups['bullets'],
                                      self._groups['obstacles'], True, False,
                                      bullet_collide_id)

        # Handle item pick-up.
        hits = pg.sprite.groupcollide(self._groups['tanks'],
                                      self._groups['items'], False, False)
        for tank, items in hits.items():
            for item in items:
                tank.pickup(item)
                # item.apply_effect(tank)

        # Tank/tank collision.
        all_tanks = list(self._groups['tanks'])
        for i in range(0, len(all_tanks)):
            tank_a = all_tanks[i]
            for tank_b in all_tanks[i + 1:]:
                if collide_hit_rect(tank_a, tank_b):
                    knockback_dir = tank_b.rot
                    tank_a.vel += vec(tank_b.KNOCKBACK,
                                      0).rotate(knockback_dir)
                    tank_b.vel -= vec(tank_b.KNOCKBACK,
                                      0).rotate(knockback_dir)

    def draw(self, screen):
        screen.blit(self.image, self._camera.apply(self.rect))
        # self._groups['all'].draw(screen)
        for sprite in self._groups['all']:
            screen.blit(sprite.image, self._camera.apply(sprite.rect))
            # pg.draw.rect(screen, (255, 255, 255), self._camera.apply(sprite.hit_rect), 1)
        for ai in self._ai_mobs:
            ai.draw_health(screen, self._camera)
        self._player.draw_hud(screen, self._camera)
Пример #13
0
 def fire(self):
     ammo = self._tank.get_ammo_count()
     if ammo > 0:
         if ammo == 1:
             self._ammo_timer = Timer()
         self._tank.fire()
Пример #14
0
class Tank(SpriteW, MovableNonlinear, Rotatable, Damageable):
    KNOCKBACK = 100

    _SPEED_CUTOFF = 100
    _TRACK_DELAY = 100

    def __init__(self, x, y, img, groups):
        self._layer = cfg.TANK_LAYER
        SpriteW.__init__(
            self, x, y, img,
            (groups['all'], groups['tanks'], groups['damageable']))
        MovableNonlinear.__init__(self, x, y)
        Rotatable.__init__(self)
        Damageable.__init__(self, self.hit_rect)
        self.groups = groups
        self.MAX_ACCELERATION = 768
        self._barrels = []
        self._items = []
        self.hit_rect.center = self.pos
        self._track_timer = Timer()

    def update(self, dt):
        self.rotate(dt)
        self.move(self.groups['obstacles'], dt)
        for item in self._items:
            if item.effect_subsided():
                self._items.remove(item)
        can_spawn_track = self._track_timer.elapsed_time() > Tank._TRACK_DELAY
        if self.vel.length_squared() > Tank._SPEED_CUTOFF and can_spawn_track:
            self._spawn_tracks()

    @property
    def range(self):
        return self._barrels[0].range

    def pickup(self, item):
        item.apply_effect(self)
        if item.DURATION > 0:
            self._items.append(item)

    def equip_barrel(self, barrel):
        barrel.id = self.id
        self._barrels.append(barrel)

    def _spawn_tracks(self):
        Tracks(*self.pos, self.hit_rect.height, self.hit_rect.height, self.rot,
               self.groups)
        self._track_timer.restart()

    def rotate_barrel(self, dir):
        # pass
        for barrel in self._barrels:
            barrel.rot = dir
            barrel.rotate()

    def get_ammo_count(self):
        return self._barrels[0].get_ammo_count()

    def fire(self):
        for barrel in self._barrels:
            barrel.fire()

    def attempt_reload(self):
        if self._barrels[0].can_reload():
            self.reload()

    def reload(self):
        for barrel in self._barrels:
            barrel.reload()

    def kill(self):
        for barrel in self._barrels:
            barrel.kill()
        super().kill()
Пример #15
0
class Barrel(SpriteW, Rotatable):
    _FIRE_SFX = 'shoot.wav'

    def __init__(self, color, type, parent, offset, image, groups):
        self._layer = cfg.BARREL_LAYER
        SpriteW.__init__(self, *parent.rect.center, image, (groups['all'], ))
        Rotatable.__init__(self)
        self.groups = groups

        # Bullet parameters.
        self._type = type
        self._color = color
        self._ammo_count = _STATS[self._type]["max_ammo"]

        # Parameters used for position.
        self._parent = parent
        self._offset = offset

        self._fire_delay = _STATS[self._type]["fire_delay"]
        self._fire_timer = Timer()
        self._fire_sfx = sfx_loader.get_sfx(Barrel._FIRE_SFX)

    def update(self, dt):
        self.rect.center = cfg.Vec2(*self._parent.rect.center) + \
                                    self._offset.rotate(-self.rot)

    @property
    def range(self):
        return Bullet.range(self._type)

    @property
    def fire_delay(self):
        return self._fire_delay

    @fire_delay.setter
    def fire_delay(self, new_fire_delay):
        self._fire_delay = new_fire_delay

    def fire(self):
        if self._fire_timer.elapsed_time() > self._fire_delay:
            self._fire_timer.restart()
            self._spawn_bullet()
            self._fire_sfx.play()

    def _spawn_bullet(self):
        fire_pos = cfg.Vec2(*self.rect.center) + \
                            cfg.Vec2(self.hit_rect.height, 0).rotate(-self.rot)
        Bullet(*fire_pos, self.rot, self._type, self._color, self.id,
               self.groups)
        MuzzleFlash(*fire_pos, self.rot, self.groups)
        self._ammo_count -= 1

    def can_reload(self):
        return self._ammo_count == 0 and self._fire_timer.elapsed_time(
        ) > RELOAD_DURATION

    def get_ammo_count(self):
        return self._ammo_count

    def reload(self):
        self._ammo_count = _STATS[self._type]["max_ammo"]

    def kill(self):
        self._parent = None
        super().kill()
Пример #16
0
 def __init__(self, x, y, rot, groups):
     self._layer = cfg.EFFECTS_LAYER
     SpriteW.__init__(self, x, y, MuzzleFlash.IMAGE, groups['all'])
     self.rotate_image(rot - MuzzleFlash.IMG_ROT)
     # Rotatable.rotate_image(self, self.image, rot - MuzzleFlash.IMG_ROT)
     self._spawn_timer = Timer()
Пример #17
0
class GamePlayingState:
    def __init__(self, game):
        self._game = game
        self._paused = False
        self._game_over = False

    def enter(self):
        self.create_level()

    def create_level(self):
        """ Creates a new player and restarts level sprites. """
        self._paused = False
        self._game.ui.clear()
        self._player = PlayerCtrl()
        self._level = Level('level_1.tmx', self._player, self)
        self._timer = Timer()

    def exit(self):
        # Save score or something
        self._game.ui.clear()

    def process_events(self, event):
        if not self._game_over:
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_p:
                    self.pause()

    def pause(self):
        if self._paused:
            self._game.ui.pop_menu()
            Timer.unpause_timers()
        else:
            actions = [{
                'action': self.pause,
                'text': 'Resume'
            }, {
                'action': self.create_level,
                'text': 'Restart'
            }, {
                'action':
                lambda: self._game.set_state(GameNotPlayingState),
                'text':
                'Main Menu'
            }]
            self._game.ui.make_menu("Game Paused", actions, 24, cfg.WHITE)
            Timer.pause_timers()
        self._paused = not self._paused

    def game_over(self):
        actions = [{
            'action': lambda: self._game.set_state(GamePlayingState),
            'text': 'Play Again'
        }, {
            'action': lambda: self._game.set_state(GameNotPlayingState),
            'text': 'Main Menu'
        }, {
            'action': self._game.quit,
            'text': 'Quit'
        }]
        if self._player.alive():
            title = "You win!"
        else:
            title = "Game Over!"
        self._game.ui.make_menu(title, actions, 24, cfg.WHITE)
        self._timer.pause()
        self._game_over = True

    def handle_input(self, active_bindings, mouse_state, mouse_x, mouse_y):
        if not (self._paused or self._game_over):
            self._player.handle_keys(active_bindings)
            self._player.handle_mouse(mouse_state, mouse_x, mouse_y)

    def update(self, dt):
        if not self._paused:
            self._level.update(dt)

    def draw(self):
        self._level.draw(self._game.screen)
        self._game.ui.draw(self._game.screen)
        total_secs = self._timer.elapsed_time() // 1000
        mins = total_secs // 60
        secs = total_secs % 60
        gtext.render(self._game.screen,
                     f"{mins:02d}:{secs:02d}",
                     24,
                     cfg.WHITE,
                     location='n')