v1.3: Ablauf gefixt. Tutorial und Startsequenz waren in einer Klasse - jetzt getrennt. Reihenfolge immer: Anleitung -> Moduswahl -> Startsequenz -> Spiel -> Abschluss (10s) -> Anleitung. 57 Tests.
This commit is contained in:
1 parent
e3a0c5a57d
commit
441bdb440c
5 files changed
+136
-90
No files matched your search
+41
-32
@@ -1,4 +1,8 @@
|
||||
"""Tutorialbild, Ampel-Startsequenz und Reissverschluss-Effekt."""
|
||||
"""Vorspann: Anleitungsbild und Startsequenz (Ampel + Reissverschluss).
|
||||
|
||||
Bewusst zwei getrennte Bausteine, damit die Reihenfolge im Hauptprogramm
|
||||
eindeutig ist: **Anleitung → Moduswahl → Startsequenz → Spiel**.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -8,61 +12,65 @@ from . import config, scene
|
||||
from .input_map import Action
|
||||
|
||||
|
||||
class Intro:
|
||||
"""Vorspann vor dem ersten Koffer.
|
||||
class Tutorial:
|
||||
"""Zeigt das Anleitungsbild und wartet auf A / Space.
|
||||
|
||||
Ablauf: Tutorialbild (wartet auf Bestätigung) → drei Punkte mit Ton →
|
||||
Reissverschluss, der den Auflieger "öffnet".
|
||||
Kommt vor jeder Runde – auch nach einem Ergebnis.
|
||||
"""
|
||||
|
||||
def __init__(self, assets, *, show_instruction: bool = True) -> None:
|
||||
def __init__(self, assets) -> 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()
|
||||
self.done = assets.instruction is None
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
def _start_countdown(self) -> None:
|
||||
self.phase = "countdown"
|
||||
def handle(self, action: Action) -> None:
|
||||
if action is Action.PRIMARY:
|
||||
self.done = True
|
||||
|
||||
def update(self, dt: float) -> bool:
|
||||
return self.done
|
||||
|
||||
def draw(self, surface: pygame.Surface) -> None:
|
||||
if self.assets.instruction is not None:
|
||||
surface.blit(self.assets.instruction, (0, 0))
|
||||
return
|
||||
scene.draw_top_bar(surface, self.assets, 0.0)
|
||||
scene.draw_background(surface, self.assets)
|
||||
scene.clear_bottom_bar(surface)
|
||||
|
||||
|
||||
class StartSequence:
|
||||
"""Ampel (rot/gelb/grün) und Reissverschluss, der den Auflieger öffnet."""
|
||||
|
||||
def __init__(self, assets) -> None:
|
||||
self.assets = assets
|
||||
self.timer = 0.0
|
||||
self.dot_index = 0
|
||||
self.finished = False
|
||||
self.assets.play("beep1")
|
||||
|
||||
def handle(self, action: Action) -> None:
|
||||
if self.phase == "instruction" and action is Action.PRIMARY:
|
||||
self._start_countdown()
|
||||
"""Während der Startsequenz wird keine Eingabe gebraucht."""
|
||||
|
||||
def update(self, dt: float) -> bool:
|
||||
"""Weiterrechnen; Rückgabe ``True``, wenn der Vorspann fertig ist."""
|
||||
self.timer += dt
|
||||
if self.phase == "countdown":
|
||||
if not self.finished:
|
||||
index = int(self.timer // config.INTRO_DOT_DELAY)
|
||||
if index >= len(config.INTRO_DOT_COLORS):
|
||||
self.phase = "zip"
|
||||
self.finished = True
|
||||
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
|
||||
return self.timer >= config.INTRO_ZIP_DURATION
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
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, [])
|
||||
scene.clear_bottom_bar(surface)
|
||||
|
||||
if self.phase == "countdown":
|
||||
if not self.finished:
|
||||
if 0 <= self.dot_index < len(config.INTRO_DOT_COLORS):
|
||||
pygame.draw.circle(
|
||||
surface,
|
||||
@@ -73,8 +81,9 @@ class Intro:
|
||||
),
|
||||
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
|
||||
else:
|
||||
duration = config.INTRO_ZIP_DURATION or 1.0
|
||||
progress = min(1.0, self.timer / duration)
|
||||
width = int(config.TRAILER_WIDTH * progress)
|
||||
pygame.draw.rect(
|
||||
surface,
|
||||
|
||||
Reference in new issue
Block a user