PyGame é legal, lembra a mim a antiga API gráfica do Colour BASIC do MSX (eita saudosismo!).
No entanto o Kao Félix apresentou recentemente um outro módulo menos conhecido, chamado Pyglet, que, a primeira vista, achei mais pythónica. =D
Gostaria então de sugirir dois tutoriais do Kao Félix:
Instalando Pyglet
Se você possui o EasyInstall, basta executar:
bash$ sudo easy_install -U pyglet
Primeira aplicação
Resolvi fazer minha primeira aplicação segundo as dicas do Kao Félix, mas adaptando a meu jeito próprio de programar.
Iniciaremos com o hash-bang, as peculiaridades de Python e os
import
s dos submódulos de Pyglet que vamos precisar:#!/usr/bin/env python
# coding: UTF-8
from __future__ import division
__metaclass__ = type
from pyglet import app, clock, resource, sprite
from pyglet.window import key, Window
Carregando os recursos iniciais
Esta é classe singleton para carregar os recursos de mídia que precisaremos.
Fiz o seguinte: baixei a bola do Kao, mas pode também baixar daqui mesmo – preferível, para não sobrecarregar o link dele.
O arquivo de som está no pacote do KDE, mas você pode baixar daqui.
Nessa classe singleton, implementaremos o método
__new__
(apenas para singleton) e __init__
para carregar as mídias.Para carregar uma imagem usamos
resource.image()
. Para áudio, resource.media()
:class Loader:
"""Singleton class for loading resources"""
__inst = None
__initialized = False
def __new__(cls, *args, **keyw):
if not cls.__inst:
cls.__inst = object.__new__(cls)
return cls.__inst
def __init__(self):
if not self.__initialized:
self.__initialzed = True
self.images = {}
self.sounds = {}
image = resource.image("char.png")
image.anchor_x = image.width // 2
image.anchor_y = image.height // 2
self.images["ball"] = image
self.sounds["pop"] = resource.media(
"pop.wav",
streaming=False
)
O parâmetro
streaming=False
indica que o arquivo de áudio deve ser completamente carregado para a memória – e não tratado como um fluxo (stream).Gerenciando o teclado
Uma nova classe será usada para gerenciar o teclado. O construtor armazenará uma referência para a janela principal e o método
handle_input()
gerenciará as teclas:class KeyHandler(key.KeyStateHandler):
"""Class for handling key events"""
def __init__(self, window):
super(KeyHandler, self).__init__()
self.window = window
def handle_input(self, dt):
speed = 320 * dt
dx, dy = 0, 0
if self[key.RIGHT]:
dx = 1
elif self[key.LEFT]:
dx = -1
if self[key.UP]:
dy = 1
elif self[key.DOWN]:
dy = -1
self.window.ball.x += dx * speed
self.window.ball.y += dy * speed
Repare que nosso objeto
window
terá um atributo ball
, que é um sprite.Agora nosso sprite
Vamos criar agora uma classe que estende
sprite.Sprite
, a classe de sprite de Pyglet.O único método que implementaremos será o construtor, que buscará em
Loader
a imagem que desejamos:class Ball(sprite.Sprite):
"""Sprite that's a ball"""
def __init__(self, *args, **keyw):
super(Ball, self).__init__(
Loader().images["ball"],
*args, **keyw
)
Janela principal
Finalmente a aplicação!
Por um mal hábito adquirido programando Tkinter, tenho o hábito de usar a mesma classe para aplicação e janela principal, porém você não precisa fazer
No entanto vou mostrar aqui da forma como estou habituado.
O construtor:
- ajustará o título da janela (
set_caption()
); - criará uma nova bola (classe
Ball
); - registrará o manipulador de eventos de teclas (
push_handlers()
); - e registrará o método
handle_input()
do manipulador de eventos de teclas para execução periódica (clock.schedule_interval()
).
class MainApplication(Window):
"""Main window and application"""
def __init__(self):
super(MainApplication, self).__init__()
self.set_caption("Teste de movimento")
self.ball = Ball(x=300, y=240)
handler = KeyHandler(self)
self.push_handlers(handler)
clock.schedule_interval(handler.handle_input, 1/60)
Manipulando outros eventos
Os métodos de
Window
que manipulam eventos têm nome iniciado por on_
, seguido pelo nome do evento. Por exemplo: on_close
, on_draw
, on_key_press
, on_key_release
.Vamos implementar
on_close()
para tocar o som ao sair e on_draw()
para exibir o sprite: def on_close(self):
Loader().sounds["pop"].play()
super(MainApplication, self).on_close()
def on_draw(self):
self.clear()
self.ball.draw()
Fazendo funcionar
Para terminar, precisamos instanciar a aplicação e chamar o ciclo principal de Pyglet.
Veja que esse tipo de programação onde um módulo toma o controle e programamos os métodos que atenderão eventos caracteriza um framework.
if __name__ == "__main__":
window = MainApplication()
app.run()
Conclusão
Vemos aqui um ótimo módulo – ou melhor, framework – para criação de aplicações gráficas usando as bibliotecas SDL e OpenGL.
[]'s
Cacilhas, La Batalema