Pygame doesn't kill
Question:
If player and enemy collide, I want the program to detect a collision between player and enemy(almost bottom of code). If this happens, its supposed to run the "killBullet()" function. It actually runs it, but "self.kill()" doesnt work. It really drives me nuts, since appearently it works on "update".
import pygame
import random
from pygame.locals import (
RLEACCEL,
K_UP,
K_DOWN,
K_LEFT,
K_RIGHT,
K_ESCAPE,
KEYDOWN,
QUIT,
)
pygame.mixer.init()
pygame.font.init()
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
global lives
lives = 3
class Player(pygame.sprite.Sprite):
def __init__(self):
super(Player, self).__init__()
self.surf = pygame.image.load("jet.png").convert()
self.surf.set_colorkey((255, 255, 255), RLEACCEL)
self.rect = self.surf.get_rect()
def update(self, pressed_keys):
if pressed_keys[K_UP]:
self.rect.move_ip(0, -5)
move_up_sound.play()
if pressed_keys[K_DOWN]:
self.rect.move_ip(0, 5)
move_down_sound.play()
if pressed_keys[K_LEFT]:
self.rect.move_ip(-5, 0)
if pressed_keys[K_RIGHT]:
self.rect.move_ip(5, 0)
#Keep on screen
if self.rect.left < 0:
self.rect.left = 0
if self.rect.right > SCREEN_WIDTH:
self.rect.right = SCREEN_WIDTH
if self.rect.top <= 0:
self.rect.top = 0
if self.rect.bottom >= SCREEN_HEIGHT:
self.rect.bottom = SCREEN_HEIGHT
class Enemy(pygame.sprite.Sprite):
def __init__(self):
super(Enemy, self).__init__()
self.surf = pygame.image.load("missile.png").convert()
self.surf.set_colorkey((255, 255, 255), RLEACCEL)
self.rect = self.surf.get_rect(
center=(
random.randint(SCREEN_WIDTH + 20, SCREEN_WIDTH + 100),
random.randint(0, SCREEN_HEIGHT),
)
)
self.speed = random.randint(5, 20)
def killBullet(self):
self.kill()
#global lives
def update(self):
self.rect.move_ip(-self.speed, 0)
if self.rect.right < 0:
self.kill()
class Cloud(pygame.sprite.Sprite):
def __init__(self):
super(Cloud, self).__init__()
self.surf = pygame.image.load("cloud.png").convert()
self.surf.set_colorkey((0, 0, 0), RLEACCEL)
self.rect = self.surf.get_rect(
center=(
random.randint(SCREEN_WIDTH + 20, SCREEN_WIDTH + 100),
random.randint(0, SCREEN_HEIGHT),
)
)
def update(self):
self.rect.move_ip(-5, 0)
if self.rect.right < 0:
self.kill()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
ADDENEMY = pygame.USEREVENT + 1
pygame.time.set_timer(ADDENEMY, 250)
ADDCLOUD = pygame.USEREVENT + 2
pygame.time.set_timer(ADDCLOUD, 1000)
player = Player()
enemies = pygame.sprite.Group()
cloud = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
font = pygame.font.SysFont(None, 30)
clock = pygame.time.Clock()
timer = 0
pygame.mixer.music.load("Apoxode_-_Electric_1.mp3")
pygame.mixer.music.play(loops=-1)
move_up_sound = pygame.mixer.Sound("Rising_putter.ogg")
move_down_sound = pygame.mixer.Sound("Falling_putter.ogg")
collision_sound = pygame.mixer.Sound("Collision.ogg")
running = True
while running:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
elif event.type == QUIT:
running = False
elif event.type == ADDENEMY:
new_enemy = Enemy()
enemies.add(new_enemy)
all_sprites.add(new_enemy)
elif event.type == ADDCLOUD:
new_cloud = Cloud()
cloud.add(new_cloud)
all_sprites.add(new_cloud)
pressed_keys = pygame.key.get_pressed()
player.update(pressed_keys)
enemies.update()
cloud.update()
# Fill the screen with blue
screen.fill((135, 206, 250))
text = font.render(str(timer), True, (255,255,255))
screen.blit(text, (0,(SCREEN_HEIGHT-text.get_rect().height)))
timer=timer+1
for entity in all_sprites:
screen.blit(entity.surf, entity.rect)
if pygame.sprite.spritecollideany(player, enemies):
Enemy().killBullet()
lives -= 1
print(lives)
if lives <= 0:
player.kill()
move_up_sound.stop()
move_down_sound.stop()
collision_sound.play()
running = False
pygame.display.update()
clock.tick(30)
pygame.mixer.music.stop()
pygame.mixer.quit()
Answers:
pygame.sprite.spritecollideany
tests whether a sprite intersects anything in a group and returns the first sprite detected or None
. You have to kill
the detected Sprite instead of a new enemy instance:
while running:
# [...]
enemy = pygame.sprite.spritecollideany(player, enemies)
if enemy:
enemy.killBullet()
lives -= 1
# [...]
I tried running the game and noticed that the one collision continues to reduce the number of lives automatically. I saw you commented out the global lives
in the killBullet method and moved the lives -=
operator back up there.
def killBullet(self):
self.kill()
global lives
lives -= 1
That way the missile disappears, and the game keeps going. I guess you could replace the jet asset with a little explosion image and then display an interim screen with the number of lives decreasing.
If player and enemy collide, I want the program to detect a collision between player and enemy(almost bottom of code). If this happens, its supposed to run the "killBullet()" function. It actually runs it, but "self.kill()" doesnt work. It really drives me nuts, since appearently it works on "update".
import pygame
import random
from pygame.locals import (
RLEACCEL,
K_UP,
K_DOWN,
K_LEFT,
K_RIGHT,
K_ESCAPE,
KEYDOWN,
QUIT,
)
pygame.mixer.init()
pygame.font.init()
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
global lives
lives = 3
class Player(pygame.sprite.Sprite):
def __init__(self):
super(Player, self).__init__()
self.surf = pygame.image.load("jet.png").convert()
self.surf.set_colorkey((255, 255, 255), RLEACCEL)
self.rect = self.surf.get_rect()
def update(self, pressed_keys):
if pressed_keys[K_UP]:
self.rect.move_ip(0, -5)
move_up_sound.play()
if pressed_keys[K_DOWN]:
self.rect.move_ip(0, 5)
move_down_sound.play()
if pressed_keys[K_LEFT]:
self.rect.move_ip(-5, 0)
if pressed_keys[K_RIGHT]:
self.rect.move_ip(5, 0)
#Keep on screen
if self.rect.left < 0:
self.rect.left = 0
if self.rect.right > SCREEN_WIDTH:
self.rect.right = SCREEN_WIDTH
if self.rect.top <= 0:
self.rect.top = 0
if self.rect.bottom >= SCREEN_HEIGHT:
self.rect.bottom = SCREEN_HEIGHT
class Enemy(pygame.sprite.Sprite):
def __init__(self):
super(Enemy, self).__init__()
self.surf = pygame.image.load("missile.png").convert()
self.surf.set_colorkey((255, 255, 255), RLEACCEL)
self.rect = self.surf.get_rect(
center=(
random.randint(SCREEN_WIDTH + 20, SCREEN_WIDTH + 100),
random.randint(0, SCREEN_HEIGHT),
)
)
self.speed = random.randint(5, 20)
def killBullet(self):
self.kill()
#global lives
def update(self):
self.rect.move_ip(-self.speed, 0)
if self.rect.right < 0:
self.kill()
class Cloud(pygame.sprite.Sprite):
def __init__(self):
super(Cloud, self).__init__()
self.surf = pygame.image.load("cloud.png").convert()
self.surf.set_colorkey((0, 0, 0), RLEACCEL)
self.rect = self.surf.get_rect(
center=(
random.randint(SCREEN_WIDTH + 20, SCREEN_WIDTH + 100),
random.randint(0, SCREEN_HEIGHT),
)
)
def update(self):
self.rect.move_ip(-5, 0)
if self.rect.right < 0:
self.kill()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
ADDENEMY = pygame.USEREVENT + 1
pygame.time.set_timer(ADDENEMY, 250)
ADDCLOUD = pygame.USEREVENT + 2
pygame.time.set_timer(ADDCLOUD, 1000)
player = Player()
enemies = pygame.sprite.Group()
cloud = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
font = pygame.font.SysFont(None, 30)
clock = pygame.time.Clock()
timer = 0
pygame.mixer.music.load("Apoxode_-_Electric_1.mp3")
pygame.mixer.music.play(loops=-1)
move_up_sound = pygame.mixer.Sound("Rising_putter.ogg")
move_down_sound = pygame.mixer.Sound("Falling_putter.ogg")
collision_sound = pygame.mixer.Sound("Collision.ogg")
running = True
while running:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
elif event.type == QUIT:
running = False
elif event.type == ADDENEMY:
new_enemy = Enemy()
enemies.add(new_enemy)
all_sprites.add(new_enemy)
elif event.type == ADDCLOUD:
new_cloud = Cloud()
cloud.add(new_cloud)
all_sprites.add(new_cloud)
pressed_keys = pygame.key.get_pressed()
player.update(pressed_keys)
enemies.update()
cloud.update()
# Fill the screen with blue
screen.fill((135, 206, 250))
text = font.render(str(timer), True, (255,255,255))
screen.blit(text, (0,(SCREEN_HEIGHT-text.get_rect().height)))
timer=timer+1
for entity in all_sprites:
screen.blit(entity.surf, entity.rect)
if pygame.sprite.spritecollideany(player, enemies):
Enemy().killBullet()
lives -= 1
print(lives)
if lives <= 0:
player.kill()
move_up_sound.stop()
move_down_sound.stop()
collision_sound.play()
running = False
pygame.display.update()
clock.tick(30)
pygame.mixer.music.stop()
pygame.mixer.quit()
pygame.sprite.spritecollideany
tests whether a sprite intersects anything in a group and returns the first sprite detected or None
. You have to kill
the detected Sprite instead of a new enemy instance:
while running:
# [...]
enemy = pygame.sprite.spritecollideany(player, enemies)
if enemy:
enemy.killBullet()
lives -= 1
# [...]
I tried running the game and noticed that the one collision continues to reduce the number of lives automatically. I saw you commented out the global lives
in the killBullet method and moved the lives -=
operator back up there.
def killBullet(self):
self.kill()
global lives
lives -= 1
That way the missile disappears, and the game keeps going. I guess you could replace the jet asset with a little explosion image and then display an interim screen with the number of lives decreasing.