Skip to content

Tutorials · Navigation and AI · Chapter 12

The watch, finished

30 minutes Uses: Area, Canvas, Rect, Text, Theme, emit_to, heard, hide, in_group, keep_number, kept_number, move_to, pause, position, set_text, show

By the end

  • A key on the store room’s table that the thief takes as she passes, and loses when she is caught
  • A way out at the courtyard gate: back there with the key, she is away
  • Three chances: caught a third time, the watch wins
  • Words across the top of the screen that say what to do and how the night ended, and a game that stops when it ends
  • A guard read in Play: his routes, his mind in the Inspector, and the Problems tab’s rows
  • The watch exported, a game that runs without the editor
On this page

A key and a way out

Eleven chapters made a keep that watches. This one makes it a game. The thief comes in at the courtyard gate, takes the key from the store room’s table, and gets out the way she came in. Each time a guard catches her she is put back at the gate, and the key goes back on its table. She has three chances.

The key gets an Area, so it notices her, and a script that takes it when she does.

  1. Select key, on the store room’s table. Under Groups, type key into Add group and press Enter.
  2. Click Add component and choose AreaComponent. In its Shape, set Size to 12 and 12, clicking each box once, typing and pressing Enter. Every other field stays as it comes, as the pots’ Area did in chapter 6.
  3. In Assets, press Create, choose New script, type key, and press Enter. In the Code tab, replace everything in key.rgs with the script below, and press Ctrl+S.
  4. Select key, click Add component and choose Key. It has no fields.
rgs key.rgs
/// The key on the store room's table. The thief takes it as she passes it;
/// caught, she loses it, and it is back on the table.
component Key : Area {
    fn on_enter(other: NodeId) {
        if in_group(other, "thief") {
            keep_number("key", 1.0);
            emit_to("word", "taken");
            hide();
        }
    }

    fn on_signal() {
        if heard("dropped") {
            show();
        }
    }
}

Her Area, the one chapter 6 gave her, touches the key’s: on_enter runs, in_group says it is her, and the key keeps a number that says she has it, tells the words across the top, which the next section makes, and hides.

The key’s Area Shape Size
The box the key notices her with, in world units, about its middle: 12 by 12, the key’s picture and a little over, so she takes it by walking onto the table, not by brushing the wall beside it. A new Area’s is 64 by 64, which would reach across half the store room.
keep_number
Keeps a number under a name until the game closes, for any script to read with kept_number. keep_number("key", 1.0) says she has the key; 0 says she has not. It lands at the end of the step, as keep_point does, so the other scripts read it from the next step on.
kept_number
Reads a kept number as it was when the step began, or the default given if nothing was ever kept under that name. kept_number("key", 0.0) > 0.5 is the scripts’ way of asking whether she has the key: before she first takes it nothing is kept, and the default, 0, says no.
hide
Makes this node invisible, at once. An invisible Area overlaps nothing, so a hidden key cannot be taken again: she can stand on the empty table and nothing happens.
show
Makes this node visible again, and its Area notices her again. The key shows itself when it hears dropped.
taken and dropped
Two more signals. The key sends taken to the group word, the words across the top, when she takes it. Her own script sends dropped to the group key, and to the group word, when she is caught with it. Each is heard on the step after it is sent.

The way out

The way out is where she came in: the courtyard gate, where she stands as the game begins. It is a node with only an Area and a script.

  1. Select keep, press + Add node and choose Node. Rename it way_out.
  2. Set its Position: click its x box once, type 600 and press Enter; then its y box, 312, the same way. That is her start.
  3. Click Add component and choose AreaComponent. In its Shape, set Size to 32 and 32. Every other field stays as it comes.
  4. In Assets, press Create, choose New script, type way_out, and press Enter. In the Code tab, replace everything in way_out.rgs with the script below, and press Ctrl+S.
  5. Select way_out, click Add component and choose WayOut.
rgs way_out.rgs
/// Where the thief came in. Back here with the key, she is away.
component WayOut : Area {
    fn on_enter(other: NodeId) {
        if in_group(other, "thief") && kept_number("key", 0.0) > 0.5 {
            emit_to("word", "away");
        }
    }
}
The way out’s Area Shape Size
32 by 32: two tiles square about the gate. Coming into the courtyard is not enough; she has to come back to the gate itself.
away
The signal the way out sends to the words when she steps onto it with the key. Without the key it sends nothing, and she can walk through the gate as often as she likes.

Three chances

Her script, from chapter 8, puts her back at the gate when she is caught. Now it also counts how often, takes the key from her, and says when the watch has won.

  1. Click the Code tab, then thief.rgs in its Scripts list. Replace everything in it with the script below, and press Ctrl+S.
  2. Select thief. Her Thief now shows Chances 3 and Caught 0, greyed, as the script declares them: nothing to type.
  3. Press Ctrl+S.
rgs thief.rgs
/// The thief. Caught by a guard, she is put back where she came in, and the
/// key, if she had it, is back on its table. Caught too often, the watch has
/// won.
component Thief {
    /// Where she starts again when she is caught.
    #[hidden]
    start: Vec2,
    /// How many times she may be caught before the watch wins.
    chances: i32 = 3,
    /// How many times she has been caught.
    #[readonly]
    caught: i32 = 0,

    fn on_create() {
        start = position();
    }

    fn on_signal() {
        if heard("caught") {
            caught += 1;
            move_to(start);
            if kept_number("key", 0.0) > 0.5 {
                keep_number("key", 0.0);
                emit_to("key", "dropped");
                emit_to("word", "dropped");
            }
            if caught >= chances {
                emit_to("word", "lost");
            }
        }
    }
}
Chances
The Thief’s Chances: how many times she may be caught before the watch wins. 3, as the script gives it. 1 makes every catch the end of the night.
Caught
The Thief’s Caught, read-only: how many times a guard has caught her this game, counted by her script, live in the Inspector in Play.
lost
The signal her script sends to the words on the catch that uses up her last chance.

Caught with the key, she is put back on the way out, but that does not get her away: her script takes the key from her as it puts her there. A moment later the key is back on its table, and the words across the top are the first ones again.

Words across the top

The night needs words: what the thief is to do, and how it ended. They go in a Label under a Canvas, which draws over the camera’s picture rather than in the keep, so they stay across the top of the screen wherever she walks. Interfaces’ A canvas and a plate teaches both at length; here they are used once.

  1. Select keep, press + Add node and choose Canvas. Rename it hud.
  2. In its Canvas, set Scale Mode to ShrinkToFit. Reference Size stays 1280, 720, Space stays Screen and Use Safe Area stays ticked, as a new Canvas has them.
The Canvas’s Reference Size
The canvas’s own size in UI units: the window the words were laid out for. The keep’s window is 1280 by 720, as a new Canvas has it, so it stays. Every offset under the canvas is in these units.
The Canvas’s Scale Mode
How the canvas fits a window of another size. ShrinkToFit scales it to the largest 16 by 9 field that fits inside the window, so the words are never cut off however the window is shaped. A new Canvas has ScaleWithHeight.
The Canvas’s Space and Use Safe Area
Screen draws the canvas over the camera’s picture, as a HUD is. Use Safe Area keeps it inside the part of a phone’s screen nothing covers; both stay as they come.

A new Canvas comes with a Theme beside it, at its defaults. A Theme recolours the controls under its canvas only when you press its Apply theme; the words keep the colours you give them below, so it stays as it comes.

  1. Select hud, press + Add node and choose Label. Rename it word: it goes under hud.
  2. Under Groups, type word into Add group and press Enter: it is the group the three scripts tell.
  3. In its Rect, set Anchor Min and Anchor Max both to 0.5, 0, Offset Min to -480, 24, Offset Max to 480, 64, and Pivot to 0.5, 0, clicking each box once, typing and pressing Enter.
  4. In its Text, select everything in Text and type Take the key from the store room, and get out the way you came in. Scale stays 2, as it comes. Set Align to Center.
  5. Click Color. If the button at the top left of the picker that opens reads U8, press it so that it reads F: each channel then runs from 0 to 1. Set it to 0.8388, 0.7682, 0.6172, alpha 1, a pale beige.
  6. Click Outline and set it the same way to 0.0497, 0.0194, 0.0307, alpha 1, a dark plum, and set Outline Width to 2.
Anchor Min, Anchor Max
The Rect’s two points of the canvas it is held to, as fractions of its width and height: 0, 0 is the top left corner, 1, 1 the bottom right. Both at 0.5, 0, the words are held to the middle of the top edge, whatever the window’s width.
Offset Min, Offset Max
The Rect’s top left and bottom right corners, in UI units from the anchors. -480, 24 and 480, 64 make a box 960 wide and 40 high, centred, 24 below the top.
Pivot
The point of the Rect, as fractions of its own size, that counts as its position. 0.5, 0 names the middle of its top edge, the point it is held by. It does not place the box: the anchors and offsets do.
Text
The Label’s words, as the game begins. The scripts change them as the night goes.
Scale
How big the letters are, as a share of the font’s own size. The keep has no font of its own, so the words are drawn in the built-in font; 2, as a new Text has it, reads across the top of a 1280 by 720 window without crowding it.
Align
Left, Center or Right: where the words sit across the box. The box is centred and wider than any of the four lines, so Center keeps each line in the middle of the screen. A new Text is Left.
Color
The letters’ colour, as red, green, blue and alpha, each 0 to 1 in the picker’s F mode. 0.8388, 0.7682, 0.6172 is Tiny Dungeon’s pale beige.
Outline, Outline Width
A ring of colour drawn behind each letter, and how far it reaches, in UI units. 2 units of Tiny Dungeon’s dark plum, 0.0497, 0.0194, 0.0307, the colour its pictures are outlined in, keep the beige letters apart from whatever is behind them. A new Text’s width is 0, which draws none.

What the words say

  1. In Assets, press Create, choose New script, type word, and press Enter. In the Code tab, replace everything in word.rgs with the script below, and press Ctrl+S.
  2. Select word, click Add component and choose Word. It has no fields.
  3. Press Ctrl+S.
rgs word.rgs
/// The words across the top of the screen: what the thief is to do, and how
/// the night ends. Caught, she has lost the key, so the words go back to the
/// first ones.
component Word {
    fn on_signal() {
        if heard("dropped") {
            set_text("TextComponent", "text", "Take the key from the store room, and get out the way you came in.");
        }
        if heard("taken") {
            set_text("TextComponent", "text", "Now out the way you came in.");
        }
        if heard("away") {
            set_text("TextComponent", "text", "Away with the key. The night is yours.");
            pause();
        }
        if heard("lost") {
            set_text("TextComponent", "text", "Caught once too often. The watch wins.");
            pause();
        }
    }
}

Each signal writes a line into the Label’s Text with set_text, as the kitchen door’s script wrote its picture’s region in chapter 10. dropped writes the line the game began with, so a thief who has lost the key is told to fetch it again. The two that end the night also stop the game.

pause
Pauses the game at the end of the step. Nothing in the keep is set to run while paused, so everything stops where it is: the guards, the cat, the thief under your keys. The words stay on the screen. In Play, press F5 to stop; in the exported game, close its window.

The night, played

  1. Press F5. The words across the top say what to do.
  2. Walk the thief up into the store room by its door off the corridor, and onto the key on its table. The key goes, and the words change.
  3. Press F5 again to stop.
The game: the corridor with its long patterned carpet across the middle, the store room’s door in its north wall, the courtyard below with its patch of mud, and the thief at the courtyard gate on the right; across the top, small beige letters ringed in dark plum read Take the key from the store room, and get out the way you came in.
After 30 steps, 0.5 s: the night begins.
The game: the store room and the kitchen beside it, the thief standing on the store room’s empty table, the hole in the floor below her; across the top the words read Now out the way you came in.
After 30 steps, 0.5 s: the key taken. For this picture the thief was placed on the key from the start.

Debugging a guard

When a guard does something you did not expect, the editor’s Play can show you why, while it runs. Four things answer most questions: the routes, the Inspector read live, the cone, and the Problems tab.

Where he is going

The Routes gizmo draws every walker’s way, all at once, as chapter 5 showed for the cat: a line through the cells of its way, a cross on its Target and a ring as wide as its Arrive Distance. A route that stops short, or bends where you did not expect, is the map answering: a wall where you thought there was a door, a price, a link switched off.

  1. Press F5. Press Bake on the strip, and in the strip’s Gizmos menu leave Routes and Navigation ticked and untick the rest.
  2. Walk the thief up into the corridor and west along the carpet, towards the corridor guard.
  3. Select guard_corridor, type navagent into the Inspector’s search box and press Enter. Watch his Target and Speed as he notices her.
Play, looking through a camera pulled back to the whole keep, the map’s wash over its floors: in the corridor the corridor guard, selected, a short lime line from him to a cross at the thief’s feet a little east of him; in the great hall the hall guard near his round’s top left corner with a lime line east along the hall’s top to a cross, his pale cone ahead of him, and the cat by the hearth with a short line to a cross beside it; the Inspector narrowed with the search box, navagent, to his Nav Agent: Target 130.0 and 247.0, Moving ticked, Speed 24.00, Arrive Distance 4.00, Face Walk ticked, Use Links unticked
After 70 steps, about 1.2 s, of Play: three walkers, three routes. The corridor guard has glimpsed her and creeps to where she stands, his Speed his script’s creep, 24; the hall guard walks to his round’s next corner, and the cat to a spot by the hearth. For this picture the thief was placed on the carpet near him from the start, and the camera was pulled back to the whole keep. The wider view reaches the hall guard, so he is awake and walks; in your own Play, with the view on the corridor, he sleeps at his corner and draws no route.

What is on his mind

In Play the Inspector shows a walker’s fields as they are now, on every step. His Nav Agent’s Target follows her while he chases, Moving is ticked while he walks, and Speed is what his script last set: 40 on his round, 24 creeping, 72 running. His Guard shows his mind: Mode and Sees, read-only and greyed, change the step he changes his mind. The bell’s script shows its countdown in Left, and in Chased whether a guard is after her.

  1. With guard_corridor still selected, type guard into the Inspector’s search box instead and press Enter. Keep the thief near him: Mode goes from Patrol to Suspicious to Chase, and Sees is ticked while she is in his cone.
  2. Select bell, type bell into the search box and press Enter: Chased is ticked while he chases her, and Left counts down.
  3. Select thief, type thief and press Enter: Caught counts his catches.
  4. Press F5 again to stop.
Play, looking through the game camera at the corridor’s west end: the corridor guard with a red mark over his head, selected, his pale cone reaching east over the thief a few steps ahead of him and a lime line from him to a cross at her feet; across the top of the Viewport the words Take the key from the store room, and get out the way you came in., and in the strip under it Looking through game camera — pan to take it back; the Inspector narrowed with the search box, guard, to his Guard: A 40.0 and 232.0, B 600.0 and 232.0, Corners 2, Hearing 320.00 u, Sight 112.00 u, Cone 0.60, Walls 1, Sure 64.00 u, Walk 40.00, Creep 24.00, Run 72.00, Summoned unticked, Mode Chase and Sees ticked, both greyed; the Animation tab has alert lit
After 100 steps, about 1.7 s, of Play: Mode Chase, Sees ticked, his alert clip on. For this picture the thief was placed on the carpet near him from the start.

Which way he faces

His cone is art, turned by its own script to point the way he last walked. It tells you which way he faces, and roughly how far he sees: 112, his Sight, and 0.6 of a radian either side, his Cone. It is not his sight. A wall hides her from him even where the picture crosses it, as chapter 7 showed, and Sees is the one to believe.

The Problems tab

A walker that never moves is usually two settings that disagree. The Problems tab names four such pairs, without Play: the Hierarchy marks the node’s row with a triangle, the status bar counts them, and clicking the count opens the tab. Each row says what is wrong and what to do.

  1. Choose View → Panels → Problems. In the keep as you built it, the tab reads No problems: none of the rows below.
“This node has a Nav Agent and a Path Follow”
Two movers on one node: the Path Follow puts it back on its path after the agent walks, every step, so it never leaves its path. Keep one: remove the Path Follow, as chapters 5, 6 and 8 did. A Nav Agent or a Path Follow on a body Driven By Keys gets a row of its own: the keys move it instead. Set Driven By to Script.
“This Nav Agent stands outside every Nav Region”
The walker plans on the first region holding it, and none does, so it finds no way anywhere and stops as soon as it is sent. Move it onto the region, or grow the region’s Size to take it in.
“This Path Follow walks the Path on …” and “This Path Follow walks its parent’s Path …”
A follower whose path is missing. The first: its Path names a node that is not there, or one with no Path. The second: its Path is empty, and its parent has no Path, or it has no parent. It walks nothing. Pick the node in its Path, or move the follower under the Path it should walk.
“This Nav Region’s bake blocked nothing”
Solid boxes stand in the region, and its bake made none of them a wall, so walkers walk through them. It shows after a Bake, as chapter 2 showed. Tick Blocks nav on the walls’ tile layer, or put the walls on a collision layer the region’s Mask holds.
The Problems tab: All 3, Errors 0, and under Warnings 3 three rows, each with a warning sign: guard_hall, This Path Follow walks the Path on hall_round, and no node in the scene is called that — pick the node in its Path; guard_hall, This node has a Nav Agent and a Path Follow, and the Path Follow moves it after the agent every step, so the agent’s walk is undone — keep one of the two, or move the Path Follow to a parent or a child; cat, This Nav Agent stands outside every Nav Region, so it finds no way anywhere and stops as soon as it is sent — move it onto a region, or grow a region’s Size to take it in
Three of the four rows at once. For this picture, three mistakes were made in a copy of the keep: the hall guard was given back his Path Follow from chapter 1, hall_round was renamed hall_path, and the cat was dragged out past the keep’s top right corner.

The watch, exported

The watch is finished, and a finished game is one you can hand to someone who does not have the editor. Export writes it to a folder of its own: your project, with its pictures prepared for the game to load, and a copy of the player that came with Rengy, named after your project’s folder. Nothing is compiled: the scripts run as they are. Exporting has the whole of it.

  1. Save with File → Save all: Export copies the files as they are on disk.
  2. Click the Build tab, or choose View → Panels → Build if it is not there.
  3. In its Export section, the line under Export says where the game will be written, ending in navigation-and-ai/dist/navigation-and-ai/navigation-and-ai: your project’s folder, then dist, then a folder and a file both named after it.
  4. Press Export. When it is done, the editor opens the new folder in your file manager.
  5. Double-click navigation-and-ai, or navigation-and-ai.exe on Windows. On Linux, if double-clicking does not start it, run ./navigation-and-ai in a terminal in that folder.
The Build tab: Build now beside the line Interpreter — scripts run directly, nothing to build; the Export section open, with the Export and Cook only buttons and under them the line navigation-and-ai/dist/navigation-and-ai/navigation-and-ai; and a folded Cook assets section
The Build tab’s Export section: the two buttons, and under them where the game will be written.

The export is the same player running the same files, so the night plays out in it as it does when you press F5: the words, the key, the guards and their bell, and the ending. Nothing about a walker, a map, a path or a Timer needs the editor.

The game: the corridor and its carpet, the courtyard below with its mud, and the thief at the courtyard gate on the right; across the top the words read Away with the key. The night is yours.
After 400 steps, about 6.7 s, in the player the export runs: back at the gate with the key, the night is hers, and the game has stopped. For this picture the thief was placed on the key from the start, then walked down out of the store room by its door, west along the carpet, down into the courtyard and east to the gate.

What the chapter set

The key and the way out

NodeComponentFieldValue
keynodeGroupskey
AreaShape Size12, 12
Keyadded
way_outnodeparentkeep
Position600, 312
AreaShape Size32, 32
WayOutadded

The words

NodeComponentFieldValue
hudnodeparentkeep
CanvasScale ModeShrinkToFit
wordnodeparenthud
Groupsword
RectAnchor Min0.5, 0
Anchor Max0.5, 0
Offset Min-480, 24
Offset Max480, 64
Pivot0.5, 0
TextTextTake the key from the store room, and get out the way you came in.
Color0.8388, 0.7682, 0.6172, alpha 1
AlignCenter
Outline0.0497, 0.0194, 0.0307, alpha 1
Outline Width2
Wordadded

Every other field is as it comes: the Canvas’s Reference Size 1280, 720, Space Screen and Use Safe Area ticked, its Theme at its defaults, and the Text’s Scale 2.

The thief

NodeComponentFieldValue
thiefThiefChances3, as the script gives it
Caught0, read-only

Check it works