Making games

Game UI

A game’s interface (a HUD, a pause menu, a health bar) is a UI document, a .ogui file, shown on screen by a Canvas component.

Making a document

In the Assets panel, choose New UI Document, then double-click it. It opens in a tab of its own beside Scene, and while that tab is in front:

  • the middle of the window is the document’s design surface,
  • the left dock lists the document’s Elements instead of the Hierarchy,
  • the Inspector shows the selected element’s properties.

Click Scene to go back to the scene; the document stays open in its tab.

Add at the top of the Elements list puts in a new element:

ElementWhat it is
panelA box that holds other elements, with a background.
row, columnLay their children out side by side, or one above another.
labelText.
imageA picture.
buttonSomething to click.
progressA bar that fills: health, loading.
sliderA value the player drags.
text_inputA field the player types into.
widgetAnother UI document, placed inside this one. Make a health bar once and use it in every HUD.

Every element has a name. Names matter: scripts reach elements by them.

Showing it in the game

Add a Canvas to an object (Scene → Canvas makes one) and pick the document in its Document field. The canvas draws over the whole screen, whatever its transform says, and draws in the scene view while the game runs.

PropertyWhat it does
VisibleDrawn at all.
OrderWhich canvas is on top when two overlap: higher draws later.
ScalingConstantPixels keeps everything the same size in pixels on every screen. ScaleWithScreen scales the document as if it were made for Reference size, so it fills the same share of any screen.
Screen matchWith ScaleWithScreen, for a screen of a different shape: 0 follows its width, 1 its height, in between blends.

From a script

Scene.canvas("HUD") finds the canvas on the object named HUD. An element is named by its path: its name, with the names of the elements it’s inside in front, like "menu/start". Inside a widget, the path goes through it: "hud/health/fill".

var score = 120
var has_save = Save.exists("progress")

var hud = Scene.canvas("HUD")
hud.set_text("score", "Score: {score}")
hud.set_visible("pause_menu", true)
hud.set_enabled("menu/continue", has_save)
hud.set("health/fill", "value", 0.75)
var name = hud.get("name_field", "text")

When the player uses the UI, the scripts on the canvas’s own object get:

on_ui_click(path) runs when a button is clicked, on_ui_change(path, value) when a slider is moved or a text input typed in (value is the new value or text), and on_ui_submit(path, text) when Enter is pressed in a text input. The reference lists them with the other hooks.

fn on_ui_click(path) {
    if path == "menu/start" {
        Scene.load("assets://scenes/level1.otsn")
    } else if path == "menu/quit" {
        Engine.quit()
    }
}

A tidy way to organize this: one script on the canvas’s object owns the UI, and everything else sends it what to show. The Escape example’s hud.cog works that way.