nodes/menu.pyΒΆ

Part of Clear Code Zelda.

 1"""Title screen: shown before the level so the game opens on a menu.
 2
 3Starting from a menu also gives the browser the user gesture it wants before
 4any audio plays, so the soundtrack can start with the level.
 5"""
 6
 7from __future__ import annotations
 8
 9from settings import TEXT_COLOUR, UI_BG_COLOUR, UI_BORDER_COLOUR_ACTIVE
10
11from simvx.core import Input, Node2D, Signal
12
13BACKDROP_COLOUR = (0.05, 0.08, 0.06, 1.0)
14DIM_TEXT_COLOUR = (0.62, 0.66, 0.62, 1.0)
15
16CONTROLS = [
17    "walk                 WASD / arrows      left stick",
18    "sword attack         SPACE              A",
19    "cast the spell       CTRL               B",
20    "swap weapon          Q                  left shoulder",
21    "swap spell           E                  right shoulder",
22    "upgrade screen       M                  START",
23    "quit                 ESC",
24    "",
25    "On a touch screen the same pad is drawn on the glass.",
26]
27
28
29class StartScreen(Node2D):
30    """Title card. ENTER, SPACE, a pad button or a tap begins the game."""
31
32    # The prompt blinks off a timer, which is not a Property.
33    dynamic = True
34
35    start_requested = Signal()
36
37    def __init__(self, **kwargs):
38        super().__init__(name="StartScreen", **kwargs)
39        self.z_index = 2000
40        self._blink = 0.0
41
42    def on_update(self, dt: float):
43        self._blink += dt
44        # One action covers the keyboard, a pad button and a tap, because the
45        # web runtime delivers a touch as a left click.
46        if Input.just_pressed("start"):
47            self.start_requested.emit()
48
49    def on_draw(self, renderer):
50        sw, sh = self.viewport_size
51        renderer.rect((0, 0), (sw, sh), fill=BACKDROP_COLOUR)
52
53        title = "CLEAR CODE ZELDA"
54        tw = renderer.text_width(title, 4.0)
55        renderer.text(title, ((sw - tw) / 2, sh * 0.16), fill=TEXT_COLOUR, scale=4.0)
56
57        sub = "A SimVX port of Clear Code's Pygame ARPG tutorial"
58        sww = renderer.text_width(sub, 1.6)
59        renderer.text(sub, ((sw - sww) / 2, sh * 0.16 + 72), fill=DIM_TEXT_COLOUR, scale=1.6)
60
61        # The panel is sized from its widest line, so nothing spills over its edge.
62        line_scale = 1.4
63        panel_w = max(renderer.text_width(line, line_scale) for line in CONTROLS) + 48
64        panel_h = 26 * len(CONTROLS) + 32
65        panel_x = (sw - panel_w) / 2
66        panel_y = sh * 0.34
67        renderer.rect((panel_x, panel_y), (panel_w, panel_h), fill=UI_BG_COLOUR)
68        for i, line in enumerate(CONTROLS):
69            renderer.text(line, (panel_x + 24, panel_y + 20 + i * 26), fill=TEXT_COLOUR, scale=line_scale)
70
71        if int(self._blink * 2) % 2 == 0:
72            prompt = "SPACE, ENTER, A OR A TAP TO PLAY"
73            pw = renderer.text_width(prompt, 2.0)
74            renderer.text(prompt, ((sw - pw) / 2, sh * 0.86), fill=UI_BORDER_COLOUR_ACTIVE, scale=2.0)