Score, UI and restart
An anchored CanvasLayer, localized labels and one score increment per successful stomp.
Hierarchy
Create Prefabs/Hud.rprefab with a CanvasLayer root named Hud, a Control child named Root, and its ScoreLabel, MessageLabel, StartButton, InstructionsLabel children. Types are Label, Label, Button, Label.
Leave Hud.Layer = 1. Use Full Rect and Mouse Filter = Ignore on Root. Labels also use Ignore; keep the button's default Stop. Anchors choose the reference point and offsets define the rectangle relative to it:
| Control | Left, Top, Right, Bottom anchors | Left, Top, Right, Bottom offsets |
|---|---|---|
| ScoreLabel | 0, 0, 0, 0 | 24, 16, 280, 52 |
| MessageLabel | 0.5, 0.5, 0.5, 0.5 | −300, −90, 300, −30 |
| StartButton | 0.5, 0.5, 0.5, 0.5 | −100, 20, 100, 68 |
| InstructionsLabel | 0, 1, 1, 1 | 0, −48, 0, −16 |
Center MessageLabel and InstructionsLabel text. ScoreLabel and MessageLabel use font size 24. At 960 × 640, the button occupies (380, 340)…(580, 388).
UI code
Attach the complete Scripts/SquashHud.cs to Hud:
Complete SquashHud.cs
using Reckfell;
public partial class SquashHud : CanvasLayer
{
[Signal] public delegate void StartRequestedEventHandler();
private Label _score = null!;
private Label _message = null!;
private Label _instructions = null!;
private Button _button = null!;
public override void _EnterTree()
{
_score = GetEntity<Label>("Root/ScoreLabel");
_message = GetEntity<Label>("Root/MessageLabel");
_instructions = GetEntity<Label>("Root/InstructionsLabel");
_button = GetEntity<Button>("Root/StartButton");
_button.Pressed += OnPressed;
_instructions.Text = L("WASD / стрелки · Space — прыжок", "WASD / arrows · Space to jump");
}
public override void _ExitTree()
{
if (ReckfellObject.IsInstanceValid(_button))
_button.Pressed -= OnPressed;
}
public void SetScore(int score) => _score.Text = L("Счёт: ", "Score: ") + score;
public void ShowReady() => ShowMessage(L("Прыгайте на противников сверху", "Jump onto hazards from above"), L("Начать", "Start"));
public void ShowGameOver() => ShowMessage(L("Игра окончена", "Game over"), L("Ещё раз", "Restart"));
public void ShowPlaying()
{
_message.Hide();
_button.Hide();
}
public void ShowSetupError()
{
ShowMessage(L("Проверьте Prefabs/Mob.rprefab", "Check Prefabs/Mob.rprefab"), "");
_button.Disabled = true;
}
private void ShowMessage(string message, string buttonText)
{
_message.Text = message;
_message.Show();
_button.Text = buttonText;
_button.Show();
}
private void OnPressed() => EmitSignal(SignalName.StartRequested);
private static string L(string ru, string en) => TranslationServer.GetLocale().StartsWith("ru") ? ru : en;
}Russian labels are used when TranslationServer.GetLocale() starts with ru; otherwise English is used. Language is evaluated when text is created or updated. The prototype does not provide an in-game language-switch menu.
If the visible button cannot be clicked, check its Mouse Filter = Stop and decorative Controls above it, which need Ignore. A root Control using Ignore does not disable its child button's input.
Who changes score
SquashGame subscribes to each spawned hazard's Squashed signal. A successful event during an active round adds 1 to Score. The update chain is Squashed → SquashGame.Score → Hud.SetScore(). HUD only displays that value; the spawn timer awards no survival points.
The button's StartRequested asks the controller to begin. It resets score and player, removes old hazards and hides the button. Defeat preserves final score; restarting returns to 0. This is in-memory state, not persistent high-score storage.
The script connects the button once; no second editor connection is needed. Test several rounds: one stomp must still give one point after restarting. See the complete controller.