def __init__( self, orientation: str, position: Vec, screen_length: int, visible_length: int, total_length: int, width: int, fill_color: Color = (242, 242, 242), bar_color: Color = (64, 64, 64), ): self.length = length = screen_length # self.ratio = max(1, total_length / visible_length) self.sector_length = sector_length = length // total_length self.remainder = remainder = length - (sector_length * total_length) self.scroll_length = visible_length * sector_length + remainder if orientation == "y": dimensions = Vector(width, length) else: dimensions = Vector(length, width) self.orientation = orientation self.position = position self.dimensions = dimensions self.width = width self.fill_color = fill_color self.bar_color = bar_color self.display = pygame.Surface(dimensions) self.display.fill(fill_color)
def get_map_xy(self) -> Vector: x, y = pygame.mouse.get_pos() sx, sy = self.screen_tile_size px, py = self.position mx, my = self.margin dx, dy = (px + mx, py + my) pos_x, pos_y = (x - dx) // sx, (y - dy) // sy if min(pos_x, pos_y) < 0: return Vector(-1, -1) scroll_x, scroll_y = self.curr_scroll return Vector(pos_x + scroll_x, pos_y + scroll_y)
def calc_map_size(self) -> Vector: width, height = self.map_hw() map_tile_size = self.map_tile_size map = self.map sw, sh = self.width, self.height mw, mh = map.width, map.height max_scroll = Vector(max(mw - sw, 0), max(mh - sh, 0)) dimensions = Vector(width * map_tile_size, height * map_tile_size) self.dimensions = dimensions self.max_scroll = max_scroll self.calc_map_display() return dimensions
def get_xy(self) -> Vector: x, y = pygame.mouse.get_pos() sx, sy = self.screen_tile_size px, py = self.position mx, my = self.margin dx, dy = (px + mx, py + my) return Vector((x - dx) // sx, (y - dy) // sy)
def move_hero_keys( self, keys: Union[MovementKeys, Tuple[str, str, str, str]] = ("up", "down", "left", "right") ) -> Tuple[bool, bool]: if not isinstance(keys, MovementKeys): keys = MovementKeys(*keys) keys = MovementKeys(*keys) keyboard = Window.get_keyboard() hx, hy = self.hero_position h, v = False, False if keyboard.key_pressed(keys.up): hy -= 1 v = not v if keyboard.key_pressed(keys.down): hy += 1 v = not v if keyboard.key_pressed(keys.left): hx -= 1 h = not h if keyboard.key_pressed(keys.right): hx += 1 h = not h hero_position = Vector(hx, hy) if (h or v) and self.can_move_to(hero_position): self.move_hero_to(hero_position) return h, v else: return False, False
def scroll(self, delta: Union[Vec, int], dy: Optional[int] = None) -> Vector: if type(delta) == int: if dy is not None: delta = Vector(delta, dy) else: raise TypeError( "scroll takes two integers or one tuple/vector") xmax, ymax = max_scroll = self.max_scroll if max(max_scroll) == 0: return Vector(0, 0) curr_scroll = self.curr_scroll new_scroll = clamp_2(add_v(curr_scroll, delta), (0, xmax), (0, ymax)) self.curr_scroll = new_scroll return new_scroll
def get_screen_position(self, x: int, y: int) -> Vector: scroll_x, scroll_y = self.curr_scroll cx, cy = x - scroll_x, y - scroll_y sx, sy = self.screen_tile_size px, py = self.position mx, my = self.margin dx, dy = px + mx, py + my return Vector(cx * sx + dx, cy * sy + dy)
def set_scrollbar(self): sw, sh = self.screen_size sx, sy = self.curr_scroll vw, vh = self.size mw, mh = self.get_map_size() scroll_width = self.scroll_width self.has_scrollbar = True scroll_y_position = Vector(sw - scroll_width, 0) scroll_x_position = Vector(0, sh - scroll_width) self.scroll_bar_y = ScrollBar("y", scroll_y_position, sh, vh, mh, scroll_width) self.scroll_bar_x = ScrollBar("x", scroll_x_position, sw, vw, mw, scroll_width) self.scroll_bar_y.update(sy) self.scroll_bar_x.update(sx)
def calc_map_display(self): sx, sy = self.screen_tile_size map_tile_size = self.map_tile_size factor = (sx / map_tile_size, sy / map_tile_size) width, height = self.map_hw() map_size = Vector(width * sx, height * sy) self.factor = factor self.map_size = map_size
def calc_size(self, position: Vec, screen_size: Vec, screen_tile_size: Vec) -> Tuple[int, int]: sw, sh = screen_size tx, ty = screen_tile_size height = sh - position[1] length = height // ty inner_height = length * ty margin = (height - inner_height) // 2 self.height = height self.inner_height = inner_height self.length = length self.margin = margin self.screen_size = Vector(*screen_size) self.screen_tile_size = Vector(*screen_tile_size) self.width = ty self.position = Vector(*position) return height, length
def __init__(self, position: Vec, size: Vec, screen_size: Vec, tile_size: Optional[Vec] = None, *, fill_color: Color = (192, 192, 192), limit_margin: bool = False) -> None: self.calc_size(size, screen_size, tile_size, position, limit_margin=limit_margin) self.fill_color = fill_color self.curr_scroll = Vector(0, 0) self.max_scroll = Vector(0, 0) self.map_size = None self.bgimage_override = None self.screen = pygame.Surface(screen_size) self.screen.fill(fill_color)
def compute_dimensions() -> Tuple[Vector, Vector, Vector, Vector, Vector, Margin]: info = pygame.display.Info() (curr_w, curr_h) = current_size = Vector(info.current_w, info.current_h) (vw, vh) = visible_map_size = Vector(30, 16) (tw, th) = (vw + 2, vh + 2) screen_tile_size = tx, ty = (curr_w // tw, curr_h // th) min_tile = min(screen_tile_size) # min_tile_type = "x" if min_tile == tx else "y" screen_tile_size = tx, ty = (min_tile, min_tile) (mt, mr, mb, ml) = margin = Margin(20, 0, 0, tx + 2) canvas_position = Vector(ml, mt) # canvas_size = (cw, ch) = (vw * tx, vh * ty) canvas_size = Vector(curr_w - mr - ml, curr_h - mt - mb) return ( canvas_position, visible_map_size, canvas_size, current_size, screen_tile_size, margin )
def set_map(self, map: Map, tileset: Optional[Tileset] = None): self.map = map self.tileset = tileset self.show_layers = 0b1111 if tileset: self.map_tile_size = tileset.tile_size else: self.map_tile_size = self.screen_tile_size[0] self.curr_scroll = Vector(0, 0) dimensions = self.calc_map_size() self.display = pygame.Surface(dimensions)
def move_hero_key_y( self, keys: Union[MovementKeys, MovementKeysUD, Tuple[str, str]] = ("up", "down") ) -> bool: if not isinstance(keys, (MovementKeysUD, MovementKeys)): keys = MovementKeysUD(*keys) keyboard = Window.get_keyboard() hx, hy = self.hero_position moved = False if keyboard.key_pressed(keys.up): hy -= 1 moved = not moved if keyboard.key_pressed(keys.down): hy += 1 moved = not moved hero_position = Vector(hx, hy) if moved and self.can_move_to(hero_position): self.move_hero_to(hero_position) return moved return False
def move_hero_key_x( self, keys: Union[MovementKeys, MovementKeysLR, Tuple[str, str]] = ("left", "right") ) -> bool: if not isinstance(keys, (MovementKeysLR, MovementKeys)): keys = MovementKeysLR(*keys) keyboard = Window.get_keyboard() hx, hy = self.hero_position moved = False if keyboard.key_pressed(keys.left): hx -= 1 moved = not moved if keyboard.key_pressed(keys.right): hx += 1 moved = not moved hero_position = Vector(hx, hy) if moved and self.can_move_to(hero_position): self.move_hero_to(hero_position) return moved return False
def move_hero_to(self, position: Vec): x, y = position width, height = self.get_map_size() if (0 <= x < width) and (0 <= y < height): p0 = self.hero_position self.hero_position = Vector(*position) mx, my = self.max_scroll if max(mx, my) > 0: sx, sy = self.curr_scroll width, height = self.size map_width, map_height = self.get_map_size() half_w, half_h = width // 2, height // 2 rw, rh = width % 2, height % 2 dx, dy = sub_v(p0, position) to_x, to_y = 0, 0 if dx > 0 and sx > 0 and (map_width - x) > half_w: # indo para a esquerda, posição atual está a > meia tela da borda direita to_x = -dx elif dx < 0 and sx <= mx and x > half_w + rw: # indo para a direita, posição atual está a > meia tela da borda esquerda to_x = -dx if dy > 0 and sy > 0 and (map_height - y) > half_h: # subindo, posição atual está a > meia tela do fundo to_y = -dy elif dy < 0 and sy <= my and y > half_h + rh: # descendo, posição atual está a > meia tela do topo to_y = -dy self.scroll((to_x, to_y)) hx, hy = self.get_hero_screen_position() self.hero.set_position(hx, hy)
def calc_size(self, size: Vec, screen_size: Vec, tile_size: Optional[Vec] = None, position: Optional[Vec] = None, *, limit_margin: bool = False) -> Tuple[Vector, Vector, Vector]: sw, sh = screen_size width, height = size if limit_margin is None: limit_margin = self.limit_margin else: self.limit_margin = limit_margin if tile_size == None: tile_size = Vector(sw // width, sh // height) if limit_margin: min_tile = min(tile_size) tile_size = Vector(min_tile, min_tile) else: tile_size = Vector(*tile_size) tx, ty = tile_size (vw, vh) = display_size = Vector(width * tx, height * ty) margin = Vector((sw - vw) // 2, (sh - vh) // 2) self.width = width self.height = height self.margin = margin self.screen_tile_size = tile_size self.display_size = display_size self.screen_size = screen_size if position is not None: self.position = Vector(*position) return display_size, margin, tile_size
def add_v(a: Vec, b: Vec) -> Vector: return Vector(a[0] + b[0], a[1] + b[1])
def place_hero(self, hero: Sprite, position: Vec = (0, 0)): self.hero = hero self.hero_position = Vector(*position)
def get_display_position(self, x: int, y: int) -> Vector: tile_size = self.map_tile_size return Vector(x * tile_size, y * tile_size)
def size(self) -> Vector: return Vector(self.width, self.height)
def clamp_2(values: Vec, limit_x: Vec, limit_y: Vec) -> Vector: x, y = values lx0, lx1 = limit_x ly0, ly1 = limit_y return Vector(max(lx0, min(x, lx1)), max(ly0, min(y, ly1)))
def clamp(values: Vec, limit: Vec) -> Vector: x, y = values l0, l1 = limit return Vector(max(l0, min(x, l1)), max(l0, min(y, l1)))
def sub_v(a: Vec, b: Vec) -> Vector: return Vector(a[0] - b[0], a[1] - b[1])
def get_positions(margin: Margin) -> Tuple[Vector, Vector]: tilebar_position = Vector(0, margin.top) label_position = Vector(margin.left, 2) return tilebar_position, label_position
def map_hw(self) -> Vector: map = self.map map_w, map_h = map.width, map.height display_w, display_h = self.width, self.height return Vector(min(map_w, display_w), min(map_h, display_h))