Capítulo 16 - Sons e explosões

Nenhum jogo tem graça se não tiver bons efeitos visuais e sonoros. É importante ter em mente, também, que mesmo que não estejamos desenvolvendo, exatamente, um jogo, a ludificação (ou gamificação, um anglicismo comum para o mesmo termo) – a adição de elementos comuns aos jogos para a melhoria da experiência do usuário em programas mais tradicionais – é uma prática crescentemente adotada.

O arquivo esqueleto.py, usado como base para jogos feitos com a linguagem Python e a biblioteca Pygame:

#!/usr/bin/python 
# -*- coding: utf-8 -*- 
# 
# esqueleto.py - versão 0.99 - Cesar Brod 
# 
# Para executar esse programa, você deve ter a linguagem Python 
# instalada em seu sistema, assim como a biblioteca Pygame. 
# 
# Usuários de sistemas Debian e seus derivados podem usar seu 
# gerenciador de pacotes e instalar python e python-pygame ou, na linha 
# de comandos digitar: 
# 
# sudo apt-get install python python-pygame 
# 
# Este programa foi desenvolvido para o livro "De Tartaruga à Cobra - 
# programação e arte", de Cesar Brod, Editora Novatec, São Paulo, 2013. 
# 

import sys  # reconhece eventos do sistema 
import pygame 
from pygame.locals import *  # constantes para a interação com o sistema 
pygame.init()  # inicializa as funções da biblioteca Pygame 
tamanho = largura, altura = 500, 420  # define o tamanho da tela 
preto = 0, 0, 0  # RGB para a cor preta 
cenario = pygame.display.set_mode(tamanho)  # cria o cenário do jogo 
quadros_por_segundo = pygame.time.Clock()  # permite o controle de velocidade da animação 

while 1:  # Repetição infinita, qualquer condição que seja sempre verdadeira 
# As linhas abaixo verificam se a ação de fechamento da janela (QUIT) foi 
# chamada e, caso positivo, fecha o programa 
    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            sys.exit() 

# *** PAUSA *** 
# A linha abaixo introduz uma pausa que pode ser interessante em casos de 
# teste. Para que a pausa aconteça, remova o # do começo da linha a seguir. 
# 
#    raw_input("Presione Enter para continuar...") 
# 
# Durante uma pausa, ou a qualquer momento da execução do programa, pode 
# ser importante exibir, na tela, suas variáveis, a fim de testar a lógica 
# do programa e os resultados esperados 
# 
#    print 'variavel_1 = ' + str(variavel_1) + ' | variavel_2 = ' + str(variavel_2) 
    tecla = pygame.key.get_pressed() 
    cenario.fill(preto)  # pinta o cenário de preto 
    pygame.display.flip()  # imprime o cenário atualizado 
    quadros_por_segundo.tick(60)  # animações rodam a 60 quadros por segundo 

O programa bola_sprite.py, com a execução passo-a-passo:

#!/usr/bin/python 
# -*- coding: utf-8 -*- 
# 
# bola_sprite.py - versão 0.99 - Cesar Brod 
# 
# Para executar esse programa, você deve ter a linguagem Python 
# instalada em seu sistema, assim como a biblioteca Pygame. 
# 
# Usuários de sistemas Debian e seus derivados podem usar seu 
# gerenciador de pacotes e instalar python e python-pygame ou, na linha 
# de comandos digitar: 
# 
# sudo apt-get install python python-pygame 
# 
# Este programa foi desenvolvido para o livro "De Tartaruga à Cobra - 
# programação e arte", de Cesar Brod, Editora Novatec, São Paulo, 2013. 
# 

import sys  # reconhece eventos do sistema 
from PIL import Image  # funções para a manipulação de imagens 
import pygame  # funções para jogos 
from pygame.locals import *  # constantes para a interação com o sistema 
pygame.init()  # inicializa as funções da biblioteca Pygame 

print 'Carreguei as bibliotecas de funções necessárias' 

tamanho = largura, altura = 500, 420  # define o tamanho da tela 
velocidade_bola = [1, 1] 
velocidade_raquete = [1, 1] 
gravidade = 1  # define o aumento da velocidade em y, simulando a gravidade 
coordenadas_bola = [0, 0] 
coordenadas_raquete = [175, 400] 
imagem_bola = "bola.png"  # a imagem que será usada para a bola 
l_bola, a_bola = (Image.open(imagem_bola)).size  # obtém a largura e altura da bola
preto = 0, 0, 0  # RGB para a cor preta 
branco = 255, 255, 255 # RGB para a cor branca 
cenario = pygame.display.set_mode(tamanho)  # cria o cenário do jogo 
clock = pygame.time.Clock()  # permite o controle de velocidade da animação 

print 'Inicializei as variáveis necessárias' 

class raquete(pygame.sprite.Sprite): 

    def __init__(self, l_raquete, a_raquete): 
        pygame.sprite.Sprite.__init__(self) 
        self.l_raquete = l_raquete 
        self.a_raquete = a_raquete 
        self.image = pygame.Surface([self.l_raquete, self.a_raquete]) 
        self.image.fill(branco) 
        self.rect = self.image.get_rect()  

class bola(pygame.sprite.Sprite): 

    def __init__(self, imagem_bola): 
        pygame.sprite.Sprite.__init__(self) 
        self.image = pygame.image.load(imagem_bola) 
        self.rect = self.image.get_rect() 

print 'Defini as classes' 

# Inicializa um grupo de sprites para a animação 
personagens = pygame.sprite.Group() 

# Faz com que bola_1 e raquete_1 sejam conhecidos como personagens 
bola_1 = bola(imagem_bola) 
raquete_1 = raquete(150, 20) 
personagens.add(bola_1) 
personagens.add(raquete_1) 

print 'Criei um grupo de sprites a partir das classes' 

while 1:  # Repetição infinita, qualquer condição que seja sempre verdadeira 

    print 
    print 'Estou na repetição infinita' 
    print 
    print 'Coordenadas da bola:    x = ' + str(coordenadas_bola[0]) + ', y = ' + str(coordenadas_bola[1]) 
    print 'Coordenadas da raquete: x = ' + str(coordenadas_raquete[0]) + ', y = ' + str(coordenadas_raquete[1]) 
    print 'Velocidade da bola:     x = ' + str(velocidade_bola[0]) + ', y = ' + str(velocidade_bola[1]) 

# As linhas abaixo verificam se a ação de fechamento da janela (QUIT) foi 
# chamada e, caso positivo, fecha o programa 
    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            print 'A janela foi fechada e encerrei o programa' 
            sys.exit() 

# Não permite que a bola "caia" abaixo do limite da tela 
    if coordenadas_bola[1] > altura - a_bola: 
        print 'Evitei que a bola ficasse abaixo do limite da tela' 
        coordenadas_bola[1] = altura - a_bola 

    coordenadas_bola[0] = coordenadas_bola[0] + velocidade_bola[0] 
    coordenadas_bola[1] = coordenadas_bola[1] + velocidade_bola[1] 

    if coordenadas_bola[0] > largura - l_bola or coordenadas_bola[0] < 0: 
        print 'A bola mudou de direção no eixo x' 
        velocidade_bola[0] = -velocidade_bola[0] 

    if coordenadas_bola[1] > altura - a_bola or coordenadas_bola[1] < 0: 
        print 'A bola mudou de direção no eixo y' 
        velocidade_bola[1] = -velocidade_bola[1] 

    if velocidade_bola[1] >= 0: 
        print 'A bola está descendo' 
        velocidade_bola[1] = velocidade_bola[1] + gravidade 
 
    else: 
        print 'A bola está subindo' 
        velocidade_bola[1] = velocidade_bola[1] + 1.1*gravidade 

# Habilita a verificação de teclas pressionadas 
    tecla = pygame.key.get_pressed() 

# Usa as setas para mover a raquete 
    if (tecla[K_LEFT]): 
        print 'A seta para a esquerda foi pressionada' 
        coordenadas_raquete[0] = coordenadas_raquete[0] - velocidade_raquete[0] 
    elif (tecla[K_RIGHT]): 
        print 'A seta para a direita foi pressionada' 
        coordenadas_raquete[0] = coordenadas_raquete[0] + velocidade_raquete[0] 

    print 'Atribuo as coordenadas aos sprites' 
    bola_1.rect.x = coordenadas_bola[0] 
    bola_1.rect.y = coordenadas_bola[1] 
    raquete_1.rect.x = coordenadas_raquete[0] 
    raquete_1.rect.y = coordenadas_raquete[1] 

# Teste de colisão 
    print 'coordenadas_bola[1] : ' + str(coordenadas_bola[1]) 
    if pygame.sprite.collide_rect(bola_1, raquete_1) == True: 
        print 'Detectei uma colisão entre bola e raquete! ' 
        pygame.mixer.Sound('/usr/lib/libreoffice/share/gallery/sounds/apert.wav').play() 
        print 'Toquei um som! ' 

# Não permite que a bola "penetre" na raquete 
        if coordenadas_bola[1] > raquete_1.rect.top: 
           coordenadas_bola[1] = raquete_1.rect.top 
           print 'Coordenada do eixo y da bola : ' + str(coordenadas_bola[1]) + ' altura : ' + str(altura) +  ' topo da raquete : ' + str(raquete_1.rect.top) 
           print 'Evitei que a bola penetrasse na raquete' 
        else: 
           velocidade_bola[1] = -velocidade_bola[1] - 1.1 * gravidade  # "impulsiona" a bola para cima 
           print 'Impulsionei a bola para cima' 

# *** PAUSA *** 
# A linha abaixo introduz uma pausa que pode ser interessante em casos de 
# teste. Para que a pausa aconteça, remova o # do começo da linha a seguir. 
# 
    raw_input("Presione Enter para continuar...") 
# 
# Durante uma pausa, ou a qualquer momento da execução do programa, pode 
# ser importante exibir, na tela, suas variáveis, a fim de testar a lógica 
# do programa e os resultados esperados 
# 
#    print 'variavel_1 = ' + str(variavel_1) + ' | variavel_2 = ' + str(variavel_2) 
    tecla = pygame.key.get_pressed() 
    cenario.fill(preto)  # pinta o cenário de preto 
    personagens.draw(cenario)  # imprime os sprites no cenário 
    pygame.display.flip()  # imprime o cenário atualizado 
    print 'Pintei a nova cena no quadro' 
    clock.tick(60)  # animações rodam a 60 quadros por segundo 

A primeira modificação da classe Bola, incluindo a animação do sprite (você precisará do arquivo com imagens adicionais):

class bola(pygame.sprite.Sprite): 

    def __init__(self): 
        super(bola, self).__init__() 
        self.images = [] 
        self.images.append(pygame.image.load('bola.png')) 
        self.images.append(pygame.image.load('bola1.png')) 
        self.images.append(pygame.image.load('bola2.png')) 
        self.images.append(pygame.image.load('bola3.png')) 
        self.images.append(pygame.image.load('bola4.png')) 
        self.images.append(pygame.image.load('bola5.png')) 
        self.images.append(pygame.image.load('bola6.png')) 
        self.images.append(pygame.image.load('bola7.png')) 
        self.images.append(pygame.image.load('bola8.png')) 
        self.images.append(pygame.image.load('bola9.png')) 
        self.index = 0 
        self.image = self.images[self.index] 
        self.rect = self.image.get_rect() 

    def update(self): 
        self.index += 1 
        if self.index >= len(self.images): 
            self.index = 0 
        self.image = self.images[self.index]

A classe Bola incluindo as imagens para a "explosão" da bola (você precisará destas imagens.):

class bola(pygame.sprite.Sprite): 

    def __init__(self): 
        super(bola, self).__init__() 
        self.images = [] 
        self.images.append(pygame.image.load('bola.png')) 
        self.images.append(pygame.image.load('bola1.png')) 
        self.images.append(pygame.image.load('bola2.png')) 
        self.images.append(pygame.image.load('bola3.png')) 
        self.images.append(pygame.image.load('bola4.png')) 
        self.images.append(pygame.image.load('bola5.png')) 
        self.images.append(pygame.image.load('bola6.png')) 
        self.images.append(pygame.image.load('bola7.png')) 
        self.images.append(pygame.image.load('bola8.png')) 
        self.images.append(pygame.image.load('bola9.png')) 
        self.images.append(pygame.image.load('bola10.png')) 
        self.images.append(pygame.image.load('bola11.png')) 
        self.images.append(pygame.image.load('bola12.png')) 
        self.images.append(pygame.image.load('bola13.png')) 
        self.index = 0 
        self.image = self.images[self.index] 
        self.rect = self.image.get_rect() 

    def update(self): 
        self.index += 1 
        if self.index >= 10: 
            self.index = 0 
        self.image = self.images[self.index] 

    def explode(self): 
        self.image = self.images[self.index]

Trecho responsável pela impressão da mensagem de final de jogo:

        if explode >= 13: 
            explode = 9 
            pygame.mixer.Sound('/usr/lib/libreoffice/share/gallery/sounds/explos.wav').play() 
            # determina a fonte e o tamanho 
            fonte1 = pygame.font.Font("/usr/share/cups/fonts/FreeMonoBoldOblique.ttf", 20) 
            fonte2 = pygame.font.Font("/usr/lib/python2.7/dist-packages/pygame/freesansbold.ttf", 12) 
            # aplica a fonte a um texto 
            texto1 = fonte1.render(u'Você deixou a bola cair!', 1, branco) 
            texto2 = fonte2.render('Pressione S para continuar ou N para terminar', 1, branco) 
            # posiciona o texto na tela a partir das coordenadas x=100, y=100 
            cenario.blit(texto1, (80, 100)) 
            cenario.blit(texto2, (80, 130)) 
            # exibe o texto 
            pygame.display.flip() 
            resposta = False 
            while not resposta: 
                for event in pygame.event.get(): 
                    tecla = pygame.key.get_pressed() 
                    if (tecla[K_n]): 
                        print 'A tecla N foi pressionada' 
                        sys.exit() 
                    elif (tecla[K_s]): 
                        print 'A tecla S foi pressionada' 
                        coordenadas_bola[1] = a_bola 
                        velocidade_bola[1] = 1 
                        resposta = True 

Atenção: O serviço de compartilhamento utilizado para armazenar os arquivos desse livro, o UbuntuOne, foi descontinuado. O novo link para os arquivos referenciados no livro são os seguintes:

raquete.png
bola.png
imagem da máquina virtual
explode.tar.bz2
bolas.tar.bz2



Design: Dobro Comunicação. Desenvolvimento: Brod Tecnologia. Powered by Drupal