示例#1
0
class TwoWayImage(pygame.sprite.Sprite):
    """Sprite which moves in two directions and loops; used to make background/foreground."""

    def __init__(self, speed, image_dir, rearrange_coeff, image_type):

        super(TwoWayImage, self).__init__()

        self.speed = speed
        self.image_dir = image_dir

        # Total number of images; multiplied for rearrange offset
        self.rearrange_coeff = rearrange_coeff
        self.image_type = image_type

        if self.image_type == "foreground":
            self.image = cache_image.get(self.image_dir, convert_alpha=False)
        else:
            self.image = cache_image.get(self.image_dir)
        self.rect = self.image.get_rect()

        self.alpha_timer = Timer()
        self.alpha = 255
        self.is_dying = False,

        if self.image_type == "foreground":
            self.hitmask = pygame.mask.from_surface(self.image)

    def rearrange(self):
        """Reset the sprite if it goes offscreen."""

        # If screen_width isn't divisible by speed, the offset will vary:
        natural_offset = self.rect.x + SCREEN_WIDTH
        self.rect.x = (self.rearrange_coeff * SCREEN_WIDTH) + natural_offset

    def kill(self):
        """Remove foreground terrain for boss battles by fading its alpha."""

        if self.alpha_timer.elapsed_time() > 60:
            self.alpha -= 3
            self.image.set_alpha(self.alpha)
            self.alpha_timer.reset()

    def update(self):
        """Update image movement, rearranging or killing alpha as necessary."""

        if self.alpha <= 0:
            all_sprites_list.remove(self)
            if self.image_type == "foreground":
                foreground_list.remove(self)

        if self.is_dying == True:
            self.kill()

        self.rect.x -= self.speed

        if self.rect.x < (0 - self.rect.width):
            self.rearrange()
示例#2
0
class HeadLaserBeam(pygame.sprite.Sprite):

    def __init__(self, head):

        super(HeadLaserBeam, self).__init__()

        self.head = head # Bad variable name TODO

        self.beam_size_timer = Timer()
        self.beam_height = 1
        self.beam_incrementer = 1

        self.update_beam_image(self.beam_height)
        self.rect.centery = self.head.rect.centery + 10

    def update_beam_height(self):
        """Pulse height, and remove from sprite lists for 1.5 seconds when height=0."""

        max_beam_height = 15
        beam_downtime = 1500 # Time where there is no beam, aka no damage taken by player

        if self.beam_height <= 0:
            enemy_projectile_list.remove(self)

            if self.beam_size_timer.elapsed_time() > beam_downtime:
                enemy_projectile_list.add(self)
                self.beam_height = 1
                self.beam_incrementer = 1

        elif self.beam_size_timer.elapsed_time() > 60:
            enemy_projectile_list.add(self)
            if self.beam_height >= max_beam_height:
                self.beam_incrementer *= -1

            self.beam_height += self.beam_incrementer

            self.beam_size_timer.reset()

    def update_beam_image(self, beam_height):

        self.image = pygame.Surface([640, beam_height])
        self.image.fill(BLUE)
        self.rect = self.image.get_rect()

    def kill(self):

        all_sprites_list.remove(self)
        enemy_projectile_list.remove(self)

    def update(self):

        self.update_beam_height()
        self.update_beam_image(self.beam_height)
        self.rect.centery = self.head.rect.centery + 10
示例#3
0
文件: __init__.py 项目: kalail/Game
class Bot(GameObject):
    """Bot

    Basic tier 1 unit.

    """

    fire_rate = 3.0
    fire_dist = 20
    movement_speed = 60.0 

    def __init__(self, position):
        super(Bot, self).__init__('assets/circle.png', position)
        self._fire_timer = Timer(Bot.fire_rate)

    def _fire(self, position):
        diff_x = position[0] - self.position[0]
        diff_y = position[1] - self.position[1]
        aim = helpers.normalize((diff_x, diff_y))
        l = Bot.fire_dist
        fire_pos = (self.position[0] + aim[0] * l, self.position[1] + aim[1] * l)
        return Pulse(position=fire_pos, direction=aim)
    
    def fire(self, position):
        if self._fire_timer.check():
            self._fire_timer.reset()
            return self._fire(position)
        return []

    def update(self, delta, **kwargs):
        self._fire_timer.update(delta)
        dist = Bot.movement_speed * delta
        self.move(dist, 0)
        targets = [(400, 400), (200, 200), (300, 300)]
        if targets:
            target = random.choice(targets)
            shot = self.fire(target)
        if shot:
            return [shot]
        return []

    def __str__(self):
        return 'Bot'
示例#4
0
class FadeOut(pygame.sprite.Sprite):

    def __init__(self, surface):
        super(FadeOut, self).__init__()

        self.surface = surface

        # Alpha value for transparency:
        self.alpha = 255

        # Incrementer will change the 'direction' and speed of the fade:
        self.alpha_incrementer = -25

        # Inc_delay = frames that pass before next alpha update:
        self.alpha_inc_delay = 60

        # Flag for completion:
        self.is_complete = False

        self.image = pygame.Surface((800, 600))
        self.rect = self.image.get_rect()
        self.image.fill((0, 0, 0))
        self.image.set_alpha(255)

        self.fade_timer = Timer()

    def update(self):

        self.image.set_alpha(self.alpha)
        self.surface.blit(self.image, (0, 0))

        if not self.is_complete:

            if self.alpha < 0:
                self.alpha = 0
                self.is_complete = True

            if self.fade_timer.elapsed_time() > self.alpha_inc_delay:
                self.alpha += self.alpha_incrementer
                self.fade_timer.reset()
示例#5
0
class BossWarning(pygame.sprite.Sprite):
    """Flash a 'WARNING!' message in the center of the SCREEN."""

    def __init__(self, txt_img, xpos_center, ypos_center, kill_time):
        super(BossWarning, self).__init__()

        self.kill_time = kill_time

        self.image = cache_image.get("screen_messages/boss_warning" + "_F1.png")
        self.image.set_colorkey(BLACK)
        self.rect = self.image.get_rect()
        self.rect.centerx = xpos_center
        self.rect.centery = ypos_center

        self.anim_timer = Timer()
        self.kill_timer = Timer()
        self.frame_idx = 2

    def update(self):
        """Flash the sign by switching images and destroy it after a set time."""

        if self.kill_timer.elapsed_time() > self.kill_time:
            self.kill()
        try:
            flash_time = 360
            if self.anim_timer.elapsed_time() > flash_time:
                self.anim_timer.reset()
                self.image = cache_image.get("screen_messages/boss_warning_F{}.png"
                                             .format(self.frame_idx))
                self.image.set_colorkey(BLACK)
                self.frame_idx += 1
        except pygame.error:
            self.frame_idx = 1

    def kill(self):

        all_sprites_list.remove(self)
示例#6
0
class Boss2(EnemyLinear):

    def __init__(self, dict_enemy):
        """Boss 2 housing class. Controls all body parts."""
        super(Boss2, self).__init__(dict_enemy)
        self.image_dir = self.params["image"]

        self.has_entered = False
        self.is_attacking = False
        self.is_dying = False
        self.is_dead = False

        self.next_attack_timer = Timer()

        self.attack_scheduler = ActionScheduler()

        self.image = pygame.transform.scale2x(self.image) # Debug only
        self.hitmask = pygame.mask.from_surface(self.image)

        self.initialize_body_parts()

    def initialize_body_parts(self):
        """Set up head and claw body parts as separate sprites."""

        from models.bosses.boss_2_head import Boss2Head

        head = Boss2Head(self)
        self.head = head

    def add_body_parts(self):
        """Add body parts to necessary lists."""

        all_sprites_list.add(self.head)

    def enter(self):

        if self.has_entered:
            return

        if self.rect.centerx <= 550 and self.rect.centery <= SCREEN_HEIGHT / 2:
            self.has_entered = True
            self.next_attack_timer.reset()
            self.head.attack_scheduler.reset()
            self.attack_scheduler.reset()

        if not self.has_entered:
            self.add_body_parts()

            if self.rect.centerx >= 550:
                self.rect.x -= 1

            if self.rect.centery >= SCREEN_HEIGHT / 2:
                self.rect.y -= 1

    def reset_attack_parameters(self):
        """Reset all parameters for boss's (and body parts') attacks."""

        self.next_attack_timer.reset()
        self.attack_scheduler.reset()

        self.head.reset_attack_parameters()

    def laser_head_attack(self, time_offset):

        attack_times =  [750, 10000, 10750]
        attack_speeds = [6,       0,    -6]
        attack_times =  [(x + time_offset) for x in attack_times]

        self.attack_scheduler.update(attack_times)

        if not self.attack_scheduler.is_done_action:
            idx = self.attack_scheduler.action_idx
            current_speed = attack_speeds[idx]
            self.rect.x += current_speed

            if idx == 1:
                self.head.laser_attack(time_offset + 750)

        else:
            self.reset_attack_parameters()

        self.is_attacking = self.attack_scheduler.is_doing_action

    def update(self):

        self.enter()

        if self.has_entered and not self.is_dying:
            if self.next_attack_timer.elapsed_time() > 2500:
                self.laser_head_attack(2500)
示例#7
0
class FallingBlock(EnemyLinear):
    """Environment Block that will fall unless supported by a floor block."""

    def __init__(self, dict_enemy):

        super(FallingBlock, self).__init__(dict_enemy)

        # NOTE: falling_block_list is only used for collision logic
        # FallingBlock()s are added to enemy_sprite_list and use that logic
        falling_block_list.add(self)

        self.fall_timer = Timer()

        self.fall_speed = 3
        self.is_falling = False

    def check_collision(self, sprite_list):
        """Check for vertical collision with a sprite list, skipping itself."""

        for block in sprite_list:
            # Continue falling if self = the only block in the list:
            if self == block:
                if len(sprite_list) == 1:
                    self.is_falling = True
                    self.fall_timer.reset()
                continue

            # 15 = the 'edge cushion' needed to keep the block from falling:
            x_range = range(block.rect.x - self.rect.width + 15,
                            block.rect.x + block.rect.width - 15)
            y_range = range(block.rect.y, block.rect.y + block.rect.height)

            if (self.rect.x in x_range
                and self.rect.y + self.rect.height in y_range):

                    self.rect.y = (block.rect.y
                                   - self.rect.height
                                   + (self.fall_speed / 2)
                                   )

                    self.is_falling = False
            else:
                if not self.is_falling:
                    self.is_falling = True
                    self.fall_timer.reset()

    def fall(self, fall_speed):
        """Move the block downward, with a slight pause at the top for visual effect."""

        if self.fall_timer.elapsed_time() > 60:
            self.rect.y += (fall_speed * 4)
        else:
            self.rect.y += fall_speed


    def update(self):
        """Kill if necessary; check collisions; update fall speed."""

        if (self.rect.centerx < -700
                or self.rect.centerx > SCREEN_WIDTH + 700
                or self.rect.centery < -200
                or self.rect.centery > SCREEN_HEIGHT + 200):
            self.kill()

        self.check_collision(falling_block_list)

        if self.is_falling:
            self.fall(self.fall_speed)

        self.rect.x -= 3
class ActionScheduler():
    """
    Allows for scheduling of actions via an array of times, an action index,
    a timer, and 4 booleans (Note: all booleans won't always be used  on any
    given instance. They exist to cover a range of functionality.)

    This times array...

    action_times = [0, 1000, 2000, 3000]

    ...means that an action occurs at 1-second, 2-seconds, and 3-seconds. These elements
    are considered thresholds for 'sub_actions', and the entire array constitutes one
    total 'action.'

    For example, in enemy pathing, these could be changes of direction. So each change
    in direction would be a 'sub_action', whereas the enemy's entire 'path_times' array
    would be one total 'action.'

    'action_idx' increments at each new time element in the times array.

    'is_doing_action' = True while the timer < last time in the times array.
    (Note that there is no 'is_doing_subaction', because 'action_idx' won't increment
    until the timer hits the next 'subaction' threshold; it will remain the same for the
    duration of a 'subaction', so any behavior logic can simply reference that index.)

    'is_done_action' = True only when timer > last time in times array.

    'is done_subaction' will be True for only one 'update' cycle per 'subaction' completed.
    This sounds confusing, because it is...This was used to solve a problematic edge
    condition that arises when elapsed time > total_time and 'is_done_subaction' is set to
    True: it never gets set back to false. We solve that with some if-else logic and the
    self.kill() method:

    self.kill() and 'is_dead' are used only for actions that occur ONCE per 'subaction'
    threshold.

    Example:

        Condition:
            elapsed time = 1001
            action_times[-1] = 1000

        What happens:
            the first time through self.update(), 'is_done_action' and
            'is_done_subaction' are set to True

            the NEXT time through self.update(), because 'is_done_action'
            is True, we go through our is_looped or kill conditions

            from there, if 'is_dead' == True, update returns None.

    """

    def __init__(self, is_looped=None):

        self.is_doing_action = False
        self.is_done_action = False
        self.is_done_subaction = False
        self.is_dead = False

        self.action_idx = 0
        self.timer = Timer()
        self.is_looped = is_looped

    def reset(self):
        """Loop an action by resetting booleans, index, and timer variables."""

        self.is_doing_action = False
        self.is_done_action = False
        self.action_idx = 0
        self.timer.reset()

    def kill(self):
        """Used to properly assign 'is_done_subaction' to False when a total action is done."""

        self.is_doing_action = False
        self.is_done_action = True
        self.is_done_subaction = False
        self.is_dead = True

    def execute_final_action(self):
        """Determine whether to loop the action again or kill it."""

        if self.is_looped:
            self.reset()
        else:
            self.kill()

    def update(self, action_times):
        """
        Check if 'is_dead' or 'is_done_action', otherwise proceed normally:
        Flip 'is_doing_action' to True.
        Increment 'action_idx' when elapsed time reaches next 'subaction' threshold.
        If timer > total time, flip 'is_doing_action' = False, and 'is_done_action' = True.
        """

        if self.is_dead: return

        self.is_doing_action = True
        self.is_done_subaction = False

        if self.is_done_action:
            self.execute_final_action()

        elif self.timer.elapsed_time() > action_times[-1]:
            self.action_idx = -1
            self.is_done_action = True
            self.is_done_subaction = True

        elif self.timer.elapsed_time() > action_times[self.action_idx]:
            self.is_done_subaction = True
            self.action_idx += 1
示例#9
0
class FourWayImage(pygame.sprite.Sprite):
    """Sprite that can move in four directions on a loop; used to create background/foreground."""

    def __init__(self, params, image_dir, image_type):

        super(FourWayImage, self).__init__()

        self.params = params
        self.image_type = image_type

        self.directions = self.params["directions"]
        self.speed = self.params["speed"]

        self.image_dir = image_dir

        if self.image_type == "foreground":
            self.image = cache_image.get(self.image_dir, convert_alpha=False)
        else:
            self.image = cache_image.get(self.image_dir)

        self.image = pygame.transform.scale2x(self.image)
        self.rect = self.image.get_rect()

        if self.image_type == "foreground":
            self.hitmask = pygame.mask.from_surface(self.image)

        # Used for re-arranging later:
        self.initial_x_pos = 0
        self.initial_y_pos = 0

        # Used to ensure accurate movement to screen edges:
        self.width_check = 0
        self.height_check = 0

        self.path_pointer = 0

        # For perfect diagonal movement, y and x must move at different speeds,
        # so we get a fraction here as a coefficient for later:
        self.diagonal_speed_coeff = Fraction(SCREEN_HEIGHT, SCREEN_WIDTH) * self.speed
        self.diagonal_counter = 1

        self.is_dying = False
        self.alpha = 255
        self.alpha_timer = Timer()

    def path(self, direction, coefficient):
        """
        Move the sprite in various directions.

        Diagonal movement was very tricky, as the screen is not square,
        so 1 : 1 movement doesn't produce desired results.

        Neither does decimal movement, as trying to move by decimals of a pixel
        results in de-syncing the background.

        Instead we have to produce whole-number pixel movement based on a ratio
        we calculate using the speed, screen height, and screen width:

        *********************************************************************
        EXAMPLE:

        SCREEN_HEIGHT / SCREEN_WIDTH = (3/4)
        speed: 5
        coefficient = 5 * (3/4) = (15/4)
        diagonal_counter = 1

        ticker will increment up to coefficient's denominator,
        y will increment by the denominator amount.

        when the ticker == the denominator,
        y += total moved space, aka: ((denominator - 1) * denominator)
        and diagonal_counter will reset to 1:

        Ticker      Moved_Space
        1           4
        2           8
        3           12
        4           15

        4 updates = 15 moved pixels = our original coefficient!

        (Some additional if-else logic had to be implemented for coefficients
        that were < 1 (i.e., if speed == 1 or 2), so as to not get negative movement.
        """

        if direction == "right":
            self.rect.x -= self.speed
            self.width_check += self.speed

        elif direction == "down":
            self.rect.y -= self.speed
            self.height_check += self.speed

        elif direction == "up":
            self.rect.y += self.speed
            self.height_check += self.speed

        elif direction in ["upright", "downright"]:

            # For diagonal movement, we have to use our coefficient:
            if self.diagonal_counter < coefficient.denominator:

                if direction == "upright":
                    # Special conditions if coefficient < 1:
                    if coefficient < 1:
                        self.rect.y += 1
                    else:
                        self.rect.y += coefficient.denominator
                elif direction == "downright":
                    if coefficient < 1:
                        self.rect.y -= 1
                    else:
                        self.rect.y -= coefficient.denominator

                self.diagonal_counter += 1

            else:
                if coefficient < 1:
                    next_move = 0
                else:
                    moved_space = (coefficient.denominator - 1) * coefficient.denominator
                    next_move = coefficient.numerator - moved_space

                if direction == "upright":
                    self.rect.y += next_move
                elif direction == "downright":
                    self.rect.y -= next_move

                self.diagonal_counter = 1

            self.rect.x -= self.speed
            self.width_check += self.speed
            self.height_check += float(self.diagonal_speed_coeff)

    def kill(self):

        if self.alpha_timer.elapsed_time() > 60:
            self.alpha_timer.reset()
            self.alpha -= 3
            self.image.set_alpha(self.alpha)

    def update(self):
        """Update based on 'directions' parameter; loop when finished."""

        if self.alpha <= 0:
            all_sprites_list.remove(self)
            if self.image_type == "foreground":
                foreground_list.remove(self)

        if self.is_dying:
            self.kill()

        # Continuous x-loop for foreground only:
        if self.image_type == "foreground" and self.rect.x < (self.initial_x_pos - 1600):
            self.rect.x = 0

        try:
            current_direction = self.directions[self.path_pointer]

            # Reset flags if they reach screen dimensions (more precise than a timer):
            if self.image_type == "background":
                if self.width_check >= SCREEN_WIDTH or self.height_check >= SCREEN_HEIGHT:

                    # TODO: Fix looped clipping:
                    self.width_check = 0
                    self.height_check = 0

                    self.path_pointer += 1

            else:
                # Foreground moves at 2x the speed of background, thus double the checks:
                if self.width_check >= SCREEN_WIDTH * 2 or self.height_check >= SCREEN_HEIGHT * 2:

                    self.width_check = 0
                    self.height_check = 0

                    self.path_pointer += 1

            self.path(current_direction, self.diagonal_speed_coeff)

        except IndexError:

            self.rearrange()

    def rearrange(self):
        """Reset images for looping."""

        self.rect.x = self.initial_x_pos - self.speed
        self.rect.y = self.initial_y_pos
        self.path_pointer = 0
def main(cfg):
    cprint("-- preparing..")
    max_iter = cfg['solver']['max_iter']
    summary_iter = cfg['solver']['summary_iter']
    save_iter = cfg['solver']['save_iter']
    ckpt_dir = os.path.join(cfg['path']['ckpt_dir'], cfg.cfg_name)
    ckpt_file = os.path.join(ckpt_dir, cfg.cfg_name)

    output_path = '../train_inter_results/'
    mkdir_p(output_path)

    tf.logging.info("-- constructing network..")
    with tf.Graph().as_default():

        with tf.device('/cpu:0'):
            with tf.name_scope('data_provider'):
                sample = {
                    'sample_radii': cfg.radii,
                    'cls': cfg.cls,
                    'x_min': cfg.min_x,
                    'y_min': cfg.min_y,
                    'z_min': cfg.min_z,
                    'x_max': cfg.max_x,
                    'y_max': cfg.max_y,
                    'z_max': cfg.max_z,
                    'num_points': cfg.num_points,
                    'CENTER_PERTURB': cfg.CENTER_PERTURB,
                    'CENTER_PERTURB_Z': cfg.CENTER_PERTURB_Z,
                    'SAMPLE_Z_MIN': cfg.sample_z_min,
                    'SAMPLE_Z_MAX': cfg.sample_z_max,
                    'QUANT_POINTS': cfg.QUANT_POINTS,
                    'QUANT_LEVEL': cfg.QUANT_LEVEL
                }
                dataset = ObjectProvider(
                    edict({
                        'batch_size': cfg.solver.batch_size,
                        'dataset': 'kitti',
                        'split': 'train',
                        'is_training': True,
                        'num_epochs': None,
                        'sample': sample
                    }))
                dataset.data_size = 100000  # FIXME. random number

            global_step = tf.get_variable(
                'global_step', [],
                initializer=tf.constant_initializer(0),
                trainable=False)
            learning_rate = _configure_learning_rate(cfg, dataset.data_size,
                                                     global_step)
            bn_decay = get_bn_decay(cfg, dataset.data_size, global_step)

            optimizer = _configure_optimizer(cfg, learning_rate)
            tf.summary.scalar('learning_rate', learning_rate)

        # Calculate the gradients for each model tower.
        towers_ph_points = []
        towers_ph_obj = []
        towers_ph_is_training = []

        tower_grads = []
        tower_losses = []
        device_scopes = []
        scope_name = 'rpn'
        with tf.variable_scope(scope_name):
            for gid in range(cfg.num_gpus):
                with tf.name_scope('gpu%d' % gid) as scope:
                    with tf.device('/gpu:%d' % gid):
                        with tf.name_scope("train_input"):
                            ph_points = tf.placeholder(tf.float32,
                                                       shape=(None,
                                                              cfg.num_points,
                                                              3))
                            ph_obj = tf.placeholder(tf.float32, shape=(None, ))

                            ph_is_training = tf.placeholder(tf.bool, shape=())

                            net = Net(ph_points=ph_points,
                                      is_training=ph_is_training,
                                      bn_decay=bn_decay,
                                      cfg=cfg)
                            net.losses(target_objs=ph_obj,
                                       cut_off=cfg.iou_cutoff,
                                       gl=global_step)

                        all_losses = tf.get_collection(tf.GraphKeys.LOSSES,
                                                       scope)
                        sum_loss = tf.add_n(all_losses)

                        for loss in all_losses:
                            tf.summary.scalar(loss.op.name, loss)
                        tf.summary.scalar("sum_loss_tower", sum_loss)

                        # Reuse variables for the next tower.
                        tf.get_variable_scope().reuse_variables()

                        # Calculate the gradients for the batch of data
                        grads = optimizer.compute_gradients(sum_loss)

                        # Keep track of the gradients across all towers.
                        tower_grads.append(grads)
                        tower_losses.append(sum_loss)
                        device_scopes.append(scope)

                        # Collect all placeholders
                        towers_ph_points.append(ph_points)
                        towers_ph_obj.append(ph_obj)
                        towers_ph_is_training.append(ph_is_training)

        total_loss = tf.add_n(tower_losses, name='total_loss')
        grads = _average_gradients(tower_grads)
        apply_gradient_ops = optimizer.apply_gradients(grads,
                                                       global_step=global_step)

        # Add histograms for trainable variables.
        for var in tf.trainable_variables():
            tf.summary.histogram(var.op.name, var)

        # Track the moving averages of all trainable variables.
        # if cfg.solver.moving_average_decay:
        with tf.name_scope('expMovingAverage'):
            variable_averages = tf.train.ExponentialMovingAverage(
                0.005, global_step)
            # cfg.solver.moving_average_decay, global_step)
            averages_op = variable_averages.apply(tf.trainable_variables())
        # else:
        # averages_op = None

        # Group all updates to into a single train op.
        train_op = tf.group(apply_gradient_ops, averages_op)
        train_tensor = control_flow_ops.with_dependencies([train_op],
                                                          total_loss,
                                                          name='train_op')

        # Create a saver
        saver = tf.train.Saver(tf.global_variables(), max_to_keep=20)
        init = tf.global_variables_initializer()

        # =================================================================== #
        # Kicks off the training.
        # =================================================================== #\
        # GPU configuration
        if cfg.num_gpus == 0: config = tf.ConfigProto(device_count={'GPU': 0})
        else:
            config = tf.ConfigProto(allow_soft_placement=True,
                                    log_device_placement=False)

        with tf.Session(config=config) as sess:

            dataset.set_session(sess)

            # initialization / session / writer / saver
            print('initializing a network may take minutes...')
            sess.run(init)

            tf.train.start_queue_runners(sess=sess)

            train_writer, eval_writer = _set_filewriters(ckpt_dir, sess)
            merged = tf.summary.merge_all()

            ckpt_dir = os.path.join(cfg.path.ckpt_dir, cfg.cfg_name)
            weight_file = tf.train.latest_checkpoint(ckpt_dir)
            if weight_file is not None:
                saver.restore(sess, weight_file)
                tf.logging.info('%s loaded' % weight_file)
            else:
                tf.logging.info(
                    'Training from the scratch (no pre-trained weight_filets)..'
                )

            train_timer = Timer()
            print('start training...')
            stat_correct = []

            def inference(feed_dict):
                loc, conf_iou = sess.run([net.pred_locs, net.pred_conf_iou],
                                         feed_dict)
                return loc, conf_iou

            for step in range(max_iter):

                train_timer.tic()
                feed_dict = {}
                for i in range(cfg.num_gpus):
                    b_points, b_objs, b_locs = dataset.get_batch()
                    feed_dict[towers_ph_points[i]] = b_points
                    feed_dict[towers_ph_obj[i]] = b_objs
                    feed_dict[towers_ph_is_training[i]] = True

                gl, loss, _ = sess.run([global_step, total_loss, train_tensor],
                                       feed_dict=feed_dict)

                if gl % 100 == 0:
                    cprint("gl: {} loss: {:.3f}".format(gl, loss))

                train_timer.toc()
                if gl % summary_iter == 0:
                    if gl % (summary_iter * 10) == 0:
                        # Summary with run meta data
                        run_options = tf.RunOptions(
                            trace_level=tf.RunOptions.FULL_TRACE)
                        run_metadata = tf.RunMetadata()
                        summary_str, loss, _ = sess.run(
                            [merged, total_loss, train_tensor],
                            feed_dict=feed_dict,
                            options=run_options,
                            run_metadata=run_metadata)
                        train_writer.add_run_metadata(run_metadata,
                                                      'step_{}'.format(gl), gl)
                        train_writer.add_summary(summary_str, gl)
                    else:
                        # Summary
                        summary_str = sess.run(merged, feed_dict=feed_dict)
                        train_writer.add_summary(summary_str, gl)

                    log_str = (
                        '{} Epoch: {:3d}, Step: {:4d}, Learning rate: {:.4e}, Loss: {:5.3f}\n'
                        '{:14s} Speed: {:.3f}s/iter, Remain: {}').format(
                            datetime.datetime.now().strftime('%m/%d %H:%M:%S'),
                            int(cfg.solver.batch_size * gl /
                                dataset.data_size), int(gl),
                            round(learning_rate.eval(session=sess), 6), loss,
                            '', train_timer.average_time,
                            train_timer.remain(step, max_iter))
                    print(log_str)
                    train_timer.reset()

                if gl % save_iter == 0:
                    print('{} Saving checkpoint file to: {}'.format(
                        datetime.datetime.now().strftime('%m/%d %H:%M:%S'),
                        ckpt_dir))
                    saver.save(sess, ckpt_file, global_step=global_step)

                evaluate_iter = 100000
class AnimationScheduler():
    """Class to handle various types of sprite animations."""

    def __init__(self, is_looped, is_seesaw=False):

        self.is_looped = is_looped
        self.is_seesaw = is_seesaw
        self.is_done_animating = False

        self.frame_idx = 0
        self.timer = Timer()
        if self.is_seesaw:
            self.frame_incrementer = 1

    def reset(self):
        """Reset boolean, frame index, and timer."""
    
        self.is_done_animating = False
        self.frame_idx = 0
        self.timer.reset()

    def looped_update(self, anim_times, static_time_threshold):
        """Update looped animation based on a schedule of times or a single static threshold."""

        if anim_times is not None:
            if self.timer.elapsed_time() > anim_times[self.frame_idx]:
                self.frame_idx += 1
                self.timer.reset()

        elif self.timer.elapsed_time() > static_time_threshold:
            self.frame_idx += 1
            self.timer.reset()

    def seesaw_update(self, anim_times, static_time_threshold):
        """Update an animation that loops by playing itself backwards and forwards."""

        try:
            if self.timer.elapsed_time() > static_time_threshold:
                self.frame_idx += self.frame_incrementer
                self.timer.reset()
        except pygame.error:
            self.frame_incrementer *= -1

    def normal_update(self, anim_times):
        """Update linear animation that plays one time before flipping 'is_done_animating'."""

        if self.is_done_animating:
            return

        # Necessary edge condition:
        elif len(anim_times) < 2:
            if self.timer.elapsed_time() > anim_times[self.frame_idx]:
                self.frame_idx += 1
                self.is_done_animating = True

        elif self.frame_idx == len(anim_times) - 1 and self.timer.elapsed_time() > anim_times[-1]:
            self.is_done_animating = True

        # This needs to be separated from the above if-statement to preserve the last frame of
        # animation. If we tried to flip 'is_done_animating' AND increment frame_idx at the same
        # time, we don't get to see the last frame of the animation. Separating here ensures that:
        elif self.frame_idx == len(anim_times) - 2 and self.timer.elapsed_time() > anim_times[-2]:
            self.frame_idx += 1

        elif self.timer.elapsed_time() > anim_times[self.frame_idx]:
            self.frame_idx += 1
            self.timer.reset()

    def get_next_frame(self, image_dir, convert_alpha=True):
        """Return next frame in the animation."""

        # Using aTry-Except block allows me to easily add new frame assets to a
        # looped animation without updating any code whatsoever!
        try:
            image = cache_image.get(image_dir + "_F{}.png".format(self.frame_idx), convert_alpha)
        except pygame.error:
            if self.is_looped:
                self.reset()
                image = cache_image.get(image_dir + "_F{}.png".format(self.frame_idx), convert_alpha)
            elif self.is_seesaw:
                self.frame_incrementer *= -1
                self.frame_idx += self.frame_incrementer
                image = cache_image.get(image_dir + "_F{}.png".format(self.frame_idx), convert_alpha)

        return image

    def update(self, anim_times=None, static_time_threshold=120):
        """Update based on type of animation."""

        if self.is_looped:
            self.looped_update(anim_times, static_time_threshold)

        elif self.is_seesaw:
            self.seesaw_update(anim_times, static_time_threshold)

        else:
            self.normal_update(anim_times)
示例#12
0
class Level(object):
    """Deploy waves of enemies based on a dictionary of parameters."""

    def __init__(self, dict_level):

        self.params = dict_level

        self.wave_timer = Timer()
        self.wave_idx = 1
        self.level_scheduler = ActionScheduler()
        self.wave_scheduler = ActionScheduler()

        self.level_number = self.params["level_number"]
        self.is_complete = False

        self.initialize_level_assets()
        self.boss = self.initialize_boss()

        # Wave parameters + deployment times
        self.deployment_times = {0: 0}
        self.waves = {0: 0}
        # self.initialize_waves()

        self.last_level = key_or_none("last", self.params)

    def initialize_level_assets(self):
        """Initialize background and foreground art for the level."""

        # Boolean which determines if level is sidescrolling or multi-directional
        self.has_directional_bg = key_or_none("has_directional_bg", self.params)

        if self.has_directional_bg is None:
            self.background = TwoWayBackground(self.params["bg_params"])
            self.foreground = TwoWayForeground(self.params["fg_params"])
        else:
            self.background = FourWayBackground(self.params["bg_params"])
            self.foreground = FourWayForeground(self.params["fg_params"])

    def initialize_boss(self):
        """Initialize the level's boss, based on params."""

        params_dict = self.params["boss"]
        klass = params_dict["class"]
        params = params_dict["params"]

        boss = klass(params)

        return boss

    def initialize_waves(self):
        """Unpack wave and deployment time parameters into separate dicts."""

        # NOTE: DO NOT TOUCH THESE BLOCKS!!!

        # Loops for collecting Deployment Times:
        deployment_times = self.params["deployment_times"]

        for wave_num in deployment_times:
            try:
                for subwave_times in deployment_times[wave_num]:
                    self.deployment_times[len(self.deployment_times)] = subwave_times
            except TypeError:
                self.deployment_times[len(self.deployment_times)] = deployment_times[wave_num]
        # Multiply times by 1000 to account for milliseconds:
        for wave_num in self.deployment_times:
            self.deployment_times[wave_num] *= 1000

        # Loop for collecting Waves:
        waves = self.params["waves"]

        for wave_num in waves:
            if isinstance(waves[wave_num][0], list):
                for wave_params in waves[wave_num]:
                    self.waves[len(self.waves)] = wave_params
            else:
                self.waves[len(self.waves)] = waves[wave_num]

    def load_wave(self, params_wave):
        """
        Return a wave of enemies based on the parameters dictionary, accounting
        for positional offsets, vertical flips, and horizontal flips.
        """

        # Get parameters from the dict:
        next_wave = []

        num_enemy = params_wave[0]
        klass = params_wave[1]
        params_enemy = params_wave[2]
        offsets = params_wave[3]
        vertical_flips = params_wave[4]
        horizontal_flips = params_wave[5]

        # Special offsets applied to FallingBlocks to spawn simultaneously:
        if klass == FallingBlock:
            for i in range(num_enemy):
                enemy = klass(params_enemy)
                if offsets is not None:
                    enemy.rect.centerx += offsets[i][0]
                    enemy.rect.centery += offsets[i][1]

                next_wave.append(enemy)

        else:
            # Apply any x- or y- shifts:
            for i in range(0, num_enemy):
                enemy = klass(params_enemy)
                if offsets is not None:
                    enemy.rect.centerx += offsets[0]
                    enemy.rect.centery += offsets[1]

                next_wave.append(enemy)

            # Apply flips ([i - 1] because params are not 0-indexed):
            if horizontal_flips is not None:
                for i in horizontal_flips:
                    next_wave[i - 1].flip_path_horizontal()

            if vertical_flips is not None:
                for i in vertical_flips:
                    next_wave[i - 1].flip_path_vertical()

        all_sprites_list.add(next_wave)
        enemy_sprite_list.add(next_wave)

    def display_boss_warning(self):
        """Flash a warning message that the boss is approaching."""

        warning = BossWarning("screen_messages/boss_warning",
                              SCREEN_WIDTH / 2, 200, 6000)
        all_sprites_list.add(warning)

        message = TextToScreen("screen_messages/boss_approaching",
                               SCREEN_WIDTH / 2, 300, 6000)
        all_sprites_list.add(message)

    def release_wave(self, wave, offset):

        if self.wave_scheduler.is_done_action:
            self.wave_scheduler.reset()
            self.wave_timer.reset()
            self.wave_idx += 1
            return

        wave_times = [((x * 1000) + offset) for x in wave["wave_times"]]
        enemy_params = wave["enemies"]

        self.wave_scheduler.update(wave_times)
        wave_idx = self.wave_scheduler.action_idx - 1

        #TODO: Temporary hack, should fix
        if wave_idx == -2:
            wave_idx = -1

        if self.wave_scheduler.is_done_subaction or self.wave_scheduler.is_done_action:
            self.load_wave(enemy_params[wave_idx])

    def run(self):
        """Load all waves and deploy them based on a timed schedule."""

        # try:

        # Level completion conditions:
        if self.boss.is_dead == True:
            self.is_complete = True

        last_wave = self.params["waves"][self.wave_idx - 1]
        current_wave = self.params["waves"][self.wave_idx]

        start_time = (current_wave["deployment_time"] - last_wave["deployment_time"]) * 1000


        if self.wave_timer.elapsed_time() > start_time:
            if current_wave["wave_times"] == "BOSS":
                all_sprites_list.add(self.boss)
                boss_list.add(self.boss)

            elif current_wave["wave_times"] == "WARNING":
                self.wave_timer.reset()
                self.wave_idx += 1

                self.display_boss_warning()
                self.foreground.kill()

            else:
                self.release_wave(current_wave, start_time)