🤔 Para Refletir :
"Quer ouvir um paradoxo? Desenvolvedores que fazem jogos envolventes."
- InterPlay

Criando Jogo com Python - Pygame - Parte 4 - modulos adicionais e classe sprite

haunter224

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

tut4_1.png

tut4_2.png


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]


 
Voltar
Topo Inferior