Modulo Input, Modulo Cache, Classe Sprite
Para quem chegou agora neste tópico, não deixe de rever os tutoriais anteriores
Preparar ambiente para python - pygame
Primeira janela do jogo
Classe game e primeiro sprite
Continuando com o tutorial,
neste tutorial vamos criar o modulo Input , o modulo cache, e a classe sprite, no root do nosso projeto vamos criar 3 novos arquivos
input.py , cache.py, sprite.py. Feito isto comecemos com a classe Sprite
Código:
__author__ = 'Fabio almeida'
__version__ = "0.1"
__description__ = "Class Sprite"
import cache
import graphics
import pygame
class Sprite:
# construtor da nossa classe
# podemos passar uma string ou uma imagem diretamente
def __init__(self, filename=None, image=None):
self.src_rect = None
self.position = pygame.Rect(0, 0, 1, 1)
self.z = 0
self._loaded = False
self.visible = True
self._data = image
self.filename = filename
# metodo responsavel por desenhar o nosso sprite
def draw(self, surface):
# se tivermos uma imagem carregada
if self._data:
# defenimos o nosso rectangulo de destino para ter a mesma largura e altura que o nosso src_rect
self.position.width = self.src_rect.width
self.position.height = self.src_rect.height
# desenhamos o sprite no nosso surface
surface.blit(self._data, self.position, self.src_rect)
# metodo responsavel por carregar uma imagem para o nosso sprite
# deve ser chamado no game.load_content()
def load_image(self, filename):
# se ja existir a imagem devemos eliminar
# para libertamos recursos
if self._data:
del self._data
# caqrregamos a imagem do nosso cache
self._data = cache.images(filename)
# convertemos para ter uma camada suave no alpha
self._data.convert_alpha()
self.src_rect = self._data.get_rect()
self.position.width = self.src_rect.width
self.position.height = self.src_rect.height
# Limpamos a nossa imagem para liberar recursos
def dispose(self):
del self._data
self.filename = None
self._loaded = False
# este metodo serve para informar o modulo
# graphics que deve desenhar este sprite
# todos os frames
def auto_draw(self, autodraw):
if autodraw:
graphics.add_sprite(self)
else:
graphics.remove_sprite(self)
# Getters e setters
def get_x(self):
return self.position.x
def get_y(self):
return self.position.y
def set_x(self, value):
self.position.x = value
def set_y(self, value):
self.position.y = value
# propriedades
x = property(get_x, set_x)
y = property(get_y, set_y)
Passemos agora ao nosso modulo Input
Código:
__author__ = 'Fabio Almeida'
__version__ = "0.1"
__description__ = "Modulo reponsavel por tratar do input pelo teclado"
import pygame
# array que vai conter as teclas carregadas
_keys = []
# array que vai conter as teclas carregadas no ultimo update
_last_keys = []
# array que contem os butoes do mouse
_mouse_buttons = [False, False, False]
# array que contem os butoes do mouse no ultimo update
_last_mouse_buttons = _mouse_buttons
"""
Keys from pygame
KeyASCII ASCII Common Name
K_BACKSPACE \b backspace
K_TAB \t tab
K_CLEAR clear
K_RETURN \r return
K_PAUSE pause
K_ESCAPE ^[ escape
K_SPACE space
K_EXCLAIM ! exclaim
K_QUOTEDBL " quotedbl
K_HASH # hash
K_DOLLAR $ dollar
K_AMPERSAND & ampersand
K_QUOTE quote
K_LEFTPAREN ( left parenthesis
K_RIGHTPAREN ) right parenthesis
K_ASTERISK * asterisk
K_PLUS + plus sign
K_COMMA , comma
K_MINUS - minus sign
K_PERIOD . period
K_SLASH / forward slash
K_0 0 0
K_1 1 1
K_2 2 2
K_3 3 3
K_4 4 4
K_5 5 5
K_6 6 6
K_7 7 7
K_8 8 8
K_9 9 9
K_COLON : colon
K_SEMICOLON ; semicolon
K_LESS < less-than sign
K_EQUALS = equals sign
K_GREATER > greater-than sign
K_QUESTION ? question mark
K_AT @ at
K_LEFTBRACKET [ left bracket
K_BACKSLASH \ backslash
K_RIGHTBRACKET ] right bracket
K_CARET ^ caret
K_UNDERSCORE _ underscore
K_BACKQUOTE ` grave
K_a a a
K_b b b
K_c c c
K_d d d
K_e e e
K_f f f
K_g g g
K_h h h
K_i i i
K_j j j
K_k k k
K_l l l
K_m m m
K_n n n
K_o o o
K_p p p
K_q q q
K_r r r
K_s s s
K_t t t
K_u u u
K_v v v
K_w w w
K_x x x
K_y y y
K_z z z
K_DELETE delete
K_KP0 keypad 0
K_KP1 keypad 1
K_KP2 keypad 2
K_KP3 keypad 3
K_KP4 keypad 4
K_KP5 keypad 5
K_KP6 keypad 6
K_KP7 keypad 7
K_KP8 keypad 8
K_KP9 keypad 9
K_KP_PERIOD . keypad period
K_KP_DIVIDE / keypad divide
K_KP_MULTIPLY * keypad multiply
K_KP_MINUS - keypad minus
K_KP_PLUS + keypad plus
K_KP_ENTER \r keypad enter
K_KP_EQUALS = keypad equals
K_UP up arrow
K_DOWN down arrow
K_RIGHT right arrow
K_LEFT left arrow
K_INSERT insert
K_HOME home
K_END end
K_PAGEUP page up
K_PAGEDOWN page down
K_F1 F1
K_F2 F2
K_F3 F3
K_F4 F4
K_F5 F5
K_F6 F6
K_F7 F7
K_F8 F8
K_F9 F9
K_F10 F10
K_F11 F11
K_F12 F12
K_F13 F13
K_F14 F14
K_F15 F15
K_NUMLOCK numlock
K_CAPSLOCK capslock
K_SCROLLOCK scrollock
K_RSHIFT right shift
K_LSHIFT left shift
K_RCTRL right ctrl
K_LCTRL left ctrl
K_RALT right alt
K_LALT left alt
K_RMETA right meta
K_LMETA left meta
K_LSUPER left windows key
K_RSUPER right windows key
K_MODE mode shift
K_HELP help
K_PRINT print screen
K_SYSREQ sysrq
K_BREAK break
K_MENU menu
K_POWER power
K_EURO euro
"""
def update():
# se a janela do jogo estiver ativa
if pygame.key.get_focused():
# como estamos a usar 2 variaveis
# que estao defenidas dentro de um modulo
# usamos a palavra global para o metodo saber que nao queremos defenir
# uma nova variavel mas sim usar a que esta defenida
global _keys, _last_keys, _last_mouse_buttons, _mouse_buttons
# setamos o _last_keys para conter as teclas que estavas carregadas no ultimo update
_last_keys[:] = _keys[:] # usamos o : para selecao
# _keys[3:8] = [] neste caso limpavamos as posicoes 3 ate ao 8
# defenimos uma variavel temporaria para conter as teclas que estao a ser carregadas
# get_pressed retorna um array com todas as keys do teclado, tendo o valor 0 se nao forem carregadas
# e o valor 1 se forem carregadas
Key_pressed = pygame.key.get_pressed()
# limpamos a variavel keys
_keys = []
# e adicionamos as keys que estiverem a ser clicadas
for key in range(0, len(Key_pressed)):
if Key_pressed[key] == 1: # se estivermos a carregar na tecla
_keys.append(key) # adicionamos as _keys
# obtemos os butoes do mouse
_last_mouse_buttons[:] = _mouse_buttons[:]
_mouse_buttons = pygame.mouse.get_pressed()
# metodo para saber se uma tecla esta a ser presionada
# no RGSS seria Input.press?
def is_key_press(key):
return key in _keys
# metodo para saber se uma tecla foi carregada e largada
# no RGSS seria Input.trigger?
def is_key_pressed(key):
global _last_keys, _keys
return (key in _last_keys) and (key not in _keys)
# retorna um array contendo [x,y] posicao relativa a janela
def mouse_pos():
return pygame.mouse.get_pos()
# retorna um array contendo [x, y] movimentro relativo desde o ultimo update
def mouse_movement():
return pygame.mouse.get_rel()
# retorna verdadeiro se o butao esquerdo estiver a ser clicado, caso contrario retorna falso
def mouse_left_button_down():
return _mouse_buttons[0]
# retorna verdadeiro se o butao do meio estiver a ser clicado, caso contrario retorna falso
def mouse_middle_button_down():
return _mouse_buttons[1]
# retorna verdadeiro se o butao direito estiver a ser clicado, caso contrario retorna falso
def mouse_right_button_down():
return _mouse_buttons[2]
# retorna verdadeiro se o butao esquerdo foi clicado e agora largado, caso contrario retorna falso
def mouse_left_button_up():
return not _mouse_buttons[0] and _last_mouse_buttons[0]
# retorna verdadeiro se o butao do meio foi clicado e agora largado, caso contrario retorna falso
def mouse_middle_button_up():
return not _mouse_buttons[1] and _last_mouse_buttons[1]
# retorna verdadeiro se o butao direito foi clicado e agora largado, caso contrario retorna falso
def mouse_right_button_up():
return not _mouse_buttons[2] and _last_mouse_buttons[2]
E agora o modulo Cache
Código:
__author__ = 'Fabio almeida'
__version__ = "0.1"
__description__ = "Cache Module"
import pygame
import os
# variaveis onde guardamos as nossas texturas
_images = {}
_sounds = {}
_music = {}
# caminho para a nossa pasta res
_root_directory = os.path.dirname(os.path.realpath(__file__)) + "/res/"
# Limpa tudo o que estiver em cache
def clear():
clear_images()
clear_music()
clear_sounds()
# Limpa a cache de imagens
def clear_images():
del _images
# limpa a cache de sons
def clear_sounds():
del _sounds
# limpa a cache de musicas
def clear_music():
del _music
# obtem uma imagem da pasta characters
# filename -> nome da imagem.extensao
def characters(filename):
filename = "graphics/characters/{0}".format(filename)
if not filename in _images.keys():
_images[filename] = _load_surface_from_disk(_root_directory + filename)
return _images[filename]
# obtem uma imagem da pasta backgronds
# filename -> nome da imagem.extensao
def backgrounds(filename):
filename = "graphics/backgrounds/{0}".format(filename)
if not filename in _images.keys():
_images[filename] = _load_surface_from_disk(_root_directory + filename)
return _images[filename]
# obtem uma imagem da pasta tilesets
# filename -> nome da imagem.extensao
def tilesets(filename):
filename = "graphics/tilesets/{0}".format(filename)
if not filename in _images.keys():
_images[filename] = _load_surface_from_disk(_root_directory + filename)
return _images[filename]
# obtem uma imagem da pasta animations
# filename -> nome da imagem.extensao
def animations(filename):
filename = "graphics/animations/{0}".format(filename)
if not filename in _images.keys():
_images[filename] = _load_surface_from_disk(_root_directory + filename)
return _images[filename]
# obtem uma imagem da pasta images
# filename -> nome da imagem.extensao
def images(filename):
filename = "graphics/images/{0}".format(filename)
if not filename in _images.keys():
_images[filename] = _load_surface_from_disk(_root_directory + filename)
return _images[filename]
# carrega uma imagem de um local do disco
# filename -> caminho completo para a imagem
def load_graphics_from_file(filename):
if not filename in _images.keys():
_images[filename] = _load_surface_from_disk(filename)
return _images[filename]
# metodo interno para carregar imagens
def _load_surface_from_disk(filename):
return pygame.image.load(filename)
Vamos agora utilizar estes modulos e a classe sprite no nosso jogo.
Primeiro vamos ao nosso arquivo game.py e vamos faxer algumas alterações
no inicio vamos alterar os nossos imports
Código:
import os
import pygame
import graphics
import input
from sprite import *
reparem que no final, em vez de adicionar import sprite, usei um from sprite import *
isto é o mesmo que no ruby fazer
Código:
require modulo
include modulo
ou seja estou a importar tudo que esta dentro do arquivo, directamente para o nosso game.py
podendo assim acessar directamente classes.
Vamos agora remover a nossa variavel e os comentarios logo apos a declaracao da classe Game
Código:
class Game:
# vamos criar uma variavel logo
# apenas para o tutorial
# ao defenirmos uma variavel dentro de uma class
# esta passa a ser uma variavel de class
# no ruby seria algo como
# @@logo
logo = None
e dentro do __init__ vamos adicionar no final o nosso sprite
Código:
self.spr = Sprite()
e dentro do nosso load content vamos carregar o nosso sprite
Código:
def load_content(self):
self.spr.load_image("condado_logo.png")
self.spr.auto_draw(True)
Reparem na linha self.spr.auto_draw(true), isto serve para informar o nosso modulo Graphics, que este sprite é para ser sempre redesenhado
No update vamos adicionar
Código:
input.update()
# defenimos a posicao central do nosso sprite para ser a posicao do mouse
self.spr.position.center = input.mouse_pos()
Ficando assim
Código:
def update(self, gametime=None):
if gametime is None:
gametime = self.get_last_gametime()
input.update()
# defenimos a posicao central do nosso sprite para ser a posicao do mouse
self.spr.position.center = input.mouse_pos()
Vamos agora alterar o nosso Draw, ficando assim
Código:
def draw(self, surface=None):
self.Graphics.draw()
#aqui é o espaço para desenhar mais coisas
self.Graphics.update()
self.tick(30)
vamos agora alterar o modulo graphics, ficando assim
Código:
__author__ = 'Fabio almeida'
__version__ = "0.2"
__description__ = "Modulo graphics, modulo responsavel por tratar dos graphicos do jogo"
import pygame
_instance = None
def get_context():
global _instance
return _instance
def add_sprite(sprite):
if sprite not in get_context().sprites:
get_context().sprites.append(sprite)
def remove_sprite(sprite):
if sprite in get_context().sprites:
get_context().sprites.remove(sprite)
class Graphics:
def __init__(self, width, height, title):
self.surface = pygame.display.set_mode((width, height), pygame.HWSURFACE)
pygame.display.set_caption(title)
pygame.display.flip()
# Adicionamos um arrays de sprites que precisam de ser desenhados
self.sprites = []
# flag que controla se devemos limpar o ecra a cada frame
self.auto_clear = True
# defenimos a variavel _instance para ser este objeto
# isto e uma singleton class
global _instance
_instance = self
def update(self):
pygame.display.update()
def fullscreen(self, fullscreen):
pass
def bitmap(self):
return self.surface
def draw(self):
if self.auto_clear:
self.clear()
for sp in sorted(self.sprites, key=lambda sprite: sprite.z):
sp.draw(surface=self.surface)
def clear(self, color=(30, 30, 30)):
self.surface.fill(color)
E finalmente o nosso __main__.py
Código:
__author__ = 'Fabio almeida'
__version__ = "0.3"
__description__ = "tutorial sobre python com pygame"
# importamos os modulos necessarios
import pygame
import sys
import game
# iniciamos o modulo pygame
pygame.init()
try:
# o nosso jogo
meu_game = game.Game(title="Condado Braveheart - Primeiro jogo", fullscreen=False, width=800, height=600)
# carregamos os recursos necessarios ao jogo
meu_game.load_content()
# Iniciamos o loop do jogo
# Aqui vamos desenhar tudo e atualizar o nosso jogo
while meu_game.running:
# Obtemos os eventos SDL
events = pygame.event.get()
for event in events:
# Se clicarmos no X para fechar a janela
if event.type == pygame.QUIT:
meu_game.running = False # Finalizamos o loop
# agora damos um update e um draw no nosso jogo
meu_game.update()
meu_game.draw()
# aqui vamos tratar das excepcoes do nosso codigo
except Exception as ex:
print(ex.message)
finally:
# caso aconteca algum erro,
# limpamos os recursos
# e saimos do processo
if meu_game:
meu_game.unload_content()
pygame.quit()
se correrem agora o código o logótipo fica centrado na posição do mouse
No proximo tutorial vamos criar um Sprite animado e utilixar o Tiled - Editor de mapas para criar o nosso mapa e carrega-lo no nosso jogo.
[descarga]https://dl.dropboxusercontent.com/u/42148742/Tuts/PythonPygame/Tutorial_3.zip[/descarga]