Skip to content

Tutorials · Interfaces · Chapter 5

The title screen

35 minutes Uses: Canvas, Stack, Button, Focus, Shortcut, CanvasGroup, Theme, AudioSource, pressed, change_scene, quit, anneal_number, keep_number, play_sound, in_group, wait

By the end

  • scenes/title.ron, the scene the game opens on: New game, Settings (greyed until chapter 6) and Quit, each with a picture for each state
  • A menu the arrows, Tab and Enter walk, and Escape to quit
  • title.rgs and title_menu.rgs: the menu fades in, New game opens the delve and Quit quits
On this page

A scene for the title

Until now the game has been one scene, the delve. A title is a scene of its own, and the game will open on it. It has no room to look at, only a camera, a canvas and a menu on the canvas, so it is quick to make.

  1. Press Ctrl+S to save the delve, then choose File → New scene. An empty scene takes its place.
  2. Click + Add node and choose Node. Rename it Title. It is the scene’s root.
  3. Select Title, click + Add node and choose Camera. Rename it camera.
  4. In its Camera, set Scaling to Letterbox, Extent to 180, Width to 320 and Background to 118, 59, 54, alpha 255. If the colour picker reads F at its top left, press it back to U8, as in chapter 1.
  5. Select Title, click + Add node and choose Canvas. Rename it title_canvas. Set its Scale Mode to ShrinkToFit.

The camera is the delve’s own: it shows a world 320 units wide and 180 high, with bars at the sides or the top if the window is another shape. The title has no world to show, but the camera’s Background is the dark red behind the menu, the same as the delve’s, so the two screens match.

The canvas needs a palette, which is chapter 4’s with one change.

  1. In title_canvas’s Theme, set Panel to 255, 255, 255, alpha 255, Panel Accent to 254, 231, 97, alpha 255 and Panel Danger to 232, 69, 55, alpha 255.
  2. Set Text to 236, 227, 206, alpha 255, Text Accent to 254, 174, 52, alpha 255 and Text Danger to 255, 228, 220, alpha 255.
  3. Set Button to 255, 255, 255, alpha 255 and Button Text to 63, 38, 49, alpha 255, a dark plum.
  4. Set Hover Lift to 0.15 and Press Sink to 0.35.
  5. Press Ctrl+S and save the scene in the scenes folder as title.ron.
  6. Choose File → Project settings…, open its General tab and set Startup scene to scenes/title.ron. Close the window.

From now on the game opens on the title. The delve is still a scene you can open and play on its own: the editor’s Play plays the scene that is open, so open scenes/title.ron before F5 to play the whole game, and Build → Run / Stop game starts on the startup scene, as an exported game does.

The menu is a frame holding a column of three buttons: New game, Settings and Quit. Each button is a Panel with a Text and a Button on one node, and each wears a different picture for each thing that can happen to it: resting, lit, held down and disabled. The pictures come from the pack you downloaded in chapter 1.

  1. Copy the four files below into your project’s art folder, each from where the list says it is in the unzipped download. Then press Refresh in the Assets panel.

The name, the fade and the frame

  1. Select title_canvas, click + Add node and choose Label. Rename it title_name.
  2. In its Rect, set Anchor Min and Anchor Max both to 0.5, 0, Offset Min to -360, 176, Offset Max to 360, 272 and Pivot to 0.5, 0. That is a box 720 wide and 96 high, centred across the top of the screen.
  3. In its Text, set Text to The Delve and Align to Center. Scale stays 2, twice the size of chapter 1’s title.
  4. Set Outline to 63, 38, 49, alpha 255 and Outline Width to 3. Under Effects, set Shadow to 0, 0, 0, alpha 153, Shadow Offset to 4, 4 and Shadow Softness to 0.
  5. Click Add component and choose ThemeRoleComponent. Set Role to Accent. The title’s colour comes from the palette, in a moment.
  6. Select title_canvas, click + Add node and choose Fade Group. Rename it title_fade. Its Rect stays as it comes, so it fills the canvas.
  7. In its Canvas Group, set Alpha to 0. The menu will start out invisible, and a script below fades it in.
  8. Select title_fade, click + Add node and choose Panel. Rename it title_frame.
  9. In its Rect, set Anchor Min and Anchor Max both to 0.5, 0, Offset Min to -130, 320, Offset Max to 130, 531 and Pivot to 0.5, 0.
  10. In its Panel, set Texture to panel_brown.png and Border to 8. Its Color comes from the palette too.

A stack for the buttons

The frame is 260 wide and 211 high. Three buttons would be a chore to place one by one, and a Stack places them for you, as chapter 2’s did for the counters.

  1. Select title_frame, click + Add node and choose Stack. Rename it title_menu. Its Rect stays as it comes, so it fills the frame.
  2. In its Stack, set Fit to Fixed, Spacing to 12, Padding to 20, Item to 49 and Align to Center. Axis stays Vertical.
title_menu selected, its Inspector narrowed with the search box, stack, to its Stack: Axis Vertical, Fit Fixed, Spacing 12.00, Padding 20.00, Item 49.00 and Align Center; the Viewport shows THE DELVE in gold on the dark red screen, with a blue outline round the frame’s rectangle below it
Item
A Stack’s Item: how long each child is along the Stack’s axis, in UI units, when Fit is Fixed. Here each button is 49 high. Even ignores it, and Elements takes each child’s length from its own Layout Element instead. A new Stack’s is 48.
Align
Where a run of children shorter than the Stack sits in the room that is left over, along the axis: Start against the top, or the left, Center in the middle, End against the bottom, or the right. A Fixed run of three buttons and two gaps is 3 × 49 + 2 × 12 = 171 long, and the frame’s room is 211 − 2 × 20 = 171: nothing is left over, so no choice shows yet. Center keeps the menu in the middle of its frame whichever way the frame is made bigger. A new Stack’s is Start.

The Stack chooses how long each button is, and the button chooses how wide: a button whose Rect fills its slot, as these do, is as wide as the Stack’s room, 220, which is the frame’s 260 less the padding on both sides.

The buttons

  1. Select title_menu, click + Add node and choose Button. Rename it new_game. Its Rect stays as it comes: the Stack places it.
  2. In its Panel, set Texture to buttonLong_beige.png and Border to 8.
  3. In its Text, set Text to New game, Scale to 0.75 and Align to Center.
  4. In its Button, set Action to new_game, Hovered Texture to buttonLong_grey.png, Pressed Texture to buttonLong_beige_pressed.png and Disabled Texture to buttonLong_blue.png.
  5. With new_game selected, press Ctrl+D. Rename the copy settings, and set its Text to Settings and its Action to settings.
  6. Press Ctrl+D again. Rename the new copy quit, and set its Text to Quit and its Action to quit.
  7. Select settings and tick Disabled in its Button. Chapter 6 makes the screen it opens, and unticks it.
  8. Select title_canvas and press Apply theme, at the foot of its Theme. It writes the gold into the title, the plain panel colour into the frame and the buttons’ faces, and the plum Button Text into their words.
new_game selected, its Inspector narrowed with the search box, button, to its Button: Action new_game, Disabled unticked, Normal and Hovered white and Pressed light grey, and Hovered Texture, Pressed Texture and Disabled Texture each set to a buttonLong picture; the Viewport shows THE DELVE in gold on the dark red screen, with a blue outline round New game’s button, and the menu itself not drawn
Disabled
A Button’s Disabled: when it is ticked, the button takes no press and no focus, shows its Disabled Texture, and its face and the word on it dim. A disabled button fires no action. Settings is the one disabled button here, until chapter 6.
Hovered Texture, Pressed Texture, Disabled Texture
The pictures the button’s face swaps to, in place of its Panel’s own, while the pointer or the focus is on it, while it is held down, and while it is disabled. Empty, the face keeps the Panel’s picture and only the tints change. Here the face lights to the grey buttonLong_grey.png, sinks to the flat buttonLong_beige_pressed.png when held, and turns the blue buttonLong_blue.png when disabled, which, dimmed, shows as a dull grey-violet over the frame.

The three tints under Action, Normal, Hovered and Pressed, are chapter 4’s: Apply theme wrote them, from the palette’s white Button, lifted and sunk: 255, 255, 255 at rest and lit, and 211, 211, 211 held down.

Close up of the menu: NEW GAME and QUIT both in pale, lit buttons, QUIT with ESC at its right edge, and SETTINGS greyed between them
Quit under the pointer, in its Hovered Texture; New game wears it too, for the focus.
Close up of the menu: NEW GAME in a flat, darker tan button, held down, QUIT in a tan button with ESC at its right edge, and SETTINGS greyed between them
New game held down: its Pressed Texture.

The arrows and Tab

A menu is for keys as well as the pointer. The control that holds the focus is the lit one, and it is the one Enter or Space presses. The arrow keys move it, and Tab and Shift+Tab step it on and back. A screen opens with its first control focused, which is why New game was lit in the pictures above.

  1. Select new_game, click Add component and choose FocusComponent. Do the same for settings and for quit. The list that a Focus link opens offers only nodes that have a Focus component of their own, so all three get theirs first.
  2. In new_game’s Focus, set Up to quit, Down to settings, Next to settings and Previous to quit. Each is a box: click it and pick the node.
  3. In settings’s Focus, set Up to new_game, Down to quit, Next to quit and Previous to new_game.
  4. In quit’s Focus, set Up to settings, Down to new_game, Next to new_game and Previous to settings.
new_game selected, its Inspector narrowed with the search box, focus, to a Focus component: Mode All, Subtree Focus Inherit, Subtree Pointer Inherit, Up quit, Down settings, Left and Right empty, Next settings and Previous quit, with a Clear Links button under them; above it the Button’s Hovered row, which also matches the word focus; the Viewport shows THE DELVE in gold with a blue outline round New game’s button
Up, Down
The node the focus moves to when Up or Down is pressed on this one, by name. Empty, the engine picks the nearest control in that direction by position. Here the three buttons loop: Up on New game goes to Quit, and Down on Quit goes round to New game.
Next, Previous
The node Tab and Shift+Tab step to. Empty, the Tab order is reading order, the Hierarchy’s order. Here Tab goes down the menu and round, as the arrows do.

The Focus’s other five rows, Mode, Subtree Focus, Subtree Pointer, Left and Right, stay as they come, and the Clear Links button forgets every link. Chapter 7 sets Mode, and chapter 14 and chapter 16 the rest.

Settings is disabled, so it cannot take the focus, and the links through it have to go somewhere else. A link to a control that is hidden or disabled falls back to the nearest control the keys can reach.

Close up of the menu: NEW GAME in a tan button, SETTINGS greyed, and QUIT in the pale lit button, with ESC at its right edge
The arrow key from New game: past the disabled Settings to Quit.

Escape to quit

A Shortcut presses its control from a key, with no focus needed. Quit takes Esc, the key a player reaches for to leave a menu.

  1. Select quit, click Add component and choose ShortcutComponent. Set its Action to ui_cancel.
quit selected, its Inspector narrowed with the search box, shortcut, to its Shortcut: Action ui_cancel, Key empty and Show Label ticked; the Viewport shows THE DELVE in gold with a blue outline round Quit’s button
Action
A Shortcut’s Action: the input action whose key presses this control, as if it were clicked. ui_cancel is on Esc in the starter’s input map, and the key’s name is drawn inside the button’s right edge, at half the size of its words: the ESC on Quit.

The Shortcut’s Key and Show Label stay as they come, and chapter 16 defines them. The key on the button comes from the input map, so if the project’s ui_cancel is moved to another key, the button shows that key.

Your first scripts

Everything so far was clicks. A menu has to do something when a button is pressed, and that is written in Rengy Script, a small language the editor runs as it is, with nothing to install. A script is a text file in your project. You add it to a node as a component, and it works on that node’s own components. Three scripts finish the title: one fades the menu in, one answers its buttons, and one changes a script the project already has.

  1. Copy the two sounds below into a new folder audio in your project, beside art, each from where the list says. Then press Refresh in the Assets panel.

The fade

  1. In Assets, click Assets in the path bar over the tree, so the script is written at the project’s top, then press Create, choose New script, type title, and press Enter.
  2. In the Code tab, replace everything in title.rgs with the script below, and press Ctrl+S.
rgs title.rgs
/// The title's menu, faded in as the title opens. The Canvas Group on this
/// node starts at alpha 0, where the menu is not drawn and takes no key; this
/// brings it to 1 over half a second.
component Title {
    fn on_create() {
        anneal_number("CanvasGroupComponent", "alpha", 1.0, 0.5, .OutQuad);
    }
}
  1. Select title_fade, click Add component and choose Title.

component Title declares a script component, named as its file. on_create is a hook: the engine calls it once, as the node enters the scene. anneal_number moves a number on another component of this node from where it is to a target, over some seconds, with an easing: here the Canvas Group’s alpha goes to 1.0 in 0.5 seconds, .OutQuad, quick at first and slowing to the end. The menu starts at 0, which is what Alpha is for.

The Code panel with title.rgs open: a comment saying the title’s menu is faded in as the title opens, then component Title with an on_create that anneals CanvasGroupComponent’s alpha to 1.0 over 0.5 seconds with .OutQuad; the Scripts list at the left names door.rgs, exit.rgs, hero.rgs, pickup.rgs, shrine.rgs, spikes.rgs, title.rgs and title_menu.rgs
title_fade selected, its Inspector narrowed with the search box, group, to the Node’s Groups and Advanced rows and its Canvas Group: Alpha 0.000, Interactable ticked, Blocks Input unticked and Ignore Parent Groups unticked; the Viewport shows only THE DELVE in gold on the dark red screen, with a blue outline round the whole canvas
Alpha
A Canvas Group’s Alpha: a number from 0 to 1 that multiplies every colour the group’s subtree draws, all at once. 0 draws nothing and takes no click or key. 1 draws everything as it is. The title anneals it from 0 to 1 over half a second, so the frame, the buttons and their words fade in together. Put the Alpha on the group and not on each node: one number does the fade. The name stays at full strength, because it is on the canvas, outside the group.
Eight steps in: THE DELVE in gold on the dark red screen, and the menu half faded in, a brown frame with NEW GAME, SETTINGS and QUIT in faint buttons, QUIT with ESC at its right edge, SETTINGS the faintest
Eight steps in: the menu half faded in.
One second in: THE DELVE in gold, and under it the menu whole, a brown frame with NEW GAME in a pale, lit button, SETTINGS greyed and dim, and QUIT in a tan button with ESC at its right edge
One second in: the menu whole, New game lit.

The buttons

  1. In Assets, press Create, choose New script, type title_menu, and press Enter.
  2. In the Code tab, replace everything in title_menu.rgs with the script below, and press Ctrl+S.
rgs title_menu.rgs
/// The title's menu: New game starts a fresh run in the delve, and Quit
/// closes the game. Settings has no screen to open yet, so it is disabled: a
/// later chapter makes one.
component TitleMenu {
    /// The health a new game starts with.
    start_health: f32 = 10.0,

    fn loop() {
        // A button pressed by a click, by Enter while it holds the focus, or
        // by its Shortcut presses its action on the game's next step.
        if pressed("new_game") {
            // What a run keeps outlasts a change of scene, so a new game puts
            // it back as a run starts: full health, and nothing picked up.
            keep_number("health", start_health);
            keep_number("potions", 0.0);
            keep_number("elixirs", 0.0);
            keep_number("keys", 0.0);
            keep_number("gems", 0.0);
            keep_number("coins", 0.0);
            // A sound asked for on the step that changes scene plays on after
            // it.
            play_sound("click");
            change_scene("delve");
        }
        if pressed("quit") {
            play_sound("back");
            // The game closes at the end of the step that asks, which would
            // cut the sound off, so it waits a tenth of a second first.
            await wait(0.1);
            quit();
        }
    }
}
  1. Select title_menu, click Add component and choose TitleMenu. Its Start Health starts at the script’s own 10: leave it.
  2. Click Add component again and choose AudioSourceComponent. Untick Positional, and leave Bus as Sfx.
  3. In its Triggers, press the + beside it twice. Set the first entry’s Name to click and its Clip to click_001.ogg, and the second’s Name to back and its Clip to back_001.ogg. Each Mode stays Shuffle, and each Pitch and Volume as it comes, 1 to 1.

pressed("new_game") is true for one step: the first after New game is pressed, by a click let go on it, or by Enter or Space while it holds the focus. pressed("quit") is true the same way, and also on the step after Esc, because Quit’s Shortcut presses its action.

The Code panel with title_menu.rgs open: a comment on the title’s menu, a Start Health field at 10.0, and a loop that checks pressed new_game, keeps health and the five counts and calls change_scene; the Scripts list at the left names the same eight scripts
pressed
True on the step an action goes down. A Button fires its Action, a Shortcut the action it names, and a script hears either with pressed.
keep_number
Keeps a number under a name until the game closes, so it outlasts a change of scene. A new game puts the run’s numbers back as it starts: health to Start Health, and the potions, elixirs, keys, gems and coins to 0.
play_sound
Plays the trigger of this node’s Audio Source that has that name: click or back. A sound asked for on the step that changes scene plays on after it.
change_scene
Moves the game to a fresh copy of the scene with that name, its file’s name without .ron, at the end of the step. Kept values carry over.
quit and wait
quit() closes the game at the end of the step, and in the editor stops Play. A closing game would cut the sound off, so await wait(0.1) pauses the loop for a tenth of a second first.

The way out

The stairs in the delve were only stairs. Now the hero who walks onto them goes back to the title. You already have exit.rgs; this version replaces it.

  1. In the Code tab’s Scripts list, click exit.rgs, replace everything in it with the script below, and press Ctrl+S.
rgs exit.rgs
/// The way out, down the stairs. The hero who steps onto them leaves the delve
/// for the title.
component Exit : Area {
    fn on_enter(other: NodeId) {
        if in_group(other, "hero") {
            change_scene("title");
        }
    }
}

The stairs are an Area, a region that tells its script who walks into it: on_enter runs when something does, and other is that node. in_group is true if it is in the group, here "hero", so a coin or a spike never sends the game to the title. Nothing in it reads a control, so there is no action to hear.

The title scene

The camera

ComponentFieldValue
CameraScalingLetterbox
Extent180
Width320
Background118, 59, 54, alpha 255

The canvas and its palette

ComponentFieldValue
CanvasScale ModeShrinkToFit
ThemePanel255, 255, 255, alpha 255
Panel Accent254, 231, 97, alpha 255
Panel Danger232, 69, 55, alpha 255
Text236, 227, 206, alpha 255
Text Accent254, 174, 52, alpha 255
Text Danger255, 228, 220, alpha 255
Button255, 255, 255, alpha 255
Button Text63, 38, 49, alpha 255
Hover Lift0.15
Press Sink0.35

The name

ComponentFieldValue
RectAnchor Min0.5, 0
Anchor Max0.5, 0
Offset Min-360, 176
Offset Max360, 272
Pivot0.5, 0
TextTextThe Delve
Color254, 174, 52, alpha 255, written by Apply theme
AlignCenter
Outline63, 38, 49, alpha 255
Outline Width3
Shadow0, 0, 0, alpha 153
Shadow Offset4, 4
Shadow Softness0
Theme RoleRoleAccent

The fade, the frame and the menu

NodeComponentFieldValue
title_fadeCanvas GroupAlpha0
title_frameRectAnchor Min0.5, 0
Anchor Max0.5, 0
Offset Min-130, 320
Offset Max130, 531
Pivot0.5, 0
PanelColor255, 255, 255, alpha 255, written by Apply theme
Texturepanel_brown.png
Border8
title_menuStackFitFixed
Spacing12
Padding20
Item49
AlignCenter
Audio SourcePositionalunticked
Triggersclick with click_001.ogg; back with back_001.ogg; each Mode Shuffle, Pitch and Volume 1 to 1
TitleMenuStart Health10

The buttons

NodeComponentFieldValue
new_game, settings, quitPanelColor255, 255, 255, alpha 255, written by Apply theme
TexturebuttonLong_beige.png
Border8
TextScale0.75
Color63, 38, 49, alpha 255, written by Apply theme
AlignCenter
ButtonNormal255, 255, 255, alpha 255, written by Apply theme
Hovered255, 255, 255, alpha 255, written by Apply theme
Pressed211, 211, 211, alpha 255, written by Apply theme
Hovered TexturebuttonLong_grey.png
Pressed TexturebuttonLong_beige_pressed.png
Disabled TexturebuttonLong_blue.png
new_gameTextTextNew game
ButtonActionnew_game
FocusUpquit
Downsettings
Nextsettings
Previousquit
settingsTextTextSettings
ButtonActionsettings
Disabledticked
FocusUpnew_game
Downquit
Nextquit
Previousnew_game
quitTextTextQuit
ButtonActionquit
ShortcutActionui_cancel
FocusUpsettings
Downnew_game
Nextnew_game
Previoussettings

The scene’s root, Title, is an empty node. The script components Title and TitleMenu add the rest. Every other field of every node is as it comes.

Check it works