Mudanças entre as edições de "Introdução a Python - Parte 2"

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar
 
(18 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 1: Linha 1:
 
__toc__
 
__toc__
  
''[http://pygame.org Pygame] é um conjunto de módulos Python projetados para a escrita de jogos. Pygame adiciona funcionalidade sobre a excelente biblioteca [http://www.libsdl.org/ SDL]. Isso possibilita que se criem jogos repletos de recursos e programas multimidia com a linguagem Python. Pygame é altamento portável e roda em praticamente todas as plataformas e sistemas operacionais. Pygame já foi transferido milhões de vezes, e sua página oficial já recebeu milhões de acessos.'' (traduzido do [http://pygame.org/hifi.html parágrafo inicial encontrado na página oficial])
+
''[http://pygame.org Pygame] é um conjunto de módulos Python projetados para a escrita de jogos 2D. Pygame adiciona funcionalidade sobre a excelente biblioteca [http://www.libsdl.org/ SDL]. Isso possibilita que se criem jogos repletos de recursos e programas multimidia com a linguagem Python. Pygame é altamento portável e roda em praticamente todas as plataformas e sistemas operacionais. Pygame já foi transferido milhões de vezes, e sua página oficial já recebeu milhões de acessos.'' (traduzido do [http://pygame.org/hifi.html parágrafo inicial encontrado na página oficial])
  
 
= Referências =
 
= Referências =
Linha 20: Linha 20:
 
     libav-tools libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsmpeg-dev \
 
     libav-tools libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsmpeg-dev \
 
     libsdl1.2-dev libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev \
 
     libsdl1.2-dev libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev \
     libtiff5-dev libx11-6 libx11-dev fluid-soundfont-gm \
+
     libtiff5-dev libx11-6 libx11-dev fluid-soundfont-gm libfreetype6-dev \
 
     xfonts-base xfonts-100dpi xfonts-75dpi xfonts-cyrillic fontconfig fonts-freefont-ttf
 
     xfonts-base xfonts-100dpi xfonts-75dpi xfonts-cyrillic fontconfig fonts-freefont-ttf
 
   
 
   
Linha 32: Linha 32:
 
Este primeiro exemplo mostra como se pode criar um pequeno programa com uma imagem em movimento. Muitos elementos de pygame já aparecem nesta simples demonstração ...
 
Este primeiro exemplo mostra como se pode criar um pequeno programa com uma imagem em movimento. Muitos elementos de pygame já aparecem nesta simples demonstração ...
  
<syntaxhighlight lang=python>
+
<syntaxhighlight lang=python n>
 
#!/usr/bin/python3
 
#!/usr/bin/python3
  
Linha 90: Linha 90:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
... e é necessário copiar [http://tele.sj.ifsc.edu.br/~msobral/mcc/ball.gif este arquivo de imagem] para seu computador (para mesmo diretório onde está o programa exemplo).
+
Baixe os [http://tele.sj.ifsc.edu.br/~msobral/mcc/ball.tgz arquivos deste exemplo] para experimentá-lo. O programa está no script ''ball.py''.
  
  
 
Algumas observações:
 
Algumas observações:
* a bola provavelmente se movimenta muito rápido na tela ... reduza sua velocidade para melhor visualizá-la.
+
* Antes de mais nada, o módulo ''pygame'' deve ser importado e inicializado (linhas 4 e 7)
 +
* A bola provavelmente se movimenta muito rápido na tela ... reduza sua velocidade para melhor visualizá-la.
  
 
= Elementos da API pygame =
 
= Elementos da API pygame =
 +
 +
* [http://pygame.org/docs/#reference Referência]
 +
 +
 +
A API Pygame dispõe de um conjunto de elementos que podem ser usados em aplicativos gráficos. Basicamente eles se dividem em:
 +
* Representação da tela ou de um elemento gráfico (ex: uma imagem, como a da bola)
 +
* Eventos, tais como os do mouse, teclado e temporizadores
 +
* Cores e fontes
 +
* Funções para desenho
 +
* Imagens e Sprites
 +
* Temporização
 +
* Mouse e teclado
 +
* ... e alguns outros
 +
 +
Nesta introdução a Python são apresentados alguns desses elementos, de forma que se possam implementar o jogo proposto ao final da oficina (ou algum outro que se ache mais interessante !).
 +
 +
== Display ==
 +
 +
O [http://pygame.org/docs/ref/display.html display] em Pygame representa a tela ou uma janela. Um display é iniciado da seguinte forma:
 +
 +
<syntaxhighlight lang=python>
 +
resolucao = (largura, altura)
 +
janela = pygame.display.set_mode(resolucao)
 +
</syntaxhighlight>
 +
 +
A resolução é uma [[Introdução_a_Python_-_Parte_1#Tuplas|tupla]] que especifica as dimensões da janela. Se a resolução for (0,0), então a janela terá a dimensão da tela (modo tela cheia). Há outros dois parâmetros opcionais, que podem ser usados para escolher o tipo exato de display. Maiores detalhes podem ser lidos na [http://pygame.org/docs/ref/display.html#pygame.display.set_mode referência sobre a inicialização do display].
 +
 +
Uma vez iniciado, um display pode ser usado como uma superfície. No exemplo, essa superfície é referenciada pela variável ''janela''. O que se pode fazer cm uma superfície, que é um elemento fundamental de pygame para representar imagens, é apresentado na próxima seção. Por enquanto, é importante saber que, sempre que se fizerem modificações na tela, deve-se executar o seguinte:
 +
 +
<syntaxhighlight lang=python>
 +
pygame.display.flip()
 +
</syntaxhighlight>
 +
 +
Todas as modificações que se fazem na tela não são apresentadas imediatamente. A tela é composta por dois buffers, sendo um o buffer cujo conteúdo é apresentado, e outro onde se fazem atualizações. O método [http://pygame.org/docs/ref/display.html#pygame.display.flip flip] troca os buffers, invertendo seus papéis. Com isso, modificações na tela são acumuladas e ao final podem ser apresentadas de uma vez só.
 +
 +
== Surface (superfície) ==
 +
 +
Um [http://pygame.org/docs/ref/surface.html superfície] representa uma imagem, possuindo uma resolução fixa.. Qualquer elemento em pygame do tipo imagem, seja carregada de um arquivo ou gerada dinamicamente, é uma superfície. Operações típicas que podem ser feitas em superfícies são cópia de outras imagens, desenho, preenchimento com cores, deslocamento, entre outras.
 +
 +
Uma superfície possui coordenadas corrspondentes a suas dimensões, as quais são representadas por um retângulo. A classe [http://pygame.org/docs/ref/rect.html Rect] possui a fucionalidade para representar e manipular esse retângulo. O retângulo de uma superfície pode ser obtido pelo método [http://pygame.org/docs/ref/surface.html#pygame.Surface.get_rect get_rect], como se pode ver na linha 25 do [[Introdução_a_Python_-_Parte_2#Um_primeiro_exemplo|exemplo da bola]]:
 +
 +
<syntaxhighlight lang=python>
 +
ballrect = ball.get_rect()
 +
</syntaxhighlight>
 +
 +
O retângulo possui os atributos ''right'',''left'',''top'',''bottom'', para os limites de cada lado. Se esses atributos forem modificados, pode-se usar o retângulo para desenhar uma imagem em outra posição da tela. A modificação do retângulo pode ser feita facilmente com o método [http://pygame.org/docs/ref/rect.html#pygame.Rect.move move], como feito na linha 37 do [[Introdução_a_Python_-_Parte_2#Um_primeiro_exemplo|exemplo da bola]]:
 +
 +
<syntaxhighlight lang=python>
 +
ballrect = ballrect.move(speed)
 +
</syntaxhighlight>... sendo que o parâmetro passado para ''move'' é uma tupla contendo os incrementos a serem feitos em suas coordenadas.
 +
 +
 +
Algumas das operações de superfície são usadas no [[Introdução_a_Python_-_Parte_2#Um_primeiro_exemplo|exemplo]]. Nele se trabalha com duas superfícies: ''screen'', que representa a tela da janela, e ''ball'', que representa a imagem da bola. A cada ciclo de execução, a bola é desenhada numa posição da tela, como mostrado nas linhas 37 a 52 destacadas a seguir:
 +
 +
<syntaxhighlight lang=python>
 +
    #
 +
    # move a bola de acordo com "speed". Isso muda as coordenadas do retângulo
 +
    # que a contém
 +
    ballrect = ballrect.move(speed)
 +
 +
    # se limites horizontais de movimentação foram atingidos, então velocidade horizontal
 +
    # é invertida
 +
    if ballrect.left < 0 or ballrect.right > width:
 +
        speed[0] = -speed[0]
 +
    # se limites verticais de movimentação foram atingidos, então velocidade vertical
 +
    # é invertida
 +
    if ballrect.top < 0 or ballrect.bottom > height:
 +
        speed[1] = -speed[1]
 +
 +
    # pinta toda a tela de preto
 +
    screen.fill(black)
 +
 +
    # copia a imagem da bola para a região definida por "ballrect"
 +
    screen.blit(ball, ballrect)
 +
</syntaxhighlight>
 +
 +
 +
A cada vez que se move o retângulo da bola (e após refletir a bola nas paredes, caso necessário), pinta-se toda a tela de preto. Isso é fundamental para limpar a tela antes de redesenhar a bola:
 +
 +
<syntaxhighlight lang=python>
 +
screen.fill(black)
 +
</syntaxhighlight>
 +
 +
... e, em seguida, desenha-se a bola na nova posição ditada pelo retângulo ''ballrect'':
 +
 +
<syntaxhighlight lang=python>
 +
screen.blit(ball, ballrect)
 +
</syntaxhighlight>
 +
 +
Assim, toda vez que se precisar desenhar uma superfície sobre outra, usa-se o método [http://pygame.org/docs/ref/surface.html#pygame.Surface.blit blit] da superfície que será modificada.
 +
 +
Por fim, note que o display deve ser atualizado após redesenhar a bola, como se pode ver na linha 55:
 +
 +
<syntaxhighlight lang=python>
 +
pygame.display.flip()
 +
</syntaxhighlight>
 +
 +
== Imagens e Sprites ==
 +
 +
Imagens são superfícies cujo conteúdo (seus pixels) são carregados de um arquivo. Diversos formatos de imagem são suportados. Uma imagem é criada usando a função [http://pygame.org/docs/ref/image.html#pygame.image.load load], tendo como resultado uma superfície que representa a imagem:
 +
 +
<syntaxhighlight lang=python>
 +
ball = pygame.image.load('ball.gif')
 +
</syntaxhighlight>
 +
 +
Após carregada, uma imagem pode ser usada como uma superfície qualquer, podendo inclusive ser modificada e salva novamente em arquivo (ver função [http://pygame.org/docs/ref/image.html#pygame.image.save save]).
 +
 +
[http://pygame.org/docs/ref/sprite.html Sprites] são elementos visíveis, que podem ser agrupados e desenhados ou removidos em conjuntos. Outras funcionalidades úteis são detecção de colisão ou sobreposição de elementos visuais, e controle da ordem em que são desenhados (para representar objetos que estão sobre outros). Apesar de, a rigor, ser um elemento importante para a criação de jogos, sprites fogem do escopo desta introdução. No entanto, a documentação fornece uma boa explicação.
 +
 +
== Eventos ==
 +
 +
Jogos e aplicativos gráficos somente são funcionais se puderem interagir com o usuário de alguma forma. A interação pode ser por teclado, mouse, joystick ou outros dispositivos. Pygame trata as entradas desses dispositivos e as apresenta para aplicativos na forma de [http://pygame.org/docs/ref/event.html eventos].
 +
 +
Eventos representam cliques e movimentações de mouse, teclas pressionadas ou liberadas, ativação de temporizadores e acontecimentos de interesse (ex: uma requisição para terminação do programa). Eventos podem ser recebidos de forma bloqueante usando a função [http://pygame.org/docs/ref/event.html#pygame.event.wait wait], ou verificados com a função [http://pygame.org/docs/ref/event.html#pygame.event.get get]. No [[Introdução_a_Python_-_Parte_2#Um_primeiro_exemplo|exemplo da bola]], usa-se a função ''get'' para coletar todos os eventos pendentes antes de novamente movimentar e redesenhar a bola:
 +
 +
<syntaxhighlight lang=python>
 +
    for event in pygame.event.get():
 +
        # apenas evento QUIT é considerado: ele faz com que a
 +
        # aplicação termine. Demais eventos são ignorados
 +
        if event.type == pygame.QUIT: sys.exit()
 +
</syntaxhighlight>
 +
 +
Como ''get'' retorna uma lista de eventos pendentes, pode-se iterá-la para tratar cada evento. No exemplo, trata-se apenas o evento ''pygame.QUIT'', que representa uma requisição para terminação do programa, ignorando-se outros eventos que possam ter ocorrido. Assim, se o mouse foi movimentado ou clicado sobre a tela, nenhum efeito terá sobre o aplicativo, pois os eventos correspondentes n]ao são tratados. Os tipos de evento podem ser vistos na documentação, sendo alguns deles:
 +
 +
{|border=1
 +
!Tipo de evento
 +
!Atributos
 +
!Significado
 +
|-
 +
|QUIT || none|| pedido de terminação do programa
 +
|-
 +
|ACTIVEEVENT || gain, state|| Programa recebeu foco do mouse
 +
|-
 +
|KEYDOWN || unicode, key, mod|| tecla pressionada
 +
|-
 +
|KEYUP || key, mod|| tecla liberada
 +
|-
 +
|MOUSEMOTION || pos, rel, buttons|| movimentação do mouse
 +
|-
 +
|MOUSEBUTTONUP || pos, button|| botão do mouse pressionado
 +
|-
 +
|MOUSEBUTTONDOWN || pos, button|| botão do mouse liberado
 +
|-
 +
|>= USEREVENT || None || evento gerado pelo próprio programa (ex: timer)
 +
|}
 +
 +
== Cores ==
 +
 +
Cores são tuplas contendo os valores para vermelho, verde e azul (RGB). Por exemplo, as cores preta e branca podem ser definidas assim:
 +
 +
<syntaxhighlight lang=python>
 +
preta = (0,0,0)
 +
branca = (255, 255, 255)
 +
</syntaxhighlight>
 +
 +
Os valores para vermelho, verde e azul podem ser obtidos com ferramentas específicas, como esta:
 +
*[http://www.rapidtables.com/web/color/RGB_Color.htm Tabela de cores RGB]
 +
 +
 +
Pygame possui a classe [http://pygame.org/docs/ref/color.html Color], que auxilia algumas operações sobre cores.
 +
 +
== Temporização ==
 +
 +
Jogos dependem de controle de tempo. O [[Introdução_a_Python_-_Parte_2#Um_primeiro_exemplo|exemplo da bola]] mostra que é necessário temporizar sua movimentação, do contrário a bola se move tão rápido quanto o programa possa ser executado. Pygame possui no [http://pygame.org/docs/ref/time.html módulo time] algumas facilidades para monitorar tempo e definir temporizadores. Temporizadores são úteis para dispararem eventos que sinalizem que um tempo de interesse acabou de transcorrer. Com isso, podem-se realizar coisas como apresentar uma imagem por 2 segundos, e então removê-la da tela.
 +
 +
 +
A criação de um temporizador deve ser feita usando a função [http://pygame.org/docs/ref/time.html#pygame.time.set_timer set_timer]:
 +
 +
<syntaxhighlight lang=python>
 +
# programa um timer para daqui a 2 segundos. Ele vai gerar um evento
 +
# do tipo USEREVENT+1
 +
python.time.set_timer(USEREVENT+1, 2000)
 +
</syntaxhighlight>
 +
 +
 +
Para tratar o evento desse timer, o programa deve ter algo assim em seu tratador de eventos:
 +
 +
<syntaxhighlight lang=python>
 +
for event in pygame.event.get():
 +
  if event.type == USEREVENT+1:
 +
    print('Passaram 2 segundos !')
 +
    # desativa o timer
 +
    pygame.time.set_timer(USEREVENT+1, 0)
 +
</syntaxhighlight>
 +
 +
Deve-se notar que o temporizador gera o evento periodicamente. Para desativá-lo deve-se chamar ''set_timer'' passando o tempo ''0'' (zero) como parâmetro.
 +
 +
== Um exercício ==
 +
 +
# Experimente modificar o [[Introdução_a_Python_-_Parte_2#Um_primeiro_exemplo|exemplo]] para que a bola seja paralisada na tela se um clique do mouse ocorrer sobre ela. Se um novo clique for feito, a bola volta a se movimentar.
 +
# Modifique o exemplo para que se crie um jogo de arremesso:
 +
#* A janela deve ser ampliada para ocupar toda a tela
 +
#* A bola fica no canto inferior esquerdo
 +
#* Um alvo é colocado em torno do canto superior direito
 +
#* Com o mouse se clica na bola, faz-se um movimento de arremesso em direção ao alvo (mantendo o botão do mouse pressionado)
 +
#* Ao se liberar o botão do mouse, ou quando a bola ultrapassar certo limiar, ela deve ser arremessada na direção do movimento
 +
#* A velocidade do arremesso depende da velocidade com que se arrastou a bola
 +
#* A direção do arremesso depende da direção com que se arrastou a bola
 +
#* O movimento da bola sofre efeito da gravidade
 +
#* Se a bola acertar o alvo, soma-se um ponto
  
 
= Um jogo de memória =
 
= Um jogo de memória =
  
* [http://tele.sj.ifsc.du.br/~msobral/mcc/cartoes.tgz Imagens de cartas do baralho]
+
Jogo de memória é um jogo clássico. Uma variedade de tipos e quantidades de cartões podem ser usadas. Esse jogo é relativamente fácil de implementar com pygame. A figura a seguir mostra um jogo de memória rudimentar que demorou cerca de 4 horas para ser criado (começando-se do zero ... nem se conhecia pygame antes disso !).
 +
 
 +
[[imagem:oficina-python-mem.png|400px]]
  
  
[[imagem:oficina-python-mem.png|400px]]
+
Tente implementá-lo com o conteúdo apresentado nesta oficina. Tudo que é necessário para criá-lo foi informado. Para os cartões podem-se usar [http://tele.sj.ifsc.edu.br/~msobral/mcc/cartoes.tgz estes arquivos de imagem de cartas de baralho].

Edição atual tal como às 19h00min de 22 de outubro de 2016

Pygame é um conjunto de módulos Python projetados para a escrita de jogos 2D. Pygame adiciona funcionalidade sobre a excelente biblioteca SDL. Isso possibilita que se criem jogos repletos de recursos e programas multimidia com a linguagem Python. Pygame é altamento portável e roda em praticamente todas as plataformas e sistemas operacionais. Pygame já foi transferido milhões de vezes, e sua página oficial já recebeu milhões de acessos. (traduzido do parágrafo inicial encontrado na página oficial)

Referências

Como instalar

Em distribuições Ubuntu, a instalação de Pygame para Python3 deve ser feita com esta sequência de comandos:

sudo apt-get update
sudo apt-get install mercurial python3-dev python3-setuptools python3-numpy python3-opengl \
    libav-tools libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsmpeg-dev \
    libsdl1.2-dev libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev \
    libtiff5-dev libx11-6 libx11-dev fluid-soundfont-gm libfreetype6-dev \
    xfonts-base xfonts-100dpi xfonts-75dpi xfonts-cyrillic fontconfig fonts-freefont-ttf
 
sudo apt-get install python3-pip
sudo apt-get build-dep python-pygame
sudo pip3 install hg+http://bitbucket.org/pygame/pygame

Um primeiro exemplo

Este primeiro exemplo mostra como se pode criar um pequeno programa com uma imagem em movimento. Muitos elementos de pygame já aparecem nesta simples demonstração ...

#!/usr/bin/python3

import sys
import pygame

# inicia as estruturas internas do pygame
pygame.init()

# algumas variáveis necessárias:
# size: tamanho da janela
# speed: velocidade da bola
# black: tupla que representa cor preta

size = width, height = 320, 240
speed = [2, 2]
black = (0, 0, 0)

# cria a tela da janela, dimensionando de acordo com a variável "size"
screen = pygame.display.set_mode(size)

# carrega a imagem da bola
ball = pygame.image.load("ball.gif")

# obtém o retângulo que contém as dimensões da imagem da bola
ballrect = ball.get_rect()

# laço que nunca termina ...
while True:
    # trata quaisquer eventos pendentes do pygame
    for event in pygame.event.get():
        # apenas evento QUIT é considerado: ele faz com que a
        # aplicação termine. Demais eventos são ignorados
        if event.type == pygame.QUIT: sys.exit()

    # move a bola de acordo com "speed". Isso muda as coordenadas do retângulo 
    # que a contém
    ballrect = ballrect.move(speed)

    # se limites horizontais de movimentação foram atingidos, então velocidade horizontal
    # é invertida
    if ballrect.left < 0 or ballrect.right > width:
        speed[0] = -speed[0]
    # se limites verticais de movimentação foram atingidos, então velocidade vertical
    # é invertida
    if ballrect.top < 0 or ballrect.bottom > height:
        speed[1] = -speed[1]

    # pinta toda a tela de preto
    screen.fill(black)

    # copia a imagem da bola para a região definida por "ballrect"
    screen.blit(ball, ballrect)

    # mostra a imagem que foi copiada
    pygame.display.flip()

Baixe os arquivos deste exemplo para experimentá-lo. O programa está no script ball.py.


Algumas observações:

  • Antes de mais nada, o módulo pygame deve ser importado e inicializado (linhas 4 e 7)
  • A bola provavelmente se movimenta muito rápido na tela ... reduza sua velocidade para melhor visualizá-la.

Elementos da API pygame


A API Pygame dispõe de um conjunto de elementos que podem ser usados em aplicativos gráficos. Basicamente eles se dividem em:

  • Representação da tela ou de um elemento gráfico (ex: uma imagem, como a da bola)
  • Eventos, tais como os do mouse, teclado e temporizadores
  • Cores e fontes
  • Funções para desenho
  • Imagens e Sprites
  • Temporização
  • Mouse e teclado
  • ... e alguns outros

Nesta introdução a Python são apresentados alguns desses elementos, de forma que se possam implementar o jogo proposto ao final da oficina (ou algum outro que se ache mais interessante !).

Display

O display em Pygame representa a tela ou uma janela. Um display é iniciado da seguinte forma:

resolucao = (largura, altura)
janela = pygame.display.set_mode(resolucao)

A resolução é uma tupla que especifica as dimensões da janela. Se a resolução for (0,0), então a janela terá a dimensão da tela (modo tela cheia). Há outros dois parâmetros opcionais, que podem ser usados para escolher o tipo exato de display. Maiores detalhes podem ser lidos na referência sobre a inicialização do display.

Uma vez iniciado, um display pode ser usado como uma superfície. No exemplo, essa superfície é referenciada pela variável janela. O que se pode fazer cm uma superfície, que é um elemento fundamental de pygame para representar imagens, é apresentado na próxima seção. Por enquanto, é importante saber que, sempre que se fizerem modificações na tela, deve-se executar o seguinte:

pygame.display.flip()

Todas as modificações que se fazem na tela não são apresentadas imediatamente. A tela é composta por dois buffers, sendo um o buffer cujo conteúdo é apresentado, e outro onde se fazem atualizações. O método flip troca os buffers, invertendo seus papéis. Com isso, modificações na tela são acumuladas e ao final podem ser apresentadas de uma vez só.

Surface (superfície)

Um superfície representa uma imagem, possuindo uma resolução fixa.. Qualquer elemento em pygame do tipo imagem, seja carregada de um arquivo ou gerada dinamicamente, é uma superfície. Operações típicas que podem ser feitas em superfícies são cópia de outras imagens, desenho, preenchimento com cores, deslocamento, entre outras.

Uma superfície possui coordenadas corrspondentes a suas dimensões, as quais são representadas por um retângulo. A classe Rect possui a fucionalidade para representar e manipular esse retângulo. O retângulo de uma superfície pode ser obtido pelo método get_rect, como se pode ver na linha 25 do exemplo da bola:

ballrect = ball.get_rect()

O retângulo possui os atributos right,left,top,bottom, para os limites de cada lado. Se esses atributos forem modificados, pode-se usar o retângulo para desenhar uma imagem em outra posição da tela. A modificação do retângulo pode ser feita facilmente com o método move, como feito na linha 37 do exemplo da bola:

ballrect = ballrect.move(speed)

... sendo que o parâmetro passado para move é uma tupla contendo os incrementos a serem feitos em suas coordenadas.


Algumas das operações de superfície são usadas no exemplo. Nele se trabalha com duas superfícies: screen, que representa a tela da janela, e ball, que representa a imagem da bola. A cada ciclo de execução, a bola é desenhada numa posição da tela, como mostrado nas linhas 37 a 52 destacadas a seguir:

    #
    # move a bola de acordo com "speed". Isso muda as coordenadas do retângulo 
    # que a contém
    ballrect = ballrect.move(speed)

    # se limites horizontais de movimentação foram atingidos, então velocidade horizontal
    # é invertida
    if ballrect.left < 0 or ballrect.right > width:
        speed[0] = -speed[0]
    # se limites verticais de movimentação foram atingidos, então velocidade vertical
    # é invertida
    if ballrect.top < 0 or ballrect.bottom > height:
        speed[1] = -speed[1]

    # pinta toda a tela de preto
    screen.fill(black)

    # copia a imagem da bola para a região definida por "ballrect"
    screen.blit(ball, ballrect)


A cada vez que se move o retângulo da bola (e após refletir a bola nas paredes, caso necessário), pinta-se toda a tela de preto. Isso é fundamental para limpar a tela antes de redesenhar a bola:

screen.fill(black)

... e, em seguida, desenha-se a bola na nova posição ditada pelo retângulo ballrect:

screen.blit(ball, ballrect)

Assim, toda vez que se precisar desenhar uma superfície sobre outra, usa-se o método blit da superfície que será modificada.

Por fim, note que o display deve ser atualizado após redesenhar a bola, como se pode ver na linha 55:

pygame.display.flip()

Imagens e Sprites

Imagens são superfícies cujo conteúdo (seus pixels) são carregados de um arquivo. Diversos formatos de imagem são suportados. Uma imagem é criada usando a função load, tendo como resultado uma superfície que representa a imagem:

ball = pygame.image.load('ball.gif')

Após carregada, uma imagem pode ser usada como uma superfície qualquer, podendo inclusive ser modificada e salva novamente em arquivo (ver função save).

Sprites são elementos visíveis, que podem ser agrupados e desenhados ou removidos em conjuntos. Outras funcionalidades úteis são detecção de colisão ou sobreposição de elementos visuais, e controle da ordem em que são desenhados (para representar objetos que estão sobre outros). Apesar de, a rigor, ser um elemento importante para a criação de jogos, sprites fogem do escopo desta introdução. No entanto, a documentação fornece uma boa explicação.

Eventos

Jogos e aplicativos gráficos somente são funcionais se puderem interagir com o usuário de alguma forma. A interação pode ser por teclado, mouse, joystick ou outros dispositivos. Pygame trata as entradas desses dispositivos e as apresenta para aplicativos na forma de eventos.

Eventos representam cliques e movimentações de mouse, teclas pressionadas ou liberadas, ativação de temporizadores e acontecimentos de interesse (ex: uma requisição para terminação do programa). Eventos podem ser recebidos de forma bloqueante usando a função wait, ou verificados com a função get. No exemplo da bola, usa-se a função get para coletar todos os eventos pendentes antes de novamente movimentar e redesenhar a bola:

    for event in pygame.event.get():
        # apenas evento QUIT é considerado: ele faz com que a
        # aplicação termine. Demais eventos são ignorados
        if event.type == pygame.QUIT: sys.exit()

Como get retorna uma lista de eventos pendentes, pode-se iterá-la para tratar cada evento. No exemplo, trata-se apenas o evento pygame.QUIT, que representa uma requisição para terminação do programa, ignorando-se outros eventos que possam ter ocorrido. Assim, se o mouse foi movimentado ou clicado sobre a tela, nenhum efeito terá sobre o aplicativo, pois os eventos correspondentes n]ao são tratados. Os tipos de evento podem ser vistos na documentação, sendo alguns deles:

Tipo de evento Atributos Significado
QUIT none pedido de terminação do programa
ACTIVEEVENT gain, state Programa recebeu foco do mouse
KEYDOWN unicode, key, mod tecla pressionada
KEYUP key, mod tecla liberada
MOUSEMOTION pos, rel, buttons movimentação do mouse
MOUSEBUTTONUP pos, button botão do mouse pressionado
MOUSEBUTTONDOWN pos, button botão do mouse liberado
>= USEREVENT None evento gerado pelo próprio programa (ex: timer)

Cores

Cores são tuplas contendo os valores para vermelho, verde e azul (RGB). Por exemplo, as cores preta e branca podem ser definidas assim:

preta = (0,0,0)
branca = (255, 255, 255)

Os valores para vermelho, verde e azul podem ser obtidos com ferramentas específicas, como esta:


Pygame possui a classe Color, que auxilia algumas operações sobre cores.

Temporização

Jogos dependem de controle de tempo. O exemplo da bola mostra que é necessário temporizar sua movimentação, do contrário a bola se move tão rápido quanto o programa possa ser executado. Pygame possui no módulo time algumas facilidades para monitorar tempo e definir temporizadores. Temporizadores são úteis para dispararem eventos que sinalizem que um tempo de interesse acabou de transcorrer. Com isso, podem-se realizar coisas como apresentar uma imagem por 2 segundos, e então removê-la da tela.


A criação de um temporizador deve ser feita usando a função set_timer:

# programa um timer para daqui a 2 segundos. Ele vai gerar um evento
# do tipo USEREVENT+1
python.time.set_timer(USEREVENT+1, 2000)


Para tratar o evento desse timer, o programa deve ter algo assim em seu tratador de eventos:

for event in pygame.event.get():
  if event.type == USEREVENT+1:
    print('Passaram 2 segundos !')
    # desativa o timer
    pygame.time.set_timer(USEREVENT+1, 0)

Deve-se notar que o temporizador gera o evento periodicamente. Para desativá-lo deve-se chamar set_timer passando o tempo 0 (zero) como parâmetro.

Um exercício

  1. Experimente modificar o exemplo para que a bola seja paralisada na tela se um clique do mouse ocorrer sobre ela. Se um novo clique for feito, a bola volta a se movimentar.
  2. Modifique o exemplo para que se crie um jogo de arremesso:
    • A janela deve ser ampliada para ocupar toda a tela
    • A bola fica no canto inferior esquerdo
    • Um alvo é colocado em torno do canto superior direito
    • Com o mouse se clica na bola, faz-se um movimento de arremesso em direção ao alvo (mantendo o botão do mouse pressionado)
    • Ao se liberar o botão do mouse, ou quando a bola ultrapassar certo limiar, ela deve ser arremessada na direção do movimento
    • A velocidade do arremesso depende da velocidade com que se arrastou a bola
    • A direção do arremesso depende da direção com que se arrastou a bola
    • O movimento da bola sofre efeito da gravidade
    • Se a bola acertar o alvo, soma-se um ponto

Um jogo de memória

Jogo de memória é um jogo clássico. Uma variedade de tipos e quantidades de cartões podem ser usadas. Esse jogo é relativamente fácil de implementar com pygame. A figura a seguir mostra um jogo de memória rudimentar que demorou cerca de 4 horas para ser criado (começando-se do zero ... nem se conhecia pygame antes disso !).

Oficina-python-mem.png


Tente implementá-lo com o conteúdo apresentado nesta oficina. Tudo que é necessário para criá-lo foi informado. Para os cartões podem-se usar estes arquivos de imagem de cartas de baralho.