Rozdział 21 · Projekt: kosmiczny strzelec

Zasoby gry: grafika i dźwięk

Prawdziwe sprite'y zamiast prostokątów — i klasę, która ładuje je dokładnie raz.

Do tej pory statek, wrogowie i pociski były rysowane prostokątami i kółkami — Przydatne na pierwsze kroki (Rozdział 20.3). Ostateczna wersja używa własnych sprite'ów, narysowane specjalnie na potrzeby tego projektu, zamiast geometrycznych włóczek.

Sprite'y Projektu

Real Window: Mały pomarańczowy wróg Scout po lewej i większy różowo-czerwony myśliwiec po prawej, niebieski statek gracza poniżej
Trzy własne sprite'y jednocześnie: zwiadowca (scout), myśliwiec (fighter) i statek gracza) – różne sylwetki i kolory, dzięki czemu przeciwnicy są czytelni na pierwszy rzut oka.

Wszystkie obrazy są zapisywane jako pliki .png z przezroczystym tłem. Po załadowaniu przechodzą do Surface obsługującego kanał alfa (flaga pygame.SRCALPHA przy tworzeniu takiej Surface, rozdział 20.17, — to jest właściwość samej Surface w pygame, a nie pliku PNG), dlatego przezroczyste piksele pozostają przezroczyste również na ekranie. Sprite'y rysowane są bezpośrednio przez pygame.draw w osobnym piśmie scripts/generate_chapter_21_assets.py, a nie pobrana skądś — proste kształty geometryczne, bez żadnego istniejącego komercyjnego sprite'a.

PlikRolaFunkcje
player_ship.pngStatek GraczaSylwetka w kształcie strzały, jasna kabina, światło silnika
enemy_scout.pngSzybki, tani wrógMały, pomarańczowo-czerwony trójkąt
enemy_fighter.pngPowoli, drogi WroguWiększy, purpurowo-czerwony, z bocznymi modułami
bullet.pngPocisk GraczaMała, jasnożółta kapsułka
explosion_sheet.pngAnimacja eksplozji6 klatek z rzędu – sekcja 21.20 przecina je przez subsurface()

AssetStore - Załaduj raz

Rozdział 20.24 już ostrzegała: pobieranie pliku w pętli gry to częsta przyczyna Spadki klatek. Tutaj wszystko jest ładowane raz podczas tworzenia gry, w osobnej klasie:

fragment_asset_store.py
class AssetStore:
    def __init__(self, image_dir, audio_dir):
        self.images = {{}}
        for key in ("player_ship", "enemy_scout", "enemy_fighter", "bullet"):
            self.images[key] = pygame.image.load(image_dir / f"{{key}}.png").convert_alpha()

        self.sounds = {{}}
        for key in ("laser", "explosion", "player_hit"):
            path = audio_dir / f"{{key}}.wav"
            try:
                self.sounds[key] = pygame.mixer.Sound(str(path))
            except (pygame.error, FileNotFoundError):
                self.sounds[key] = None
convert_alpha() — to samo znaczenie, co w rozdziale 20
pygame.image.load(...) już zachowuje przezroczystość załadowanego PNG samo w sobie — .convert_alpha() nie „tworzy” przezroczystości, lecz przygotowuje kopię w formacie pikseli ekranu do szybkiego ponownego rysowania (rozdział 20.19). Tutaj jest wywoływana zaraz po załadowaniu, dopóki obrazów jest mało i nie trzeba tego odkładać.
Dźwięk jest opcjonalny na początku gry
Jeśli w systemie nie ma urządzenia dźwiękowego (np. przy automatycznym testowaniu), pygame.mixer.Sound(...) może się nie zdać — wtedy self.sounds[key] pozostałości None, ale gra nadal się uruchamia i działa, tylko bez dźwięku. Rozdział 21.21 pokazuje, jak odtwarzanie uwzględnia to przy każdym połączeniu.