Bei Aufprall schütteln
Teil des Abschnitts Sound und Spielgefühl der Pygame-Journey von Coddy. Lektion 22 von 23.
Nun zum Bildschirmzittern. Ein Lasertreffer erhöht den Wert ein wenig: shake = min(shake + 6, 15), damit eine Kette von Abschüssen gut lesbar bleibt. Ein Zusammenstoß kostet ein Leben und sollte stärker spürbar sein: Dabei wird shake = 15 gesetzt.
Für das Zittern zeichnet das Spiel auf eine world-Surface und kopiert sie mit einem Versatz auf den Bildschirm, wie in der Kisten-Demo:
world.fill((12, 14, 30))
enemies.draw(world)
# ... auch das Raumschiff, die Laser, Explosionen und Funken auf world
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)Nur das Spielfeld wird auf die world gezeichnet. Punktestand, Leben und Welle werden nach dem Blit auf den Bildschirm gezeichnet. Dadurch bleiben sie an Ort und Stelle und gut lesbar, während alles andere ruckelt.
Aufgabe
Mittel- Erstelle vor der Schleife
world = pygame.Surface((640, 480))undshake = 0. - Füge dort, wo ein Laser einen Gegner zerstört,
shake = min(shake + 6, 15)hinzu. Setze dort, wo ein Gegner mit dem Schiff zusammenstößt,shake = 15. - Zeichne die Hintergrundfüllung, die Sprites, die Explosionen und die Funken auf
worldstatt aufscreen. - Wähle dann wie gezeigt den Versatz, fülle den Bildschirm schwarz und blitte
worldan den Versatz. Lasse den Text danach auf dem Bildschirm.
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()
particles = []
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)
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)
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]
screen.fill((12, 14, 30))
enemies.draw(screen)
lasers.draw(screen)
screen.blit(player.image, player.rect)
explosions.draw(screen)
for p in particles:
pygame.draw.circle(screen, (255, 170, 60), (p["x"], p["y"]), p["life"] // 10 + 1)
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()
Alle Lektionen in Sound und Spielgefühl
6Star Patrol aufpolieren
Star-Patrol-SoundsFunken bei jedem TrefferÜbe selbstständig: Pygame-Playground