TutorialsDijkstra’s Algorithm

2  Paint the Maze

Goal

By the end of this chapter, the land answers your hands. Choose a terrain with its button, its picture or a number key, and paint the map with a click or with Enter. The arrow keys walk the orange ring, and D brings the supplied map back.

The game as it is at the end of this chapter. Click the game to play.

If your game and this chapter part ways, here is the chapter’s finished project. Open it and compare, or start Chapter 3 from it.

Weighted Maze, Chapter 2 finishedMyth project · 1.7 MB

To open it, start Myth Engine, choose File › Open Project... and pick the downloaded file.

Starting with this chapter? It begins where Chapter 1 ends, and Chapter 1’s Goal has that chapter’s finished project.

2.1 The Idea

In Chapter 1 the map lay on the table, and nothing answered. You could click a cell all day. This chapter hands you the brush.

Choose Forest and click the road beside the camp, and pines grow there. Of the four terrain buttons, the tan one is the terrain you’re painting with, the brush. The orange ring marks the selected cell, the one the keyboard paints, and the arrow keys walk it from cell to cell.

Here’s a question worth asking before you build anything. What does painting change? It looks like the cell’s picture, but it isn’t. In Chapter 1, every cell showed the picture its cost called for, and the costs lived in Maze Cells. So painting changes a cost in Maze Cells, and the picture follows. The cell you click never draws anything by itself.

That matters for what’s coming. Each cost you paint is a price. You pay a cell’s cost when you step onto it, and the camp, where you start, costs nothing. In Chapter 3, Dijkstra’s algorithm reads these costs, and nothing else.

The keys are new too. The game never asks whether the Enter key went down. It asks whether Paint was pressed. Paint is a Command, a name for something the player means, and the keys are whatever the player presses for it.

One quiet piece turns up here too: a Function that answers which cell lies next door. The arrow keys need it now, and the search asks it again in Chapter 3.

2.2 The Plan

Here’s how the pieces work together. Read each line from left to right. Most of the names are new again, so skim them now. Come back at the end of the chapter, when every name is a piece you’ve built.

  • A terrain button or its picture is clicked, or 1 to 4 is pressed -> Choose Brush makes that terrain $brush -> every Terrain Button colors itself again.
  • An arrow key is pressed -> Move Selection asks Select Neighbor, which asks Find Grid Neighbor for the next cell -> $selectedCell changes -> Show Selection moves the ring.
  • A cell is clicked -> Paint Map Cell makes it $selectedCell and sends paintRequested -> Change Terrain calls Paint Selected Cell.
  • Enter is pressed -> Change Terrain calls Paint Selected Cell too.
  • Paint Selected Cell writes the brush’s cost into Maze Cells and sends terrainChanged -> every Map Cell shows its picture again.
  • D is pressed -> Restore Defaults puts Maze Cells back, puts the ring on the camp, and sends terrainChanged.

2.3 Set Up

This chapter’s Set up card has no ART block and no GAME SETTINGS block. It brings the game’s controls, one new Global Variable, and a block about what changes.

COMMANDS are the controls, seven of them. Make them all now, in Game Settings, under Input Manager. The Set up card on the Making page shows how each one is made and given its key. Six are Buttons, with one key each. Move Selection is a 2D Axis, with a row for each arrow.

The Input Manager opens on your project’s one Input Context, Default. An Input Context is a set of Commands that the game can switch on and off together. Weighted Maze needs only this one. It’s chosen already, so every Command you add goes into it.

GLOBAL VARIABLES has one new row, $selectedCell, the number of the cell the ring stands on. Add it on Reset Trial’s Globals card, with + and New Global…, as in Chapter 1. A new Global is already a Number at 0. It needs only its name.

Two Actions in this chapter, Set Data Cell and Reset Data Table, stay out of the Action List until Advanced Mode is on. Turn it on now, with Settings > Advanced Mode.

The card’s last block, REMOVED, needs a warning before you reach it. This time, don’t delete what it lists. Show Map Cell, Show Terrain Choice and Show Terrain Picture lose their names, but their work stays. Each takes on a new job in this chapter, and a new name to match, and the part that needs it renames it. Show Terrain Choice Data is renamed too.

A renamed Logic Component stays on its Object, and keeps every value its placements gave it. So the eight terrain placements still hold their terrains, under Per Instance Variables. There’s nothing in the Scene to change.

Set upWhat this chapter adds
COMMANDS (Game Settings > Input Manager)
Choose RoadButton
Keybindings1
Choose ForestButton
Keybindings2
Choose MudButton
Keybindings3
Choose WallButton
Keybindings4
Move Selection2D Axis
LeftLeft Arrow
RightRight Arrow
UpUp Arrow
DownDown Arrow
PaintButton
KeybindingsEnter
Restore DefaultsButton
KeybindingsD
GLOBAL VARIABLES
$selectedCellNumberstarts at 0
REMOVED
Logic Component: Show Map Cell
Logic Component: Show Terrain Choice
Logic Component: Show Terrain Picture
Data Structure: Show Terrain Choice Data

2.4 The Brush

First, the sidebar answers.

Click Forest. Its button turns tan, and Road’s goes pale. Click the picture of mud beside the third button, and Mud turns tan instead. The map doesn’t change at all. Choosing a brush never does.

The brush is $brush, the Global Variable that has said Road since Chapter 1. Three things will set it: the buttons, the pictures beside them, and, in the next part, the number keys. All three call one Function to do it.

2.4.1 Choose Brush

Choose Brush makes one terrain the brush, but only a real one. It’s handed a name, terrain, and before anything else it looks for that name’s row in Terrains, the check Show Terrain Choice makes.

Only then does it set $brush. So a name that isn’t a terrain can never become the brush, and painting always finds a cost. Its Description, like several in this chapter, says the learner where this book says the player. A Function card on the Making page shows how to make it.

FunctionChoose Brush

Makes one terrain the brush, the terrain the learner paints with. terrain must be a row of Terrains (Road, Forest, Mud or Wall); a name Terrains does not list leaves the brush as it is.

PARAMETERS
NameTypeStarts at
terrainTextRoad
ACTIONS
1Check Data Row Exists
Action Name
isKnownTerrain
Table
"Terrains"
Row
terrain
2IfisKnownTerrain.value == true
Then
3Change Variable
Variable
$brush
Value
terrain

2.4.2 Highlight Terrain Choice

This Function colors one Terrain Button: tan, its chosenTint, while the button’s terrain is the brush, and pale, its plainTint, the rest of the time.

You’ve built this before. It’s the If and Else from the end of Show Terrain Choice, moved into a Function so two Events can share it.

One thing is new. The button comes in as a Parameter, button, because a Function has no Object of its own. It’s an Object, Structural, with one Required Component: the Sprite. Both settings are under its row’s Settings arrow, as A Function card on the Making page shows. The two Change Sprite Tint Property Actions name the Object they color. On each block, Applies To is the box after the word on, and it starts at Self. Pick button.

FunctionHighlight Terrain Choice

Colors one Terrain Button: chosenTint while its terrain is the brush, plainTint otherwise.

PARAMETERS
NameTypeStarts at
buttonObjectStructural
Required Components
Slot Namesprite
Component TypeSprite
terrainTextRoad
chosenTintColor#dab674
plainTintColor#ede2cd
ACTIONS
1Ifterrain == $brush
Then
2Change Sprite Tint Property
Applies To
button
Value
chosenTint
3Otherwise
4Change Sprite Tint Property
Applies To
button
Value
plainTint

2.4.3 Choose Terrain

Show Terrain Choice learns to choose, so it gets a new name. Right-click it in the Resources, choose Rename, and type Choose Terrain. It stays on the Terrain Button. Every placement keeps its terrain, under Per Instance Variables.

Its Data Structure follows. Rename Show Terrain Choice Data to Choose Terrain Data the same way. The Data Structures card shows the new name at once. But the Logic still reads it as self.showTerrainChoiceData, the name Myth gave it in Chapter 1. The card says self.chooseTerrainData, the name a new one would get. Both reach the same label field, so leave your boxes as they are.

Open Choose Terrain. The pointed block beside When Created is its Mode, and it still says Show Terrain Choice. The game never reads that name. It’s there for you, so give it the new one: right-click it, choose Rename Mode…, and type Choose Terrain.

The card below shows Choose Terrain as it ends up, with no marks. A new name makes a new card. So here is what changes from your Show Terrain Choice. The Components card gets a second line, self.sprite, because Choose Terrain hands itself to Highlight Terrain Choice as the button. If it doesn’t turn up by itself, press the card’s + and pick Sprite.

Your steps 7 to 10, the If with its Else, go. Right-click that If and choose Delete. Delete takes only the If. What it held stays behind, standing apart: the Else and two Change Sprite Tint Property blocks. Delete each of them the same way.

In their place comes the card’s step 7, a call to Highlight Terrain Choice. It sits at the end of step 2’s line, so right-click step 2’s If and choose Add inside Then. Pick the Function in the window, and join it with Connect to sequence. Its button box already says self. Type the other three as the card has them.

Two Events are new. A click on the button runs UI Activated, and its terrain becomes the brush. And whenever $brush changes, Variable Changed runs on every Terrain Button, and each one colors itself again.

So the click colors nothing by itself. It changes $brush, and every Terrain Button follows the change on its own.

Each Event has a line of its own, from its Mode down to End. Press Add Event and pick UI Activated. Its big block joins the canvas, with a Mode beside it and End below. Nothing is between them yet. Its Mode may say Mode 1. Leave it, or rename it as you did the first.

An Action you add now lands beside that newest Event. So add Choose Brush right away, and Connect to sequence joins it to UI Activated’s line. Then add Variable Changed the same way, with brush picked in its second window, and its call after it.

The card heads the two Events with the names Myth gives them: On Hud Activated, and On Variable Changed · Brush. You never type either one. From Chapter 3, you’ll pick Events from a list by names like these.

Logic ComponentChoose TerrainAttach to: Terrain Button

One terrain the learner can paint with. The button shows the terrain's name and, unless it is a Wall, what entering it costs (from Terrains); activating it makes that terrain the brush, and the button is highlighted while it is. Each Terrain Button placement sets terrain, a row of Terrains (Road, Forest, Mud or Wall). chosenTint and plainTint are the button colors with and without the highlight.

Attach toAny Object
DATA STRUCTURES
Choose Terrain Dataself.chooseTerrainData
COMPONENTS
self.textText / UI
self.spriteSprite
SHARED VARIABLES
NameTypeKindStarting Value
chosenTintColorConstant#dab674
plainTintColorConstant#ede2cd
PER INSTANCE VARIABLES
NameTypeStarting Value
terrainTextRoad
When Created
WhenCreate
1Check Data Row Exists
Action Name
isKnownTerrain
Table
"Terrains"
Row
self.terrain
2IfisKnownTerrain.value == true
Then
3Change Component Value
Component Value
self.chooseTerrainData.label
Value
self.terrain
4Ifdata('Terrains', self.terrain, 'cost') >= 0
Then
5Change Component Value
Component Value
self.chooseTerrainData.label
Value
self.terrain + " " + data('Terrains', self.terrain, 'cost')
6Change Component Value
Component Value
self.text.text
Value
self.chooseTerrainData.label
7Highlight Terrain ChoiceFunction
button
self
terrain
self.terrain
chosenTint
@self.chosenTint
plainTint
@self.plainTint
On Hud Activated
WhenUI Activated
1Choose BrushFunction
terrain
self.terrain
On Variable Changed · Brush
WhenVariable ChangedGlobal Variable: brush
1Highlight Terrain ChoiceFunction
button
self
terrain
self.terrain
chosenTint
@self.chosenTint
plainTint
@self.plainTint
Data StructureChoose Terrain Data

What one Terrain Button keeps: label, the words it shows (the terrain's name, and its cost unless it is a Wall).

labelTextdefault (empty)

The Terrain Button’s card, next, is your first Changes card, and all it shows is the renames you’ve already made. Changes cards on the Making page shows how to read one.

ObjectTerrain ButtonAddDelete
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 216, Y 48
Text / UI
TextTerrain
Font Size17
EmphasisBold
Color#203F43
AlignmentCenter
RenderingVector
Sprite
Z Index Within Object-1
SpritePanel
Transform > SizeX 216, Y 48
Tint (on its placement)#EEE3CC
UI Interaction(as it is added)
Data Structure
From LogicChoose Terrain
Data StructureChoose Terrain Data
From LogicShow Terrain Choice
Data StructureShow Terrain Choice Data
Logic
Choose Terrain
Show Terrain Choice

2.4.4 Choose Terrain By Picture

Show Terrain Picture gets the same treatment. Rename it Choose Terrain By Picture, and its Mode too, and leave its When Created Event as it is.

One Event is new, UI Activated again, on a line of its own. A click on the picture calls Choose Brush with its terrain, as the button does. The buttons don’t need telling, because they follow $brush.

Logic ComponentChoose Terrain By PictureAttach to: Terrain Preview

Shows the Terrain Tiles picture of one terrain beside its button (Terrains frame); activating the picture makes that terrain the brush, as its button does. Each Terrain Preview placement sets terrain, a row of Terrains (Road, Forest, Mud or Wall).

Attach toAny Object
PER INSTANCE VARIABLES
NameTypeStarting Value
terrainTextRoad
When Created
WhenCreate
1Check Data Row Exists
Action Name
isKnownTerrain
Table
"Terrains"
Row
self.terrain
2IfisKnownTerrain.value == true
Then
3Set Frame
Frame
data('Terrains', self.terrain, 'frame')
On Hud Activated
WhenUI Activated
1Choose BrushFunction
terrain
self.terrain

The Terrain Preview’s card shows that rename too, and it’s done already.

ObjectTerrain PreviewAddDelete
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 54, Y 54
Sprite
Z Index Within Object-1
SpriteTerrain Tiles
Transform > SizeX 54, Y 54
UI Interaction(as it is added)
Logic
Choose Terrain By Picture
Show Terrain Picture

Run the game. Try a button, then a picture: the tan moves each time, and the map stays exactly as it was.

2.5 The Number Keys

Now the keyboard chooses too. Press 2, and Forest turns tan, or press 4, and Wall does. Each number is the key of one Command from the Set up: Choose Road on 1, Choose Forest on 2, Choose Mud on 3, Choose Wall on 4.

2.5.1 Choose Terrain By Key

Choose Terrain By Key has four Events, and each makes one call. Each Event is a Command Pressed, set to its Command in a second window. It runs once each time that key goes down. Holding the key doesn’t repeat it. Add the Events one at a time, and give each its call right after you add it, so the call lands by its own Event.

Every call is Choose Brush, with its terrain’s name: Road, Forest, Mud or Wall. The names go in bare, with no quote marks. These boxes take a word as it is, as Values, quote marks and all explains. Once you’ve typed one, the block draws it in quote marks, “Road”. It’s still the bare word you typed.

It never asks which key was pressed. Map Choose Road to another key in the Input Manager, and this Logic works the same.

Make it, and attach it to the Selection. The ring is the keyboard’s home in this game, and the arrow keys come to it next.

Logic ComponentChoose Terrain By KeyAttach to: Selection

Lets the keyboard choose the brush: Choose Road, Choose Forest, Choose Mud and Choose Wall (keys 1, 2, 3 and 4 in the Input Manager) each make their terrain the brush.

Attach toAny Object
When Choose Road Is Pressed
WhenCommand PressedCommand: Choose Road
1Choose BrushFunction
terrain
Road
When Choose Forest Is Pressed
WhenCommand PressedCommand: Choose Forest
1Choose BrushFunction
terrain
Forest
When Choose Mud Is Pressed
WhenCommand PressedCommand: Choose Mud
1Choose BrushFunction
terrain
Mud
When Choose Wall Is Pressed
WhenCommand PressedCommand: Choose Wall
1Choose BrushFunction
terrain
Wall

Run the game, and press 3. Mud turns tan. Press 1, and Road is the brush again, tan at the top of the list.

2.6 The Ring Walks

Next, the orange ring learns to move.

Press the right arrow. The ring steps off the camp onto the road beside it. Press Down, and it drops a row. Hold a key down, and it still takes one step: one press, one step. At the top of the map, Up does nothing, and the ring stays.

Behind the ring is one number. It’s $selectedCell, the cell the ring stands on, and the arrow keys change it. Show Selection moves the ring.

2.6.1 Show Selection

In Chapter 1, Show Selection put the ring on the camp. Now it keeps the ring on $selectedCell, wherever that goes.

When the ring is made, Show Selection sets $selectedCell to the camp and moves the ring there. Its new Event is Variable Changed, with selectedCell picked in its second window. It runs whenever $selectedCell changes, and moves the ring to the new cell. But it doesn’t run as the game starts. Variable Changed compares the Global with what it held a moment before, and at the very start there’s nothing before to compare with. So When Created’s change doesn’t count, and When Created moves the ring itself.

Your Set Position was step 2. On the card it’s step 3, because two new steps come in above it. A new block always joins the end of the line, so the quickest way is to start the line again. Do it before you add the new Event. Take both old steps out with Delete, and add the card’s three in order. Then add Variable Changed, and its two steps after it.

Logic ComponentShow SelectionAttach to: SelectionAddDelete

Keeps the Selection, the ring around the cell the keyboard will paint, on the selected cell (the Project Global selectedCell). The Selection starts on the Camp (Maze Settings startCell).

Attach toAny Object
When Created
WhenCreate
1Cell Screen PositionFunction
Action Name
place
cell
data('Maze Settings', 'rules', 'startCell')
1Change Variable
Variable
$selectedCell
Value
data('Maze Settings', 'rules', 'startCell')
2Cell Screen PositionFunction
Action Name
campPosition
cell
$selectedCell
3Set Position
Position Relative To
Screen
X
campPosition.x
Y
campPosition.y
X
place.x
Y
place.y
On Variable Changed · Selected Cell
WhenVariable ChangedGlobal Variable: selectedCell
1Cell Screen PositionFunction
Action Name
cellPosition
cell
$selectedCell
2Set Position
Position Relative To
Screen
X
cellPosition.x
Y
cellPosition.y

2.6.2 Find Grid Neighbor

Here is the chapter’s one hard idea, and it gets room.

Find Grid Neighbor answers one question: which cell is next to this one, in this direction? You hand it a cell and a direction. It hands back the neighbor.

You might think that’s one sum: to go right, add 1. But cells are numbered the way you read a page, and a page wraps. Put the ring on cell 12, at the left edge of the second row, and press Left. Take 1 off its number, and you land on the far right of the row above, clear across the map. There’s nothing to its left. That’s the edge.

So Find Grid Neighbor never steps along the numbers. First it turns the cell back into a place, a column and a row, with the same sums as Cell Screen Position. Then it takes the step from the direction’s row of Directions. Now the question is plain. Is the column 0 or more and below 12, and the row 0 or more and below 10? If so, it’s a cell. Its number is the row times 12, plus the column. If not, the step went off the map, and the answer is -1, no cell at all.

Count it through. From the camp, cell 0, press Right, and the column goes from 0 to 1. The row stays 0. Both are inside, so the neighbor is 0 times 12, plus 1: cell 1, the road beside the camp. Now press Left on cell 12. Its column is 0, so the step makes it -1, and that’s below 0. The answer is -1. The ring stays where it is.

Find Grid Neighbor reads two tables, one new and one that needs a new column. Both come before its card.

The four directions are rows of a new table, Directions. Each row says how far one step goes across, in columnStep, and down, in rowStep. Up is -1, one row less, because rows count down from the top of the map. Keep the rows in the card’s order. In Chapter 3, the search looks around each cell in that same order: up, right, down, left. Its two columns are the fields of Directions Entry, on the card after it, as in Chapter 1. A Data Table card shows how to make one.

Data TableDirectionsData Structure: Directions Entry
Row 0Up
columnStep0
rowStep-1
Row 1Right
columnStep1
rowStep0
Row 2Down
columnStep0
rowStep1
Row 3Left
columnStep-1
rowStep0
Data StructureDirections Entry

One row of the "Directions" Data Table.

columnStepNumberdefault 0
rowStepNumberdefault 0

Maze Settings needs one more column for the map’s ten rows: rows, a Number with the Default 10. Its columns are the fields of Maze Settings Entry, so open that from the Resources and press Add Field. The new field comes last, after goalCell. The card lists it second, as the finished game has it, but the order doesn’t matter. The Logic finds a column by its name.

Data StructureMaze Settings EntryAddDelete

One row of the "Maze Settings" Data Table.

columnsNumberdefault 12
rowsNumberdefault 10
startCellNumberdefault 0
goalCellNumberdefault 119

A new field fills the rows already there with 0, whatever Value you give it. So open Maze Settings and type 10 into the rules row too.

Data TableMaze SettingsData Structure: Maze Settings EntryAddDelete
Row 0rules
columns12
rows10
startCell0
goalCell119

Now the Function itself. Its first three steps are Declare Variables: column, row and neighbor, which last only while the Function runs. Steps 4 and 5 are Cell Screen Position’s sums. The % sign gives what’s left over after dividing, and floor() drops the fraction. So cell 12 is 12 % 12 = 0 across, and floor(12 / 12) = 1 down.

The If’s condition is four tests joined by &&, so all four must be true. That’s the whole guard against wrapping. It’s one box, typed as the card spells it, as If, Else and Repeat shows.

The answer is neighbor. It starts at -1 every time the Function is called, and Otherwise sets -1 again. Either would do alone. The Otherwise says it where the edge is found, so the If reads as the whole answer: a cell, or -1. The Return, step 13, hands it back. So the Return Type is Number.

FunctionFind Grid Neighbor

The cell next to one cell in one direction (a row of Directions: Up, Right, Down or Left), or -1 when that side of the cell is the edge of the map. Cells count as Cell Screen Position counts them: Cell 00 is the top-left cell, and a row holds Maze Settings columns cells.

PARAMETERS
NameTypeStarts at
cellNumber0
directionTextUp
RETURN TYPENumber
ACTIONS
1Declare Variable
Name
column
Value
0
2Declare Variable
Name
row
Value
0
3Declare Variable
Name
neighbor
Value
-1
4Change Variable
Variable
column
Value
cell % data('Maze Settings', 'rules', 'columns')
5Change Variable
Variable
row
Value
floor(cell / data('Maze Settings', 'rules', 'columns'))
6Change Variable
Variable
column
Operator
+=
Value
data('Directions', direction, 'columnStep')
7Change Variable
Variable
row
Operator
+=
Value
data('Directions', direction, 'rowStep')
8Ifcolumn >= 0 && column < data('Maze Settings', 'rules', 'columns') && row >= 0 && row < data('Maze Settings', 'rules', 'rows')
Then
9Change Variable
Variable
neighbor
Value
row * data('Maze Settings', 'rules', 'columns')
10Change Variable
Variable
neighbor
Operator
+=
Value
column
11Otherwise
12Change Variable
Variable
neighbor
Value
-1
13Return
Value
neighbor

A player only ever sees the ring stop at the edge of the map. In Chapter 3 the search asks this Function too, about every cell it settles.

2.6.3 Select Neighbor

Move Selection, next, has four Events, one for each arrow. Each needs the same two moves: ask Find Grid Neighbor for the cell next door, then go there only if it’s on the map. Select Neighbor makes those two moves for all four. So the edge is checked in one place, and each arrow makes one call, with its direction.

FunctionSelect Neighbor

Moves the selection (the Project Global selectedCell) one cell in one direction, a row of Directions. At the edge of the map the selection stays where it is.

PARAMETERS
NameTypeStarts at
directionTextUp
ACTIONS
1Find Grid NeighborFunction
Action Name
next
cell
$selectedCell
direction
direction
2Ifnext.value >= 0
Then
3Change Variable
Variable
$selectedCell
Value
next.value

2.6.4 Move Selection

Move Selection is four Events, each making one call to Select Neighbor. Each is a 2D Direction Pressed. The Command it waits for shares this Logic’s name, Move Selection, so pick that Command in the Event’s second window. Then press its Direction on the Event’s block: Up, Right, Down or Left. Events: the When bars shows where that is.

Each call passes its direction’s name, bare, like Choose Terrain By Key’s terrains. Give each Event its call right after you add it, as you did there. Attach it to the Selection.

Logic ComponentMove SelectionAttach to: Selection

Lets the arrow keys move the Selection: each direction of the Move Selection Command (the arrow keys in the Input Manager) moves it one cell up, right, down or left. At the edge of the map it stays.

Attach toAny Object
When Move Selection Up Is Pressed
When2D Direction PressedCommand: Move SelectionDirection: Up
1Select NeighborFunction
direction
Up
When Move Selection Right Is Pressed
When2D Direction PressedCommand: Move SelectionDirection: Right
1Select NeighborFunction
direction
Right
When Move Selection Down Is Pressed
When2D Direction PressedCommand: Move SelectionDirection: Down
1Select NeighborFunction
direction
Down
When Move Selection Left Is Pressed
When2D Direction PressedCommand: Move SelectionDirection: Left
1Select NeighborFunction
direction
Left
ObjectSelectionAddDelete
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 64, Y 64
Sprite
Scene Depth Draw Order4
Z Index Within Object4
SpriteCell Outline
Transform > SizeX 64, Y 64
Tint (on its placement)#FF9D36
Logic
Show Selection
Choose Terrain By Key
Move Selection

Run the game and walk the ring right up to the left edge of the map, then press Left once more. It stays.

2.7 Painting

Now the land answers.

Choose Forest, and click the road right next to the camp. Pines grow there. Walk the ring somewhere with the arrows and press Enter, and that cell takes the brush too. Click the camp, and the ring goes there, but the tent stays.

A click on a cell does two things, and neither is painting. The cell makes itself the selected cell. Next it asks Maze Rules to paint. Maze Rules decides, writes the new cost into Maze Cells, and tells every cell. Each one shows the picture its cost calls for, the way it did when the map was laid out.

2.7.1 Paint Selected Cell

Paint Selected Cell is the one place the map’s costs change. First its If asks three questions at once, joined by &&. Is the selected cell not the camp? Not the tower? And is its cost not already the brush’s cost? Only when all three are true does it paint.

Painting is one Action, Set Data Cell, which writes one cell of a table: the cost column, in the selected cell’s row. Its Row box takes a row’s number or its name, and the card gives the name, made by dataRow. That turns the cell’s number into its row’s name: cell 12’s row is Cell 12. The If above it reaches the same row by number, with data(). Either works. Type each the way its card has it.

The Function sends terrainChanged after that, and every cell hears it. When nothing was painted, nothing is sent.

FunctionPaint Selected Cell

Paints the selected cell (the Project Global selectedCell) with the brush: its cost in Maze Cells becomes the brush terrain's cost from Terrains, and terrainChanged tells every cell. The Camp and the Tower are never painted, and a cell that already has that cost is left alone, so nothing is told.

ACTIONS
1If$selectedCell != data('Maze Settings', 'rules', 'startCell') && $selectedCell != data('Maze Settings', 'rules', 'goalCell') && data('Maze Cells', $selectedCell, 'cost') != data('Terrains', $brush, 'cost')
Then
2Set Data Cell
Table
"Maze Cells"
Row
dataRow('Maze Cells', $selectedCell)
Column
"cost"
Value
data('Terrains', $brush, 'cost')
3Trigger Custom Event
Custom Event
terrainChanged

2.7.2 Change Terrain

Change Terrain, on Maze Rules, is where both ways of painting arrive, Enter and a click, and both end in the same call. Attach it to Maze Rules as soon as it’s made, because the click at the end of the next part needs it there.

The message it listens for, paintRequested, is a new Custom Event. Nothing sends it or listens for it yet, so the Add Event window doesn’t list it. Make its Event with Add Custom Event…, as you did for placedOnMap in Chapter 1. Paint Map Cell sends it in a moment.

Logic ComponentChange TerrainAttach to: Maze Rules

Changes the terrain of the selected cell when the learner paints it: with a click or a touch on a cell (paintRequested, sent by the cell), or with the Paint Command (Enter in the Input Manager).

Attach toAny Object
When Paint Is Pressed
WhenCommand PressedCommand: Paint
1Paint Selected CellFunction
On Paint Requested
WhenpaintRequestedCustom Event
1Paint Selected CellFunction

2.7.3 Paint Map Cell

Show Map Cell gets its new name now. Rename it Paint Map Cell, and its Mode, as you did Show Terrain Choice. Its first Event, On Placed on Map, stays as it is, and two Events are new.

Remember the UI Interaction each Map Cell kept in Chapter 1? This is what it was for. A click runs UI Activated: the cell sets $selectedCell to its own number, self.mapPlace.cell, and sends paintRequested. When terrainChanged arrives, the cell asks Cell Picture for its picture again, and shows it.

This time terrainChanged is waiting in the Add Event window, under Custom Events > Project Events, because Paint Selected Cell already sends it.

Every cell hears terrainChanged, and each one looks up its own cost. So only the cell you painted changes. The other 119 show what they showed before.

Logic ComponentPaint Map CellAttach to: Map Cell

One cell of the map the learner can paint. It shows the picture its cost calls for, and draws its picture again whenever the terrain changes. Activating it (a click or a touch) selects it and asks Maze Rules to paint it with the brush. Its cell number is its Map Place cell, which Lay Out Map gives it.

Attach toAny Object
DATA STRUCTURES
Map Placeself.mapPlace
On Placed on Map
WhenplacedOnMapCustom Event
1Cell Screen PositionFunction
Action Name
place
cell
self.mapPlace.cell
2Set Position
Position Relative To
Screen
X
place.x
Y
place.y
3Cell PictureFunction
Action Name
picture
cell
self.mapPlace.cell
4Set Frame
Frame
picture.value
On Hud Activated
WhenUI Activated
1Change Variable
Variable
$selectedCell
Value
self.mapPlace.cell
2Trigger Custom Event
Custom Event
paintRequested
On Terrain Changed
WhenterrainChangedCustom Event
1Cell PictureFunction
Action Name
newPicture
cell
self.mapPlace.cell
2Set Frame
Frame
newPicture.value

The rename made every change on the Map Cell’s card, its Data Structure’s From Logic line included.

ObjectMap CellAddDelete
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 64, Y 64
Sprite
Z Index Within Object-1
SpriteTerrain Tiles
Transform > SizeX 64, Y 64
UI Interaction(as it is added)
Data Structure
From LogicPaint Map Cell
From LogicShow Map Cell
Data StructureMap Place
Logic
Paint Map Cell
Show Map Cell

Run the game and paint. Try the keys too: 3, the arrows, then Enter, and the cell under the ring turns to mud. Click the tower. The ring moves onto it, and the flag stays.

2.8 The Supplied Map Comes Back

Last, a way back.

Paint walls across the road until the map is yours, and then press D. Every cell goes back to the terrain it started with, and the ring goes back to the camp.

2.8.1 Restore Defaults

Restore Defaults, on Maze Rules, listens for the Restore Defaults Command, D. It doesn’t copy 120 costs back one by one. Reset Data Table puts the whole table back the way you wrote it in the editor, every cost from your import. After that, the ring goes back to the camp, and terrainChanged tells every cell to show its picture again.

Painting while the game runs never touches Maze Cells in your editor. The game paints its own copy. Reset Data Table sets that copy back to what you wrote.

Logic ComponentRestore DefaultsAttach to: Maze Rules

Puts the supplied map back when the learner presses the Restore Defaults Command (D in the Input Manager): every cell gets the cost written in Maze Cells in the editor, the Selection goes back to the Camp, and every cell draws its picture again.

Attach toAny Object
When Restore Defaults Is Pressed
WhenCommand PressedCommand: Restore Defaults
1Reset Data Table
Table
"Maze Cells"
2Change Variable
Variable
$selectedCell
Value
data('Maze Settings', 'rules', 'startCell')
3Trigger Custom Event
Custom Event
terrainChanged

The card for Maze Rules lists Change Terrain and Restore Defaults above Reset Trial, as the finished game has them. Yours land below it, and that’s fine. Each row of Attached Logic has a number, the order Maze Rules runs its Logic in. It matters only when two of them wait for the same Event, and none of these three do.

ObjectMaze RulesAddDelete
Logic
Change Terrain
Restore Defaults
Reset Trial

Run the game, paint a few cells, and press D.

Play it!

Watch for each of these.

  • Road is tan at the start, and the ring stands on the camp.
  • Click Forest: its button turns tan, and Road’s goes pale. Click the mud picture: Mud turns tan. The map doesn’t change.
  • Press 1, 2, 3 and 4 in turn, and Road, Forest, Mud and Wall each take the tan.
  • Each press of an arrow key moves the ring one cell. Holding the key moves it once.
  • At the top of the map Up does nothing, and at the left edge Left does nothing.
  • Choose Forest and click the road right next to the camp. Pines grow there.
  • Press Enter, and the cell under the ring takes the brush.
  • Choose Wall and paint a cell: a gray rubble wall stands there.
  • Click the camp or the tower. The ring moves there, and the tent or the flag stays.
  • Press D. Every cell goes back to its first terrain, and the ring goes back to the camp.
  • Cost still shows two dashes, and the Status line still says Paint terrain. The search comes in Chapter 3.
How it works

The buttons, the pictures and the keys all set $brush through Choose Brush, and the buttons color themselves when it changes. The arrow keys move $selectedCell through Find Grid Neighbor, and the ring follows. A click or Enter asks Maze Rules to paint. Paint Selected Cell writes the cost into Maze Cells, and every cell draws itself again.

Underneath is Chapter 1’s idea, one step deeper: nothing on the screen is painted. A number in Maze Cells changes, and the picture follows it. In Chapter 3, the search reads those same numbers. Every cell you step onto costs what you painted, and the camp, where you start, costs nothing.

2.9 If It Didn’t Work

Something may be off the first time, and that’s all right. Run the game, watch what it does, and follow the chain one piece at a time.

Clicking a terrain button does nothing? Find the UI Activated block in Choose Terrain. Its line should hold Choose Brush, with an arrow into it. A block standing apart does nothing, so join it with Connect to sequence. Did Choose Brush land by another Event? Right-click it there and choose Delete. Then right-click UI Activated’s Mode, choose Add unattached Action here, and add it again.

The keys choose, but the buttons never change color? Perhaps Choose Terrain has no Variable Changed Event, or it names another Global. It should say brush. Look at Highlight Terrain Choice’s If too: terrain == $brush, with the $.

All four buttons say Road 1? The placements have lost their terrains, which happens if Show Terrain Choice was deleted instead of renamed. Select each placement and type its terrain into Terrain, under Per Instance Variables, as in Chapter 1: Forest, Mud or Wall. The buttons are right again.

Pressing 1 to 4 does nothing? Look in the Input Manager, where each Choose Command needs its key. Choose Terrain By Key belongs on the Selection.

The ring won’t move at all? Perhaps Maze Settings still holds 0 in its rows column, the map’s height. Add Field put that 0 in the rules row, and a map 0 rows tall has no room for any step, so Find Grid Neighbor answers -1 every time. Type 10.

The ring moves the wrong way? Look at the Direction pressed on each Event’s block in Move Selection, and the name each one passes on.

The ring jumps to the far side of the map at an edge? Look at Find Grid Neighbor’s If. It needs all four tests, joined by &&. With || between them, one true test is enough, and the ring wraps.

A click moves the ring but paints nothing? Follow the chain. Is Change Terrain on Maze Rules? Does it listen for paintRequested, spelled the way Paint Map Cell sends it? Is Paint Selected Cell’s Set Data Cell joined inside its If? And does Paint Map Cell have its terrainChanged Event? Without that Event, the cost in Maze Cells changes, but the picture never follows it.

Each of these is one small fix. Make it, run the game again, and you’re back with the chapter. The catch-up download in the Goal is this chapter’s game, finished, to compare with yours.

Challenge

The controls are yours to choose. Some players would rather keep their hand on the letters. Give Move Selection a second set of keys: I for Up, J for Left, K for Down and L for Right. In the Input Manager, press Add Keybinding under Move Selection. Pick the direction in the new row’s list, click its No Input Assigned button, and press the key. Run the game and walk the ring with your new keys. Move Selection never changed. It listens for the Command, and the Command now has two keys for each way.

You can paint the map now, and the compass still waits at the camp. In Chapter 3, Step wakes the search.