Beispiel #1
0
    def init_camera(self, feature_dimensions, map_size,
                    camera_width_world_units):
        """Initialize the camera (especially for feature_units).

    This is called in the constructor and may be called repeatedly after
    `Features` is constructed, since it deals with rescaling coordinates and not
    changing environment/action specs.

    Args:
      feature_dimensions: See the documentation in `AgentInterfaceFormat`.
      map_size: The size of the map in world units.
      camera_width_world_units: See the documentation in `AgentInterfaceFormat`.

    Raises:
      ValueError: If map_size or camera_width_world_units are falsey (which
          should mainly happen if called by the constructor).
    """
        if not map_size or not camera_width_world_units:
            raise ValueError(
                "Either pass the game_info with raw enabled, or map_size and "
                "camera_width_world_units in order to use feature_units or camera"
                "position.")
        map_size = point.Point.build(map_size)
        self._world_to_world_tl = transform.Linear(point.Point(1, -1),
                                                   point.Point(0, map_size.y))
        self._world_tl_to_world_camera_rel = transform.Linear(
            offset=-map_size / 4)
        world_camera_rel_to_feature_screen = transform.Linear(
            feature_dimensions.screen / camera_width_world_units,
            feature_dimensions.screen / 2)
        self._world_to_feature_screen_px = transform.Chain(
            self._world_to_world_tl, self._world_tl_to_world_camera_rel,
            world_camera_rel_to_feature_screen, transform.PixelToCoord())
Beispiel #2
0
  def update_transformations(self):

    # Create transformations
    self._world_to_minimap = transform.Linear(point.Point(1, -1),
                                              point.Point(0, self._map_size.y))
    max_map_dim = self._map_size.max_dim()
    self._minimap_to_fl_minimap = transform.Linear(
        self._minimap_size / max_map_dim)
    self._world_to_fl_minimap = transform.Chain(
        self._world_to_minimap,
        self._minimap_to_fl_minimap,
        transform.Floor())

    # Flip and zoom to the camera area. Update the offset as the camera moves.
    # Get camera corner
    cam_x   = -1 * (self._camera_pos['x'] - (self._camera_width / 2))
    cam_y   =  1 * (self._camera_pos['y'] + (self._camera_width / 2))
    cam_pos = point.Point(x = cam_x, y = cam_y)

    self._reorient_world  = transform.Linear(point.Point(1, -1), offset=cam_pos)
    self._world_to_screen = transform.Linear(point.Point(1, 1),
                                             point.Point(0, 0))
    #self._world_to_screen = transform.Linear(point.Point(1, -1),
    #                                         point.Point(0, self._map_size.y))
    self._screen_to_fl_screen = transform.Linear(
        self._screen_size / self._camera_width)
    self._world_to_fl_screen = transform.Chain(
        self._reorient_world,
        self._world_to_screen,
        self._screen_to_fl_screen,
        transform.PixelToCoord())
Beispiel #3
0
 def _world_tl_to_minimap_px(raw_unit):
     # TODO configurable resolution
     minimap_px = point.Point(64.0, 64.0)
     map_size = point.Point(88.0, 96.0)
     pos_transform = transform.Chain(
         transform.Linear(minimap_px / map_size.max_dim()),
         transform.PixelToCoord())
     screen_pos = pos_transform.fwd_pt(point.Point(raw_unit.x, raw_unit.y))
     return screen_pos.x, screen_pos.y
Beispiel #4
0
 def _init_camera(self):
     self._world_to_world_tl = transform.Linear(
         point.Point(1, -1), point.Point(0, self._map_size.y))
     self._world_tl_to_world_camera_rel = transform.Linear(
         offset=-self._map_size / 4)
     self._world_to_feature_screen_px = transform.Chain(
         self._world_to_world_tl, self._world_tl_to_world_camera_rel,
         transform.Linear(
             (self._screen_size_px / self._camera_width_world_units),
             self._screen_size_px / 2), transform.PixelToCoord())
Beispiel #5
0
 def _init_camera(self, feature_dimensions, map_size,
                  camera_width_world_units):
     """Initialize the feature_units camera."""
     if not map_size or not camera_width_world_units:
         raise ValueError(
             "Either pass the game_info with raw enabled, or map_size and "
             "camera_width_world_units in order to use feature_units.")
     map_size = point.Point.build(map_size)
     self._world_to_world_tl = transform.Linear(point.Point(1, -1),
                                                point.Point(0, map_size.y))
     self._world_tl_to_world_camera_rel = transform.Linear(
         offset=-map_size / 4)
     world_camera_rel_to_feature_screen = transform.Linear(
         feature_dimensions.screen / camera_width_world_units,
         feature_dimensions.screen / 2)
     self._world_to_feature_screen_px = transform.Chain(
         self._world_to_world_tl, self._world_tl_to_world_camera_rel,
         world_camera_rel_to_feature_screen, transform.PixelToCoord())
Beispiel #6
0
  def init_window(self):
    """Initialize the pygame window and lay out the surfaces."""
    if os.name == "nt":
      # Enable DPI awareness on Windows to give the correct window size.
      ctypes.windll.user32.SetProcessDPIAware()  # pytype: disable=module-attr

    pygame.init()

    if self._render_rgb and self._rgb_screen_px:
      main_screen_px = self._rgb_screen_px
    else:
      main_screen_px = self._feature_screen_px

    window_size_ratio = main_screen_px
    if self._feature_screen_px and self._render_feature_grid:
      # Want a roughly square grid of feature layers, each being roughly square.
      num_feature_layers = (len(features.SCREEN_FEATURES) +
                            len(features.MINIMAP_FEATURES))
      feature_cols = math.ceil(math.sqrt(num_feature_layers))
      feature_rows = math.ceil(num_feature_layers / feature_cols)
      features_layout = point.Point(feature_cols,
                                    feature_rows * 1.05)  # make room for titles

      # Scale features_layout to main_screen_px height so we know its width.
      features_aspect_ratio = (features_layout * main_screen_px.y /
                               features_layout.y)
      window_size_ratio += point.Point(features_aspect_ratio.x, 0)

    window_size_px = window_size_ratio.scale_max_size(
        _get_max_window_size()).ceil()

    # Create the actual window surface. This should only be blitted to from one
    # of the sub-surfaces defined below.
    self._window = pygame.display.set_mode(window_size_px, 0, 32)
    pygame.display.set_caption("Starcraft Viewer")

    # The sub-surfaces that the various draw functions will draw to.
    self._surfaces = []
    def add_surface(surf_type, surf_loc, world_to_surf, world_to_obs, draw_fn):
      """Add a surface. Drawn in order and intersect in reverse order."""
      sub_surf = self._window.subsurface(
          pygame.Rect(surf_loc.tl, surf_loc.size))
      self._surfaces.append(_Surface(
          sub_surf, surf_type, surf_loc, world_to_surf, world_to_obs, draw_fn))

    self._scale = window_size_px.y // 30
    self._font_small = pygame.font.Font(None, int(self._scale * 0.5))
    self._font_large = pygame.font.Font(None, self._scale)

    def check_eq(a, b):
      """Used to run unit tests on the transforms."""
      assert (a - b).len() < 0.0001, "%s != %s" % (a, b)

    # World has origin at bl, world_tl has origin at tl.
    self._world_to_world_tl = transform.Linear(
        point.Point(1, -1), point.Point(0, self._map_size.y))

    check_eq(self._world_to_world_tl.fwd_pt(point.Point(0, 0)),
             point.Point(0, self._map_size.y))
    check_eq(self._world_to_world_tl.fwd_pt(point.Point(5, 10)),
             point.Point(5, self._map_size.y - 10))

    # Move the point to be relative to the camera. This gets updated per frame.
    self._world_tl_to_world_camera_rel = transform.Linear(
        offset=-self._map_size / 4)

    check_eq(self._world_tl_to_world_camera_rel.fwd_pt(self._map_size / 4),
             point.Point(0, 0))
    check_eq(
        self._world_tl_to_world_camera_rel.fwd_pt(
            (self._map_size / 4) + point.Point(5, 10)),
        point.Point(5, 10))

    if self._feature_screen_px:
      # Feature layer locations in continuous space.
      feature_world_per_pixel = (self._feature_screen_px /
                                 self._feature_camera_width_world_units)
      world_camera_rel_to_feature_screen = transform.Linear(
          feature_world_per_pixel, self._feature_screen_px / 2)

      check_eq(world_camera_rel_to_feature_screen.fwd_pt(point.Point(0, 0)),
               self._feature_screen_px / 2)
      check_eq(
          world_camera_rel_to_feature_screen.fwd_pt(
              point.Point(-0.5, -0.5) * self._feature_camera_width_world_units),
          point.Point(0, 0))

      self._world_to_feature_screen = transform.Chain(
          self._world_to_world_tl,
          self._world_tl_to_world_camera_rel,
          world_camera_rel_to_feature_screen)
      self._world_to_feature_screen_px = transform.Chain(
          self._world_to_feature_screen,
          transform.PixelToCoord())

      world_tl_to_feature_minimap = transform.Linear(
          self._feature_minimap_px / self._map_size.max_dim())

      check_eq(world_tl_to_feature_minimap.fwd_pt(point.Point(0, 0)),
               point.Point(0, 0))
      check_eq(world_tl_to_feature_minimap.fwd_pt(self._map_size),
               self._map_size.scale_max_size(self._feature_minimap_px))

      self._world_to_feature_minimap = transform.Chain(
          self._world_to_world_tl,
          world_tl_to_feature_minimap)
      self._world_to_feature_minimap_px = transform.Chain(
          self._world_to_feature_minimap,
          transform.PixelToCoord())

    if self._rgb_screen_px:
      # RGB pixel locations in continuous space.

      # TODO(tewalds): Use a real 3d projection instead of orthogonal.
      rgb_world_per_pixel = (self._rgb_screen_px / 24)
      world_camera_rel_to_rgb_screen = transform.Linear(
          rgb_world_per_pixel, self._rgb_screen_px / 2)

      check_eq(world_camera_rel_to_rgb_screen.fwd_pt(point.Point(0, 0)),
               self._rgb_screen_px / 2)
      check_eq(
          world_camera_rel_to_rgb_screen.fwd_pt(
              point.Point(-0.5, -0.5) * 24),
          point.Point(0, 0))

      self._world_to_rgb_screen = transform.Chain(
          self._world_to_world_tl,
          self._world_tl_to_world_camera_rel,
          world_camera_rel_to_rgb_screen)
      self._world_to_rgb_screen_px = transform.Chain(
          self._world_to_rgb_screen,
          transform.PixelToCoord())

      world_tl_to_rgb_minimap = transform.Linear(
          self._rgb_minimap_px / self._map_size.max_dim())

      check_eq(world_tl_to_rgb_minimap.fwd_pt(point.Point(0, 0)),
               point.Point(0, 0))
      check_eq(world_tl_to_rgb_minimap.fwd_pt(self._map_size),
               self._map_size.scale_max_size(self._rgb_minimap_px))

      self._world_to_rgb_minimap = transform.Chain(
          self._world_to_world_tl,
          world_tl_to_rgb_minimap)
      self._world_to_rgb_minimap_px = transform.Chain(
          self._world_to_rgb_minimap,
          transform.PixelToCoord())

    # Renderable space for the screen.
    screen_size_px = main_screen_px.scale_max_size(window_size_px)
    minimap_size_px = self._map_size.scale_max_size(screen_size_px / 4)
    minimap_offset = point.Point(0, (screen_size_px.y - minimap_size_px.y))

    if self._render_rgb:
      rgb_screen_to_main_screen = transform.Linear(
          screen_size_px / self._rgb_screen_px)
      add_surface(SurfType.RGB | SurfType.SCREEN,
                  point.Rect(point.origin, screen_size_px),
                  transform.Chain(  # surf
                      self._world_to_rgb_screen,
                      rgb_screen_to_main_screen),
                  self._world_to_rgb_screen_px,
                  self.draw_screen)
      rgb_minimap_to_main_minimap = transform.Linear(
          minimap_size_px / self._rgb_minimap_px)
      add_surface(SurfType.RGB | SurfType.MINIMAP,
                  point.Rect(minimap_offset,
                             minimap_offset + minimap_size_px),
                  transform.Chain(  # surf
                      self._world_to_rgb_minimap,
                      rgb_minimap_to_main_minimap),
                  self._world_to_rgb_minimap_px,
                  self.draw_mini_map)
    else:
      feature_screen_to_main_screen = transform.Linear(
          screen_size_px / self._feature_screen_px)
      add_surface(SurfType.FEATURE | SurfType.SCREEN,
                  point.Rect(point.origin, screen_size_px),
                  transform.Chain(  # surf
                      self._world_to_feature_screen,
                      feature_screen_to_main_screen),
                  self._world_to_feature_screen_px,
                  self.draw_screen)
      feature_minimap_to_main_minimap = transform.Linear(
          minimap_size_px / self._feature_minimap_px)
      add_surface(SurfType.FEATURE | SurfType.MINIMAP,
                  point.Rect(minimap_offset,
                             minimap_offset + minimap_size_px),
                  transform.Chain(  # surf
                      self._world_to_feature_minimap,
                      feature_minimap_to_main_minimap),
                  self._world_to_feature_minimap_px,
                  self.draw_mini_map)

    if self._feature_screen_px and self._render_feature_grid:
      # Add the feature layers
      features_loc = point.Point(screen_size_px.x, 0)
      feature_pane = self._window.subsurface(
          pygame.Rect(features_loc, window_size_px - features_loc))
      feature_pane.fill(colors.white / 2)
      feature_pane_size = point.Point(*feature_pane.get_size())
      feature_grid_size = feature_pane_size / point.Point(feature_cols,
                                                          feature_rows)
      feature_layer_area = self._feature_screen_px.scale_max_size(
          feature_grid_size)
      feature_layer_padding = feature_layer_area // 20
      feature_layer_size = feature_layer_area - feature_layer_padding * 2

      feature_font_size = int(feature_grid_size.y * 0.09)
      feature_font = pygame.font.Font(None, feature_font_size)

      feature_counter = itertools.count()
      def add_feature_layer(feature, surf_type, world_to_surf, world_to_obs):
        """Add a feature layer surface."""
        i = next(feature_counter)
        grid_offset = point.Point(i % feature_cols,
                                  i // feature_cols) * feature_grid_size
        text = feature_font.render(feature.full_name, True, colors.white)
        rect = text.get_rect()
        rect.center = grid_offset + point.Point(feature_grid_size.x / 2,
                                                feature_font_size)
        feature_pane.blit(text, rect)
        surf_loc = (features_loc + grid_offset + feature_layer_padding +
                    point.Point(0, feature_font_size))
        add_surface(surf_type,
                    point.Rect(surf_loc, surf_loc + feature_layer_size),
                    world_to_surf, world_to_obs,
                    lambda surf: self.draw_feature_layer(surf, feature))

      # Add the minimap feature layers
      feature_minimap_to_feature_minimap_surf = transform.Linear(
          feature_layer_size / self._feature_minimap_px)
      world_to_feature_minimap_surf = transform.Chain(
          self._world_to_feature_minimap,
          feature_minimap_to_feature_minimap_surf)
      for feature in features.MINIMAP_FEATURES:
        add_feature_layer(feature, SurfType.FEATURE | SurfType.MINIMAP,
                          world_to_feature_minimap_surf,
                          self._world_to_feature_minimap_px)

      # Add the screen feature layers
      feature_screen_to_feature_screen_surf = transform.Linear(
          feature_layer_size / self._feature_screen_px)
      world_to_feature_screen_surf = transform.Chain(
          self._world_to_feature_screen,
          feature_screen_to_feature_screen_surf)
      for feature in features.SCREEN_FEATURES:
        add_feature_layer(feature, SurfType.FEATURE | SurfType.SCREEN,
                          world_to_feature_screen_surf,
                          self._world_to_feature_screen_px)

    # Add the help screen
    help_size = point.Point(
        (max(len(s) for s, _ in self.shortcuts) +
         max(len(s) for _, s in self.shortcuts)) * 0.4 + 4,
        len(self.shortcuts) + 3) * self._scale
    help_rect = point.Rect(window_size_px / 2 - help_size / 2,
                           window_size_px / 2 + help_size / 2)
    add_surface(SurfType.CHROME, help_rect, None, None, self.draw_help)

    # Arbitrarily set the initial camera to the center of the map.
    self._update_camera(self._map_size / 2)