def __init__(self, parent=None, main=None): """ :param parent: родительский элемент class Division :param main: Main приложения (default=None (<=> parent.main)) """ self._parent = parent self._main = main if main is None and parent is not None: self._main = parent.main if main is not None or parent is not None: if parent is not None: parent.add_child(self) self._rect = FRect(0, 0, 100, 100) self.absolute_position = False else: self._rect = FRect(0, 0, 0, 0) self.absolute_position = True self._abs_rect = self.calculate_global_rect() self.in_step = False self._elements = [] self._disabled = [] self.step_time = 1 self.event = None self.hover = False self.press = False self.select = False self.selected = None self.post_init()
def preview(self, size): """ Возвращает preview для инвентаря. :param size: (width, height) :return: pygame.Surface """ i_img = self._image[0] img_b_rect = i_img.get_bounding_rect() img = i_img.subsurface(img_b_rect) r = FRect(img_b_rect).fit(FRect(0, 0, *size)) return pygame.transform.scale(img, [int(e) for e in r.size])
def set_rect(self, rect): """ Изменить прямоугольник расположения. :param rect: Rect() """ self._rect = FRect(rect) if self.in_step: self._abs_rect = self.calculate_global_rect()
def _get_rect(self): """ Прямоугольник, описанный около объекта. Создаётся из pymunk.bb главного shape. :return: """ bb = self.bb r = FRect(bb.left, bb.bottom, bb.right - bb.left, bb.top - bb.bottom) return r
def draw(self, surface): super().draw(surface) b_rect = self._abs_rect if self.content: ir = FRect(0, 0, b_rect.w * .8, b_rect.h * .8) ir.center = b_rect.center r = FRect(self.content.get_rect()) r.fit_ip(ir) surface.blit(pygame.transform.scale(self.content, r.pygame.size), r.topleft)
def calculate_global_rect(self): """ Абсолютная позиция (прямоугольник) относительно области отрисовки. Рекомендуется вызывать только в Division.start_step, используйте get_global_rect :return: Rect() """ if self._parent is not None: rect = self._parent.global_rect elif self._main is not None: rect = self._main.get_visible_rect() else: return FRect(self._rect) if self.absolute_position: return FRect(*map(sum, zip(rect.topleft, self._rect.topleft)), *self._rect.size) else: s_rect = self._rect s_tl = Vec2d(s_rect.topleft) s_sz = Vec2d(s_rect.size) return FRect(*(s_tl / 100 * rect.size + rect.topleft), *(s_sz / 100 * rect.size))
def __init__(self, center, screen_rect, constraint, zoom_con=None, zoom_offset=1): """ :param center: Начальная позиция камеры :param screen_rect: Прямоугольник отображаемой области c масштабированием 1, важен лишь размер :param constraint: Область, в которую камере разрешено заходить [x1, y1, x2, y2] :param zoom_con: Ограничения масштабирования. [min, max] :param zoom_offset: """ self._constraint = pygame.Rect(constraint) self.i_size = list(screen_rect.size) self.screen_shift = list(screen_rect.topleft) if zoom_con is None: self.zoom_con = [None, None] else: self.zoom_con = zoom_con self.zoom_offset = zoom_offset self._target_zoom = 1 / zoom_offset if self.zoom_con[ 0] is not None and self._target_zoom < self.zoom_con[0]: self._target_zoom = self.zoom_con[0] if self.zoom_con[ 1] is not None and self._target_zoom > self.zoom_con[1]: self._target_zoom = self.zoom_con[1] self.move_speed = 6 self.zoom_speed = 2 self.rect = FRect(0, 0, *self.i_size) self.rect.center = center self.rect.clamp_ip(self._constraint) self._c_rect = FRect(self.rect) self.zoom = 1
def _set_rect(self, rect): if self._body is not None: self._body.position = FRect(rect).center
def _get_rect(self): r = FRect(*self._pos, 0, 0) r.inflate_ip(*self._size) return r
def _set_rect(self, rect): body = self._get_body() if body is not None: body.position = FRect(rect).center
class Camera: """ Класс камеры. Содержит набор методов для выбора отображаемой области уровня, масштабирования. """ def __init__(self, center, screen_rect, constraint, zoom_con=None, zoom_offset=1): """ :param center: Начальная позиция камеры :param screen_rect: Прямоугольник отображаемой области c масштабированием 1, важен лишь размер :param constraint: Область, в которую камере разрешено заходить [x1, y1, x2, y2] :param zoom_con: Ограничения масштабирования. [min, max] :param zoom_offset: """ self._constraint = pygame.Rect(constraint) self.i_size = list(screen_rect.size) self.screen_shift = list(screen_rect.topleft) if zoom_con is None: self.zoom_con = [None, None] else: self.zoom_con = zoom_con self.zoom_offset = zoom_offset self._target_zoom = 1 / zoom_offset if self.zoom_con[ 0] is not None and self._target_zoom < self.zoom_con[0]: self._target_zoom = self.zoom_con[0] if self.zoom_con[ 1] is not None and self._target_zoom > self.zoom_con[1]: self._target_zoom = self.zoom_con[1] self.move_speed = 6 self.zoom_speed = 2 self.rect = FRect(0, 0, *self.i_size) self.rect.center = center self.rect.clamp_ip(self._constraint) self._c_rect = FRect(self.rect) self.zoom = 1 def update(self, upd_time): tc, cc = self.rect.center, self._c_rect.center ts, cs = self.rect.size, self._c_rect.size # print(cs, self.zoom, self.zoom_offset, self.zoom / self.zoom_offset) dis_x, dis_y = tc[0] - cc[0], tc[1] - cc[1] ds_x, ds_y = ts[0] - cs[0], ts[1] - cs[1] if abs(ds_x) < .5: self._c_rect.w = ts[0] else: self._c_rect.w += ds_x * self.zoom_speed * upd_time / 1000 if abs(ds_y) < .5: self._c_rect.h = ts[1] else: self._c_rect.h += ds_y * self.zoom_speed * upd_time / 1000 if abs(dis_x) < .5: self._c_rect.centerx = tc[0] else: self._c_rect.centerx = cc[ 0] + dis_x * self.move_speed * upd_time / 1000 if abs(dis_y) < .5: self._c_rect.centery = tc[1] else: self._c_rect.centery = cc[ 1] + dis_y * self.move_speed * upd_time / 1000 self._c_rect.clamp_ip(self._constraint) def get_rect(self): """ Прямоугольник в системе координат уровня, который камера освещает на данный момент.. :return: Rect() """ return self._c_rect # rect = pygame.Rect(0, 0, 0, 0) # rect.center = self.c_rect.center # rect.inflate_ip(self.c_rect.width // 2 * 2, self.c_rect.height // 2 * 2) # return rect def move(self, shift): """ Сдвинуть камеру на вектор. :param shift: (x, y) """ self.rect.x += shift[0] self.rect.y += shift[1] self.rect.clamp_ip(self._constraint) def move_smooth(self, coef): """ Сдвиг камеры на процент текущего размера области отображения. :param coef: (x (%), y (%)) :return: """ self.rect.x += self._c_rect.width * coef[0] / 100 self.rect.y += self._c_rect.height * coef[1] / 100 self.rect.clamp_ip(self._constraint) def get_zoom(self): """ Целевое масштабирование камеры. :return: int """ return self._target_zoom * self.zoom_offset def set_zoom(self, zoom): """ Установить целевое масштабирование камеры. :param zoom: int """ # absolute zoom zoom = zoom / self.zoom_offset if zoom <= 0: return center = self.rect.center if self.zoom_con[ 0] is not None and zoom < self.zoom_con[0] / self.zoom_offset: zoom = self.zoom_con[0] / self.zoom_offset if self.zoom_con[ 1] is not None and zoom > self.zoom_con[1] / self.zoom_offset: zoom = self.zoom_con[1] / self.zoom_offset premade = [e / zoom for e in self.i_size] if premade[0] > self._constraint.size[0] or premade[ 1] > self._constraint.size[1]: m_ind = min((0, 1), key=lambda e: self._constraint.size[e] - premade[e]) self.set_zoom(self.i_size[m_ind] / self._constraint.size[m_ind] * self.zoom_offset) return self.rect.size = premade self.rect.center = center self.rect.clamp_ip(self._constraint) self._target_zoom = zoom def reload_zoom(self, old_offset=1): self.set_zoom(self.get_zoom() * old_offset) zoom = property(get_zoom, set_zoom) def get_current_zoom(self): """ Масштабирование камеры в данный момент. :return: int """ return self.i_size[0] / self._c_rect.width def get_center(self): """ Целевая позиция камеры :return: (x, y) """ return self.rect.center def set_center(self, pos): """ Установка целевой позиции камеры. :param pos: (x, y) """ self.rect.center = pos center = property(get_center, set_center) def get_constraint(self): return self._constraint def set_constraint(self, rect): self._constraint = pygame.Rect(rect) self.reload_zoom() constraint = property(get_constraint, set_constraint) def move_constraint(self, rect): self._constraint = pygame.Rect(rect) self.rect.clamp_ip(self._constraint) def get_size(self): return self.i_size def set_size(self, size): self.i_size = size self.reload_zoom() size = property(get_size, set_size) def instant_move(self): self._c_rect.center = self.rect.center def instant_zoom(self): self._c_rect.size = self.rect.size def instant_target(self): """ Мнгновенно установить камеру в целевую позицию """ self._c_rect = self.rect.copy() def world_to_local(self, pos): rect = self.get_rect() tl = rect.topleft zoom = self.get_current_zoom() return (Vec2d(pos) - tl) * zoom def local_to_world(self, pos): rect = self.get_rect() tl = rect.topleft zoom = self.get_current_zoom() return Vec2d(pos) / zoom + tl