HUD Anchors

a game HUD pinned to screen corners that follows the window.

▶ Run in browser

Tags: ui hud anchors layout responsive

A heads-up display is placed by anchors, never by coordinates. Each top-level Control names the edge or corner it belongs to with anchor= and how far in from that edge it sits with inset=, and the engine keeps it there whatever size the window becomes:

ProgressBar(anchor=Anchor.TOP_LEFT, inset=16, size=(220, 22))
Label("Score: 0", anchor=Anchor.TOP_RIGHT, inset=16)
Label("...", anchor=Anchor.CENTER_BOTTOM, inset=12)

The health bar is a ProgressBar hugging the top-left corner: setting its value resizes the fill and updates the percentage it draws, and its fill_colour steps from green through amber to red as health falls. The score in the top-right corner is a content-sized Label, so it re-fits as the number grows while its right edge stays 16 pixels from the window edge. The hint is centred along the bottom. Resize the window and every piece keeps its gutter.

Health is one Axis1D action, Up heals and Down hurts, read with Input.value("health"). With the mouse or a finger, hold on the health bar to heal it and anywhere else to hurt it.

Source

 1# /// simvx
 2# tags = ["ui", "hud", "anchors", "layout", "responsive"]
 3# web = { width = 800, height = 600, responsive = true }
 4# ///
 5"""HUD Anchors: a game HUD pinned to screen corners that follows the window.
 6
 7A heads-up display is placed by anchors, never by coordinates. Each top-level
 8`Control` names the edge or corner it belongs to with `anchor=` and how far in
 9from that edge it sits with `inset=`, and the engine keeps it there whatever
10size the window becomes:
11
12    ProgressBar(anchor=Anchor.TOP_LEFT, inset=16, size=(220, 22))
13    Label("Score: 0", anchor=Anchor.TOP_RIGHT, inset=16)
14    Label("...", anchor=Anchor.CENTER_BOTTOM, inset=12)
15
16The health bar is a `ProgressBar` hugging the top-left corner: setting its
17`value` resizes the fill and updates the percentage it draws, and its
18`fill_colour` steps from green through amber to red as health falls. The score
19in the top-right corner is a content-sized `Label`, so it re-fits as the number
20grows while its right edge stays 16 pixels from the window edge. The hint is
21centred along the bottom. Resize the window and every piece keeps its gutter.
22
23Health is one `Axis1D` action, Up heals and Down hurts, read with
24`Input.value("health")`. With the mouse or a finger, hold on the health bar to
25heal it and anywhere else to hurt it.
26"""
27
28from simvx.core import Anchor, Axis1D, Colour, Input, Key, Label, Node, Pointer, ProgressBar
29from simvx.graphics import App
30
31HEAL_RATE = 60.0  # health points per second while healing or hurting
32
33
34class HudAnchorsDemo(Node):
35    input_context = {"health": [Axis1D(low=Key.DOWN, high=Key.UP)], "press": [Pointer.PRIMARY]}
36
37    def on_ready(self):
38        self.score = 0
39        self.health_bar = self.add_child(
40            ProgressBar(name="HealthBar", anchor=Anchor.TOP_LEFT, inset=16, size=(220, 22), value=75.0)
41        )
42        self.score_label = self.add_child(
43            Label("Score: 0", name="Score", anchor=Anchor.TOP_RIGHT, inset=16, font_size=16.0)
44        )
45        self.score_label.text_colour = Colour.hex("#FFD166")
46        hint = self.add_child(
47            Label(
48                "Up / Down, or hold the bar to heal and elsewhere to hurt",
49                name="Hint",
50                anchor=Anchor.CENTER_BOTTOM,
51                inset=12,
52                font_size=13.0,
53            )
54        )
55        hint.text_colour = Colour.LIGHT_GRAY
56
57    def on_update(self, dt: float):
58        direction = Input.value("health")
59        if Input.pressed("press"):
60            direction = 1.0 if self.health_bar.is_point_inside(Input.mouse_position) else -1.0
61
62        bar = self.health_bar
63        bar.value = min(max(bar.value + direction * HEAL_RATE * dt, bar.min_value), bar.max_value)
64        if bar.percentage < 0.3:
65            bar.fill_colour = Colour.hex("#E63946")
66        elif bar.percentage < 0.6:
67            bar.fill_colour = Colour.hex("#F4A261")
68        else:
69            bar.fill_colour = Colour.hex("#43C463")
70
71        self.score += 1
72        self.score_label.text = f"Score: {self.score}"
73
74
75if __name__ == "__main__":
76    App(title="SimVX HUD Anchors", width=800, height=600).run(HudAnchorsDemo())