nodes/screen_transition.pyΒΆ

Part of GDQuest Open RPG.

 1"""Black overlay fade-in/out for scene transitions."""
 2
 3from __future__ import annotations
 4
 5from collections.abc import Callable
 6
 7from simvx.core import Node2D
 8
 9
10class ScreenTransition(Node2D):
11    """Renders a fullscreen black quad with tweenable alpha."""
12
13    FADE_TIME = 0.45
14
15    def __init__(self) -> None:
16        super().__init__()
17        self.alpha = 0.0
18        self._target = 0.0
19        self._dir = 0
20        self._on_complete: Callable[[], None] | None = None
21        # ScreenTransition draws on top of everything
22        self.z_index = 10000
23
24    def fade_out(self, callback: Callable[[], None] | None = None) -> None:
25        """Fade to black."""
26        self._target = 1.0
27        self._dir = 1
28        self._on_complete = callback
29
30    def fade_in(self, callback: Callable[[], None] | None = None) -> None:
31        """Fade from black back to transparent."""
32        self._target = 0.0
33        self._dir = -1
34        self._on_complete = callback
35
36    def on_update(self, dt: float) -> None:
37        if self._dir == 0:
38            return
39        # Persistent overlay added once: its `alpha` fade animates every frame from
40        # non-Property state, so dirty it each fading frame (it emits 0 ops at rest,
41        # so `dynamic` could miss the first 0->N upload without a structure change).
42        self.queue_redraw()
43        step = dt / self.FADE_TIME
44        if self._dir > 0:
45            self.alpha = min(self._target, self.alpha + step)
46        else:
47            self.alpha = max(self._target, self.alpha - step)
48        if self.alpha == self._target:
49            self._dir = 0
50            cb = self._on_complete
51            self._on_complete = None
52            if cb is not None:
53                cb()
54
55    def on_draw(self, renderer) -> None:
56        if self.alpha <= 0.0:
57            return
58        w, h = self.viewport_size
59        renderer.rect((0, 0), (w, h), fill=(0.0, 0.0, 0.0, float(self.alpha)))