Pygame – Drag and Drop

Hoje irei apresentar um exemplo de como carregar imagens com a biblioteca Pygame e como movimentar estas imagens utilizando o mouse (Drag and Drop).

Resumidamente, este exemplo tem o objetivo de mostrar como carregar uma imagem com fundo transparente, como redimensionar esta imagem utilizando a função SCALE da Pygame e como utilizar os eventosde mouse (MOUSEBUTTONDOWN e MOUSEBUTTONUP).

Bom, primeiramente é necessário carregar uma imagem. No exemplo foi utilizada a seguinte imagem:

chew

Neste exemplo a imagem deve estar na mesma pasta do arquivo fonte, caso contrário é necessário definir o caminho correto da imagem.

Ok, imagem salva, vamos ao código:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# Importa as bibliotecas utilizadas
import sys, pygame
from pygame import mouse

# Define uma cor padrao em RGB
WHITE = (255, 255, 255)

# Cria uma classe para armazenar os atributos do nosso heroi
class Hero(object):
    # Deixei alguns valores por padrao apenas por comodidade
    def __init__(self, image_path = "chew.png", scale = (100,160), position = [100, 200]):
        # Caminho para a imagem que ira representar o heroi
        self.image_path = image_path
        # Posicao inicial do heroi na tela
        self.position = position
        # Escala fixa do heroi
        self.scale = scale
        # Variavel utilizada para saber se o heroi esta selecionado ou nao
        self.held = False

        # Carrega a imagem do heroi
        self.image = pygame.image.load(self.image_path).convert_alpha()
        # Redimensiona a imagem para a escala definida
        self.image = pygame.transform.scale(self.image, self.scale)

# Classe principal responsavel pela logica do jogo
class Game(object):
    def __init__(self):
        # Inicializa a biblioteca pygame
        pygame.init()

        # Define a largura e altura da janela em pixels 600x400
        self.main_window = pygame.display.set_mode((600, 400))

        # Define um nome para a janela
        pygame.display.set_caption("Drag and Drop")

        # Utiliza uma lista para armazenar os herois do jogo
        self.heroes = []

        # Utilizado para controlar a velocidade de quadros (de atualizacoes da tela)
        self.clock = pygame.time.Clock()

    # Funcao utilizada para criar e carregar a imagem de todos os herois
    def create_heroes(self):
        self.heroes.append(Hero("chew.png", (100, 160), [100, 200]))
        self.heroes.append(Hero("chew.png", (80, 128), [50, 100]))
        self.heroes.append(Hero("chew.png", (50, 80), [400, 300]))
        self.heroes.append(Hero("chew.png", (25, 40), [300, 250]))

    # Funcao utilizada para verificar se a posicao do mouse esta em cima
    # de um heroi (passado por parametro)
    def is_over(self, mouse_pos, hero):
        # Verifica a posicao no eixo X
        if mouse_pos[0] > hero.position[0] and mouse_pos[0] < hero.position[0] + hero.scale[0]:
            # Verifica a posicao no eixo Y
            if mouse_pos[1] > hero.position[1] and mouse_pos[1] < hero.position[1] + hero.scale[1]:
                return True
        return False

    # Funcao chamada quando o usuario clica com o mouse
    def mouse_button_down(self):
        # Obtem a posicao atual do mouse
        mouse_pos = mouse.get_pos()

        for i in xrange(0, len(self.heroes)):
            # Somente "ativa" a imagem_selecionada se o usuario clicou em cima da imagem
            if self.is_over(mouse_pos, self.heroes[i]):
                self.heroes[i].held = True

    # Funcao chamada quando o usuario solta o botao do mouse
    def mouse_button_up(self):
        # 'Libera' todos os herois
        for i in xrange(0, len(self.heroes)):
            self.heroes[i].held = False

    # Funcao responsavel por atualizar a posicao de todos os herois
    def update_position(self):
        # Obtem a posicao atual do mouse
        mouse_pos = mouse.get_pos()

        for i in xrange(0, len(self.heroes)):
            # Se a variavel imagem_selecionada estiver "ativa" (True), atualiza a posicao da imagem
            if self.heroes[i].held:
                # Define as posicoes X e Y da imagem, posiciona a imagem com o mouse centralizado
                self.heroes[i].position[0] = mouse_pos[0] - self.heroes[i].scale[0]/2
                self.heroes[i].position[1] = mouse_pos[1] - self.heroes[i].scale[1]/2

    # Funcao que roda o jogo
    def run(self):
        # Chama a funcao para criar os herois
        self.create_heroes()

        # Loop principal do jogo
        while True:

            # Verifica se algum evento aconteceu
            for event in pygame.event.get():
                # Verifica se foi um evento de saida (pygame.QUIT), em caso afirmativo fecha a aplicacao
                if event.type == pygame.QUIT: 
                    sys.exit()
                # Se o usuario soltar o botao do mouse "ativa" a variavel imagem_selecionada
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    self.mouse_button_down()
                # Se o usuario soltar o botao do mouse "desativa" a variavel imagem_selecionada
                elif event.type == pygame.MOUSEBUTTONUP:
                    self.mouse_button_up()

            # Chama a funcao que atualiza a posicao dos herois
            self.update_position()

            # Preenche a tela com uma cor, neste caso preto (definido logo apos importar as bibliotecas)
            self.main_window.fill(WHITE)
            
            # Coloca a imagem de todos os herois na tela com base na posicao
            for i in xrange(0, len(self.heroes)):
                self.main_window.blit(self.heroes[i].image, self.heroes[i].position)
            
            # Atualiza a tela visivel ao usuario
            pygame.display.flip()

            # Limita a taxa de quadros (framerate) a 60 quadros por segundo (60fps)
            self.clock.tick(60)

if __name__ == "__main__":
    game = Game()
    game.run()

 

O código é relativamente simples. A classe Hero é utilizada para armazenar alguns atributos do herói (e.x. posição, escala, etc), bem como carregar (linha 22) e redimensionar (linha 24) a imagem. A classe Game é responsável por toda a lógica do ‘jogo’, como por exemplo criar a janela principal, criar os heróis e verificar os eventos de mouse. A função is_over é responsável por verificar se a posição do mouse está sobre uma determinada imagem. A função mouse_button_down é chamada quando o usuaário clica em alguma posição da tela e é responsável por verificar se o usuário clicou em alguma imagem. A função mouse_button_up é chamada quando o usuário solta o botão do mouse e é responsável por ‘liberar’ todas as imagens. A função update_position é responsável por atualizar a posição de todas as imagens.

No mais, o código está cheio de comentários para facilitar o entendimento, mas qualquer dúvida é só deixar um comentário aqui em baixo.

 

Atualização: neste exemplo foi utilizado Python 2.7.11 e Pygame 1.9.3.