Âm thanh đội tuần tra sao
Thuộc phần Âm thanh và cảm giác chơi trong hành trình Pygame của Coddy. Bài học 20 trên 23.
Star Patrol ở phần 3 đã hoạt động, nhưng không có âm thanh. Chương này sẽ thêm âm thanh và cảm giác như trong phần này, bắt đầu với hiệu ứng âm thanh và nhạc.
Mỗi âm thanh ứng với một khoảnh khắc mà game đã có sẵn một dòng lệnh:
- thêm tia laser:
laser.ogg, âm lượng nhỏ vì nó phát nhiều lần mỗi giây; - tia laser phá hủy kẻ địch:
explosion.ogg; - mất một mạng, ở cả hai nơi:
hit.ogg.
Nhạc thay đổi theo trạng thái của game. level.ogg lặp lại từ đầu. Giai điệu chiến thắng bắt đầu khi đợt cuối cùng bị tiêu diệt hết:
if not enemies:
wave += 1
if wave < len(WAVES):
...
else:
play_music("assets/music/win.ogg", 0)
if lives <= 0:
play_music("assets/music/lose.ogg", 0)Cả hai dòng lệnh đều nằm trong hàm update, vốn chỉ chạy khi game đang hoạt động. Chúng chạy một lần ở khung hình game kết thúc; từ khung hình tiếp theo, hàm update bị bỏ qua nên giai điệu không phát lại.
Thử thách
Trung bìnhThêm âm thanh và nhạc cho Star Patrol.
- Tải
laser.ogg(âm lượng 0.4),explosion.oggvàhit.oggtừassets/sounds/; phát chúng khi bắn tia laser, tiêu diệt kẻ địch và mỗi khi mất một mạng. - Viết
play_music(path, loops=-1); phátassets/music/level.oggvới âm lượng nhạc 0.5. - Phát
win.oggmột lần khi chiến thắng vàlose.oggmột lần khi thua, từassets/music/.
Nhấn Chơi và bắn: bạn sẽ nghe tiếng tia laser xen lẫn tiếng nhạc. Sau đó nhấn Kiểm tra.
Tự làm thử
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())
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 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()
last_shot = 0
score = 0
lives = 3
wave = 0
image, count, speed = WAVES[wave]
spawn_wave(image, count, speed)
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
lasers.update()
enemies.update()
for enemy in enemies:
if enemy.rect.top > 480:
enemy.kill()
lives -= 1
hits = pygame.sprite.groupcollide(enemies, lasers, True, True, pygame.sprite.collide_mask)
for enemy in hits:
score += 10
explosions.add(Explosion(enemy.rect.center))
crashes = pygame.sprite.spritecollide(player, enemies, True, pygame.sprite.collide_mask)
for enemy in crashes:
lives -= 1
explosions.add(Explosion(enemy.rect.center))
if not enemies:
wave += 1
if wave < len(WAVES):
image, count, speed = WAVES[wave]
spawn_wave(image, count, speed)
explosions.update()
screen.fill((12, 14, 30))
enemies.draw(screen)
lasers.draw(screen)
screen.blit(player.image, player.rect)
explosions.draw(screen)
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()
Tất cả bài học trong Âm thanh và cảm giác chơi
4Rung màn hình và chớp sáng khi trúng đòn
Rung màn hìnhChớp sáng khi trúng đònKhựng hình khi trúng đònGiữ hiệu ứng tinh tế6Hoàn thiện đội tuần tra sao
Âm thanh đội tuần tra saoTia lửa mỗi lần va chạmTự luyện tập: Playground Pygame