O QUE É PYGAME?


PyGame é uma biblioteca voltada para o desenvolvimento de jogos sob a linguagem Python.
Com ela, podemos criar vários estilos de jogos usando ferramentas simples como Matrizes para
impressão na tela e máquinas de estados.


PRIMEIROS PASSOS


 Esse é o que devemos fazer ao iniciar um código em PyGame. Primeiramente, devemos
importar o módulo, a biblioteca PyGame. Após feito, nós iniciamos o módulo com o
comando pygame.init(). Esse comando iniciará o módulo, permitindo que ele seja interpretado.

 Após isso, nós definimos as constantes a serem utilizadas no projeto. Para este caso, eu
utilizei algumas cores, sempre utilizando seu padrão RGB, a velocidade e constantes para
as direções as quais os fantasmas irão se movimentar. Utilizaremos tais constantes depois.




 Logo após, criaremos uma variável para alocar a nossa tela. Nela, nós imprimiremos
tudo que precisarmos colocar na tela do jogo. Utilizando o comando
pygame.display.set_mode, e, após, inserindo o X e o Y, e depois, informando se queremos
alguma miscelânea, como vsync, por meio de caracteres booleanos. Devemos nos
lembrar que sempre que quisermos imprimir algo na tela, utilizaremos a variável
correspondente.

 Agora, com todas as constantes definidas, criaremos as classes. Nesse caso, como exemplo
criei uma classe chamada de "Cenário", e nela, eu criei tudo que envolvia o cenário, desde as
regras até o próprio cenário e regras.

 Como podem ver, começo a criação passando alguns parâmetros pré-estabelecidos. Entre eles
estão o pacman, e o tamanho. Defino a quantidade de vidas (coisa a qual pode ser alterada com
uma máquina de estados para selecionar a dificuldade), e, enfim, crio o mapa, que será a matriz.

 Após criarmos a matriz, devemos pintá-la e definir as regras. Por critérios de organização,
vejam abaixo:


def pintar_linha(self, tela, numero_linha, linha):
    for numero_coluna, coluna in enumerate(linha):
        x = numero_coluna * self.tamanho
        y = numero_linha * self.tamanho
        cor = BLACK
        if coluna == 2:
            cor = W_BLUE
        pygame.draw.rect(tela, cor, (x , y, self.tamanho , self.tamanho),0)
        if coluna == 1:
            pygame.draw.circle(tela, WHITE, (x+(self.tamanho//2), y+(self.tamanho//2)),self.tamanho/10, 0)



  Como pode-se ver acima, assumimos uma lógica simples para colorir a matriz.
Se o número dentro for um dois, nós a pintamos com a constante W_BLUE, que consiste
em um azul escuro. Para pintar o local, nós utilizamos o comando pygame.draw, passando
o parâmetro "rect", o qual consiste em um retangulo. Após isso dizemos em qual tela ele
será pintado, qual a cor (que para pontos com zero ou 1 será a constante BLACK, e para
pontos com um dois será W_BLUE), e em seguida, as coordenadas e o tamanho, seguidos pelo
zero para um objeto cheio e um para um contorno.

 Caso o número seja um, note que usaremos outro comando. Caso o número apresentado seja
um, nós, novamente, invocaremos o comando pygame.draw, porém, dessa vez passaremos o comando
"circle", assim, desenhando um circúlo. Esse círculo será a pontuação do jogo, e, devemos
lembrar que, quando o Pacman estiver sobre de uma posição "um", esse ponto deve ser recolorido
com a constante BLACK, e a pontuação deve ser incrementa em um.

 Com tudo isso feito, nós devemos iniciar nossa função main e criar nosso loop de jogo.
Para tal, podem perceber que nós delimitamos um novo tamanho, o qual cada personagem assumirá
dentro do jogo. Assim, nós invocamos as funções as quais adicionam os personagens dentro do jogo
além de nomeá-los por maior conveniência.

  Após isso iniciaremos nosso loop de jogo. Aqui nós chamamos todas as outras funções.
Por meio do comando fill, acompanhado da variável scrn, nós escolhemos a cor, praticamente,
a cor de fundo que a janela assumirá. Após isso, nós colocamos todos os elementos visuais
dentro do loop. Isso inclui todos os fantasmas, pacman e o cenário.

 Com tudo isso feito, devemos nos lembrar de uma coisa: estamos trabalhando com um loop.
Por que estamos usando um loop? Simples. As nossas ações devem ser mostradas em tela, e, dentro
de um jogo, coisas devem ocorrer sem nossa interferência. Logo, nós usamos a função por nome de
pygame.display.update(), a qual atualiza a tela, de maneira semelhante a função blit, que veremos
mais para a frente.

 Lembrando novamente: estamos trabalhando com um loop. Logo, surge um pergunta: de quanto em
quanto tempo o loop é invocado, já que ele ocorre independente das nossas ações? Simples, para
resolver tal problema, nós temos o comando pygame.time.delay(), com o qual nós definimos, em
microssegundos, a quantidade de tempo entre cada loop.

import pygame
pygame.init()

YELLOW = (255,255,0)
BLACK = (0,0,0)
W_BLUE = (0, 0, 153)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
ORANGE = (255, 140, 0)
PINK = (255, 15, 192)
L_BLUE = (0, 255, 255)
VELOCIDADE = 1
UP = 1
DOWN = 2
RIGHT = 3 
LEFT = 4
scrn = pygame.display.set_mode((800, 600), 0)

class Cenario(ElementoJogo):

    def __init__(self, tamanho, pac):
        self.pacman = pac
        self.moviveis = []
        self.pontos = 0
        self.estado = 0
        self.vidas = 5
        self.tamanho = tamanho
        self.matriz = [
            [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
            [2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2],
            [2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2],
            [2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2],
            [2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 0, 0, 0, 0, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 0, 0, 0, 0, 0, 0, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 0, 0, 0, 0, 0, 0, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 0, 0, 0, 0, 0, 0, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2],
            [2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2],
            [2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2],
            [2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2],
            [2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
            [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
        ]
/////////////////////////////////////
if __name__ == "__main__":
    size = 600//30
    pacman = Pacman(size)
    blinky = Fantasma(RED, size)
    inky = Fantasma(L_BLUE, size)
    clyde = Fantasma(ORANGE, size)
    pinky = Fantasma(PINK, size)

    cenario = Cenario(size, pacman)
    cenario.adicionar_movivel(pacman)
    cenario.adicionar_movivel(blinky)
    cenario.adicionar_movivel(inky)
    cenario.adicionar_movivel(clyde)
    cenario.adicionar_movivel(pinky)


while True:
    pacman.calcular_regras()
    blinky.calcular_regras()
    inky.calcular_regras()
    clyde.calcular_regras()
    pinky.calcular_regras()
    cenario.calcular_regras()
    
    scrn.fill(BLACK)
    cenario.pintar(scrn)
    pacman.pintar(scrn)
    blinky.pintar(scrn)
    inky.pintar(scrn)
    clyde.pintar(scrn)
    pinky.pintar(scrn)
    pygame.display.update()
    pygame.time.delay(100)

    eventos = pygame.event.get()
    cenario.processar_eventos(eventos)
    pacman.processar_eventos(eventos)


CRIAÇÃO DO PACMAN


Nos devemos ter em mente alguns pontos:


  1. O sistema de cores utilizará constantes com o sistema RGB
  2. Para imprimir algo na tela, usaremos um sistema de coordenadas X e Y
  3. Utlizaremos poligonos para a criação do Pacman


 Como se torna observável na função ao lado, nos criamos o pacman, o pintamos e animamos sua boca.
Para tal, nos definimos um tamanho e usar a função pygame.draw em seguida, informamos onde sera pintado,
sua cor, o formato, seguido de suas coordenadas, de seu raio (no caso do círculo) e, se vai ser apenas um
contorno ou algo preenchido.


 Após isso, pintamos a boca. Para tal, nos definimos um canto, sendo esse o centro exato do personagem
e definimos a reta de seus labios. Então, pintamos de preto esse polígono, evitando que ele seja amarelo.


 Agora, para o olho, nos definimos uma posição e a arredondamos para um inteiro. Vale ressaltar que PyGame
não reconhece números Float, logo, se colocarmos um numero que não seja do tipo Int, teremos um erro no interpretador.
Após definir a posição, utilizamos a mesma lógica dos inteiros para o seu tamanho, e em seguida, o pintamos de preto.

def pintar(self, tela):
    pygame.draw.circle(tela, YELLOW, (self.center_x, self.center_y), self.raio, 0)
                
    self.abertura += self.vel_abertura
    if self.abertura > self.raio:
        self.vel_abertura = -1
    if self.abertura <=0:
        self.vel_abertura = 1
                
                
    #Boca
    canto_boca = (self.center_x, self.center_y)
    labio_s = (self.center_x + self.raio, self.center_y - self.abertura)
    labio_i = (self.center_x + self.raio, self.center_y + self.abertura)
    pontos = [canto_boca, labio_s, labio_i]
    pygame.draw.polygon(tela, BLACK, pontos, 0)
                
    #Olho
    olho_x=int(self.center_x + self.raio/3)
    olho_y = int(self.center_y-self.raio*0.7)
    olho_raio = int(self.raio/10)
    pygame.draw.circle(tela, BLACK, (olho_x, olho_y),olho_raio, 5)
                
            

CRIAÇÃO DOS FANTASMAS


 Agora, para a criação dos quatro fantasmas utilizaremos um método diferente.
Para tal, utilizaremos a função pygame.image.load(). Essa função nos permite adicionar
sprites para o desenvolvimento de personagens. Ao invés de darmos comandos para o interpretador
para que ocorra o desenho, nós mesmos importamos uma imagem e a associamos ao porsonagem.



 Após utilizar o módulo pygame.image.load() para carregar a imagem, nós devemos deminesioná-la
para um tamanho correto. Para tal, usei o comando pygame.transform,scale(), com o qual eu alterei
seu tamanho X e Y.

 Logo após, é chegada a hora de se utilizar a função blit(). Essa função, nada mais é do que
uma forma de desenhar algo na tela. Como eu já havia guardado o fantasma em uma variável, o uso de
blit tem o papel de fazer ele aparecer em tela. Assim, eu defino quem será printado, (no caso, a
variável contorno) e suas coordenadas.

 Com tudo isso feito, basta repetir para os quatro fantasmas. Note que, por usarmos diferentes
cores para cada fantasma, eles sao entidades únicas e diferentes entre si. Se quisermos, podemos adicionar
características únicas para cada um deles, as quais vão além do visual.

class Fantasma(ElementoJogo):
    def __init__(self, cor, tamanho):
        self.tamanho = tamanho
        self.coluna = 13
        self.linha = 15
        self.linha_intencao = self.linha
        self.coluna_intencao = self.coluna
        self.velocidade = 0.5
        self.direcao = DOWN
        self.cor = cor

    def pintar(self, tela):
        if self.cor == RED:
            contorno = pygame.image.load('blinky.png')
            contorno = pygame. transform. scale(contorno, (self.tamanho, self.tamanho))

            tela.blit(contorno,(self.coluna * self.tamanho ,self.linha * self.tamanho))
        if self.cor == L_BLUE:
            contorno = pygame.image.load('inky.png')
            contorno = pygame. transform. scale(contorno, (self.tamanho*1.2, self.tamanho*1.3))

            tela.blit(contorno,(self.coluna * self.tamanho-(self.tamanho*0.2) ,self.linha * self.tamanho-(self.tamanho*0.2)))
        if self.cor == ORANGE:
            contorno = pygame.image.load('clyde.png')
            contorno = pygame. transform. scale(contorno, (self.tamanho*1.2, self.tamanho*1.2))

            tela.blit(contorno,(self.coluna * self.tamanho-(self.tamanho*0.2) ,self.linha * self.tamanho-(self.tamanho*0.2)))
        if self.cor == PINK:
            contorno = pygame.image.load('pinky.png')
            contorno = pygame. transform. scale(contorno, (self.tamanho, self.tamanho))
            
            tela.blit(contorno,(self.coluna * self.tamanho ,self.linha * self.tamanho))

REGRAS


 Aqui nessa seção, explicarei várias funções as quais nos ajudam a definir
as regras do jogo. No exemplo ao lado, eu defini as teclas do teclado para permitir
movimentos.

 Para exemplificar melhor, podemos explicar da seguinte maneira: "e" seria um evento,
logo, descrimos todos os eventos de tipo pygame.KEYDOWN. E o que é KEYDOWN? Simples, KEYDOWN
é o ato de pressionar um tecla. Logo, assim, nos incrementamos a velocidade do pacman, a
qual nada mais é do que um movimento de uma posição na matriz. Note que diferenciamos sinais
e vertical/horizontal no momento da incrementação.

 E, quando a tecla é solta, buscamos pelo evento KEYUP. Ele busca por uma tecla levantada.
Se a tecla em questão for levantada, a velocidade se torna zero, impedindo o movimento.

def calcular_regras(self):
    if self.direcao == UP:
        self.linha_intencao -= self.velocidade
    elif self.direcao == DOWN:
        self.linha_intencao += self.velocidade
    elif self.direcao == LEFT:
        self.coluna_intencao -= self.velocidade
    elif self.direcao == RIGHT:
        self.coluna_intencao += self.velocidade

def corner(self, direcoes):
    self.direcao = rd.choice(direcoes)

def aceitar_movimento(self):
    self.linha = self.linha_intencao
    self.coluna = self.coluna_intencao

def recusar_movimento(self,  direcoes):
    self.linha_intencao = self.linha
    self.coluna_intencao = self.coluna
    self.direcao = rd.choice(direcoes)

//////////////////////////////////////////
def get_direcoes(self, lin, col):
    direcoes = []
    if self.matriz[int(lin-1)][int(col)] !=2:
        direcoes.append(UP)
    if self.matriz[int(lin+1)][int(col)] !=2:
        direcoes.append(DOWN)
    if self.matriz[int(lin)][int(col-1)] != 2:
        direcoes.append(LEFT)
    if self.matriz[int(lin)][int(col+1)] !=2:
        direcoes.append(RIGHT)

return direcoes 
def processar_eventos(self, eventos):
    for e in eventos:
        if e.type == pygame.KEYDOWN:
            if e.key == pygame.K_RIGHT:
                self.vel_x = VELOCIDADE
            elif e.key == pygame.K_LEFT:
                self.vel_x = -VELOCIDADE
            elif e.key == pygame.K_UP:
                self.vel_y = -VELOCIDADE
            elif e.key == pygame.K_DOWN:
                self.vel_y = VELOCIDADE

        if e.type == pygame.KEYUP:
            if e.key == pygame.K_RIGHT:
                self.vel_x = 0
            elif e.key == pygame.K_LEFT:
                self.vel_x = 0
            elif e.key == pygame.K_UP:
                self.vel_y = 0
            elif e.key == pygame.K_DOWN:
                self.vel_y = 0

COMO FUNCIONA NOS FANTASMAS?


 Para a definição das regras, utilizei alguns preceitos basicos. Por exemplo,
eu criei um Array, o qual tinha todos os valores de movimentações possíveis para os fantasmas.
A direção que fosse possivel, ia para o array por meio do comando direcoes.append(). Assim
na função corner(), uma direção era escolhida por meio da função rd.choice(), essa qual
escolhe algum elemento randomico de um vetor.

 Com isso, uma direção é escolhida no array. Se a direção escolhida for possível,
A velocidade é incrementada, e o fantasma se movimenta. Isso ocorre uma vez a cada loop,
deixando fazendo com que os fantasmas se mexam independentemente da ação de um jogador.


MÁQUINA DE ESTADOS


 A Máquina de Estados define o estado que o jogo se encontra.
Para tal, utilizaremos ações do jogador para escolher qual estado
estará em vigência no momento.

 Como exemplo, pode-se notar na segunda seção do código: Casp as
vidas sejam iguais a zero,o estado muda para 2, esse qual deixa de pintar
a tela e pinta uma mensagem de game over.

 Nesse caso, nós manipulamos o estado do jogo por diversas ações.
Devemos manipular a máquina de estados com base nas ações do jogador,
variando entre vitória, derrota, pausa e jogando.

def pintar(self, tela):
    if self.estado==0:
        self.pintar_jogando(tela)
    elif self.estado == 1:
        self.pintar_jogando(tela)
        self.pintar_pausado(tela)
    elif self.estado == 2:
        self.pintar_jogando(tela)
        self.pintar_gameover(tela)
    elif self.estado == 3:
        self.pintar_jogando(tela)
        self.pintar_vitoria(tela)
/////////////////////////////////////////////////////////////////
    if self.vidas <=0:
        self.estado = 2
    else:
        self.pacman.linha = 1
        self.pacman.coluna = 1
else:
    if 0 <= col_intencao <28 and 0<= lin_intencao <29 and self.matriz[lin_intencao][col_intencao] !=2:
    movivel.aceitar_movimento()
        if isinstance(movivel, Pacman) and self.matriz[lin] [col] == 1:
            self.pontos +=1
            self.matriz[lin] [col] = 0
            if self.pontos >= 306:
                self.estado = 3


Aqui temos uma pequena demonstração do

projeto final



Alunos


Davi Costa Ferreira da Luz
Linkedln
Caroline Heloíse de Oliveira
Linkedln