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, MouseButton, 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    "WASD / arrows      walk",
18    "SPACE              sword attack",
19    "CTRL               cast the selected spell",
20    "Q / E              swap weapon / spell",
21    "M                  upgrade screen",
22    "ESC                quit",
23    "",
24    "On touch or mouse: drag the left-hand stick to walk,",
25    "tap ATK / MAG / Q / E / M on the right.",
26]
27
28
29class StartScreen(Node2D):
30    """Title card. ENTER, SPACE or a click 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        if Input.is_mouse_button_just_pressed(MouseButton.LEFT) or Input.is_action_just_pressed("ui_select"):
45            self.start_requested()
46
47    def on_draw(self, renderer):
48        sw, sh = self.tree.screen_size if self.tree else (1280.0, 720.0)
49        renderer.draw_rect((0, 0), (sw, sh), colour=BACKDROP_COLOUR, filled=True)
50
51        title = "CLEAR CODE ZELDA"
52        tw = renderer.text_width(title, 4.0)
53        renderer.draw_text(title, ((sw - tw) / 2, sh * 0.16), colour=TEXT_COLOUR, scale=4.0)
54
55        sub = "A SimVX port of Clear Code's Pygame ARPG tutorial"
56        sww = renderer.text_width(sub, 1.6)
57        renderer.draw_text(sub, ((sw - sww) / 2, sh * 0.16 + 72), colour=DIM_TEXT_COLOUR, scale=1.6)
58
59        # The panel is sized from its widest line, so nothing spills over its edge.
60        line_scale = 1.4
61        panel_w = max(renderer.text_width(line, line_scale) for line in CONTROLS) + 48
62        panel_h = 26 * len(CONTROLS) + 32
63        panel_x = (sw - panel_w) / 2
64        panel_y = sh * 0.34
65        renderer.draw_rect((panel_x, panel_y), (panel_w, panel_h), colour=UI_BG_COLOUR, filled=True)
66        for i, line in enumerate(CONTROLS):
67            renderer.draw_text(line, (panel_x + 24, panel_y + 20 + i * 26), colour=TEXT_COLOUR, scale=line_scale)
68
69        if int(self._blink * 2) % 2 == 0:
70            prompt = "PRESS SPACE / ENTER OR CLICK TO PLAY"
71            pw = renderer.text_width(prompt, 2.0)
72            renderer.draw_text(prompt, ((sw - pw) / 2, sh * 0.86), colour=UI_BORDER_COLOUR_ACTIVE, scale=2.0)