Classes Animated Sprite e Character 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
Modulos Adicionais e Classe Sprite
Continuando com o tutorial
Vamos criar no nosso projeto mais 2 arquivos, animated_sprite.py e character_sprite.py
antes de começar-mos a desenvolver os nossos novos aquivos vamos a classe Sprite e vamos alterar o metodo load_image
ficando assim :
Código:
# metodo responsavel por carregar uma imagem para o nosso sprite
# deve ser chamado no game.load_content()
def load_image(self, filename, folder="images"):
# 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
O que alteramos ? na definição adicionamos um parametro já com valor definido (folder="images"), para a classe sprite não serve para nada, visto que a nossa imagem é carregada pelo cache.images(filename), vai servir apenas para as classes derivadas.
agora vamos ao arquivo cache.py e vamos adicionar o seguinte metodo
Código:
# este metodo serve para carregar-mos imagens
# podendo defenir a pasta onde a imagem se encontra
def load_from(folder, filename):
filename = "graphics/{0}/{1}".format(folder, filename)
if not filename in _images.keys():
_images[filename] = _load_surface_from_disk(_root_directory + filename)
return _images[filename]
Feito isto vamos tratar dos novos arquivos , comecemos pelo arquivo animated_sprite.py
Código:
__author__ = 'Fabio almeida'
__version__ = "0.1"
__description__ = "Class Sprite"
import sprite
import cache
import math
class AnimatedSprite(sprite.Sprite):
def __init__(self, filename=None, image=None):
# aqui invocamos o metodo __init__ da classe mae
# equivalente ao super() no ruby
sprite.Sprite.__init__(self, filename, image)
self.frames = [] # para ja nao vamos usar
self._pose = 0 # pose atual
self._frame = 0 # frame atual
self.frame_delay = 5 # numero de ticks(fps) que necessita para alterar a frame atual
self.elapsed = 0 # numero de tics(fps) que passou
self.max_poses = 0 # numero maximo de poses
self.max_frames = 0 # numero maximo de frames por pose
self.frame_width = 0 # largura de um frame
self.frame_height = 0 # altura de um frame
self.animating = False # flag indentificando se o sprite anima ou nao
# Metodo responsavel para carregar a imagem
# aqui defenimos o folder=animations para carregar da pasta animations
def load_image(self, filename, folder="animations"):
self.dispose() # caso exista alguma imagem limpamos a memoria para libertar recursos
self._data = cache.load_from(folder, filename) # carregamos a nossa imagem
# o resto esta comentado na classe sprite
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
# metodo responsavel por criar a animacao
# passamos o numero de frames e o numero de poses maximo
def create_animation(self, poses, frames):
# obetemos o retangulo da imagem
re = self._data.get_rect()
# defenimos a largura e altura de cada frame
self.frame_width = math.floor(re.width / frames)
self.frame_height = math.floor(re.height / poses)
# defenimos o numero maximo de frames e poses
self.max_poses = poses
self.max_frames = frames
# defenimos a posicao inicial do nosso retangulo dentro da imagem
self.src_rect.x = 0
self.src_rect.y = 0
self.src_rect.width = self.frame_width
self.src_rect.height = self.frame_height
# Metodo responsavel por animar o nosso sprite
def animate(self):
# se estamos a animar
if self.animating:
# adicionamos mais 1 ao contador de frames
self.elapsed += 1
# se este contador for maior que o numero de frames necessarios
if self.elapsed > self.frame_delay:
# passamos a proxima frame
self.set_frame(self._frame + 1)
# resetamos o elapsed para iniciar de novo a contagem
self.elapsed = 0
# metodo responsavel por defenir a pose
def set_pose(self, index):
# se o index for maior que o numero de poses (esta fora da imagem)
if index >= self.max_poses:
# passamos a pose 0
index = 0
# defenimos a posicao y do retangulo para ser pose * altura da frame
self.src_rect.y = index * self.frame_height
# defenimos a pode atual para o index
self._pose = index
def set_frame(self, index):
# se o index for maior que o numero de frames (esta fora da imagem)
if index >= self.max_frames:
# passamos ao frame 1
index = 0
# defenimos a posicao y do retangulo para ser pose * altura da frame
self.src_rect.x = index * self.frame_width
# defenimos a frame atual para o index
self._frame = index
# obtem a pose atual
def get_pose(self):
return self._pose
# obtem o frame atual
def get_frame(self):
return self._frame
como podem ver a classe AnimatedSprite é bem básica, visto que a vamos herdar da classe Sprite, reescrevendo apenas os métodos necessários, que são o __init__ e o load_Image.
passando a explicar no __init__ estamos a alterar para poder-mos adicionar mais algumas variáveis, no método load_image vamos altera-lo para podermos carregar a imagem de um local diferente.
passando agora a classe CharacterSprite, esta classe ainda é mais básica que a anterior, visto que vai herdar da classe AnimatedSprite
Código:
__author__ = 'Fabio almeida'
__version__ = "0.1"
__description__ = "Class caracter Sprite > classe responsavel por mostrar um character"
from animated_sprite import AnimatedSprite
class CharacterSprite(AnimatedSprite):
# Defenindo as POSES
POSE_DOWN = 0
POSE_LEFT = 1
POSE_RIGHT = 2
POSE_UP = 3
# vamos alterar a assinatura deste metodo
# para usar-mos a pasta characters
def load_image(self, filename, folder="characters"):
AnimatedSprite.load_image(self, filename, folder)
# vira a esquerda
def turn_left(self):
self.set_pose(CharacterSprite.POSE_LEFT)
# vira a cima
def turn_up(self):
self.set_pose(CharacterSprite.POSE_UP)
# vira a direita
def turn_right(self):
self.set_pose(CharacterSprite.POSE_RIGHT)
# vira abaixo
def turn_down(self):
self.set_pose(CharacterSprite.POSE_DOWN)
# verifica se esta virado a cima
def is_turned_up(self):
return self._pose == CharacterSprite.POSE_UP
# verifica se esta virado a esquerda
def is_turned_left(self):
return self._pose == CharacterSprite.POSE_LEFT
# verifica se esta virado a direita
def is_turned_right(self):
return self._pose == CharacterSprite.POSE_RIGHT
# verifica se esta virado a baixo
def is_turned_down(self):
return self._pose == CharacterSprite.POSE_DOWN
Como podemos usar estas classes ?
Vamos no nosso game.py e nos imports vamos adicionar
Código:
from character_sprite import CharacterSprite
Agora no __init__ vamos trocar o nosso self.spr para:
Código:
# vamos agora criar um sprite
self.spr = CharacterSprite()
no nosso update vamos adicionar, logo após self.spr.position.center ...... isto aqui:
Código:
self.spr.animate()
if input.is_key_pressed(pygame.K_UP):
self.spr.turn_up()
elif input.is_key_pressed(pygame.K_LEFT):
self.spr.turn_left()
elif input.is_key_pressed(pygame.K_RIGHT):
self.spr.turn_right()
elif input.is_key_pressed(pygame.K_DOWN):
self.spr.turn_down()
e por fim vamos alterar o nosso load_content:
Código:
self.spr.load_image("character.png")
self.spr.create_animation(4, 4)
self.spr.animating = True
self.spr.auto_draw(True)
E ao correrem agora o código vão ver que tem um character a animar , na posição do rato, e com as teclas podemos virar o sprite
imagem usada
[descarga]https://dl.dropboxusercontent.com/u/42148742/Tuts/PythonPygame/Tutorial_5.zip[/descarga]
[okay]no próximo tutorial vamos começar a desenvolver um sistema de batalha, para isso preciso da ajuda de todos voces, vamos desenvolver um sistema único para usar-mos, por isso preciso de ideias de funcionalidades/sistemas/qualquer coisa, diferente de todos os outros.
Não precisa de ser um sistema de rpg, pode ser de shooter, beatemups, side scrooler, pokemon(like), card game........
Abraço [/okay]