1

I'm making a classic game on pygame , a fleet of aliens descends on the screen and the hero's ship needs to shoot the aliens down as the fleet moves sideways across the screen and goes down the screen. I'm using the pygame.sprite.groupcollide(ammunition, aliens, True, True) function. In the tests I did, I notice that if I hit an alien with a shot, when the fleet reaches the edge of the screen without an alien that was destroyed, the entire fleet runs down from the screen as if it were a bug. If I don't destroy any aliens, the fleet moves correctly, from right to left and then it goes down one level on the screen and so on until it disappears at the bottom of the screen. If you hit an alien with a shot, there is a problem with the entire fleet reaching the edge of the screen and descending all at once.

Code:

invasao_alien.py

import pygame
from pygame.sprite import Group
from configuracoes import Configuracoes             #módulo configurações
from nave import Nave                               #módulo nave (herói)
import jogo_funcoes as jf                           #módulo funções do jogo com aliás jf


def run_game():
    pygame.init()                                                #Inicializa o jogo e cria um objeto para a tela
    ai_configuracoes = Configuracoes()                           #objeto ai_configuracoes da Classe Configuracoes
    tela = pygame.display.set_mode ((ai_configuracoes.tela_width, ai_configuracoes.tela_height))
    pygame.display.set_caption("Space War")
    nave_espacial = Nave(ai_configuracoes, tela)                 #objeto nave_espacial da classe Nave
    municoes = Group()                                           #Cria um grupo no qual serão armazenados as munições
    aliens = Group()                                             #Cria um grupo vazio para armazenar os aliens do jogo
    jf.cria_frota(ai_configuracoes, tela, nave_espacial, aliens) #Cria uma frota de aliens (usa configurações, tela e um grupo vazio de aliens)



    while True:   #Inicia o laço principal do jogo
        jf.check_eventos(ai_configuracoes, tela, nave_espacial, municoes)           #checa os eventos
        nave_espacial.update_nave()                                                 #posicionamento da nave
        jf.update_municoes(ai_configuracoes, tela, nave_espacial, aliens, municoes) #verifica as municoes na tela ,se houve disparo
        jf.update_aliens(ai_configuracoes, aliens)
        jf.update_tela(ai_configuracoes, tela, nave_espacial, aliens,  municoes)    #update da tela



run_game()

jogo_funcoes.py

"""Módulo que armazena as  funções do jogo"""
import sys
import pygame
from municao import Municao
from alien import Alien



def check_keydown_events(evento, ai_configuracoes, tela, nave_espacial, municoes):
    """Responde a pressionamento de teclas"""
    if evento.key == pygame.K_RIGHT:
        nave_espacial.move_direita = True
    elif evento.key == pygame.K_LEFT:
        nave_espacial.move_esquerda = True
    elif evento.key == pygame.K_SPACE:                         #Esta condição cria um novo projétil e adiciona ao grupo de projéteis
        tiro_municao(ai_configuracoes, tela, nave_espacial, municoes)
    elif evento.key == pygame.K_q:
        sys.exit()

def check_eventos(ai_configuracoes, tela, nave_espacial, municoes):
    """Responde a eventos de pressionamento de teclas e do mouse"""
    for evento in pygame.event.get():                          #pegar cada evento
        if evento.type == pygame.QUIT:                         #caso seja solicitado a saída
            sys.exit()
        elif evento.type == pygame.KEYDOWN:                    #pressionamento de tecla
            check_keydown_events(evento, ai_configuracoes, tela, nave_espacial, municoes)
        elif evento.type == pygame.KEYUP:                      #soltura de tecla
            check_keyup_events(evento, nave_espacial)


def check_keyup_events(evento, nave_espacial):
    """Responde a solturas de tecla"""
    if evento.key == pygame.K_RIGHT:
        nave_espacial.move_direita = False
    elif evento.key == pygame.K_LEFT:
        nave_espacial.move_esquerda = False
    elif evento.key == pygame.K_q:
        sys.exit()


def update_tela(ai_configuracoes, tela, nave_espacial, aliens, municoes):
    """Atualiza as imagens na tela e alterna para a nova tela"""
    tela.fill(ai_configuracoes.bg_color)
    for municao in municoes.sprites():
        municao.desenha_projetil()
    nave_espacial.blitme()
    aliens.draw(tela)         #desenha cada alienigena do grupo na tela
    pygame.display.flip()


def update_municoes(ai_configuracoes, tela, nave_espacial, aliens, municoes):
    """Atualiza as posicoes dos projéteis antigos, se o projétil chega ao fim da tela é removido"""
    municoes.update()
    for municao in municoes.copy():
        if municao.rect.bottom <= 0:                               #verifica se o projétil chegou ao fim da tela
            municoes.remove(municao)
        check_municao_alien_colisoes(ai_configuracoes, tela, nave_espacial, municoes, aliens)


def check_municao_alien_colisoes(ai_configuracoes, tela, nave_espacial, municoes, aliens):
    """Responde a colisões entre projéteis e alienígenas."""
    colisoes = pygame.sprite.groupcollide(municoes, aliens, True, True)  # verifica se algum projétil atingiu os alienígenas , em caso afirmativo se livra do projétil e do alien
    if len(aliens) == 0:          #Destrói os projéteis existentes e cria uma nova frota
        municoes.empty()          #remove todos os sprites de munições
        cria_frota(ai_configuracoes, tela, nave_espacial, aliens)


def tiro_municao(ai_configuracoes, tela, nave_espacial, municoes):
    """Dispara um projétil se o limite ainda não foi lançado"""
    if len(municoes) < ai_configuracoes.municoes_permitida:         #Caso não tenha número máximo de munições na tela(3) , add munição
        nova_municao = Municao(ai_configuracoes, tela, nave_espacial)
        municoes.add(nova_municao)                                  #adicionando munição ao grupo municoes (criado no arquivo principal)



def criar_alien(ai_configuracoes, tela, aliens, qtde_aliens, linha):
    alien = Alien(ai_configuracoes, tela)                           #Cria uma nave alien
    alien_width = alien.rect.width
    alien.x = alien_width + 2 * alien_width * qtde_aliens
    alien.rect.x = alien.x
    alien.rect.y = alien.rect.height + 2 * alien.rect.height * linha
    aliens.add(alien)


def get_numero_aliens_x(ai_configuracoes, alien_largura ):
    """Determina o número de alienígenas que cabem em uma linha"""
    espaco_livre_x = ai_configuracoes.tela_width - 2 * alien_largura
    numero_aliens_x = int(espaco_livre_x / (2 * alien_largura ))
    return numero_aliens_x



def get_numero_linhas(ai_configuracoes, nave_espacial, alien):
    """Determina o número de linhas com alinígenas que cabem na tela"""
    espaco_livre_y = (ai_configuracoes.tela_height - (3 * alien.rect.height) - nave_espacial.rect.height)
    numero_linhas = int(espaco_livre_y / (2 * alien.rect.height))
    return numero_linhas


def cria_frota(ai_configuracoes, tela, nave_espacial, aliens):
    """Cria uma frota completa de aliens"""
    alien = Alien(ai_configuracoes, tela)  #Cria um alienígena
    alien_largura = alien.rect.width
    numero_aliens_x = get_numero_aliens_x(ai_configuracoes, alien_largura)   #Calcula a qtde de alienígenas que cabem numa linha
    numero_linhas = get_numero_linhas(ai_configuracoes, nave_espacial, alien)
    for linha in range(numero_linhas):                                      #laço para preencher as linhas da tela(eixo y) com aliens
        for qtde_aliens in range(numero_aliens_x):                          #laço para preencher uma linha (eixo x) com aliens
            criar_alien(ai_configuracoes, tela, aliens, qtde_aliens, linha)
        aliens.add(alien)  #Adiciona o alienígena criado ao Group()


def check_frota_bordas(ai_configuracoes, aliens):
    """Responde se algum alien chegou na borda da tela"""
    for alien in aliens.sprites():
        if alien.check_bordas():
            trocar_direcao_frota(ai_configuracoes, aliens)
            break



def trocar_direcao_frota(ai_configuracoes, aliens):
    """Faz a frota inteira descer e mudar a direcao"""
    for alien in aliens.sprites():
        alien.rect.y += ai_configuracoes.frota_drop_speed                   #horda desce na tela
        ai_configuracoes.frota_direcao *= -1                             #muda a direção do alien


def update_aliens(ai_configuracoes, aliens):
    """Verifica se a frota está numa das bordas e então atualiza as posições dos aliens"""
    check_frota_bordas(ai_configuracoes, aliens)
    aliens.update()  # Usando o método update() no Grupo aliens , fará o método update() de cada alienígena ser chamado automaticamente

municao.py

import pygame
from pygame.sprite import Sprite

class Municao(Sprite):
    """Uma classe que administra projéteis disparados  pela espaçonave"""

    def __init__(self, ai_configuracoes, tela, nave_espacial):
        """Cria um objeto para o projétil na posição atual da espaçonave"""
        super(Municao, self).__init__()                                        #herdando de Sprite
        self.tela = tela
        self.rect = pygame.Rect(0, 0, ai_configuracoes.municao_width, ai_configuracoes.municao_height) #Cria um projétil em (0,0) e define a posição correta
        self.rect.centerx = nave_espacial.rect.centerx                                                 #rect do projétil igual ao da nave
        self.rect.top = nave_espacial.rect.top                                                         #rect top do projétil igual ao topo da nave
        self.y = float(self.rect.y)             #Armazena a posição do projétil como um valor decimal na orientação y para ajustes de velocidade do mesmo
        self.color = ai_configuracoes.municao_color
        self.speed_factor = ai_configuracoes.municao_speed_factor


    def update(self):
        """Move o projétil para cima na tela"""
        self.y -= self.speed_factor             #Dá velocidade ao projétil alterando sua posição no eixo y (subindo na tela)
        self.rect.y = self.y                 #Atualiza a posição de rect


    def desenha_projetil(self):
        """Desenha o projétil na tela"""
        pygame.draw.rect(self.tela, self.color, self.rect)

alien.py

import pygame
from pygame.sprite import Sprite


class Alien(Sprite):
    """Uma classe que representa um único alienígena da frota."""
    def __init__(self, ai_configuracoes, tela):
        """Inicializa o alienígena e define sua posição inicial."""
        super(Alien, self).__init__()
        self.tela = tela
        self.ai_configuracoes = ai_configuracoes
        self.image = pygame.image.load('/home/marco_user/Documentos/Projetos/Python_ProjetoLivro/imagens/aliens-1.bmp')
        self.rect = self.image.get_rect()
        self.rect.x = self.rect.width    #Inicia cada novo alienígena próximo à parte superior esquerda da tela
        self.rect.y = self.rect.height
        self.x = float(self.rect.x)                 #Armazena a posição exata do alienígena


    def check_bordas(self):
        """Verifica se o alienígena chegou na borda da tela e devolve True"""
        tela_rect = self.tela.get_rect()
        if self.rect.right >= tela_rect.right:        #SE frota alien na borda direita da tela
            return True
        elif self.rect.left <= 0:                             #SE frota alien na borda esquerda da tela
            return True


    def update(self):
        """Move o alienígena para a direita ou para a esquerda"""
        self.x += (self.ai_configuracoes.alien_speed_factor * self.ai_configuracoes.frota_direcao) #Soma o fator de velocidade ao eixo x da imagem do alien
        self.rect.x = self.x #Atualizo a posição do rect do alien

nave.py

class Nave():
    def __init__(self, ai_configuracoes, tela):
        """Inicializa a espaçonave e define sua posição inicial."""
        self.ai_configuracoes = ai_configuracoes
        self.tela = tela
        self.image = pygame.image.load('/home/marco_user/Documentos/Projetos/Python_ProjetoLivro/imagens/nave_nova1.bmp')   #Carrega a imagem da espaçonave
        self.rect = self.image.get_rect()                    #atributo da superfície - o Pygame trata elementos como retângulos , rects
        self.tela_rect = tela.get_rect()
        self.rect.centerx = self.tela_rect.centerx            #Inicia cada nova espaçonave na parte inferior central da tela
        self.center = float(self.rect.centerx)                #Transforma self.rect.centerx em ponto flutuante para aceitar valores decimais
        self.rect.bottom = self.tela_rect.bottom              #Inicia cada nova espaçonave na parte inferior
        self.move_direita = False                             #Flag de movimento da nave para a direita
        self.move_esquerda = False                            #Flag de movimento da nave para a esquerda



    def update_nave(self):
        """Atualiza a posição da espaçonave de acordo com a flag de movimento"""
        if self.move_direita and (self.rect.right < self.tela_rect.right):  #se flag True e se antes do FIM DIREITO da tela
            self.center += self.ai_configuracoes.nave_speed_factor          #utiliza o fator de 1.5 de movimento definido em Configurações

        if self.move_esquerda and self.rect.left > 0:                       #se a flag para a esquerda for True e não for o FIM ESQUERDO da tela
            self.center -= self.ai_configuracoes.nave_speed_factor          #utiliza o fator de 1.5 de movimento

        self.rect.centerx = self.center                                     #Atualiza o objeto rect(que controla a posição da nave) de acordo com self.center


    def blitme(self):
        """Desenha a espaçonave em sua posição atual"""
        self.tela.blit(self.image, self.rect)

configuracoes.py

"""Módulo de Configurações"""

class Configuracoes():
    """Uma classe para  armazenar todas as configurações da Invasão Alienígena"""
    def __init__(self):
        """Inicializa as configurações do jogo"""
        self.tela_width = 1359            #Configuração da tela , largura
        self.tela_height = 700             #Configuracao da tela , altura
        self.bg_color = (0, 0, 0)          #Configuração da cor de fundo da tela
        self.nave_speed_factor = 1.5       #Configurações da espaçonave para ajuste da velocidade
        self.alien_speed_factor = 1        #Configuração da espaçonave alienígena para ajuste de velocidade
        self.frota_drop_speed = 10         #Configuração da velocidade com que a frota desce na tela após chegar nas bordas da tela
        self.frota_direcao = 1          #fleet_direction -1 representa direção para a esquerda da tela, 1 seria para a direita
        self.municao_width = 1           #largura do projétil
        self.municao_height = 15           #tamanho do projétil
        self.municao_color = 247, 20, 43   #cor do projétil
        self.municao_speed_factor = 1      #velocidade do projétil
        self.municoes_permitida = 3        #atributo que limita a 3 tiros ao mesmo tempo na tela
furas
  • 134,197
  • 12
  • 106
  • 148
  • 2
    Could you organize your code? It is hard to understand what you are asking for. For long code snippets, try to summarize them or include them in gist.github.com and share the link in your post. – Mazen Jun 14 '21 at 00:11
  • it is hard to tell as your code isn't formatted, but what you need to do is have an alive variable for each alien, and set it to false when it is hit. Then you also need to test if any alien has hit the side of the screen and set a move_down variable and then move them all as a block. – marienbad Jun 14 '21 at 01:33
  • Thanks for the help marienbad and Maze. Sorry for the bad formatting of my code, it's the first time I'm looking for some help with programming. – marcopereira79 Jun 15 '21 at 01:04
  • @Maze , thanks for your attention. My code is on Github: https://github.com/marcoapereira79/Python_ProjetoLivro – marcopereira79 Jun 15 '21 at 01:35

0 Answers0