Skip to content

Tutorials · Worlds and Levels · Chapter 13

Spawning and streaming

85 minutes Uses: Spawner, Placeholder, SpriteShape, WorldText, TileMap, destroy_self, in_group, spawn, position, vec2, random, wait, build_placeholder, signal, anneal_turn, pressed, emit, set_text, quit

By the end

  • rock.artifact, a rock that falls and breaks on the floor, and a rockfall whose Spawner copies it every half second while he is under it
  • A collision matrix that lets a rock fall through the ledges and through him, and a shelf to stand on under the falling stone
  • far-room.artifact, an arch of the wet wall and two torches on a map of its own, and two Placeholders that build it as the camera reaches each room
  • The bell on a body of its own that swings when he rings it with E, its words beside it, and the game ending four seconds later
  • The vale’s four ground fills drawn Opaque, and the game exported, shipping every artifact it builds as it plays
On this page

When to reach for a Spawner or a Placeholder

No grey block stands in for anything here. Chapter 11 left the crypt’s far rooms dark and its bell hanging still; this chapter brings the ceiling down in rocks while the pilgrim is under it, builds the far rooms only as he nears them, and hangs the bell so it swings when he rings it, which ends the game. Then the vale’s ground is drawn as a phone wants it, and the game is exported.

There are three ways to put a made thing into a world. A scene tile, chapters 4 and 12’s, is placed by a map on every cell painted with it, as the map loads. Reach for a Spawner for what comes and goes while the game plays, wherever and whenever a script asks: the rocks. Reach for a Placeholder for what need not exist until he is near: one cheap node stands in for a whole room until a script builds it. The table at the end of the chapter sets the three side by side.

What collides, what draws, what sorts: a Spawner and a Placeholder draw nothing and collide with nothing; what they make does. A rock is a Sprite on Props with a Character Body on the rubble collision layer, which the project lets pass through pilgrim: through the ledges, which stop him alone, and through him. A far room is a map on Ground, its wall on a layer behind, z -1, that holds nothing up, its torches scene tiles. The bell’s body is a Sprite on Props, and its words are on Words, over everything.

A rock

Every rock is one artifact, made once in a scene of its own and copied by the rockfall. Its picture, art/rock.png, 12 by 12, came with the starter: an outlined chunk of stone, lit from the top left.

  1. In Assets, with Assets clicked in the path bar, click Create, choose New script, type rock and press Enter. Click the Code tab, then rock.rgs in its Scripts list, replace everything in it with the script below, and press Ctrl+S. Click the Viewport tab.
rgs rock.rgs
/// A rock broken loose from the crypt's ceiling. Its Character Body is
/// driven by this script, which never moves it, so it only falls. It falls
/// through anything that stops the pilgrim alone, and when it lands on the
/// floor it breaks, and is gone.
component Rock : Body {
    fn on_land() {
        // It has come down on something solid: the floor. It breaks.
        destroy_self();
    }
}
component Rock : Body and on_land
A script with a Body base, for a node with a Character Body. on_land runs on the step the body comes down on something solid.
destroy_self
Takes away the node the script is on, at the end of the step: the rock breaks as it lands, and nothing of it is left.
  1. Double-click scenes/crypt.ron in Assets and press Ctrl+S. Choose File → New scene: an empty scene takes the crypt’s place.
  2. Press + Add node and choose Sprite. Rename it rock. In its Sprite, drag art/rock.png onto Texture, type Size 12, 12, its own, and Anchor 0.5, 1, set Sort Layer to Props, and tick Unshaded.
  3. Press Add component and choose CharacterBodyComponent. Type its Size 10, 10 and set Driven By to Script. Click its Layer, which reads pilgrim, tick rubble in the list and untick pilgrim. Leave the rest as it comes.
  4. Drag rock.rgs from Assets onto its Inspector: it adds Rock.
  5. Right-click rock in the Hierarchy and choose Save as artifact…. In the save dialog, open the artifacts folder and save the file as rock.artifact.
The body’s Driven By: Script
Whether the keys walk and jump the body, Keys as it comes, or a script moves it. A script that never moves it leaves it to fall: its Gravity, 1800 as it comes, adds 1800 a second to its fall every second, up to its Terminal Velocity, 900.
The body’s Layer
The collision layer the body is on, ticked by name from the project’s list: rubble, the second layer chapter 4 named, which nothing has been on until now. Which layers meet is the project’s to say, below.
A body’s box, from its feet
A Character Body’s box, 10 by 10 here, stands on the node’s place: the node is its foot. So the picture’s Anchor is 0.5, 1, its foot too, and the rock is drawn over its box.
The Sprite’s Unshaded
Draws the picture at its own colours under the room’s lights. The crypt is dark; unshaded, the rock keeps its own lit stone and stands out against the dark wall as it falls.

A shelf, and what a rock passes through

The rocks will come down between the two gates, over x 2400 to 2720. A shelf goes there first, for him to stand on under the falling stone.

  1. Double-click scenes/crypt.ron in Assets. The editor asks Save the open scene?: press Discard. The rock is in its artifact, and the scene round it is not wanted.
  2. Select halls and click the Tilemap tab. Click ledges’ row, then the stone row in the Terrains band, armed. With Line, draw from cell 156, -3 to 163, -3. Press Ctrl+S.

The shelf is eight cells, x 2496 to 2624, its top y -48: #3 at its west end, six #16 and #14 at its east, as the pool’s ledge is laid. None is plain stone, so Variety has nothing to roll. On ledges it is One-way, and stops the pilgrim collision layer alone, as chapter 4 set the layer.

  1. Choose File → Project settings… and click the Physics tab. In the Collision matrix, untick the box where rubble’s row meets pilgrim’s column.
The Project settings window on its Physics tab: Layer names, 0 pilgrim and 1 rubble, and Show all layers; the Collision matrix, Ticked pairs collide, pilgrim against pilgrim ticked, rubble against pilgrim unticked, rubble against rubble ticked; and Written to project.rengy as you change it
rubble against pilgrim, unticked.
The Collision matrix, a pair unticked
Unticked, rubble and pilgrim pass through each other: a rock falls through the ledges, which are on pilgrim alone, and through him. pilgrim still meets pilgrim, so he stands on the ledges, and rubble still meets rubble: the crypt’s floor, on every layer, stops a rock. It is written to project.rengy as you change it, for every scene.

The rockfall

  1. Close the Project settings window. In Assets, with Assets clicked in the path bar, click Create, choose New script, type rockfall and press Enter. Click the Code tab, then rockfall.rgs in its Scripts list, replace everything in it with the script below, and press Ctrl+S. Click the Viewport tab.
rgs rockfall.rgs
/// A stretch of the crypt where the ceiling is coming down. While the
/// pilgrim is under it, a rock breaks loose every half second, somewhere
/// along it, and falls. The rocks are copies of the artifact this node's
/// Spawner names rock.
component Rockfall : Area {
    /// Whether the pilgrim is under the rockfall: inside its Area.
    #[readonly]
    under: bool = false,

    fn on_enter(other: NodeId) {
        // Something has come under the rockfall. Only the pilgrim, who is in
        // the group pilgrim, brings the rocks down.
        if in_group(other, "pilgrim") {
            under = true;
        }
    }

    fn on_exit(other: NodeId) {
        if in_group(other, "pilgrim") {
            under = false;
        }
    }

    fn loop() {
        // While he is under it: a rock, made at the end of the step at a
        // point up to 150 either side of this node, just under the ceiling;
        // then half a second's wait before the next one.
        if under {
            spawn("rock", position() + vec2(random(-150.0, 150.0), 0.0));
            await wait(0.5);
        }
    }
}
component Rockfall : Area and under
A script with an Area base, as the levers’: its Area is the stretch the rocks fall over. under is whether he is inside it, set by on_enter and cleared by on_exit, and #[readonly], greyed in the Inspector, to watch.
spawn
Makes a copy of the artifact this node’s Spawner names, by the entry’s name, rock, at a point in the world, at the end of the step. The copy is a node of its own at the top of the scene’s tree, beside crypt, not under the rockfall.
position, vec2 and random
position() is where the rockfall’s node is, just under the ceiling. random(-150.0, 150.0) is a number from -150 up to 150, new at every call. So each rock starts somewhere along the stretch, up to 150 either side of the node.
await wait
Half a second before loop() comes round again: a rock every half second while he is under it.
  1. Select crypt, press + Add node and choose Area: the menu opens on Add child of crypt. Rename it rockfall, and type its Position 2560, -176: over the middle of the stretch, 16 under the ceiling’s underside.
  2. In its AreaComponent’s Shape, type Size 320, 176 and Offset 0, 88: x 2400 to 2720, from y -176 down to the floor. Leave its Layer and Mask as they come, pilgrim, as his.
  3. Press Add component and choose SpawnerComponent. Press the + beside Entries: a row, with no name and no artifact. Open it, type rock into Name, and drag artifacts/rock.artifact from Assets onto Artifact.
  4. Drag rockfall.rgs onto its Inspector: it adds Rockfall, Under greyed. Press Ctrl+S.
The Inspector on rockfall, from its AreaComponent down: its Shape, Kind Rectangle, Size 320.0 and 176.0, Outline [0 items], Offset 0.0 and 88.0, and Step, Solid, One Way, Layer 1, Include Lay…, Exclude Lay… and Material greyed; Layer and Mask pilgrim, Track empty; Rockfall, Under unticked and greyed; the SpawnerComponent, Entries [1 items] and its +, the row 1 rock open with its arrows and bin, Name rock, Artifact rock.artifact; Add component
The rockfall: its Area, and a Spawner whose one entry is the rock.
The Spawner’s Entries
The artifacts a script on this node may copy, each under a name. + adds a row; its arrows move it, and its bin takes it off. The entry is filled as it is added, before the script that spawns from it is dropped, so Problems has nothing to say at any step.
The entry’s Name and Artifact
Name is what spawn asks for, rock. Artifact is the file it copies, dragged from Assets.
  1. Press F5: Play runs the open scene. Walk him east, strike the cracked wall down, throw gate-1’s lever, and walk on under the rockfall. Leap up onto the shelf with Space.
The game in the rockfall: him standing on the shelf in the dark, the floor below; rocks come in at the top of the view one after another, each falling straight down, and each is gone at the floor; two of them fall through the shelf, one at each end
Watch the rocks: about two a second come in at the top, fall straight through the shelf where it is under them, and are gone at the floor.

A rock falls a little faster each step, 0.5 units a step more each time, and lands on the floor 27 steps after it is made; its on_land breaks it on that step. Over ten seconds under the rockfall they keep coming, about two a second, and every one is gone within three seconds. On the shelf he never moves: the first rock over it falls through, and on to the floor. Walk him back west to x 2200, and none falls.

The far room

Between gate-2 and the tower lever the crypt is dark: two rooms of 256, x 2816 to 3072 and 3072 to 3328, which chapter 11 left without even a back wall. Each will be the same room, an artifact: an arched alcove of the wet wall set in the halls’ wall, with two torches. It is made on a map of its own, in a scene of its own.

  1. Press F5 again to stop. Choose File → New scene: an empty scene takes the crypt’s place.
  2. Press + Add node and choose Node. Rename it far-room.
  3. Select far-room, press + Add node and choose Tilemap: the menu opens on Add child of far-room. Rename it room-tiles, set its Sort Layer to Ground, and leave its Position at 0, 0.
  4. Click the Tilemap tab and drop art/crypt-stone.png on New tilemap…: the editor writes art/crypt-stone-2.tilemap, as the status line says, and points room-tiles at it: the name chapter 2’s map left still holds its id. In Assets, rename it far-room.tilemap. It is cut as the crypt’s map is: 16 pixels, Columns 8, Margin 0, Spacing 0.
  5. Type back’s z -1. Click tile #57, the torch’s bracket, in the picker, and drag artifacts/torch.artifact from Assets onto Scene’s slot in the Tile band: each map names its own scene tiles, so this one needs the torch named again.
  6. Click ground’s row and press +: an empty layer goes in over ground and lights. Double-click its name and rename it torches. Leave it as a new layer comes: not Solid, z 0. Click ground’s row again and press the bin beside +. The editor asks Remove this layer?: press Remove. The room is scenery; the crypt’s own map holds him up.
  7. Click back’s row. Click #48, the back wall, in the picker, and with Rect drag from cell -8, -12 to 7, -1: the halls’ back wall over the whole room, x -128 to 128 from its middle, y -192 to 0.
  8. Click #58, the wet wall, and lay the arch over it with the four Rects in the table below.
  9. Click torches’ row and #57. With Brush, click cells -5, -6 and 4, -6: x -80 to -64 and 64 to 80, y -96 to -80, the halls’ torches’ height. Press the Tilemap tab’s Save: the map is written, and the scene round it is never saved.
ArchFrom cellTo cell
its foot, across the room-8, -47, -1
a row narrower-7, -56, -5
narrower again-6, -65, -6
its crown-4, -73, -7

back holds 192 cells, 98 of the arch and 94 of the wall: the arch is 64 high across the room, y -64 to 0, and narrows up to its crown at y -112. Two rooms side by side make an arcade.

  1. Right-click far-room in the Hierarchy and choose Save as artifact…, and save it in artifacts as far-room.artifact.
  2. Double-click artifacts/far-room.artifact in Assets. The editor asks Save the open scene?: press Discard. The artifact opens as a scene of its own. Select room-tiles and press Frame.
The editor on far-room.artifact at 224.4%: far-room over room-tiles in the Hierarchy, room-tiles lit; in the Viewport a wall of dark olive bricks, and across its lower part an arch of dark green-grey wet stone that steps up to a flat crown in the middle; on the arch two orange diamond markers, each labelled torch; the Inspector on room-tiles, its TileMapComponent with Tilemap far-room.tilemap, Tile Size 16.0 and 16.0, Grid Rectangle, a white Color, Sort Layer Ground and 4, Collision ticked
far-room.artifact: the wall, the arch and the torches’ markers. Play shows the torches themselves.

The far rooms

  1. In Assets, with Assets clicked in the path bar, click Create, choose New script, type far_room and press Enter. Click the Code tab, then far_room.rgs in its Scripts list, replace everything in it with the script below, and press Ctrl+S. Click the Viewport tab.
rgs far_room.rgs
/// A far room of the crypt, which stands in for the room it will be. Its
/// stone and its torches are not made until the camera comes near it: the
/// room is built the first time the camera reaches the rectangle of its
/// Screen Notifier, which takes in the room and as far as its torches'
/// light reaches, so the room is built, and lit, before that light can
/// reach the view.
component FarRoom : Screen {
    fn on_screen_enter() {
        // The camera has reached the rectangle of this node's Screen
        // Notifier. The room its Placeholder names is built under this node,
        // at the end of the step. Coming into view again builds nothing more:
        // a room is built once.
        build_placeholder();
    }
}
component FarRoom : Screen and on_screen_enter
A script with a Screen base, for a node with a Screen Notifier. on_screen_enter runs on the step the notifier’s rectangle comes into the camera’s view.
build_placeholder
Builds what this node’s Placeholder stands for, as its child, at the end of the step: the artifact’s nodes, and the scene tiles of any map in it, placed as it arrives. Asked again, or once built, it builds nothing more: a room is built once.
  1. Double-click scenes/crypt.ron in Assets. Select crypt, press + Add node and choose Placeholder: the menu opens on Add child of crypt. Rename it far-room-1, and type its Position 2944, 0: the first room’s middle, on the floor.
  2. In its PlaceholderComponent, drag artifacts/far-room.artifact from Assets onto Artifact.
  3. Press Add component and choose ScreenNotifierComponent. Type its Size 608, 192, and leave Enabler unticked.
  4. Drag far_room.rgs onto its Inspector: it adds FarRoom, with nothing to set. Press Ctrl+S.
The Inspector on far-room-1: Name far-room-1, Position 2944.0 and 0.0; Metadata; FarRoom, with nothing under it; the PlaceholderComponent, Artifact far-room.artifact, and an Instantiate now button; the ScreenNotifierComponent, Size 608.0 and 192.0, Enabler unticked, On Screen unticked and greyed; Add component
far-room-1: a Placeholder of the far room, and the rectangle the camera must reach.
The Placeholder’s Artifact
The artifact it stands in for. Until it is built, the node is one cheap empty node, where without it every wall tile and torch of the room would be there from the moment the scene opened. It is filled as it is added, so Problems has nothing to say at any step.
The Screen Notifier’s rectangle
A rectangle about the node, its Size: what must come into the camera’s view for on_screen_enter. 608 by 192 is the room’s 256, and 176 either side, as far as the torches’ light reaches: x 2640 to 3248, y -96 to 96. So the room is built, and its torches lit, before their light can reach the view, and nothing pops in. Enabler, unticked as it comes, would also stop the node and everything under it while the view is away.
  1. Right-click far-room-1 in the Hierarchy and choose Duplicate: far-room-1 copy appears straight after it. Double-click its name, rename it far-room-2, and type its Position 3200, 0. Press Ctrl+S.

The second room’s rectangle is x 2896 to 3504: the camera reaches each rectangle 176 before it reaches the room.

  1. Press F5 and walk him east as before, through the rockfall to gate-2’s lever. Throw it with E, and once the grate is up, hold D.
The game east of the rockfall: him at gate-2’s lever, its grate risen; he walks east under the gate into the far rooms, the view following him, past arches of green-grey wet stone set in the olive-brown back wall, torches burning on them; each arch and torch is already there, lit, as it comes into the view at the right
Watch the right edge of the view: each arch and its torches are there, lit, as they come into view.

Stood at x 2728, by gate-2’s lever, his camera on him, he brings the first rectangle into the view at once, and within two steps far-room-1 holds the room: far-room, and under it room-tiles, with a node for each torch its map paints, each with the torch’s light. far-room-2, out of the view, holds nothing yet, nor two seconds on. Walked into the second room, then west out of its rectangle’s sight and back, it holds the one room it was built with: nothing is built twice.

Without the far room, the dark: on a copy whose two Placeholders name no artifact, from the same place,

The game east of the rockfall, on a copy whose Placeholders name no artifact: him standing by gate-2’s shut grate, the stone over it; the end of the shelf at the left; east of the grate the brick back wall stops, and beyond it the view is dark
A copy whose Placeholders name no artifact: the dark where the first room stands.

The exported game, run on its own, draws the room where this copy shows the dark: a Placeholder builds in a finished game, as in the editor’s Play.

The bell

The bell has hung still since chapter 11: a Sprite on bell, with its rope and its chain. Rung, it should swing about its crown, while its words and the Area he rings it from stay level. A script turns only the node it is on, and what is under it, so the picture and the rope move onto a child, bell-body, with a script of its own that swings it.

  1. Press F5 again to stop. In Assets, with Assets clicked in the path bar, click Create, choose New script, type swing and press Enter. Click the Code tab, then swing.rgs in its Scripts list, replace everything in it with the script below, and press Ctrl+S. Click the Viewport tab.
rgs swing.rgs
/// The bell's body: its picture and its rope, hung from the bell's crown.
/// When the bell is rung it swings out one way and back through to the
/// other, twice, and comes to rest hanging straight.
component Swing {
    fn loop() {
        // Wait to be rung: the bell's Signal sends rung here.
        await signal("rung");
        // Out to one side by 0.4 of a radian (about 23 degrees) in a quarter
        // of a second; back through to as far the other side; out again; and
        // home. Each turn eases, as a bell slows at the top of its swing.
        await anneal_turn(0.4, 0.25, .OutSine);
        await anneal_turn(-0.8, 0.5, .InOutSine);
        await anneal_turn(0.8, 0.5, .InOutSine);
        await anneal_turn(-0.4, 0.25, .InSine);
    }
}
component Swing and await signal
A script with no base, on the body. signal("rung") waits until that name reaches this node: the bell’s Signal will send it here.
anneal_turn
Turns this node, and everything under it, by an angle over the seconds it is given, along a curve, from where it stands. The four take the body out about 23° one way in a quarter of a second, back through 46° to 23° the other way in half a second, through 46° again, and home: a second and a half in all.
.OutSine, .InOutSine and .InSine
Curves, as chapter 10’s are: each eases, as a bell slows at the top of its swing. .OutSine slows as it arrives, .InSine starts slowly, and .InOutSine does both.
  1. Select bell, press + Add node and choose Sprite: the menu opens on Add child of bell. Rename it bell-body, and type its Position 0, -16: the bell’s crown, 3552, -144 in the world.
  2. In its Sprite, drag art/bell.png onto Texture, type Size 32, 32, its own, and Anchor 0.5, 0, so it hangs from its crown, and set Sort Layer to Props. Drag swing.rgs onto its Inspector: it adds Swing.
  3. In the Hierarchy, drag bell-rope onto bell-body. It becomes the body’s child and keeps its Position, 0, 16, now measured from the crown: type its Position 0, 32, the bell’s lip again, 3552, -112.
  4. Select bell. Press the bin at the right of its SpriteComponent header. The editor asks Remove SpriteComponent?: press Remove. The picture is the body’s now.
  1. In Assets, with Assets clicked in the path bar, click Create, choose New script, type bell and press Enter. Click the Code tab, then bell.rgs in its Scripts list, replace everything in it with the script below, and press Ctrl+S. Click the Viewport tab.
rgs bell.rgs
/// The tower's bell, at the end of the pilgrim's road. Standing on the
/// landing at the foot of its rope, he rings it with the action key: the
/// bell swings, its words show beside it, to its left, and a little while
/// later the game is over.
component Bell : Area {
    /// Whether the pilgrim is at the foot of the rope: inside the bell's Area.
    #[readonly]
    near: bool = false,
    /// Whether it has been rung. The bell is rung once.
    #[readonly]
    rung: bool = false,

    fn on_enter(other: NodeId) {
        // Something has come to the rope. Only the pilgrim, who is in the
        // group pilgrim, can ring it.
        if in_group(other, "pilgrim") {
            near = true;
        }
    }

    fn on_exit(other: NodeId) {
        if in_group(other, "pilgrim") {
            near = false;
        }
    }

    fn loop() {
        // The action key (E) rings it, once. Its Signal sends rung to the
        // bell's body, which swings; its words say so; and four seconds
        // later, once they have been read, the game ends.
        if near && !rung && pressed("action") {
            rung = true;
            emit("rung");
            set_text("WorldTextComponent", "text", "The bell rings.");
            await wait(4.0);
            quit();
        }
    }
}
component Bell : Area, near and rung
An Area script, as the levers’: near is whether he is at the rope, inside the bell’s Area, and rung whether it has been rung, so it rings once. Both are #[readonly].
pressed, emit and set_text
pressed("action") is E or Enter going down this step. emit("rung") says the name to whoever the bell’s Signal names, the body, which hears it on the next step. set_text writes the bell’s words onto its World Text, from nothing to The bell rings.
quit
Ends the game at the end of the step: an exported game closes its window, and the editor’s Play stops. Here it comes four seconds after the words, once they have been read.
  1. With bell still selected, press Add component and choose AreaComponent. In its Shape type Size 24, 48 and Offset 0, 56, and leave its Layer and Mask as they come: x 3540 to 3564, y -96 to -48, on the landing at the rope’s foot.
  2. Press Add component and choose WorldTextComponent. Clear its Text. Type Offset -76, 0, set Sort Layer to Words, and tick Unshaded. In its Effects fold, type Outline Width 2, Shadow 0, 0, 0, alpha 0.8, and Shadow Offset 1, 2. Leave the rest as it comes.
  3. Press Add component and choose SignalComponent. Press the + beside Connections, open [0], type rung into Signal, and choose bell-body for To.
  4. Drag bell.rgs onto its Inspector: it adds Bell, Near and Rung greyed. Press Ctrl+S.
The Inspector on bell, from its Bell to Add component: Bell, Near and Rung unticked and greyed; the SignalComponent, Connections [1 items], [0] open, Signal rung, To bell-body; the WorldTextComponent, Text empty, Scale 1.0, a white Color, Align Center, Offset -76.0 and 0.0, Pixel Size ticked, Sort Layer Words and 7, Font (none), Unshaded ticked, and its Effects fold: Effect Mode Copies, a black Outline, Outline Width 2.0, a dark Shadow over a chequer, Shadow Off… 1.0 and 2.0, and Shadow Sof… 0.0 greyed, the last two labels cut short
bell: its Signal to the body, and its words, empty until it is rung.
The Hierarchy: crypt, and under it gate-2 and gate-1, each over its lever and its door, each with a dot after its name; pilgrim with tag and lantern, camera, halls with its map chip, ambient, checkpoint, crypt-bounds, mural-1 to mural-3, keyhole over bell-view; bell, lit, over bell-chain and bell-body, and bell-rope under bell-body; then tower-lever, rockfall, far-room-1 and far-room-2
The crypt’s tree: the body under the bell, the rope under the body, and the chapter’s three nodes at the end.
The bell’s words
Its World Text, empty until the bell is rung. At Offset -76, 0 they stand beside the bell, level with it and to its left, clear of his tag and of the rope. On Words they draw over everything, Unshaded keeps them white in the dark, and they have a black outline 2 wide and a shadow below and to the right.
Why two nodes
The body swings, and everything under it swings with it: the rope does. The bell itself, its Area and its words, stays level, since nothing turns it.
  1. Press F5 and walk him east as before, throw the tower lever at the door, and go into the tower. Leap up the stair onto the landing with Space, walk on to the rope’s foot under the bell, and press E.
The game in the tower, close: him on the landing under the bell, its rope hanging behind him; at the tap the words The bell rings. show to the bell’s left, and the bell and its rope swing out to one side, back through to the other, out again, and hang straight, the words still showing
Watch the bell: it swings out and back through, twice, about its crown, and hangs straight again; the words beside it stay level.

The words show within half a second of the tap, and the body swings from rest, while the bell itself, its Area and its words, never tilts. The body hangs straight again before the end. Four seconds after the words the game ends, within five seconds of the tap, the words still showing: in the editor, Play stops.

A room built by hand

A far room can also be built by hand, to look at it without walking there: the Placeholder’s button.

  1. Select far-room-1, press Frame, and press Instantiate now in its Placeholder.
The editor on the crypt at 135%, far-room-1 lit in the Hierarchy below the bell’s nodes, tower-lever and rockfall, with far-room-2 under it; in the Viewport the end of the shelf at the left, gate-2’s lever and grate, the brick back wall stopping a little east of the gate and the dark beyond it; the thin grey rectangle of far-room-1’s Screen Notifier from west of the lever far into the dark, the west edge of far-room-2’s inside it, and the move gizmo at the node; the Inspector on far-room-1, its PlaceholderComponent with Artifact far-room.artifact and Instantiate now, its ScreenNotifierComponent with Size 608.0 and 192.0; the status bar at the foot reads Instantiate now builds while playing — press Play first
Outside Play, Instantiate now builds nothing, and says why.
  1. Press F5, select far-room-1, and press Instantiate now again. On the next step the room is built under it, as build_placeholder() builds it in the game. Press F5 to stop: the room goes with the run.
Instantiate now
A Placeholder’s button, for Play: builds the artifact under each selected Placeholder on the next step, as a script’s build_placeholder() does in the game, and stopping takes it away again. Outside Play it builds nothing, since whatever it built into the scene being edited would be saved with it, and the status bar says to press Play first. Once a Placeholder is built, by hand or by script, it builds nothing more.

What a phone pays

The vale’s hills and the ravine’s lips are filled with earth, and every pixel of it is drawn blending with what is behind it, though nothing behind it ever shows. On a phone, where drawing a pixel over another is the cost that bites, ground that is solid should say so.

  1. Double-click scenes/vale.ron in Assets. Select hills-west, and in its Sprite Shape’s Fill fold tick Opaque. Do the same for hills-east, lip-west and lip-east. Press Ctrl+S.
lip-east’s Fill fold in the Inspector: Fill ticked, Texture earth.png, Fit Tile, Tile Scale 2.00, a pale beige Color, Opaque ticked
lip-east’s fill, Opaque, as the other three ground shapes’ fills are.
The fill’s Opaque
What a phone pays: ticked, the fill is drawn without blending, each pixel it covers written once and never mixed with what was drawn behind it. The earth is opaque already, so the ground looks as it did. The turf, the slab and the slab’s ends laid over its edges, whose pictures have see-through parts, are still blended. Tick it only where nothing should show through: a see-through part, or a see-through Color, comes out dark instead, as chapter 6’s copy of the mere showed.

Over the ravine, where the view shows the hills’ ends and both lips, each of the four fills draws without blending, and every band and corner over them is still blended.

The export

The game is whole: from the hut, over the drawbridge and down into the crypt, past the wall, the gates, the rocks and the far rooms, to the bell. Export writes it to a folder of its own that runs without Rengy; 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 under the Viewport.
  3. In its Export section, a line under Export says where the game will be written, ending in worlds-and-levels/dist/worlds-and-levels/worlds-and-levels: a folder and a file both named after your project folder.
  4. Press Export. When it is done, the editor opens the new folder in your file manager. Double-click worlds-and-levels there; on Linux, if double-clicking does not start it, run ./worlds-and-levels in a terminal in that folder.
What the export ships
The game, a copy of the player named after your project folder; your project’s files, the scenes, the scripts, the maps and the artifacts, crack.artifact, far-room.artifact, gate.artifact, rock.artifact and torch.artifact, each as you saved it; and in dist/content/desktop every picture, prepared for the game to load, the pictures the artifacts draw among them.
What the game builds as it plays
An artifact the game copies while it runs must be in the export, and is: the crack and the torch, which the crypt’s map places; the rock, which the rockfall spawns; and the far room, which the Placeholders build. The crypt reads all four in as it opens. The gate is no build: its two copies are in the crypt itself.

The game opens on the vale, its startup scene, as Run game does. A recorded run that plays it by its keys alone is in the crypt at step 1164, a little over 19 seconds in, and ends at step 2857, under 48 seconds, the bell rung: the whole game in under a minute.

Three ways to put things in a world

WayMadeGoneIn Hollowmere
A scene tileas its map loads, one on each cell painted with itwhen its cell is emptied or painted overthe torches, the cracked wall
A Spawnerwhile the game plays, at each spawn, where the script sayswhen it takes itself awaythe rocks
A Placeholderonce, at build_placeholder or Instantiate now, under its nodewith the scenethe far rooms

The chapter’s nodes and files

Node or fileParentPositionSettings
rock.artifactSprite rock.png, 12 by 12, Anchor 0.5, 1, Props, Unshaded; CharacterBodyComponent 10 by 10, Driven By Script, Layer rubble; Rock
far-room.tilemapcrypt-stone.png; back z -1, a Rect of #48 and the arch of #58; torches, two #57, whose Scene is torch.artifact
far-room.artifactfar-room, and under it room-tiles, a Tilemap on far-room.tilemap, Ground
rockfallcrypt2560, -176AreaComponent 320 by 176 at 0, 88; Spawner, rock, rock.artifact; Rockfall
far-room-1crypt2944, 0Placeholder far-room.artifact; ScreenNotifierComponent 608 by 192; FarRoom
far-room-2crypt3200, 0a duplicate of far-room-1
bell-bodybell0, -16Sprite bell.png, 32 by 32, Anchor 0.5, 0, Props; Swing
bell-ropebell-body0, 32as chapter 11 made it
bellcrypt3552, -128no Sprite; AreaComponent 24 by 48 at 0, 56; WorldTextComponent, empty, Offset -76, 0, Words, Unshaded, Outline Width 2, Shadow alpha 0.8, Shadow Offset 1, 2; Signal, rung to bell-body; Bell

And the crypt’s map: the shelf, a Line of stone on ledges from cell 156, -3 to 163, -3. The project: rubble against pilgrim unticked. The vale: the four ground shapes’ fills Opaque.

Check it works