python - 我使用 pygame.sprite.groupcollide 来检测 pygame 中的碰撞,但删除组精灵有问题
问题描述
我正在 pygame 上制作经典游戏,外星人舰队降落在屏幕上,当舰队侧身穿过屏幕并从屏幕上向下移动时,英雄的船需要击落外星人。我正在使用 pygame.sprite.groupcollide(ammunition, aliens, True, True) 函数。在我做的测试中,我注意到如果我用一枪击中外星人,当舰队到达屏幕边缘而没有被摧毁的外星人时,整个舰队就像一只虫子一样从屏幕上跑下来。如果我不消灭任何外星人,舰队就会正确移动,从右到左,然后在屏幕上下降一层,以此类推,直到它消失在屏幕底部。如果你用一枪击中外星人,整个舰队到达屏幕边缘并立即下降会出现问题。
代码:
入侵外星人.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
网吧.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)
外星人.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)
配置文件.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
解决方案
推荐阅读
- reactjs - Firestore - 合并来自两个不同集合的文档 - React Typescript
- docker - 如何使用 docker 桌面在 docker-swarm 上创建多个主机
- swift - 在 Swift 中,如何实现一个通用系统,通过为不同的键路径注册处理器来处理类型?
- javascript - 反应传单基本教程地图无法正确显示地图
- python - 如何在 Django Channels 中创建服务器端计时器/倒计时?
- html - HTML 嵌入 base64 png 图像无法解码
- python - BeautifulSoup - 从标签中获取所有孩子而不是第一个
- node.js - 无法在电子项目中通过 yarn 安装包(Python 语法错误?)
- mysql - 错误:设置 GCP MySQL 服务器时出错
- ios - rxswift URLSession 获取字符串响应