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