Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Como montar mapas maiores que a tela?

(Contexto) No curso do Pacman o professor ensinou a criar um mapa para o jogo, usando coordenadas pixels, exemplo: tal casa/quadrante do mapa fica em uma posição x y da tela. Mas e se o mapa fosse por exemplo o de Pokemon Fire Red, sendo muito maior que a tela. Eu pensei e cheguei a conclusão que a Relatividade poderia me ajuda, bastasse que o mapa fosse gerado em relação a um Ponto 0, (assim a casa/quadrante não teria um ponto x y definido, ela tem uma posição x y em relação ao Ponto 0, e mais, não seria preciso calcular a posição de tudo, apenas do Ponto 0, e quando fossem pintados os objetos, eles já estariam no lugar certo) e então para levar a câmera para a direita, bastasse puxar o Ponto 0 para a esquerda... (Duvida) O problema veio em um detalhe que não tem nada haver com o mapa em si. A pergunta é como usando a fila de eventos eu configuro o mouse para ser como a mão do paint, eu aperto e arrasto, e então o Ponto 0 faz o mesmo movimento que o mouse.

1 resposta
solução!

Olá Nicolas, peço desculpas pela demora no retorno.

Sobre essa questão de relatividade que você mencionou faz sentido sim, fazer o mapa ser gerado a partir do (0, 0) e "puxar" esse ponto na direção contrária do movimento desejado. De forma mais detalhada seria pegar a coordenada do centro da visão a cada movimento e calcular quais as coordenadas dentro de um quadrado ao redor dessa coordenada, que seria a parte visível no momento.

Para receber eventos de movimento do mouse você pode usar o tipo de evento pygame.MOUSEMOTION e então testar se o botão do mouse está pressionado ou não, a partir daí é possível pegar a coordenada do mouse e utilizar para mover o mapa. Segue um exemplo bem básico feito em cima do código da aula:

import pygame

pygame.init()

screen = pygame.display.set_mode((800, 800), 0)
font = pygame.font.SysFont("arial", 20, True, False)

AMARELO = (255, 255, 0)
PRETO = (0, 0, 0)
AZUL = (0, 0, 255)
VELOCIDADE = 1


class Cenario:
    def __init__(self, tamanho):
        self.tamanho = tamanho
        self.matriz = [
            # Matriz mapa mostrada em aula ...
        ]

    def pintar_linha(self, tela, numero_linha, linha):
        for numero_coluna, coluna in enumerate(linha):
            x = numero_coluna * self.tamanho
            y = numero_linha * self.tamanho
            half = self.tamanho // 2
            cor = PRETO
            if coluna == 2:
                cor = AZUL
            pygame.draw.rect(tela, cor, (x, y, self.tamanho, self.tamanho), 0)
            if coluna == 1:
                pygame.draw.circle(tela, AMARELO, (x + half, y + half),
                                   self.tamanho // 10, 0)

    def pintar(self, posicao, tela):
        # Área a ser mostrada ao redor da câmera
        distancia_renderizada = 10

        top = posicao[1] + distancia_renderizada
        right = posicao[0] + distancia_renderizada
        bottom = posicao[1] - distancia_renderizada
        left = posicao[0] - distancia_renderizada

        # Selecionando apenas a região da matriz que deve ser mostrada
        lines = self.matriz[max([bottom, 0]):min([top, 29])]
        visible_matrix = [line[max([left, 0]):min([right, 28])] for line in lines]

        for numero_linha, linha in enumerate(visible_matrix):
            self.pintar_linha(tela, numero_linha, linha)

    def processar_eventos(self, posicao, eventos):
        for e in eventos:
            if e.type == pygame.MOUSEMOTION:
                if pygame.mouse.get_pressed()[0]:
                    # Pega a coordenada do mouse
                    mouse_x, mouse_y = e.pos

                    # Converte a coordenada recebida em pixels (800, 800) para
                    # a escala da no matriz do mapa (29, 28)
                    posicao[0] = int(mouse_x / 29)
                    posicao[1] = int(mouse_y / 28)

        return posicao


if __name__ == "__main__":
    size = 600 // 30
    cenario = Cenario(size)
    posicao = [0, 0]

    while True:
        # Pintar a tela
        screen.fill(PRETO)
        cenario.pintar(posicao, screen)
        pygame.display.update()
        pygame.time.delay(100)

        # Captura os eventos
        eventos = pygame.event.get()
        for e in eventos:
            if e.type == pygame.QUIT:
                exit()
        posicao = cenario.processar_eventos(posicao, eventos)

Código acima em execução:

GIF movendo o mapa com o mouse

Ainda tem várias limitações nesse código mas já é um bom ponto de partida. Os pontos importantes são a leitura da coordenada do mouse na função processar_eventos e a seleção da área do mapa a ser mostrada em pintar

Você pode ver mais sobre movimento de câmera (sem o mouse) no capítulo 8 do livro Making games with Python & Pygame e sobre mover elementos com o mouse na página PyGame: Drag object on screen using mouse

Exemplo do jogo feito no capítulo 8 do livro "Making games with Python & Pygame":

GIF exemplo do jogo feito no capítulo 8 do livro "Making games with Python & Pygame"

Espero que isso ajude, qualquer dúvida é só falar!