🤔 Para Refletir :
"De pixel a pixel, os tiles compõem o Mapa."
- Core32

Criando Jogo com Python - Pygame - Parte 5 - AnimatedSprite e CharacterSprite

haunter224

( ͡° ͜ʖ ͡°)
Membro
Membro
Juntou-se
19 de Junho de 2015
Postagens
69
Bravecoins
0
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

character.png

[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]
 
Estou gostando do estilo que vão suas aulas, apesar de que não são bem pra mim xD Mas estou gostando de ver o rumo que andas levando. Só apontando um detalhe: os links para as aulas anteriores andam redirecionando para about:blank (EDIT: Na verdade, só o da última aula - Módulos Adicionais etc..).

Quanto ao sistema de batalha, creio que deva partir para algo simples mas que tome bastantes conceitos trabalhados no RPG Maker (Máquina de Estados, por exemplo). Não precisa explicá-los, mas usá-los de uma forma que um maker possa pegar seu código e ver uma semelhança com o RPG Maker. Ao menos para makers isso seria como uma ponte entre RGSS -> Python (e outras linguagens).
Se for RPG, um sistema Final-Fantasy da vida já é mais que bom para aprendizado (algo Secret of Mana seria legal, mas meio complexo pra passar logo de cara, ao menos quando não se está acostumado a criar sistemas sem ser via turno).
Se for Side-Scrolling, bem, não sei como sugerir algo suficientemente simples, no máximo algo como Power-Rangers - The Movie (SNES).
Se for Card-Game, dá pra brincar com algo de invocações e fazer um game baseado em power-ups e elementos (por elementos eu digo...um monstro invocado começa com atributos neutros - ou no caso de alguns específicos, já com seu atributo -, e para eles usarem golpes elementais seria necessário atribuir pontos de um elemento a eles. Se ele tiver 2 de água e quiser atribuir fogo a ele, vai ter que usar 3 de fogo - sendo 2 para nulificar a água -). Complexo, mas dá de fazer ficar simples se for feito em módulos (target.addElement, etc..., e ainda poderia ser feito adicionar elementos para inimigos, a fim de se beneficiar disso, mas a custos maiores).
 
[member=75]Alucard_2[/member]
Obrigado por avisar, ja resolvi o link.

Em relação ao sistema, queria mesmo um sistema, não para funcionar perfeito, mas para os makers(pessoas que desenvolvem jogos, e não só RPG M) incluindo eu , perceberem como se fax  um sistema ou como se pode faxer tal sistema,  estou a usar python como poderia usar qualquer outra linguagem.

Não queria fazer algo já feito, não sei se me estou a explicar bem.
mas gostei das suas ideias, e agradeço.

Vamos ver se mais alguém se interessa por este "Tópico" de produção de jogos, se não deixo ao seu critério escolher um dos exemplos que você forneceu.

Um grande abraço e não tenham "medo" do desconhecido, aprender uma nova linguagem é muito bom, porque aprendendo como se faz certas coisas pode-se aplicar a qualquer linguagem e engine.
 
Voltar
Topo Inferior