Aufblitzen und hochzählen
Teil des Abschnitts Sound und Spielgefühl der Pygame-Journey von Coddy. Lektion 23 von 23.
Zwei letzte Feinheiten. Wenn der Spieler ein Leben verliert, blinkt der ganze Bildschirm kurz rot auf, sodass der Verlust unmöglich zu übersehen ist. Wenn er Punkte erzielt, zählt die Zahl hoch, statt einfach zu springen.
Der rote Blitz ist eine Surface in Fenstergröße, die rot gefüllt und mit set_alpha() durchscheinend gemacht wird, von 0 (unsichtbar) bis 255 (deckend). Erzeuge sie einmal vor der Schleife:
red = pygame.Surface((640, 480))
red.fill((255, 0, 0))
red.set_alpha(90)Bei einem verlorenen Leben wird flash = 12 gesetzt. In jedem Frame wird der Wert heruntergezählt, und solange er über 0 liegt, zeichnet das Spiel red über die Spielwelt, vor dem Text.
Verwende für den Punktestand eine zweite Zahl, shown_score, und nähere sie in jedem Frame schrittweise dem tatsächlichen Wert an:
shown_score += (score - shown_score) * 0.2Zeichne round(shown_score). Das Spiel entscheidet weiterhin alles anhand von score; nur die Anzeige nähert sich dem Wert schrittweise an. Das ist die Regel für den gesamten Feinschliff dieses Kapitels: Er verändert, was der Spieler sieht und hört, niemals aber die Regeln.
Aufgabe
Mittel- Vor der Schleife:
flash = 0, die rote Surface mit Alpha 90 undshown_score = 0. - Setze
flash = 12an beiden Stellen, an denen ein Leben verloren geht. - Verringere neben
explosions.update()flashum 1, solange der Wert über 0 liegt, und nähereshown_scoremit dem Faktor 0.2 anscorean. - Blitte nach dem Blitten der Welt
redbei(0, 0), solangeflashüber 0 liegt. - Zeige
Score: {round(shown_score)}anstelle des Punktestands an.
Probier es selbst
import random
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Star Patrol")
clock = pygame.time.Clock()
font = pygame.font.Font(None, 32)
ship_image = pygame.image.load("assets/images/ship.png").convert_alpha()
laser_image = pygame.image.load("assets/images/laser.png").convert_alpha()
red_image = pygame.image.load("assets/images/enemy_red.png").convert_alpha()
green_image = pygame.image.load("assets/images/enemy_green.png").convert_alpha()
yellow_image = pygame.image.load("assets/images/enemy_yellow.png").convert_alpha()
explosion_frames = []
for number in range(1, 5):
explosion_frames.append(pygame.image.load(f"assets/images/explosion_{number}.png").convert_alpha())
laser_sound = pygame.mixer.Sound("assets/sounds/laser.ogg")
laser_sound.set_volume(0.4)
explosion_sound = pygame.mixer.Sound("assets/sounds/explosion.ogg")
hit_sound = pygame.mixer.Sound("assets/sounds/hit.ogg")
WAVES = [(red_image, 6, 2), (green_image, 8, 2), (yellow_image, 10, 3)]
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = ship_image
self.rect = self.image.get_rect(midbottom=(320, 470))
self.mask = pygame.mask.from_surface(self.image)
def update(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.rect.x -= 6
if keys[pygame.K_RIGHT]:
self.rect.x += 6
self.rect.clamp_ip(screen.get_rect())
class Laser(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = laser_image
self.rect = self.image.get_rect(midbottom=(x, y))
self.mask = pygame.mask.from_surface(self.image)
def update(self):
self.rect.y -= 10
if self.rect.bottom < 0:
self.kill()
class Enemy(pygame.sprite.Sprite):
def __init__(self, image, x, y, speed):
super().__init__()
self.image = image
self.rect = self.image.get_rect(center=(x, y))
self.mask = pygame.mask.from_surface(self.image)
self.speed = speed
def update(self):
self.rect.y += self.speed
class Explosion(pygame.sprite.Sprite):
def __init__(self, center):
super().__init__()
self.index = 0
self.timer = 0
self.image = explosion_frames[0]
self.rect = self.image.get_rect(center=center)
def update(self):
self.timer += 1
if self.timer == 5:
self.timer = 0
self.index += 1
if self.index == len(explosion_frames):
self.kill()
else:
self.image = explosion_frames[self.index]
def play_music(path, loops=-1):
pygame.mixer.music.load(path)
pygame.mixer.music.play(loops)
def burst(center):
for i in range(16):
particles.append({
"x": center[0],
"y": center[1],
"vx": random.uniform(-4, 4),
"vy": random.uniform(-4, 4),
"life": random.randint(15, 30),
})
def spawn_wave(image, count, speed):
for i in range(count):
x = random.randint(40, 600)
enemies.add(Enemy(image, x, -40 - i * 120, speed))
player = Player()
lasers = pygame.sprite.Group()
enemies = pygame.sprite.Group()
explosions = pygame.sprite.Group()
world = pygame.Surface((640, 480))
particles = []
shake = 0
last_shot = 0
score = 0
lives = 3
wave = 0
image, count, speed = WAVES[wave]
spawn_wave(image, count, speed)
pygame.mixer.music.set_volume(0.5)
play_music("assets/music/level.ogg")
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if lives > 0 and wave < len(WAVES):
player.update()
keys = pygame.key.get_pressed()
now = pygame.time.get_ticks()
if keys[pygame.K_SPACE] and now - last_shot >= 250:
lasers.add(Laser(player.rect.centerx, player.rect.top))
last_shot = now
laser_sound.play()
lasers.update()
enemies.update()
for enemy in enemies:
if enemy.rect.top > 480:
enemy.kill()
lives -= 1
hit_sound.play()
hits = pygame.sprite.groupcollide(enemies, lasers, True, True, pygame.sprite.collide_mask)
for enemy in hits:
score += 10
explosion_sound.play()
burst(enemy.rect.center)
shake = min(shake + 6, 15)
explosions.add(Explosion(enemy.rect.center))
crashes = pygame.sprite.spritecollide(player, enemies, True, pygame.sprite.collide_mask)
for enemy in crashes:
lives -= 1
hit_sound.play()
explosions.add(Explosion(enemy.rect.center))
burst(enemy.rect.center)
shake = 15
if not enemies:
wave += 1
if wave < len(WAVES):
image, count, speed = WAVES[wave]
spawn_wave(image, count, speed)
else:
play_music("assets/music/win.ogg", 0)
if lives <= 0:
play_music("assets/music/lose.ogg", 0)
explosions.update()
for p in particles:
p["x"] += p["vx"]
p["y"] += p["vy"]
p["life"] -= 1
particles = [p for p in particles if p["life"] > 0]
world.fill((12, 14, 30))
enemies.draw(world)
lasers.draw(world)
world.blit(player.image, player.rect)
explosions.draw(world)
for p in particles:
pygame.draw.circle(world, (255, 170, 60), (p["x"], p["y"]), p["life"] // 10 + 1)
offset = (0, 0)
if shake > 0:
amount = shake // 3
offset = (random.randint(-amount, amount), random.randint(-amount, amount))
shake -= 1
screen.fill((0, 0, 0))
screen.blit(world, offset)
score_text = font.render(f"Score: {score}", True, (240, 240, 240))
screen.blit(score_text, (10, 10))
lives_text = font.render(f"Lives: {max(lives, 0)}", True, (240, 240, 240))
screen.blit(lives_text, lives_text.get_rect(topright=(630, 10)))
if wave < len(WAVES):
wave_text = font.render(f"Wave {wave + 1}", True, (240, 240, 240))
screen.blit(wave_text, wave_text.get_rect(midtop=(320, 10)))
if lives <= 0:
message = font.render("Game over", True, (240, 240, 240))
screen.blit(message, message.get_rect(center=(320, 240)))
elif wave == len(WAVES):
message = font.render("You win!", True, (240, 240, 240))
screen.blit(message, message.get_rect(center=(320, 240)))
pygame.display.flip()
clock.tick(60)
pygame.quit()
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Sound und Spielgefühl
6Star Patrol aufpolieren
Star-Patrol-SoundsFunken bei jedem TrefferÜbe selbstständig: Pygame-Playground