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)