84 lines
3.0 KiB
Python
84 lines
3.0 KiB
Python
"""Tutorialbild, Ampel-Startsequenz und Reissverschluss-Effekt."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pygame
|
|
|
|
from . import config, scene
|
|
from .input_map import Action
|
|
|
|
|
|
class Intro:
|
|
"""Vorspann vor dem ersten Koffer.
|
|
|
|
Ablauf: Tutorialbild (wartet auf Bestätigung) → drei Punkte mit Ton →
|
|
Reissverschluss, der den Auflieger "öffnet".
|
|
"""
|
|
|
|
def __init__(self, assets, *, show_instruction: bool = True) -> None:
|
|
self.assets = assets
|
|
show_tutorial = show_instruction and assets.instruction is not None
|
|
self.phase = "instruction" if show_tutorial else "countdown"
|
|
self.timer = 0.0
|
|
self.dot_index = 0
|
|
if self.phase == "countdown":
|
|
self._start_countdown()
|
|
|
|
# ------------------------------------------------------------------
|
|
def _start_countdown(self) -> None:
|
|
self.phase = "countdown"
|
|
self.timer = 0.0
|
|
self.dot_index = 0
|
|
self.assets.play("beep1")
|
|
|
|
def handle(self, action: Action) -> None:
|
|
if self.phase == "instruction" and action is Action.PRIMARY:
|
|
self._start_countdown()
|
|
|
|
def update(self, dt: float) -> bool:
|
|
"""Weiterrechnen; Rückgabe ``True``, wenn der Vorspann fertig ist."""
|
|
self.timer += dt
|
|
if self.phase == "countdown":
|
|
index = int(self.timer // config.INTRO_DOT_DELAY)
|
|
if index >= len(config.INTRO_DOT_COLORS):
|
|
self.phase = "zip"
|
|
self.timer = 0.0
|
|
self.assets.play("zip")
|
|
elif index != self.dot_index:
|
|
self.dot_index = index
|
|
self.assets.play(f"beep{index + 1}")
|
|
return False
|
|
if self.phase == "zip":
|
|
return self.timer >= config.INTRO_ZIP_DURATION
|
|
return False
|
|
|
|
# ------------------------------------------------------------------
|
|
def draw(self, surface: pygame.Surface) -> None:
|
|
if self.phase == "instruction":
|
|
surface.blit(self.assets.instruction, (0, 0))
|
|
return
|
|
|
|
scene.draw_top_bar(surface, self.assets, 0.0)
|
|
scene.draw_background(surface, self.assets)
|
|
scene.draw_bottom_bar(surface, self.assets, [])
|
|
|
|
if self.phase == "countdown":
|
|
if 0 <= self.dot_index < len(config.INTRO_DOT_COLORS):
|
|
pygame.draw.circle(
|
|
surface,
|
|
config.INTRO_DOT_COLORS[self.dot_index],
|
|
(
|
|
config.TRAILER_X + config.TRAILER_WIDTH // 2,
|
|
config.TRAILER_Y + config.TRAILER_HEIGHT // 2,
|
|
),
|
|
config.INTRO_DOT_RADIUS,
|
|
)
|
|
elif self.phase == "zip":
|
|
progress = min(1.0, self.timer / config.INTRO_ZIP_DURATION) if config.INTRO_ZIP_DURATION else 1.0
|
|
width = int(config.TRAILER_WIDTH * progress)
|
|
pygame.draw.rect(
|
|
surface,
|
|
config.COLOR_TRAILER,
|
|
(config.TRAILER_X, config.TRAILER_Y, width, config.TRAILER_HEIGHT),
|
|
)
|