Este capítulo não pretende introduzir muitos elementos novos mas, em vez disso, propor o desenvolvimento, passo-a-passo, de uma versão do velho jogo Pong, desenvolvido originalmente em 1972 por Allan Alcorn para a Atari e até hoje um ícone dos videogames.
Para começar, visite a página http://www.ponggame.org/ e comece a planejar como será a sua própria recriação do jogo. Tenha o Zen do Python em sua mente ao escrever o seu código e lembre-se que na web você encontra informações que vão muito além do que cabe nesse livro. Revise o capítulo 14 para lembrar como qualificar suas buscas no Google, ou veja um resumo sobre como fazer isso no endereço http://brodtec.com/google.
Abaixo, o remix do jogo Pong desenvolvido nesse capítulo. Copie-o para dentro de seu editor preferido, leia os comentários dentro do programa, salve-o com o nome pong.py e execute-o com o comando python pong.py (você vai precisar da fonte 8-Bit-Wonder).
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# pong.py - versão 0.09 - Cesar Brod - 23/09/2013
#
# 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 "Aprenda a programar -
# a arte de ensinar o computador", 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
# Define o tamanho da tela a partir da opção do usuário
print 'Deseja jogar pong em tela cheia?'
print 'Pressione a tecla S, caso positivo ou qualquer,'
print 'outra tecla para jogar em uma janela.'
# Código reaproveitado de
# http://docs.python.org/2/faq/library#how-do-i-get-a-single-keypress-at-a...
# para ler apenas uma tecla pressionada
import termios, fcntl, os
fd = sys.stdin.fileno()
oldterm = termios.tcgetattr(fd)
newattr = termios.tcgetattr(fd)
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
termios.tcsetattr(fd, termios.TCSANOW, newattr)
oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
escolha = False
try:
while not escolha:
try:
tela_cheia = sys.stdin.read(1) # lê o caractere
tela_cheia = (tela_cheia).lower() # converte a resposta para letras minúsculas
escolha = True
except IOError: pass
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
# Final do código reaproveitado
if tela_cheia == 's':
tamanho = largura, altura = 0,0 # tela cheia
else:
tamanho = largura, altura = 500, 420 # janela
preto = 0, 0, 0 # RGB para a cor preta
branco = 255, 255, 255 # RGB para a cor preta
cenario = pygame.display.set_mode(tamanho) # cria o cenário do jogo
clock = pygame.time.Clock() # permite o controle de velocidade da animação
tamanho = largura, altura = cenario.get_size() # obtém a dimensão real da tela
placar_e = placar_d = 0 # o placar inicia zerado
# Fonte criada por Joiro Hatagaya (leia o arquivo 8bit_font/README.TXT)
fonte = pygame.font.Font("8bit_font/8-BIT WONDER.TTF", altura/7)
fonte_msg = pygame.font.Font(None, altura/10)
fonte_menor = pygame.font.Font(None, altura/20)
vitoria_texto = fonte_msg.render('VENCEDOR', 1, branco)
fim_texto = fonte_menor.render('Tecle F para sair do jogo', 1, branco)
continua_texto1 = fonte_menor.render('ou qualquer outra', 1, branco)
continua_texto2 = fonte_menor.render('tecla para continuar', 1, branco)
# Classe básica para todos os personagens do Pong
class personagem(pygame.sprite.Sprite):
def __init__(self, l_personagem, a_personagem):
pygame.sprite.Sprite.__init__(self)
self.l_personagem = l_personagem
self.a_personagem = a_personagem
self.image = pygame.Surface([self.l_personagem, self.a_personagem])
self.image.fill(branco)
self.rect = self.image.get_rect()
# Instancia a bola a partir de personagem e inicializa suas variáveis
bola = personagem(largura/40, largura/40)
coordenadas_bola = [largura/2, altura/2]
velocidade_bola = [2*largura/500, 2*largura/500]
# Instancia a raquete da esquerda a partir de personagem e inicializa suas variáveis
raquete_e = personagem(largura/40, altura/10)
coordenadas_raquete_e = [largura/25, altura/2]
# Instancia a raquete da direita a partir de personagem e inicializa suas variáveis
raquete_d = personagem(largura/40, altura/10)
coordenadas_raquete_d = [largura - largura/25, altura/2]
# A velocidade será a mesma para ambas as raquetes
velocidade_raquete = [altura/420, 2*altura/420]
# Inicializa um grupo de sprites para a animação
personagens = pygame.sprite.Group()
# Adiciona a bola ao grupo de sprites personagens
personagens.add(bola)
# Adiciona as raquetes ao grupo de sprites personagens
personagens.add(raquete_e)
personagens.add(raquete_d)
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
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])
print 'Largura = ' + str(largura) + ', Altura = ' + str(altura)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# Movimento da bola
bola.rect.center = (coordenadas_bola[0], coordenadas_bola[1])
coordenadas_bola[0] = coordenadas_bola[0] + velocidade_bola[0]
coordenadas_bola[1] = coordenadas_bola[1] + velocidade_bola[1]
if coordenadas_bola[0] > largura or coordenadas_bola[0] < 0:
print 'A bola mudou de direção no eixo x'
pygame.mixer.Sound('/usr/share/pyshared/pygame/examples/data/boom.wav').play()
if velocidade_bola[0] > 0: # Ponto para o jogador da esquerda
placar_e += 1
else: # Ponto para o jogador da direita
placar_d += 1
velocidade_bola[0] = -velocidade_bola[0]
coordenadas_bola[0] = largura/2
if coordenadas_bola[1] > altura or coordenadas_bola[1] < 0:
print 'A bola mudou de direção no eixo y'
velocidade_bola[1] = -velocidade_bola[1]
pygame.mixer.Sound('/usr/share/scratch/Media/Sounds/Effects/Pop.wav').play()
# Movimento das raquetes
# Habilita a verificação de teclas pressionadas
tecla = pygame.key.get_pressed()
# Usa as setas para mover a raquete direita
raquete_d.rect.center = (coordenadas_raquete_d[0], coordenadas_raquete_d[1])
if (tecla[K_UP]):
print 'A seta para cima pressionada'
coordenadas_raquete_d[1] = coordenadas_raquete_d[1] - velocidade_raquete[1]
elif (tecla[K_DOWN]):
print 'A seta para a baixo foi pressionada'
coordenadas_raquete_d[1] = coordenadas_raquete_d[1] + velocidade_raquete[1]
# Usa as teclas A e Z para mover a raquete direita
raquete_e.rect.center = (coordenadas_raquete_e[0], coordenadas_raquete_e[1])
if (tecla[K_a]):
print 'A tecla A foi pressionada'
coordenadas_raquete_e[1] = coordenadas_raquete_e[1] - velocidade_raquete[1]
elif (tecla[K_z]):
print 'A tecla Z foi pressionada'
coordenadas_raquete_e[1] = coordenadas_raquete_e[1] + velocidade_raquete[1]
# Teste de colisão
if pygame.sprite.collide_rect(bola, raquete_e) or pygame.sprite.collide_rect(bola, raquete_d) == True:
print 'Detectei uma colisão entre bola e raquete! '
pygame.mixer.Sound('/usr/lib/libreoffice/share/gallery/sounds/laser.wav').play()
velocidade_bola[0] = -velocidade_bola[0]
if velocidade_bola[0] > 0:
coordenadas_bola[0] = coordenadas_bola[0] + largura/80
if velocidade_bola[0] < 0:
coordenadas_bola[0] = coordenadas_bola[0] - largura/80
# *** 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)
cenario.fill(preto) # pinta o cenário de preto
# Linha divisória
y = altura / 200
traco = altura / 50
incremento = altura / 30
while y <= altura:
pygame.draw.line(cenario, branco, (largura/2, y), (largura/2, y+traco), largura/200)
y += incremento
# Placar
placar_e_texto = fonte.render(str(placar_e), 1, branco)
placar_d_texto = fonte.render(str(placar_d), 1, branco)
cenario.blit(placar_e_texto, (largura/2 - largura/5, altura/20))
cenario.blit(placar_d_texto, (largura/2 + largura/10, altura/20))
if placar_e >= 10 or placar_d >= 10: # Fim de jogo
pygame.mixer.Sound('/usr/lib/libreoffice/share/gallery/sounds/romans.wav').play()
if placar_e > placar_d:
cenario.blit(vitoria_texto, (largura/10, altura/4))
else:
cenario.blit(vitoria_texto, (largura/2 + largura/10, altura/4))
cenario.blit(fim_texto, (largura/2 + largura/30, altura/2 + altura/10))
cenario.blit(continua_texto1, (largura/2 + largura/30, altura/2 + altura/6))
cenario.blit(continua_texto2, (largura/2 + largura/30, altura/2 + altura/5))
pygame.display.flip()
placar_e = placar_d = 0 # reinicia o placar
resposta = False
while not resposta:
for event in pygame.event.get():
tecla = pygame.key.get_pressed()
if (tecla[K_f]):
print 'A tecla F foi pressionada'
sys.exit()
elif event.type == KEYDOWN:
print 'Outra tecla foi pressionada'
resposta = True
personagens.draw(cenario) # imprime os sprites no cenário
pygame.display.flip() # imprime o cenário atualizado
clock.tick(60) # animações rodam a 60 quadros por segundo