soma0sd

코딩 & 과학 & 교육

Pygame: 등축투영 타일맵을 가운데 배치하기

반응형

게임을 제작하다보니 소스코드의 덩치가 꽤나 커져서 깃허브에 저장소를 만들었습니다.

등축투영(isometric) 타일은 정육면체를 표현할 때 윗면만 보이는 직교좌표계 타일맵과는 다르게 세 면이 동시에 같은 넓이로 보이는 타일맵을 의미합니다. 높이 표현이 수월하며 입체 표현이 용이합니다. 그러나, 타일을 그릴 때 정사각형을 기반으로 하는 직교좌표계 타일보다 그리기가 어렵고, 캐릭터의 이동방향이 기울어져있어 조작의 직관성이 떨어진다는 단점이 있습니다.

오늘은 어제 한 타일 배치에 이어 파이게임(Pygame)의 게임화면에 배치한 등축투영 타일맵을 중앙에 배치하도록 합니다.

(왼쪽) 정렬 없이 타일맵 배치 (오른쪽) 타일맵 배치 후 중앙정렬

타일맵을 그냥 배치하면 제일 위쪽의 타일부터 배치하다보니 게임 타일맵 전체가 한쪽에 치우친 것을 볼 수 있습니다. 게임을 시작할 때 한쪽에 치우친 타일맵을 보기보단 유저가 타일맵의 중앙을 보는 것이 좋을겁니다.

타일맵 초기화

타일맵 소스코드를 보면, 타일맵 클래스의 초기화를 수행할 때 카메라의 기준위치를 잡는 self.__cam_pos_xself.__cam_pos_y이 있습니다.

    def __init__(self, tileset: "Tileset", grid=(64, 32), size=(8, 8)):
        """타일맵 초기화
        Args:
            tileset: 타일셋 클래스
            grid: 타일 배치를 위한 격자의 크기
            size: 타일맵의 크기
        """
        self.__tileset = tileset
        self.__grid = grid
        self.__map = numpy.zeros(size, numpy.uint8)
        box_width = size[0] * 0.5 * grid[0] + size[1] * 0.5 * grid[0]
        box_height = size[0] * 0.5 * grid[1] + size[1] * 0.5 * grid[1]
        mod_x = (1 - size[0] / size[1]) * box_width * 0.5
        mod_y = (1 - size[0] / size[1]) * box_height * 0.5
        self.__cam_pos_x = grid[0] * 0.5 + mod_x
        self.__cam_pos_y = -grid[1] + box_height * 0.5

그려질 타일맵의 픽셀단위 너비(box_width)와 높이(box_height)를 파악하고 게임화면의 기준위치에 대해 상대적인 위치를 구하는 과정입니다.

타일맵 출력

소스코드의 blit_to() 메서드에는 출력할 표면에서 기준위치(xcenter, ycenter)를 잡아 그곳을 중심으로 타일맵을 배치합니다. 타일을 배치하는 위치의 보정합계는 xcamycam이 됩니다.

    def blit_to(self, surface: "Surface"):
        """지정한 표면에 타일맵을 출력"""
        surface.fill(pygame.Color(0, 0, 0, 0))
        xlim, ylim = self.shape
        xcenter = surface.get_rect().centerx
        ycenter = surface.get_rect().centery
        xcam = self.__cam_pos_x - xcenter
        ycam = self.__cam_pos_y - ycenter
        _w, _h = self.__grid
        for _x, _y in product(range(xlim), range(ylim)):
            tile = self.__tileset[self[_x, _y]]
            iso_x = -_x * _w * 0.5 + _y * _w * 0.5
            iso_y = _x * _h * 0.5 + _y * _h * 0.5 - tile.get_size()[1]
            surface.blit(tile, (iso_x - xcam, iso_y - ycam))
        end_x = surface.get_rect().right
        end_y = surface.get_rect().bottom
        pygame.draw.line(surface, (255, 0, 0, 150), (0, ycenter), (end_x, ycenter))
        pygame.draw.line(surface, (255, 0, 0, 150), (xcenter, 0), (xcenter, end_y))

메서드 마지막의 pygame.draw.line()들은 기준점을 표시하는 선을 그려내는 역할을 합니다.

기준점 변경

만약 아래쪽에 UI가 있어서 유저가 보는 가운데 지점이 조금 더 올라가야 한다면 xcenterycenter 값을 변경하여 기준점을 변경할 수 있습니다.

(왼쪽) ycenter에 0.75를 곱함 (오른쪽) xcenter에 1.25를 곱함

물론 재사용하기 좋은 클래스로 만드려면 이 값을 아예 초기화 매개변수로 만들거나 해야하겠지만 일단 원하는 기능을 하도록 만들었습니다. 현재는 뭐가 마음에 안들지 모르는 일이니 코드 정리는 필요할 때마다 하려고요.

반응형
태그:

댓글

End of content

No more pages to load