Ejemplo n.º 1
0
class Level(GameState):
    """Level is a GameState with behavior for one full game level.

    Contains Sprites player, enemy, shield, hbullet, cannon, and Group player_bullets
    """
    def __init__(self, manager):
        """manager is required to be a child of GameManager with these functions:
        -kill_player()
        -next_level()
        -add_score(amount)
        -give_energy(amount)
        -spend_energy(amount)
        -give_life()
        """

        GameState.__init__(self, manager)

        self.player = Ship(*opt.player_args)
        self.enemy = EnemyBase(opt.mover_args, opt.spinner_args,
                               opt.shooter_args, self.player)
        self.shield = EnemyShield(self.enemy, opt.shield_filename, formation,
                                  formation_center)
        self.hbullet = HomingBullet(opt.homer_filename, self.player,
                                    opt.homer_speed)
        self.cannon = Cannon(opt.deactivated_cannon_args,
                             opt.standby_cannon_args, opt.firing_cannon_args,
                             self.player)
        self.ion_field = IonField(*opt.ion_field_args)
        self.player_bullets = Group()

        self.reset_positions()

    def update(self):
        self.player.update()
        self.enemy.update()
        self.shield.update()
        self.hbullet.update()
        self.cannon.update()
        self.player_bullets.update()
        self.ion_field.update()

        self.collisions()

    def handle_events(self, events, keys):
        return (event_handlers.check_quit(events, keys)
                and event_handlers.check_shoot_button(events, keys, self.shoot)
                and event_handlers.move_player(events, keys, self.player))

    def draw(self, screen):
        self.ion_field.draw(screen)
        self.enemy.draw(screen)
        self.shield.draw(screen)
        self.player.draw(screen)
        self.hbullet.draw(screen)
        self.cannon.draw(screen)
        self.player_bullets.draw(screen)

    def collisions(self):
        """Handles collisions
        """

        player = self.player
        enemy = self.enemy
        shield = self.shield
        hbullet = self.hbullet
        cannon = self.cannon
        ion_field = self.ion_field
        player_bullets = self.player_bullets

        #player with homing bullet
        if collide_mask(player,
                        hbullet) and not collide_mask(player, ion_field):
            self.kill_player()

        #player with enemy base
        if collide_mask(player, enemy):
            #if base in moving phase, give player energy
            if enemy.get_state_number() == EnemyBase.MOVING:
                self.manager.give_energy(opt.energy_from_enemy)
            #if base in spinning or shooting phase, kill player
            elif enemy.get_state_number() == EnemyBase.SPINNING:
                self.kill_player()
            elif enemy.get_state_number() == EnemyBase.SHOOTING:
                self.kill_player()

        #player with cell
        #-hitting a cell will bounce the player a bit to the left
        #-if the player hit the cell twice in a short enough span,
        # the cell is eaten and the player gets energy
        #-in case of multiple collisions, deal with cell closest to player's center
        #
        #TODO: This still isn't quite right.
        #Should be able to eat top/bottom rows with diagonal movement.
        #(vertical movement should still move player all the way left)
        pc_collides = spritecollide(player, shield, False, collide_mask)
        center_cell = self.find_centermost_cell(pc_collides)
        if center_cell is not None:
            player.rect.right = center_cell.rect.left - opt.cell_bounceback

            if not center_cell.marked:
                center_cell.mark()
            elif shield.can_eat():
                center_cell.kill()
                self.manager.give_energy(opt.energy_from_cell)
                self.manager.add_score(opt.score_cell_eat)
                shield.start_delay(opt.frames_to_eat_cell)

        #player with cannon
        if collide_mask(player, cannon):
            #if in deactivated phase, try spending required energy to activate
            if (cannon.get_state_number() == Cannon.DEACTIVATED
                    and self.manager.spend_energy(opt.cannon_energy_cost)):
                cannon.start_standby()
            #if in firing phase, kill player
            if cannon.get_state_number() == Cannon.FIRING:
                self.kill_player()
            #if in returning phase, give energy and deactivate cannon
            if cannon.get_state_number() == Cannon.RETURNING:
                cannon.start_transition(Cannon.DEACTIVATED)
                self.manager.give_energy(opt.energy_from_cannon)

        #cannon with cell
        #kill one cell and reverse cannon direction
        #assuming this is only possible if cannon in firing state
        if cannon.get_state_number() == Cannon.FIRING:
            cannon_collides = spritecollide(cannon, shield, False,
                                            collide_mask)
            if len(cannon_collides) > 0:
                cannon_collides[0].kill()
                self.manager.add_score(opt.score_cell_shoot)
                cannon.start_transition(Cannon.RETURNING)

        #cannon with enemy base -- only if cannon in firing state
        #give points corresponding to enemy state and end level
        #if enemy base is in shooting state, player also gets a life
        if cannon.get_state_number() == Cannon.FIRING and collide_mask(
                cannon, enemy):
            if enemy.get_state_number() == EnemyBase.MOVING:
                self.manager.add_score(opt.score_mover_destroy)
            elif enemy.get_state_number() == EnemyBase.SPINNING:
                self.manager.add_score(opt.score_spinner_destroy)
            elif enemy.get_state_number() == EnemyBase.SHOOTING:
                self.manager.add_score(opt.score_shooter_destroy)
                self.manager.give_life()
            self.end_level()

        #player's bullet with cell
        #kill player bullet but remove cells in a cross pattern
        #if somehow one bullet hits multiple cells one is arbitrarily selected
        bc_collides = groupcollide(player_bullets, shield, True, False,
                                   collide_mask)
        for current_bullet in bc_collides.keys():
            self.manager.add_score(opt.score_cell_shoot)
            shield.remove_cross(bc_collides[current_bullet][0])

    def find_centermost_cell(self, cells):
        """Given a list of Cell sprites, 
        returns the one whose rect.centery is closest to the player's rect.centery
        
        Returns None if list is empty
        """

        closest_cell = None

        for current_cell in cells:
            current_dist = abs(current_cell.rect.centery -
                               self.player.rect.centery)
            if closest_cell is None or current_dist < closest_dist:
                closest_cell = current_cell
                closest_dist = current_dist

        return closest_cell

    def shoot(self):
        """If cannon can be fired, fires cannon.
        
        Otherwise creates bullet moving from player's center along player's direction
        as long as options.max_player_bullets won't be exeeded
        """

        if collide_mask(self.player, self.ion_field):
            return

        if self.cannon.start_transition(Cannon.FIRING):
            return

        if len(self.player_bullets) < opt.max_player_bullets:
            new_bullet = Bullet(opt.bullet_filename, opt.bullet_speed,
                                self.player.get_rect().center,
                                self.player.get_direction())
            self.player_bullets.add(new_bullet)

    def reset_positions(self):
        """Moves sprites to their initial locations:
        player starts in left center facing south and with 0 energy
        player bullets are removed
        enemy bullet starts on enemy base
        enemy base is in moving state
        cannon is in deactivated state

        Note: shield configuration is not reset
        """

        self.player.rect.midleft = (20, int(opt.height / 2))
        self.player.set_direction(vector.SOUTH)
        self.player_bullets.empty()
        self.enemy.resume_mover_state()
        self.cannon.start_deactivated()
        self.hbullet.rect.center = self.enemy.rect.center

    def kill_player(self):
        death_animation = DeathAnimation(self.manager, self.player,
                                         (self.enemy, self.shield), self,
                                         opt.death_animation_delay,
                                         opt.death_animation_total_runtime)
        self.manager.change_state(death_animation)

    def end_level(self):
        win_animation = WinAnimation(self.manager, self.player,
                                     opt.win_animation_total_runtime,
                                     opt.exp_field_args)
        self.manager.change_state(win_animation)
Ejemplo n.º 2
0
def main():

    fps = 30
    clock = pygame.time.Clock()

    screen = pygame.display.set_mode((config.WIDTH, config.HEIGHT))

    pygame.font.init()
    font = pygame.font.Font("DejaVuSans.ttf", 24)

    if TYPE == 'HOST':
        s, game_map, conn = hostOptions(screen, font)
    elif TYPE == 'JOIN':
        s, game_map = joinOptions(screen, font)
    else:
        textOnMiddle(screen, 'Generating map...', font)
        pygame.display.flip()
        game_map = GameMap().generate(config.WIDTH, config.HEIGHT, 2500)

    #icon = pygame.image.load("pygame-icon.png")
    #icon = icon.convert_alpha()
    #icon_w, icon_h = icon.get_size()

    shooting_force = -1

    bullets = []

    cannon1 = Cannon(screen, game_map, 100, (0, 255, 0), 0)
    cannon2 = Cannon(screen, game_map, config.WIDTH - 100, (255, 0, 0), 180)

    gameEnded = False

    while True:

        msg = {"cannon": {}}
        recv_msg = {}

        shooting_force, quitGame = getInputEvents(screen, cannon1, cannon2,
                                                  bullets, game_map,
                                                  shooting_force, msg)

        if quitGame:
            if TYPE == 'HOST':
                conn.close()

            if TYPE == 'JOIN' or TYPE == 'HOST':
                print('Closing Server...')
                return s

            return

        ping = time.time()
        if TYPE == 'HOST':
            try:
                conn.send(encodeDict(msg))
                recv_msg = conn.recv(1024)
                recv_msg = decodeDict(recv_msg)
            except ConnectionResetError:
                print('Connection closed by client')
                conn.close()
                return s
            except json.decoder.JSONDecodeError:
                print('Connection closed by client')
                conn.close()
                return s

        elif TYPE == 'JOIN':
            try:
                recv_msg = s.recv(1024)
                s.send(encodeDict(msg))
                recv_msg = decodeDict(recv_msg)
            except json.decoder.JSONDecodeError:
                print('Connection closed by host')
                return s
            except ConnectionResetError:
                print('Connection closed by host')
                return s

        if 'shoot' in recv_msg:
            if TYPE == 'JOIN':
                rot = cannon1.rot
                center = cannon1.base.rect.center
            else:
                rot = cannon2.rot
                center = cannon2.base.rect.center

            bullets.append(
                Bullet(screen, game_map, center[0], center[1],
                       recv_msg['shoot']['shooting_force'], rot))

        if 'cannon' in recv_msg:
            if 'rotation' in recv_msg['cannon']:
                rotation = recv_msg['cannon']['rotation']
                if TYPE == 'JOIN':
                    cannon1.rotating = rotation
                if TYPE == 'HOST':
                    cannon2.rotating = rotation

        ping = time.time() - ping

        #reset drawing
        screen.fill((0, 0, 0))

        #draw background
        game_map.printBackground(screen)

        #draw top info
        text = font.render('10uv >>', True, (255, 255, 255))
        fps_text = font.render(
            str(round(clock.get_fps(), 2)) + ' fps', True, (255, 255, 255))
        ping_text = font.render('ping ' + str(int(ping * 1000)) + 'ms', True,
                                (255, 255, 255))
        text_w, text_h = fps_text.get_size()
        ping_text_w, _ = ping_text.get_size()
        screen.blit(text, (0, 0))
        screen.blit(fps_text, (config.WIDTH - text_w, 0))
        screen.blit(ping_text, (config.WIDTH - ping_text_w, text_h))

        #draw map ground
        game_map.printGround(screen)

        #draw shoot bar
        if shooting_force != -1:
            if shooting_force < 50:
                shooting_force += 1

            hud.drawShootForce(screen, shooting_force)

        #draw shoot bar ruler
        hud.drawShootForceRuler(screen)

        #update and draw bullets
        for bullet in bullets[:]:
            if not bullet.update():
                if bullet.collide:
                    x = int(bullet.x)
                    collision_range = range(x - 15, x + 15)
                    for i in collision_range:  #TODO: send this to game map
                        if len(game_map.map_curve) > i >= 0:
                            game_map.map_curve[i] += 10

                    if not cannon1.isAlive(collision_range):
                        winnerText = font.render('Cannon 2 won.', True,
                                                 (255, 255, 255))
                        gameEnded = True
                        break
                    if not cannon2.isAlive(collision_range):
                        winnerText = font.render('Cannon 1 won.', True,
                                                 (255, 255, 255))
                        gameEnded = True
                        break

                bullets.remove(bullet)
                del bullet
            else:
                bullet.draw()

        #update and draw cannons
        cannon1.update()
        cannon1.draw(screen)
        cannon2.update()
        cannon2.draw(screen)

        if gameEnded:
            while len(bullets) > 0:
                bullets.pop()
            winnerText_w, winnerText_h = winnerText.get_size()
            screen.blit(winnerText, (config.WIDTH / 2 - winnerText_w / 2,
                                     config.HEIGHT / 2 - winnerText_h / 2))

        #end drawing
        pygame.display.flip()

        clock.tick(fps)
Ejemplo n.º 3
0
class Level(GameState):
    """Level is a GameState with behavior for one full game level.

    Contains Sprites player, enemy, shield, hbullet, cannon, and Group player_bullets
    """
    
    def __init__(self, manager):
        """manager is required to be a child of GameManager with these functions:
        -kill_player()
        -next_level()
        -add_score(amount)
        -give_energy(amount)
        -spend_energy(amount)
        -give_life()
        """

        GameState.__init__(self, manager)

        self.player = Ship(*opt.player_args)
        self.enemy = EnemyBase(opt.mover_args, opt.spinner_args, opt.shooter_args, self.player)
        self.shield = EnemyShield(self.enemy, opt.shield_filename, formation, formation_center)
        self.hbullet = HomingBullet(opt.homer_filename, self.player, opt.homer_speed)
        self.cannon = Cannon(opt.deactivated_cannon_args, opt.standby_cannon_args,
                             opt.firing_cannon_args, self.player)
        self.ion_field = IonField(*opt.ion_field_args)
        self.player_bullets = Group()

        self.reset_positions()
        

    def update(self):
        self.player.update()
        self.enemy.update()
        self.shield.update()
        self.hbullet.update()
        self.cannon.update()
        self.player_bullets.update()
        self.ion_field.update()
        
        self.collisions()


    def handle_events(self, events, keys):
        return (event_handlers.check_quit(events, keys) and
                event_handlers.check_shoot_button(events, keys, self.shoot) and
                event_handlers.move_player(events, keys, self.player))


    def draw(self, screen):
        self.ion_field.draw(screen)
        self.enemy.draw(screen)
        self.shield.draw(screen)
        self.player.draw(screen)
        self.hbullet.draw(screen)
        self.cannon.draw(screen)
        self.player_bullets.draw(screen)


    def collisions(self):
        """Handles collisions
        """

        player = self.player
        enemy = self.enemy
        shield = self.shield
        hbullet = self.hbullet
        cannon = self.cannon
        ion_field = self.ion_field
        player_bullets = self.player_bullets
        
        #player with homing bullet
        if collide_mask(player, hbullet) and not collide_mask(player, ion_field):
            self.kill_player()
        
        #player with enemy base
        if collide_mask(player, enemy):
            #if base in moving phase, give player energy
            if enemy.get_state_number() == EnemyBase.MOVING:
                self.manager.give_energy(opt.energy_from_enemy)
            #if base in spinning or shooting phase, kill player
            elif enemy.get_state_number() == EnemyBase.SPINNING:
                self.kill_player()
            elif enemy.get_state_number() == EnemyBase.SHOOTING:
                self.kill_player()
                
        #player with cell
        #-hitting a cell will bounce the player a bit to the left
        #-if the player hit the cell twice in a short enough span,
        # the cell is eaten and the player gets energy
        #-in case of multiple collisions, deal with cell closest to player's center
        #
        #TODO: This still isn't quite right.
        #Should be able to eat top/bottom rows with diagonal movement.
        #(vertical movement should still move player all the way left)
        pc_collides = spritecollide(player, shield, False, collide_mask)
        center_cell = self.find_centermost_cell(pc_collides)
        if center_cell is not None:
            player.rect.right = center_cell.rect.left - opt.cell_bounceback
            
            if not center_cell.marked:
                center_cell.mark()
            elif shield.can_eat():
                center_cell.kill()
                self.manager.give_energy(opt.energy_from_cell)
                self.manager.add_score(opt.score_cell_eat)
                shield.start_delay(opt.frames_to_eat_cell)
            
        #player with cannon
        if collide_mask(player, cannon):
            #if in deactivated phase, try spending required energy to activate
            if (cannon.get_state_number() == Cannon.DEACTIVATED and 
                self.manager.spend_energy(opt.cannon_energy_cost)):
                cannon.start_standby()
            #if in firing phase, kill player
            if cannon.get_state_number() == Cannon.FIRING:
                self.kill_player()
            #if in returning phase, give energy and deactivate cannon
            if cannon.get_state_number() == Cannon.RETURNING:
                cannon.start_transition(Cannon.DEACTIVATED)
                self.manager.give_energy(opt.energy_from_cannon)
                
        #cannon with cell
        #kill one cell and reverse cannon direction
        #assuming this is only possible if cannon in firing state
        if cannon.get_state_number() == Cannon.FIRING:
            cannon_collides = spritecollide(cannon, shield, False, collide_mask)
            if len(cannon_collides) > 0:
                cannon_collides[0].kill()
                self.manager.add_score(opt.score_cell_shoot)
                cannon.start_transition(Cannon.RETURNING)
            
        #cannon with enemy base -- only if cannon in firing state
        #give points corresponding to enemy state and end level
        #if enemy base is in shooting state, player also gets a life
        if cannon.get_state_number() == Cannon.FIRING and collide_mask(cannon, enemy):
            if enemy.get_state_number() == EnemyBase.MOVING:
                self.manager.add_score(opt.score_mover_destroy)
            elif enemy.get_state_number() == EnemyBase.SPINNING:
                self.manager.add_score(opt.score_spinner_destroy)
            elif enemy.get_state_number() == EnemyBase.SHOOTING:
                self.manager.add_score(opt.score_shooter_destroy)
                self.manager.give_life()
            self.end_level()
        
        #player's bullet with cell
        #kill player bullet but remove cells in a cross pattern
        #if somehow one bullet hits multiple cells one is arbitrarily selected
        bc_collides = groupcollide(player_bullets, shield, True, False, collide_mask)
        for current_bullet in bc_collides.keys():
            self.manager.add_score(opt.score_cell_shoot)
            shield.remove_cross(bc_collides[current_bullet][0])


    def find_centermost_cell(self, cells):
        """Given a list of Cell sprites, 
        returns the one whose rect.centery is closest to the player's rect.centery
        
        Returns None if list is empty
        """
        
        closest_cell = None
        
        for current_cell in cells:
            current_dist = abs(current_cell.rect.centery - self.player.rect.centery)
            if closest_cell is None or current_dist < closest_dist:
                closest_cell = current_cell
                closest_dist = current_dist

        return closest_cell


    def shoot(self):
        """If cannon can be fired, fires cannon.
        
        Otherwise creates bullet moving from player's center along player's direction
        as long as options.max_player_bullets won't be exeeded
        """
        
        if collide_mask(self.player, self.ion_field):
            return

        if self.cannon.start_transition(Cannon.FIRING):
            return        
        
        if len(self.player_bullets) < opt.max_player_bullets:
            new_bullet = Bullet(opt.bullet_filename, opt.bullet_speed, 
                                self.player.get_rect().center, self.player.get_direction())
            self.player_bullets.add(new_bullet)


    def reset_positions(self):
        """Moves sprites to their initial locations:
        player starts in left center facing south and with 0 energy
        player bullets are removed
        enemy bullet starts on enemy base
        enemy base is in moving state
        cannon is in deactivated state

        Note: shield configuration is not reset
        """

        self.player.rect.midleft = (20, int(opt.height/2))
        self.player.set_direction(vector.SOUTH)
        self.player_bullets.empty()
        self.enemy.resume_mover_state()
        self.cannon.start_deactivated()
        self.hbullet.rect.center = self.enemy.rect.center


    def kill_player(self):
        death_animation = DeathAnimation(self.manager, self.player, (self.enemy, self.shield), self,
                opt.death_animation_delay, opt.death_animation_total_runtime)
        self.manager.change_state(death_animation)


    def end_level(self):
        win_animation = WinAnimation(self.manager, self.player, opt.win_animation_total_runtime, opt.exp_field_args)
        self.manager.change_state(win_animation)