nodes/menu.pyΒΆ
Part of HexGL.
1"""Title screen: the port's menu-first entry point.
2
3Draws over the live 3D scene (the track is already built and lit behind the
4scrim, so the menu doubles as an attract shot) and hands control to the race
5on SPACE / ENTER / click. Every coordinate is derived from
6``tree.screen_size``, so the screen re-lays itself out on a window resize and
7on the web export's responsive canvas.
8"""
9
10from __future__ import annotations
11
12from simvx.core import Input, Key, MouseButton, Node, Signal
13
14CONTROLS = [
15 ("W / UP or hold LMB", "thrust"),
16 ("A / D or LEFT / RIGHT", "steer"),
17 ("slide the pointer", "steer (touch / mouse)"),
18 ("S / DOWN or RMB", "brake"),
19 ("Q / E", "air-brake into a corner"),
20 ("R", "restart the race"),
21 ("ESC", "quit"),
22]
23
24
25class TitleScreen(Node):
26 """Blinking title card. Emits :attr:`started` once, then draws nothing."""
27
28 # The prompt blinks on a per-frame timer, so the draw must re-run.
29 dynamic = True
30
31 started = Signal()
32
33 def __init__(self, **kwargs) -> None:
34 super().__init__(**kwargs)
35 self.active = True
36 self._blink = 0.0
37
38 def on_update(self, dt: float) -> None:
39 if not self.active:
40 return
41 self._blink += dt
42 pressed = (
43 Input.is_key_just_pressed(Key.SPACE)
44 or Input.is_key_just_pressed(Key.ENTER)
45 or Input.is_mouse_button_just_pressed(MouseButton.LEFT)
46 )
47 if pressed:
48 self.active = False
49 self.started.emit()
50
51 def on_draw(self, renderer) -> None:
52 if not self.active:
53 return
54 w, h = self.tree.screen_size if self.tree is not None else (1280.0, 720.0)
55 cx = w * 0.5
56
57 # Scrim: dark enough to read against, light enough to show the track.
58 renderer.draw_rect((0, 0), (w, h), colour=(0.02, 0.03, 0.07, 0.72), filled=True)
59
60 renderer.draw_text(
61 "HEXGL",
62 (cx, h * 0.13),
63 scale=7.0,
64 alignment="centre",
65 colour=(0.75, 0.93, 1.0, 1.0),
66 )
67 renderer.draw_text(
68 "a SimVX port of BKcore's anti-grav racer",
69 (cx, h * 0.13 + 128),
70 scale=1.4,
71 alignment="centre",
72 colour=(0.55, 0.65, 0.80, 1.0),
73 )
74
75 y = h * 0.40
76 for keys, what in CONTROLS:
77 renderer.draw_text(keys, (cx - 24, y), scale=1.3, alignment="right", colour=(0.90, 0.95, 1.0, 1.0))
78 renderer.draw_text(what, (cx + 24, y), scale=1.3, alignment="left", colour=(0.55, 0.65, 0.80, 1.0))
79 y += 30
80
81 if int(self._blink * 2.0) % 2 == 0:
82 renderer.draw_text(
83 "PRESS SPACE or CLICK TO RACE",
84 (cx, h - 96),
85 scale=2.0,
86 alignment="centre",
87 colour=(1.0, 0.72, 0.30, 1.0),
88 )