Build a GameCreating Chess

12  Game Menu and Keyboard

Goal

By the end of this chapter, a ••• button opens the Game menu. It lists every Move of the game, the way chess players write it, with How to play and Resign beside them. And the whole game plays from the keyboard: the arrow keys, Enter and Escape. This is the last chapter. When it’s done, the game at the top of the Welcome page is yours.

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, the whole game. Open it and compare.

Chess, Chapter 12 finishedZip of a Myth project · 11.9 MB

To open it, right-click the downloaded file, choose Extract All... and then Extract. Start Myth Engine, choose File › Open Project... and pick the .mythproj file in the new folder. CREDITS.md and the licenses folder beside it come with the game.

12.1 The Idea

Thirty Moves into a long game, you stop. How did it get like this? Where did your Bishop go, and when did the Computer’s Knight slip in on d4? The Board only shows you now. It has forgotten the rest.

Chess players have an old answer to this, and it’s a pencil and a sheet of paper. After every Move, each player writes it down in a few letters: e4, Nf3, exd5, O-O. That way of writing is called standard notation. A letter names the Kind, K, Q, R, B or N, and a Pawn has none. Then comes the Square it lands on. An x marks a Capture, + a Check and # a Checkmate. Castling is O-O on the King’s side and O-O-O on the Queen’s.

This chapter gives your game that pencil. A ••• button opens the Game menu. It lists every Move, twelve full Moves to a page, with How to play and Resign under the list.

Here’s the hard part, and it’s about timing. A Move’s name has to be written down before the Move is made. Once a Pawn has landed on d5, the Board can’t tell you whether something stood there a moment ago. Think of a person keeping score at a tournament. They write the Move as the hand lets go, while they can still see where it came from.

Then the keyboard. Since Chapter 2, every Move has started with a click. This chapter adds keys, and the keys don’t need new rules. An amber outline, the Focus Mark, moves from Square to Square with the arrow keys. Enter presses the Square under it, and the game hears the same message a click sends.

12.2 The Plan

Here’s how the pieces work together. Read each line from left to right.

  • The ••• button is pressed -> Report Game Menu sends gameMenuPressed -> Game Menu opens the Game menu, and sends gameMenuOpened.
  • Move Pages hears gameMenuOpened -> it picks the newest page, and sends movePageChanged -> each Show Recorded Move shows its Move.
  • A Square is clicked -> Select and Move -> Record Move -> Name The Move writes the Move’s name in the Move History -> then Make Move makes it.
  • An arrow key is pressed -> the Command Move Focus -> Keyboard Focus steps the Focus Mark -> Enter is pressed -> squareClicked -> Select and Move, as for a click.

12.3 Set Up

Set upWhat this chapter adds
ART (sprites, from the starter kit)
Focus Outline
Promotion Outline
COMMANDS (Game Settings > Input Manager)
Move Focus2D Axis
LeftLeft Arrow
RightRight Arrow
UpUp Arrow
DownDown Arrow
Focus Row StartButton
KeybindingsHome
Focus Row EndButton
KeybindingsEnd
Press SquareButton
KeybindingsEnter, Space
CancelButton
KeybindingsEscape
Choose Piece2D Axis
LeftLeft Arrow
RightRight Arrow
PromoteButton
KeybindingsEnter, Space
Cancel ChoiceButton
KeybindingsEscape
INPUT CONTEXTS (Game Settings > Input Manager)
DefaultActive at Start(changed)
CommandsMove Focus, Focus Row Start, Focus Row End, Press Square, Cancel
Promotion ChoiceInactive at Start(new)
CommandsChoose Piece, Promote, Cancel Choice
GAME SETTINGS > Display > Page Background (Outside the Game)
Color#F4F1E9
SCENE Chess Table: PLACE THESE
ObjectXY
Game Menu Button39040
with Text / UI > Text = ••• (Edit Object Locally)
Panel Backdrop00hidden
with Z-Index = 29
with UI Interaction > Group = Game Menu (Edit Object Locally)
Game Menu Panel070hidden
Resign Button0-150hidden
with UI Interaction > Group = Game Menu (Edit Object Locally)
with Text / UI > Text = Resign (Edit Object Locally)
Close Game Menu Button160-150hidden
with UI Interaction > Group = Game Menu (Edit Object Locally)
with Text / UI > Text = Done (Edit Object Locally)
Panel Backdrop00hidden
with Z-Index = 29
with UI Interaction > Group = Resign Question (Edit Object Locally)
Resign Question070hidden
Close Resign Question Button-8025hidden
with UI Interaction > Group = Resign Question (Edit Object Locally)
with Text / UI > Text = Cancel (Edit Object Locally)
Confirm Resign Button8025hidden
with UI Interaction > Group = Resign Question (Edit Object Locally)
with Text / UI > Text = Resign (Edit Object Locally)
How To Play Button-160-150hidden
with UI Interaction > Group = Game Menu (Edit Object Locally)
with Text / UI > Text = How to play (Edit Object Locally)
Panel Backdrop00hidden
with Z-Index = 29
with UI Interaction > Group = How To Play (Edit Object Locally)
How To Play Panel070hidden
Panel Paragraph0165hidden
with Z-Index = 32
with Text / UI > Text = Select a piece, then a highlighted square. (Edit Object Locally)
Panel Paragraph080hidden
with Z-Index = 32
with Text / UI > Text = Threats: select either side’s pieces to see attack lines. Red squares mark attacks, rings mark no legal recapture, and amber marks pins to the king. Marks describe the current position; they do not predict every exchange. (Edit Object Locally)
Panel Paragraph0-5hidden
with Z-Index = 32
with Text / UI > Text = Keyboard: arrow keys to navigate, Enter to select, Escape to clear. (Edit Object Locally)
Close How To Play Button0-75hidden
with UI Interaction > Group = How To Play (Edit Object Locally)
with Text / UI > Text = Done (Edit Object Locally)
Move Words-60260hidden
with Z-Index = 32
Move Words90260hidden
with Z-Index = 32
with Text / UI > Text = {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark} (Edit Object Locally)
with Per Instance Variables > Is Black Move = Yes
Move Words-60234hidden
with Z-Index = 32
with Per Instance Variables > Line = 1
Move Words90234hidden
with Z-Index = 32
with Text / UI > Text = {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark} (Edit Object Locally)
with Per Instance Variables > Line = 1
with Per Instance Variables > Is Black Move = Yes
Move Words-60208hidden
with Z-Index = 32
with Per Instance Variables > Line = 2
Move Words90208hidden
with Z-Index = 32
with Text / UI > Text = {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark} (Edit Object Locally)
with Per Instance Variables > Line = 2
with Per Instance Variables > Is Black Move = Yes
Move Words-60182hidden
with Z-Index = 32
with Per Instance Variables > Line = 3
Move Words90182hidden
with Z-Index = 32
with Text / UI > Text = {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark} (Edit Object Locally)
with Per Instance Variables > Line = 3
with Per Instance Variables > Is Black Move = Yes
Move Words-60156hidden
with Z-Index = 32
with Per Instance Variables > Line = 4
Move Words90156hidden
with Z-Index = 32
with Text / UI > Text = {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark} (Edit Object Locally)
with Per Instance Variables > Line = 4
with Per Instance Variables > Is Black Move = Yes
Move Words-60130hidden
with Z-Index = 32
with Per Instance Variables > Line = 5
Move Words90130hidden
with Z-Index = 32
with Text / UI > Text = {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark} (Edit Object Locally)
with Per Instance Variables > Line = 5
with Per Instance Variables > Is Black Move = Yes
Move Words-60104hidden
with Z-Index = 32
with Per Instance Variables > Line = 6
Move Words90104hidden
with Z-Index = 32
with Text / UI > Text = {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark} (Edit Object Locally)
with Per Instance Variables > Line = 6
with Per Instance Variables > Is Black Move = Yes
Move Words-6078hidden
with Z-Index = 32
with Per Instance Variables > Line = 7
Move Words9078hidden
with Z-Index = 32
with Text / UI > Text = {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark} (Edit Object Locally)
with Per Instance Variables > Line = 7
with Per Instance Variables > Is Black Move = Yes
Move Words-6052hidden
with Z-Index = 32
with Per Instance Variables > Line = 8
Move Words9052hidden
with Z-Index = 32
with Text / UI > Text = {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark} (Edit Object Locally)
with Per Instance Variables > Line = 8
with Per Instance Variables > Is Black Move = Yes
Move Words-6026hidden
with Z-Index = 32
with Per Instance Variables > Line = 9
Move Words9026hidden
with Z-Index = 32
with Text / UI > Text = {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark} (Edit Object Locally)
with Per Instance Variables > Line = 9
with Per Instance Variables > Is Black Move = Yes
Move Words-600hidden
with Z-Index = 32
with Per Instance Variables > Line = 10
Move Words900hidden
with Z-Index = 32
with Text / UI > Text = {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark} (Edit Object Locally)
with Per Instance Variables > Line = 10
with Per Instance Variables > Is Black Move = Yes
Move Words-60-26hidden
with Z-Index = 32
with Per Instance Variables > Line = 11
Move Words90-26hidden
with Z-Index = 32
with Text / UI > Text = {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark} (Edit Object Locally)
with Per Instance Variables > Line = 11
with Per Instance Variables > Is Black Move = Yes
No Moves Note0260hidden
with Z-Index = 32
Panel Label-60286hidden
with Z-Index = 32
with UI Interaction > Group = Game Menu (Edit Object Locally)
with Text / UI > Text = White (Edit Object Locally)
with Text / UI > Alignment = Left (Edit Object Locally)
with Text / UI > Text Bounds = Wrap to Width (Edit Object Locally)
with Text / UI > Transform > Size X = 140 (Edit Object Locally)
Panel Label90286hidden
with Z-Index = 32
with UI Interaction > Group = Game Menu (Edit Object Locally)
with Text / UI > Text = Black (Edit Object Locally)
with Text / UI > Alignment = Left (Edit Object Locally)
with Text / UI > Text Bounds = Wrap to Width (Edit Object Locally)
with Text / UI > Transform > Size X = 140 (Edit Object Locally)
Earlier Moves Button-80-82hidden
with UI Interaction > Group = Game Menu (Edit Object Locally)
with Text / UI > Text = Earlier (Edit Object Locally)
Later Moves Button80-82hidden
with UI Interaction > Group = Game Menu (Edit Object Locally)
with Text / UI > Text = Later (Edit Object Locally)
Focus Mark16.87510hidden
with Data Structure > Values > Name = e2
Promotion Focus-19566hidden
with Data Structure > Values > Kind = Queen

ART names two pictures from the Starter Kit, already in your project. The Focus Outline marks a Square. The Promotion Outline goes around a Piece of the Promotion choice.

COMMANDS and INPUT CONTEXTS are the game’s keys. Make them all now, in Game Settings’ Input Manager, the way Keys: Commands and Input Contexts shows. Your Logic will name a Command, never a key. Press Square doesn’t care whether you pressed Enter or Space, and the game never asks.

Go in the card’s order. The first five Commands go in Default, which is selected when the Input Manager opens. Every project has Default already. The card marks it changed only because it gets these Commands, and it stays Active at Start. Then add the Input Context Promotion Choice. It starts Inactive at Start, as the card says, and it’s selected once it’s made. So the last three Commands land in it. Choose Piece is a 2D Axis with only Left and Right, so leave its Up and Down on No Input Assigned.

Why two sets of keys? While the Promotion choice is open, the arrow keys should move between its four Pieces, not across the Board. Only one set is on at a time, and the Logic switches them.

GAME SETTINGS has one line. In Display, Page Background (Outside the Game) takes a Color, #F4F1E9. Myth fits the game to any window, and in a window wider than the game, a band shows beside it. That band is the page background. Now it’s the same paper as the page under the Board.

The placements come later, part by part.

12.4 A Menu for the Game

A game that matters needs a way to stop: first a menu, then a way to give up with grace.

12.4.1 Report Game Menu and Game Menu

Logic ComponentReport Game Menu

What the Game button does: it tells whoever listens (the Game Rules) with "gameMenuPressed".

Attach toAny Object
On Hud Activated
WhenUI Activated
1Trigger Custom Event
Custom Event
gameMenuPressed
Logic ComponentGame MenuAttach to: Game Rules

Opens the Game menu when the Player presses the Game button ("gameMenuPressed"): a menu that holds the game while it is open, so the Board takes no clicks. The menu's buttons close it again (Done) or ask to resign (Resign). Once it is open, it tells its own Object "gameMenuOpened", so the Move List shows the newest page (Move Pages).

Attach toAny Object
On Game Menu Pressed
WhengameMenuPressedCustom Event
1Control Menu
Menu Element
Game Menu Panel
2Set Menu Pause State
Menu Element
Game Menu Panel
3Trigger Custom Event on Object
Custom Event
gameMenuOpened

The ••• button reports, as every button does since Chapter 6. Game Menu opens the menu. Control Menu shows the Game Menu Panel, and Set Menu Pause State holds the game still behind it, as the New Game panel does.

Then it sends gameMenuOpened, to its own Object only. Nothing listens yet. Later in this chapter, in The Move List, something will.

12.4.2 Game Menu Panel

ObjectGame Menu Panel
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 600, Y 560
UI Interaction
Element TypeText
GroupGame Menu
Cancel CommandCancel
Sprite
Scene Depth Draw Order30
SpriteSquare Highlight
Tint#EFE6CF
Transform > SizeX 600, Y 560
Text / UI
TextGame
Font Size26
EmphasisSemibold
Color#503A2B
AlignmentCenter
Transform > PositionX 0, Y 250

The Game Menu Panel is another cream card, 600 pixels wide and 560 high, with Game near its top. One line is new on a panel: Cancel Command, in UI Interaction. It’s a list of your Commands. Pick Cancel. A menu closes itself when its Cancel Command is pressed. So Escape closes the Game menu, with no Logic at all.

12.4.3 Close Game Menu

Logic ComponentClose Game Menu

What the Done button of the Game menu does: it closes the menu, and the game goes on.

Attach toAny Object
On Hud Activated
WhenUI Activated
1Control Menu
Operation
Hide
Menu Element
Game Menu Panel

Done has its own Logic. Close Game Menu answers UI Activated and closes the menu you were reading. Escape gives you the same close for free. If a quick tap leaves the menu open, hold Escape a little longer, or press Done.

12.4.4 Can Resign

FunctionCan Resign

Asks whether the Resign button can be used: while the game is not over (any Game State but Game Over). isOn (returned): true when it can.

RETURN TYPEBoolean
ACTIONS
1Declare Variable
Type
Boolean
Name
isOn
Value
false
2Check Game State
Action Name
isGameOver
Game State
Game Over
3IfisGameOver.value != true
Then
4Change Variable
Variable
isOn
Value
true
5Return
Value
isOn

Can Resign answers one question for Show Button On Or Off: can this button be used? Yes, unless the Game State is Game Over. Its answer, isOn, is declared as false, and the If makes it true. The Return hands back that Boolean.

12.4.5 Ask To Resign and the Resign Question

Logic ComponentAsk To Resign

What the Resign button of the Game menu does: the Game menu closes and the question "Resign?" opens in its place, a menu that holds the game while it is open. After every change on the Board ("positionChanged"), which the Game Rules also send when the game begins, it asks Can Resign whether the button can be used now, and turns it on or off (Show Button On Or Off).

Attach toAny Object
COMPONENTS
self.uiUI Interaction
On Hud Activated
WhenUI Activated
1Control Menu
Operation
Hide
Menu Element
Game Menu Panel
2Control Menu
Menu Element
Resign Question
3Set Menu Pause State
Menu Element
Resign Question
On Position Changed
WhenpositionChangedCustom Event
1Can ResignFunction
Action Name
canUse
2Show Button On Or OffFunction
button
self
isOn
canUse.value
ObjectResign Question
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 420, Y 200
UI Interaction
Element TypeText
GroupResign Question
Cancel CommandCancel
Sprite
Scene Depth Draw Order30
SpriteSquare Highlight
Tint#EFE6CF
Transform > SizeX 420, Y 200
Text / UI
TextResign?
Font Size26
EmphasisSemibold
Color#503A2B
AlignmentCenter
Transform > PositionX 0, Y 60

Nobody should lose a game to a slip of the mouse. So Resign asks first. Ask To Resign hides the Game menu and opens the question Resign? in its place. It holds the game too. Only one menu is ever open, so the two never pile up.

On Position Changed asks Can Resign, then gives canUse.value to Show Button On Or Off. The Resign button keeps its own faded state, as Undo does.

The Resign Question is a smaller cream card, 420 by 200, with its own Cancel Command.

12.4.6 Close Resign Question and Report Resign

Logic ComponentClose Resign Question

What the Cancel button of the question "Resign?" does: it closes the question, and the game goes on.

Attach toAny Object
On Hud Activated
WhenUI Activated
1Control Menu
Operation
Hide
Menu Element
Resign Question
Logic ComponentReport Resign

What the Resign button of the question "Resign?" does: it tells whoever listens (the Game Rules) with "resignConfirmed".

Attach toAny Object
On Hud Activated
WhenUI Activated
1Trigger Custom Event
Custom Event
resignConfirmed

The question has two buttons. Cancel runs Close Resign Question, and the game goes on. Resign runs Report Resign, which sends resignConfirmed.

12.4.7 Words

Data TableWordsData Structure: Words EntryAddDelete
Row 0Your Move
textYour move
Row 1Check
textCheck
Row 2Promotion
textPromotion: choose a Piece
Row 3Win By Checkmate
textYou win · Checkmate
Row 4Loss By Checkmate
textYou lose · Checkmate
Row 5Draw By Stalemate
textDraw · Stalemate
Row 6Draw By Insufficient Material
textDraw · Insufficient material
Row 7Draw By Fifty Move Rule
textDraw · Fifty-move rule
Row 8Draw By Threefold Repetition
textDraw · Threefold repetition
Row 9Thinking
textThinking…
Row 10Disconnected
textOpponent disconnected
Row 11Finding Hint
textFinding a hint…
Row 12Hint Not Found
textA hint could not be found.
Row 13Loss By Resignation
textYou lose · Resignation
Row 14Capture Mark
textx
Row 15Check Mark
text+
Row 16Checkmate Mark
text#

Words gets four new rows, and they all go at the end of the table. The first, Loss By Resignation, is for this part, and the other three are marks for the Move names: x, + and #. Type them all now, though the marks wait for Every Move gets a name, further on.

12.4.8 Resign

Logic ComponentResignAttach to: Game Rules

Ends the game when the Player resigns: when the Player answers "Resign?" with Resign ("resignConfirmed"), the question closes and, if the game is not over yet, the status line shows "You lose · Resignation" (the Words row Loss By Resignation) and the game is over (Game State Game Over), so the Board no longer answers and the final position stays, as at every other end of a game. Then everyone hears "positionChanged", so the buttons show what can be used now. An answer from the Computer still on its way is not used: the Computer's Logic asks whether it is still the Computer's Turn.

Attach toAny Object
On Resign Confirmed
WhenresignConfirmedCustom Event
1Control Menu
Operation
Hide
Menu Element
Resign Question
2Check Game State
Action Name
isGameOver
Game State
Game Over
3IfisGameOver.value != true
Then
4Change Variable
Variable
$status
Value
data('Words', 'Loss By Resignation', 'text')
5Set Game State
Game State
Game Over
6Trigger Custom Event
Custom Event
positionChanged

Resign ends the game when resignConfirmed arrives. First it closes the question, whatever happens next, and then it asks whether the game is already over. You can’t resign a game that has ended.

If it isn’t over, the Status Line takes You lose · Resignation, and the Game State becomes Game Over. The Board stops answering, as at every other end of a game. Last, positionChanged goes out, so every button asks again whether it can be used. That’s how Resign fades.

What if the Computer was still thinking? Its answer arrives to a game that’s over. Make Computer Move asks first whether it’s still the Computer’s Turn, since Chapter 7. So the answer is quietly dropped.

12.4.9 Game Rules

ObjectGame RulesAddDelete
Data Structure
Data StructureBoard State
Data Structure
From LogicSelect and Move
Data StructureSelect and Move Data
Data Structure
From LogicChoose Promotion
Data StructureChoose Promotion Data
Data Structure
From LogicMake Computer Move
Data StructureMake Computer Move Data
Data Structure
From LogicUndo
Data StructureUndo Data
Data Structure
From LogicGive A Hint
Data StructureGive A Hint Data
Data Structure
From LogicDraw Threat Lines
Data StructureDraw Threat Lines Data
Data Structure
From LogicMove Pages
Data StructureMove Pages Data
Logic
Select and Move
Start Turn
Choose Promotion
Look For Game End
Flip Board
New Game
Make Computer Move
Undo
Give A Hint
Show Threats
Draw Threat Lines
Settings
Save The Game
Continue The Game
Game Menu
Resign
Move Pages

Attach Game Menu and Resign now, and leave Move Pages for The Move List.

Make the five variants for this part first. Game Menu Button comes from Tool Button. The other four come from Panel Button, each with its own job Logic.

Object variantGame Menu ButtonVariant of: Tool Button
Logic
Report Game Menu
Object variantClose Game Menu ButtonVariant of: Panel Button
Logic
Close Game Menu
Object variantResign ButtonVariant of: Panel Button
Logic
Ask To Resign
Object variantClose Resign Question ButtonVariant of: Panel Button
Logic
Close Resign Question
Object variantConfirm Resign ButtonVariant of: Panel Button
Logic
Report Resign

Now place the first nine lines under PLACE THESE, on the Set up card, from Game Menu Button down to Confirm Resign Button. That’s the ••• button and the Game menu, with the menu’s Backdrop, Resign and Done. The question follows, with its own Backdrop, Cancel and Resign. All but the ••• button are hidden, placed the way Chapter 6 placed the New Game panel. The ••• button is Game Menu Button. Its words are three dots, •••, so copy them from the card if your keyboard has no key for them.

The Game menu’s Resign Button carries Ask To Resign. Its two calls on positionChanged decide whether it fades, as Report Undo’s do in Chapter 7. Each Panel Backdrop’s Group line puts it in its own panel’s UI Group. Then it opens and dims the game with that panel.

The Objects carry their colors. The button variants keep the tan, #E2D5B4, from their bases. Game Menu Panel and Resign Question keep the cream, #EFE6CF, from their Object cards.

Run the game. Is its window wider than the game? Look beside the Board. The band there is paper now, the same Page Background you set in the Set up. Now press •••.

The game dims, and the cream menu opens. Press Resign. The menu closes, and Resign? asks in its place. Press Cancel, and you’re back in your game. Now resign for real. You lose · Resignation appears under the Board, and the Pieces stay where they stood. Press ••• once more. Resign is faded.

12.5 How to Play

The game teaches itself now, in three short paragraphs.

12.5.1 How To Play Panel and Panel Paragraph

ObjectHow To Play Panel
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 600, Y 380
UI Interaction
Element TypeText
GroupHow To Play
Cancel CommandCancel
Sprite
Scene Depth Draw Order30
SpriteSquare Highlight
Tint#EFE6CF
Transform > SizeX 600, Y 380
Text / UI
TextHow to play
Font Size26
EmphasisSemibold
Color#503A2B
AlignmentCenter
Transform > PositionX 0, Y 150
ObjectPanel Paragraph
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 520, Y 80
UI Interaction
Element TypeText
GroupHow To Play
Text / UI
TextA few words on a panel.
Font Size16
Color#503A2B
Text BoundsWrap to Width
Transform > Size X520

The How To Play Panel is the third cream card of the chapter, 600 by 380. The Panel Paragraph is a block of words that wraps inside its own width, 520 pixels. Its Text Bounds is Wrap to Width, so a long sentence breaks onto a new line instead of running off the panel. Its own words, A few words on a panel., are only a stand-in. Each placement types its own.

12.5.2 Show How To Play and Close How To Play

Logic ComponentShow How To Play

What the How to play button of the Game menu does: the Game menu closes and the How to play panel opens in its place, a menu that holds the game while it is open.

Attach toAny Object
On Hud Activated
WhenUI Activated
1Control Menu
Operation
Hide
Menu Element
Game Menu Panel
2Control Menu
Menu Element
How To Play Panel
3Set Menu Pause State
Menu Element
How To Play Panel
Logic ComponentClose How To Play

What the Done button of the How to play panel does: it closes the panel, and the game goes on.

Attach toAny Object
On Hud Activated
WhenUI Activated
1Control Menu
Operation
Hide
Menu Element
How To Play Panel

Show How To Play works like Ask To Resign. The Game menu hides, and the panel opens in its place. Done runs Close How To Play.

Make two more variants from Panel Button: How To Play Button and Close How To Play Button. Each has its own Logic.

Object variantHow To Play ButtonVariant of: Panel Button
Logic
Show How To Play
Object variantClose How To Play ButtonVariant of: Panel Button
Logic
Close How To Play

Now place the next seven lines, from How To Play Button down to Close How To Play Button. They’re the button in the Game menu, the panel’s Backdrop, the panel, its three paragraphs and its Done. Type each paragraph’s words as the card has them, one placement at a time. The Threats paragraph’s apostrophe is the curly kind. Your keyboard’s straight one works too. It only looks a little different, so copy the words from the card if you’d like them to match. The panel keeps its cream, and the two button variants keep their bases’ tan.

Run the game, press •••, then How to play. Three paragraphs explain selecting, Threats and the keyboard. Press Done.

12.6 Every Move Gets a Name

Now the pencil. This part writes each Move’s name into the Move History. It shows nothing yet. The names wait in the table until the next part draws them.

Take this part slowly. This is the chapter’s hard idea.

12.6.1 Kinds, Castling and Move History

Data StructureKinds EntryAddDelete

One row of the "Kinds" Data Table, which follows it. One row per Kind of Piece, one column per Side. White and Black: the frame of the Piece Set art that shows this Kind for that Side (every Piece Set art keeps the same frame order). The columns are named for the Sides, so the Side of a Piece picks its column. promotionWords: what the Hint message adds when its Move promotes a Pawn to this Kind (empty for the King and the Pawn, which a Pawn never becomes). letter: the letter a Move of this Kind starts with in the Move History (none for a Pawn). promotionMark: what a Move that promotes a Pawn to this Kind ends with (empty for the King and the Pawn).

WhiteNumberdefault 0
BlackNumberdefault 0
promotionWordsTextdefault (empty)
letterTextdefault (empty)
promotionMarkTextdefault (empty)
Data TableKindsData Structure: Kinds EntryAddDelete
Row 0King
White0
Black6
promotionWords
letterK
promotionMark
Row 1Queen
White1
Black7
promotionWords, promote to queen
letterQ
promotionMark=Q
Row 2Rook
White4
Black10
promotionWords, promote to rook
letterR
promotionMark=R
Row 3Bishop
White2
Black8
promotionWords, promote to bishop
letterB
promotionMark=B
Row 4Knight
White3
Black9
promotionWords, promote to knight
letterN
promotionMark=N
Row 5Pawn
White5
Black11
promotionWords
letter
promotionMark
Data StructureCastling EntryAddDelete

One row of the "Castling" Data Table, which follows it. The four castlings, one row per Side and side of the Board. kingFrom and kingTo: where the King starts and lands (it moves two Squares toward the Rook). rookFrom and rookTo: where the Rook starts and lands (on the Square the King crosses). rookPasses: the Square next to the Rook's, which the Rook crosses (on the King's side it is also where the King lands). isAllowed: yes while neither the King nor this Rook has moved and the Rook has not been taken; a new game starts with every castling allowed. notation: how the Move History writes this castling (O-O on the King's side, O-O-O on the Queen's).

kingFromTextdefault (empty)
kingToTextdefault (empty)
rookFromTextdefault (empty)
rookToTextdefault (empty)
rookPassesTextdefault (empty)
isAllowedBooleandefault true
notationTextdefault (empty)
Data TableCastlingData Structure: Castling EntryAddDelete
Row 0White Kingside
kingFrome1
kingTog1
rookFromh1
rookTof1
rookPassesg1
isAllowedYes
notationO-O
Row 1White Queenside
kingFrome1
kingToc1
rookFroma1
rookTod1
rookPassesb1
isAllowedYes
notationO-O-O
Row 2Black Kingside
kingFrome8
kingTog8
rookFromh8
rookTof8
rookPassesg8
isAllowedYes
notationO-O
Row 3Black Queenside
kingFrome8
kingToc8
rookFroma8
rookTod8
rookPassesb8
isAllowedYes
notationO-O-O
Data StructureMove History EntryAddDelete

One row of the "Move History" Data Table, which follows it. Every Move of the game so far, in the order they were made, one row per Move (the first Move is row 0; each row is named by its number). from and to: the Squares the Piece moved from and to (a1 to h8). landingKind: the Kind of the Piece once it had landed: its own Kind, or, for a Promotion, the Kind the Pawn became. The number of rows is the number of Moves made. Undo takes rows off the end and plays the rest again. The table starts empty. The other columns are the Move's name as chess players write it (standard algebraic notation), in the order it is read: letter, the Kind's letter (none for a Pawn), or O-O or O-O-O for castling; fromFile and fromRank, the File and Rank it came from, written only when needed to tell two Pieces apart (and the File of a Pawn that captures); capture, x for a Capture; square, the Square it went to (none for castling); promotion, what a Pawn became (=Q); checkMark, + for Check or # for Checkmate. The Move's number is not kept: rows 0 and 1 are Move 1 (White's and Black's), rows 2 and 3 Move 2, and so on.

fromTextdefault (empty)
toTextdefault (empty)
landingKindTextdefault (empty)
letterTextdefault (empty)
fromFileTextdefault (empty)
fromRankTextdefault (empty)
captureTextdefault (empty)
squareTextdefault (empty)
promotionTextdefault (empty)
checkMarkTextdefault (empty)

First, give each table’s Entry the new fields its card names, before filling the table’s new columns. The table gains those columns with it. Kinds gets each Kind’s letter, and the mark a Pawn gets when it’s promoted to it, such as =Q. A Pawn’s letter stays empty, because a Pawn’s Move is named by its Square alone. Castling gets its two names, O-O and O-O-O.

The Move History gets seven new columns, one for each piece of a name. Read across a row, and you can spell out the Move: letter, fromFile, fromRank, capture, square, promotion, checkMark. Most of them stay empty for most Moves, and Nf3 fills only letter and square.

12.6.2 Find Other Pieces Reaching

Data StructureFind Other Pieces Reaching Result

What Find Other Pieces Reaching returns. isFileNeeded: true when the Move's name must say the File the Piece came from. isRankNeeded: true when it must say the Rank.

isFileNeededBooleandefault false
isRankNeededBooleandefault false
FunctionFind Other Pieces Reaching

Asks, before a Move is made, whether another Piece of the same Kind and Side as the one on from could also make a Legal Move to the Square to, as standard notation needs to know (a Pawn is never asked: its Capture is named by its File). from, to: the Move's Squares. enPassantSquare: the Square a Pawn may take en passant now (Board State). isFileNeeded (returned): true when the name must say the File the Piece came from (another such Piece reaches to from another File, or from the same File and the same Rank). isRankNeeded (returned): true when the name must say the Rank it came from (another such Piece reaches to from the same File). The Targets table is left empty.

PARAMETERS
fromText
toText
enPassantSquareText
RETURN TYPEFind Other Pieces Reaching Result (a Data Structure)
ACTIONS
1Declare Variable
Type
Text
Name
square
2Declare Variable
Type
Boolean
Name
isReached
Value
false
3Declare Variable
Type
Boolean
Name
isSameFile
Value
false
4Declare Variable
Type
Boolean
Name
isSameRank
Value
false
5Declare Variable
Type
Boolean
Name
isFileNeeded
Value
false
6Declare Variable
Type
Boolean
Name
isRankNeeded
Value
false
7RepeatdataCount('Position')times
Each time
8Change Variable
Variable
square
Value
dataRow('Position', local.index)
9Ifdata('Position', square, 'kind') == data('Position', from, 'kind') && data('Position', square, 'side') == data('Position', from, 'side') && square != from && data('Position', from, 'kind') != "Pawn"
Then
10Find Legal MovesFunction
from
square
enPassantSquare
enPassantSquare
11Ifdata('Targets', to, 'reachable') == true
Then
12Change Variable
Variable
isReached
Value
true
13Ifdata('Targets', to, 'reachable') == true && data('Position', square, 'file') == data('Position', from, 'file')
Then
14Change Variable
Variable
isSameFile
Value
true
15Ifdata('Targets', to, 'reachable') == true && data('Position', square, 'rank') == data('Position', from, 'rank')
Then
16Change Variable
Variable
isSameRank
Value
true
17Clear TargetsFunction
18IfisReached == true
Then
19IfisSameFile == true && isSameRank == true
Then
20Change Variable
Variable
isFileNeeded
Value
true
21Change Variable
Variable
isRankNeeded
Value
true
22Otherwise
23IfisSameFile == true
Then
24Change Variable
Variable
isRankNeeded
Value
true
25Otherwise
26Change Variable
Variable
isFileNeeded
Value
true
27Return
isFileNeeded
isFileNeeded
isRankNeeded
isRankNeeded

Here’s a puzzle notation has to solve. Say both of your Knights could reach d2, one from b1 and one from f3. Nd2 doesn’t say which one went. So chess players add the File it came from: Nbd2. If both stood on the same File, they add the Rank instead.

Find Other Pieces Reaching asks that question before the Move is made, while every Piece is still in place. The Repeat walks all sixty-four rows of Position. It looks for another Piece of the same Kind and Side, and never a Pawn, because a Pawn’s Capture always names its File anyway. For each one it finds, Find Legal Moves asks where that Piece could go. If it could reach the same Square, isReached becomes true. Steps 14 and 16 also note whether it shares the File or the Rank.

After the Repeat, Clear Targets tidies up, since Find Legal Moves filled the Targets table. Then the last If decides, once isReached is true. Most of the time the File is enough. If the other Piece shares the File, the Rank is needed instead. With three such Pieces, one may share the File and another the Rank, and then the name needs both. Its Return Type is Find Other Pieces Reaching Result. Two fields come back: isFileNeeded and isRankNeeded.

12.6.3 Name The Move

FunctionName The Move

Writes a Move's name, as chess players write it (standard algebraic notation: e4, Nf3, exd5, O-O, e8=Q, Rad1), into its row of the Move History, before the Move is made: the name depends on the position the Move is made in. The check mark (+ or #) is written when the next Turn starts (Start The Turn, Look For Game End). from, to: the Move's Squares. landingKind: the Kind the Piece lands as. enPassantSquare: the Square a Pawn may take en passant now. row: the Move's row in the Move History.

PARAMETERS
NameTypeStarts at
fromText
toText
landingKindText
enPassantSquareText
rowNumber0
ACTIONS
1Declare Variable
Type
Text
Name
movedKind
2Declare Variable
Type
Text
Name
castling
3Change Variable
Variable
movedKind
Value
data('Position', from, 'kind')
4Set Data Cell
Table
Move History
Row
row
Column
"letter"
Value
data('Kinds', movedKind, 'letter')
5Set Data Cell
Table
Move History
Row
row
Column
"square"
Value
to
6Ifdata('Position', to, 'kind') != ""
Then
7Set Data Cell
Table
Move History
Row
row
Column
"capture"
Value
data('Words', 'Capture Mark', 'text')
8IfmovedKind == "Pawn" && data('Position', from, 'file') != data('Position', to, 'file')
Then
9Set Data Cell
Table
Move History
Row
row
Column
"capture"
Value
data('Words', 'Capture Mark', 'text')
10Set Data Cell
Table
Move History
Row
row
Column
"fromFile"
Value
data('Position', from, 'fileLetter')
11IflandingKind != movedKind
Then
12Set Data Cell
Table
Move History
Row
row
Column
"promotion"
Value
data('Kinds', landingKind, 'promotionMark')
13RepeatdataCount('Castling')times
Each time
14Change Variable
Variable
castling
Value
dataRow('Castling', local.index)
15IfmovedKind == "King" && data('Castling', castling, 'kingFrom') == from && data('Castling', castling, 'kingTo') == to
Then
16Set Data Cell
Table
Move History
Row
row
Column
"letter"
Value
data('Castling', castling, 'notation')
17Set Data Cell
Table
Move History
Row
row
Column
"square"
Value
''
18Find Other Pieces ReachingFunction
Action Name
others
from
from
to
to
enPassantSquare
enPassantSquare
19Ifothers.isFileNeeded == true
Then
20Set Data Cell
Table
Move History
Row
row
Column
"fromFile"
Value
data('Position', from, 'fileLetter')
21Ifothers.isRankNeeded == true
Then
22Set Data Cell
Table
Move History
Row
row
Column
"fromRank"
Value
data('Position', from, 'rank')

Name The Move writes a name into one row of the Move History. Everything it reads is the Board before the Move.

It starts with the plain case: the Kind’s letter, then the Square it lands on. Then it looks for each extra mark. Something stands on to? That’s a Capture, and the capture column takes x. A Pawn that changes File is capturing too, even en passant, where its Square is empty. So it gets x, and its own File letter, as in exd5. A promoted Pawn gets its mark.

Castling is a King’s Move, so the Repeat over Castling checks each row. When the King goes from kingFrom to kingTo, its name becomes that row’s notation, and the square goes empty. Last, Find Other Pieces Reaching says whether the name needs a File or a Rank.

What about Check? That can’t be known yet. Whether a King is in Check depends on the Board after the Move. So the + waits, and Start The Turn writes it, further down.

12.6.4 Record Move

FunctionRecord Move

Writes a Move at the end of the Move History table just before it is made: the Squares it goes from and to, the Kind the Piece lands as (its own Kind, or the Kind a promoted Pawn becomes), and its name as chess players write it (Name The Move), which depends on the position before the Move. Each Logic that makes a Move calls it just before Make Move (Select and Move, Choose Promotion, Make Computer Move). gameRules: the Game Rules Object, whose Board State holds the en passant Square. from, to: the Move's Squares. landingKind: the Kind the Piece lands as.

PARAMETERS
NameTypeStarts at
gameRulesObjectStructural
Required Components
Slot NameboardState
Component TypeData Structure
Required SchemaBoard State
fromText
toText
landingKindText
ACTIONS
1Declare Variable
Name
lastRow
Value
0
2Control Data Row
Action Name
addedRow
Table
Move History
Row
dataCount('Move History')
3Change Variable
Variable
lastRow
Value
dataCount('Move History') - 1
4Set Data Cell
Table
Move History
Row
lastRow
Column
'from'
Value
from
5Set Data Cell
Table
Move History
Row
lastRow
Column
'to'
Value
to
6Set Data Cell
Table
Move History
Row
lastRow
Column
'landingKind'
Value
landingKind
7Name The MoveFunction
from
from
to
to
landingKind
landingKind
enPassantSquare
gameRules.boardState.enPassantSquare
row
lastRow

Record Move used to write the Move after it was made, reading lastFrom and lastTo. Now it’s called before, so it can’t read them. They aren’t set yet. It takes the Move as three Parameters instead: from, to and landingKind.

Delete the Declares for fromSquare and toSquare, and the two Changes that read lastFrom and lastTo. Keep lastRow. Add the three Parameters on the Start block. The full card shows the shorter line.

The Values of steps 4 to 6 now read from, to and landingKind. Each one names a Parameter, so type it bare over the old Value, as Look At Square did in Chapter 3. Step 7 is new. It hands the Move to Name The Move, with the new row.

12.6.5 Start Turn

Logic ComponentStart TurnAttach to: Game RulesAddDelete

Starts each Turn: the first one (White's) when the game begins, and the next one after every Move, giving the Turn to the other Side (Pass The Turn). Each Turn starts with Start The Turn: it asks whether the Side to move is in Check, then tells the Game Rules that the Turn has started ("turnStarted").

Attach toAny Object
DATA STRUCTURES
Board Stateself.boardState
When Created
WhenCreate
1Start The TurnFunction
gameRules
self
2Trigger Custom Event
Custom Event
positionChanged
On Move Made
WhenmoveMadeCustom Event
1Record MoveFunction
gameRules
self
1Pass The TurnFunction
gameRules
self
2Change Component Value
Component Value
self.boardState.selected
Value
''
3Change Component Value
Component Value
self.boardState.inspected
Value
''
4Clear TargetsFunction
5Start The TurnFunction
gameRules
self

Start Turn used to call Record Move after each Move. Delete that call, step 1 of On Move Made, because the Move makers do it now, before they move.

12.6.6 The Three Move Makers

Logic ComponentSelect and MoveAttach to: Game RulesAddDelete

Decides what a click on a Square means. A click on a Square the selected Piece may move to writes it down (Record Move) and makes it (Make Move: castling and en passant included) and tells the Game Rules "moveMade" (Start Turn then starts the other Side's Turn); when the Move takes a Pawn to its last Rank, it opens the Promotion choice instead (Game State Promotion), and Choose Promotion makes the Move. A click on a Piece of the Side to move selects it and marks its Legal Moves (Find Legal Moves); any other click clears the selection. In Threats mode a click that is not a Move also inspects the Piece clicked, of either Side (Inspect Piece). Then it tells everyone "positionChanged". Its Other is the clicked Square. Every click forgets the Hint (Forget The Hint). Escape (the Command Cancel) clears the selection and the Inspected Piece while the game is being played.

Attach toAny Object
DATA STRUCTURES
Board Stateself.boardState
Select and Move Dataself.selectAndMoveData
On Square Clicked
WhensquareClickedCustom Event
1Declare Variable
Type
Text
Name
selectedSquare
2Declare Variable
Type
Text
Name
clickedSquare
3Forget The HintFunction
4Change Variable
Variable
clickedSquare
Value
other.squareInfo.name
5Change Variable
Variable
selectedSquare
Value
self.boardState.selected
6IfselectedSquare != "" && data('Targets', clickedSquare, 'reachable') == true
Then
7Change Component Value
Component Value
self.selectAndMoveData.side
Value
self.boardState.sideToMove
8Ifdata('Position', selectedSquare, 'kind') == "Pawn" && data('Position', clickedSquare, 'rank') == data('Sides', self.selectAndMoveData.side, 'promotionRank')
Then
9Open Promotion ChoiceFunction
gameRules
self
square
clickedSquare
10Otherwise
11Record MoveFunction
gameRules
self
from
selectedSquare
to
clickedSquare
landingKind
data('Position', selectedSquare, 'kind')
12Make MoveFunction
gameRules
self
from
selectedSquare
to
clickedSquare
13Trigger Custom Event on Object
Custom Event
moveMade
14Otherwise
15Ifdata('Position', clickedSquare, 'side') == self.boardState.sideToMove && clickedSquare != selectedSquare
Then
16Change Component Value
Component Value
self.boardState.selected
Value
clickedSquare
17Find Legal MovesFunction
from
clickedSquare
enPassantSquare
self.boardState.enPassantSquare
18Otherwise
19Change Component Value
Component Value
self.boardState.selected
Value
''
20Clear TargetsFunction
21Inspect PieceFunction
gameRules
self
square
clickedSquare
22Trigger Custom Event
Custom Event
positionChanged
When Cancel Is Pressed
WhenCommand PressedCommand: Cancel
1Check Game State
Action Name
isPlaying
Game State
Playing
2IfisPlaying.value == true
Then
3Change Component Value
Component Value
self.boardState.selected
Value
''
4Clear TargetsFunction
5Change Component Value
Component Value
self.boardState.inspected
Value
''
6Trigger Custom Event
Custom Event
positionChanged
Logic ComponentChoose PromotionAttach to: Game RulesAddDelete

Closes the Promotion choice when the Player presses one of its buttons ("promotionChosen"; the button is its Other): the panel is hidden and the game is played again (Game State Playing). A Kind then writes down the waiting Pawn Move (Record Move) and makes it (Make Move), puts the chosen Kind on the Square, and tells the Game Rules "moveMade"; Cancel makes no Move, and the Pawn stays selected. Then everyone hears "positionChanged".

Attach toAny Object
DATA STRUCTURES
Board Stateself.boardState
Choose Promotion Dataself.choosePromotionData
On Promotion Chosen
WhenpromotionChosenCustom Event
1Check Game State
Action Name
isChoosing
Game State
Promotion
2IfisChoosing.value == true
Then
3Change Component Value
Component Value
self.choosePromotionData.chosenKind
Value
other.promotionChoice.kind
4Change Component Value
Component Value
self.choosePromotionData.landingSquare
Value
self.boardState.promotionSquare
5Change Component Value
Component Value
self.boardState.promotionSquare
Value
''
6Set UI Group Visibility
UI Group
"Promotion"
Visible
No
7Set Game State
Game State
Playing
8Ifself.choosePromotionData.chosenKind != ""
Then
9Record MoveFunction
gameRules
self
from
self.boardState.selected
to
self.choosePromotionData.landingSquare
landingKind
self.choosePromotionData.chosenKind
10Make MoveFunction
gameRules
self
from
self.boardState.selected
to
self.choosePromotionData.landingSquare
11Set Data Cell
Table
Position
Row
self.choosePromotionData.landingSquare
Column
"kind"
Value
self.choosePromotionData.chosenKind
12Trigger Custom Event on Object
Custom Event
moveMade
13Otherwise
14Look For CheckFunction
gameRules
self
15Trigger Custom Event
Custom Event
positionChanged
Logic ComponentMake Computer MoveAttach to: Game RulesAddDelete

Plays the Computer's Turns. When a Turn goes on ("gameContinues", from Look For Game End) and the Side to move is the Player's opponent (the Sides table), it asks the Computer for a Move (Ask The Computer: the Board waits in Computer's Turn while the Stockfish Bridge asks Stockfish at the Strength in Board State). When Stockfish answers ("computerMoveChosen"; the Move is in the Chosen Moves table) and it is still the Computer's Turn and the Move is a Legal Move, the Move slides first (Plan The Slide fills the Slides table; everyone hears "slideStarted"). When it has landed ("pieceLanded", from the Moving Piece), it is made if it is still the Computer's Turn, the way the Player's Moves are made: Record Move, Make Move, the Kind it lands as (a promoted Pawn becomes the Kind Stockfish named), then "moveMade" (Start Turn starts the Player's Turn) and "positionChanged". When Stockfish gives no Move, or one that is not legal, or does not answer within its thinking time and spareSeconds more (the answerWait timer), the position stays and the Computer is marked unavailable (Mark Computer Unavailable) until the Player presses Retry ("retryPressed"), which asks again. spareSeconds: how much longer than its thinking time the Computer may take to answer, starting Stockfish included. A Player whose device asks for less motion (the system setting "reduce motion", the Myth Global prefersReducedMotion) sees the Move made at once, with no slide.

Attach toAny Object
DATA STRUCTURES
Board Stateself.boardState
Make Computer Move Dataself.makeComputerMoveData
SHARED VARIABLES
NameTypeKindStarting Value
spareSecondsNumberConstant20
On Game Continues
WhengameContinuesCustom Event
1Ifself.boardState.sideToMove == data('Sides', self.boardState.playerSide, 'opponent')
Then
2Ask The ComputerFunction
gameRules
self
spareSeconds
@self.spareSeconds
On Computer Move Chosen
WhencomputerMoveChosenCustom Event
1Check Game State
Action Name
isThinking
Game State
Computer's Turn
2IfisThinking.value == true
Then
3Stop Recurring Timer
Timer Name
"answerWait"
4Change Component Value
Component Value
self.makeComputerMoveData.fromSquare
Value
data('Chosen Moves', 'Computer', 'from')
5Change Component Value
Component Value
self.makeComputerMoveData.toSquare
Value
data('Chosen Moves', 'Computer', 'to')
6Find Legal MovesFunction
from
self.makeComputerMoveData.fromSquare
enPassantSquare
self.boardState.enPassantSquare
7Ifdata('Targets', self.makeComputerMoveData.toSquare, 'reachable') == true
Then
8If$prefersReducedMotion == 1
Then
9Trigger Custom Event on Object
Custom Event
pieceLanded
10Otherwise
11Plan The SlideFunction
from
self.makeComputerMoveData.fromSquare
to
self.makeComputerMoveData.toSquare
12Trigger Custom Event
Custom Event
slideStarted
13Otherwise
14Clear TargetsFunction
15Mark Computer UnavailableFunction
gameRules
self
On Piece Landed
WhenpieceLandedCustom Event
1Check Game State
Action Name
isLanding
Game State
Computer's Turn
2IfisLanding.value == true
Then
3Change Component Value
Component Value
self.makeComputerMoveData.fromSquare
Value
data('Chosen Moves', 'Computer', 'from')
4Change Component Value
Component Value
self.makeComputerMoveData.toSquare
Value
data('Chosen Moves', 'Computer', 'to')
5Change Component Value
Component Value
self.makeComputerMoveData.landingKind
Value
data('Chosen Moves', 'Computer', 'landingKind')
6Set Game State
Game State
Playing
7Record MoveFunction
gameRules
self
from
self.makeComputerMoveData.fromSquare
to
self.makeComputerMoveData.toSquare
landingKind
self.makeComputerMoveData.landingKind
8Make MoveFunction
gameRules
self
from
self.makeComputerMoveData.fromSquare
to
self.makeComputerMoveData.toSquare
9Set Data Cell
Table
Position
Row
self.makeComputerMoveData.toSquare
Column
"kind"
Value
self.makeComputerMoveData.landingKind
10Trigger Custom Event on Object
Custom Event
moveMade
11Trigger Custom Event
Custom Event
positionChanged
On the Answer Wait Timer
WhenRecurring TimerTimer name: answerWait
1Check Game State
Action Name
isStillThinking
Game State
Computer's Turn
2IfisStillThinking.value == true
Then
3Mark Computer UnavailableFunction
gameRules
self
On Retry Pressed
WhenretryPressedCustom Event
1Check Game State
Action Name
isUnavailable
Game State
Computer Unavailable
2IfisUnavailable.value == true
Then
3Ask The ComputerFunction
gameRules
self
spareSeconds
@self.spareSeconds

Three pieces of Logic make Moves: Select and Move for yours, Choose Promotion for a Pawn you promote, and Make Computer Move for the Computer’s. Each one gets the same new step, a call to Record Move, right before Make Move. Each of these cards opens with a long Description. Nothing reads a Description, so read past it to the green lines, here and on every Changes card of this chapter.

Each call joins before Make Move, with the round handles, as Actions, one at a time shows. Add it inside the same panel first. Choose Promotion uses step 8’s If. Its Add Inside Then adds Record Move there, ready to join before the old Make Move. Join it to that If’s True handle, before Make Move.

Select and Move’s call goes in step 10’s Else, on the False side of its inner If. Its Add Inside Else adds Record Move in that panel. Join it there first. Make Move stays behind it, followed by the Trigger. In Make Computer Move, add the call inside On Piece Landed’s step 2, and join it after Set Game State.

Each call hands over the Kind the Piece lands as. For Select and Move, that’s the selected Piece’s own Kind, read from Position. For Choose Promotion, it’s chosenKind. For the Computer, it’s landingKind, from the Chosen Moves table.

Select and Move also gets a second Event, When Cancel Is Pressed: a Command Pressed Event for the Command Cancel, which is Escape. While the game is being played, Escape clears the selection and the Inspected Piece. Build it now, while you’re here. It needs no other part.

12.6.7 Start The Turn

FunctionStart The TurnAddDelete

Starts the Turn of the Side to move, in the position on the Board: marks a King in Check and sets the status line (Look For Check), marks the Move that gave Check with + in the Move History, then tells the Game Rules "turnStarted" (Look For Game End asks whether the game is over; if it goes on, Make Computer Move asks whether it is the Computer's Turn). gameRules: the Game Rules Object.

PARAMETERS
NameTypeStarts at
gameRulesObjectStructural
Required Components
Slot NameboardState
Component TypeData Structure
Required SchemaBoard State
ACTIONS
1Look For CheckFunction
gameRules
gameRules
2IfgameRules.boardState.checkSquare != "" && dataCount('Move History') > 0
Then
3Set Data Cell
Table
Move History
Row
dataCount('Move History') - 1
Column
"checkMark"
Value
data('Words', 'Check Mark', 'text')
4Trigger Custom Event on Object
Applies to
gameRules
Custom Event
turnStarted

Now the +. Start The Turn begins every Turn by asking Look For Check whether the Side to move is in Check. If its checkSquare isn’t empty, the last Move gave Check. Step 3 writes the Words’ Check Mark into that Move’s row.

Mind the two names. Start The Turn is this Function. Start Turn, two pieces up, is the Logic Component that calls it.

12.6.8 Look For Game End

Logic ComponentLook For Game EndAttach to: Game RulesAddDelete

Ends the game at the start of every Turn (Start Turn sends "turnStarted") when the Side to move has no Legal Move (Is Out Of Moves), when neither Side can give Checkmate (Is Material Insufficient), when the same position has come timesSeenForDraw times (Record Position, Is Position Repeated), or when fiftyMoveCountForDraw Moves in a row have had no Capture and no Pawn Move (the fifty-move rule; Make Move counts them). The status line shows the result (Show Result), a Checkmate is marked # in the Move History, and the game is over (Game State Game Over), so the Board no longer answers and the final position stays. Otherwise it tells the Game Rules "gameContinues", and the Turn goes on. timesSeenForDraw: 3, threefold repetition. fiftyMoveCountForDraw: 100, fifty Moves by each Side.

Attach toAny Object
DATA STRUCTURES
Board Stateself.boardState
SHARED VARIABLES
NameTypeKindStarting Value
timesSeenForDrawNumberConstant3
fiftyMoveCountForDrawNumberConstant100
On Turn Started
WhenturnStartedCustom Event
1Is Out Of MovesFunction
Action Name
outOfMoves
gameRules
self
2Is Material InsufficientFunction
Action Name
material
3Record PositionFunction
gameRules
self
4Is Position RepeatedFunction
Action Name
repetition
timesForDraw
@self.timesSeenForDraw
5IfoutOfMoves.value == true || material.value == true || repetition.value == true || self.boardState.fiftyMoveCount >= @self.fiftyMoveCountForDraw
Then
6Show ResultFunction
gameRules
self
isOutOfMoves
outOfMoves.value
isMaterialInsufficient
material.value
isRepeated
repetition.value
7IfoutOfMoves.value == true && self.boardState.checkSquare != "" && dataCount('Move History') > 0
Then
8Set Data Cell
Table
Move History
Row
dataCount('Move History') - 1
Column
"checkMark"
Value
data('Words', 'Checkmate Mark', 'text')
9Set Game State
Game State
Game Over
10Otherwise
11Trigger Custom Event on Object
Custom Event
gameContinues

And the #. A Checkmate is a Check with no way out. Look For Game End already knows both halves. If the Side to move has no Legal Move and its King is in Check, the new step 8 writes the Checkmate Mark over the +.

Run the game, and play a few Moves. It plays exactly as before. That’s right. The names are in the Move History, out of sight, and the next part brings them out. If one comes out wrong there, Name The Move is the place to look.

12.7 The Move List

Now the menu shows the game, twelve full Moves at a time.

12.7.1 Board State and Move Notation

Data StructureBoard StateAddDelete

What the Game Rules remember about the game besides the Position table. sideToMove: the Side whose Turn it is (White moves first). selected: the Square of the selected Piece (empty when none is selected). lastFrom and lastTo: the two Squares of the last Move (empty before the first Move). checkSquare: the Square of the King in Check (empty when the Side to move is not in Check). enPassantSquare: the Square a Pawn has just passed over with a two-Square Move, where an enemy Pawn may take it en passant on the very next Move (empty otherwise). promotionSquare: while the Promotion choice is open, the Square the selected Pawn will be promoted on (empty otherwise). playerSide: the Side the Player plays (White unless chosen otherwise), so the end of the game can say who won. fiftyMoveCount: the Moves made since the last Capture or Pawn Move, both Sides counted, for the fifty-move rule. isFlipped: whether the Board is drawn turned over, Black at the bottom (false: White at the bottom, a1 at the bottom-left). strength: the Strength the Computer plays at (Gentle, Casual, Club, Strong, or Expert; Casual unless chosen otherwise). chosenSide: while the New Game panel is open, the Side it shows as chosen. chosenStrength: while the New Game or the Settings panel is open, the Strength it shows as chosen. isShowingThreats: whether Threats mode is on (the Threats button; kept on this device). inspected: in Threats mode, the Square of the Piece the Player last clicked to look at it, of either Side (empty when none is inspected). boardFinish: the Board Finish shown, a row of the Board Finishes table (Walnut unless chosen otherwise). pieceSet: the Piece Set shown, a row of the Piece Sets table (Carved walnut unless chosen otherwise). firstShownMove: the first full Move the Game menu's Move List shows, counted from 0 (0 is Move 1); set when the menu opens and by Earlier and Later (Move Pages). movesPerPage: how many full Moves one page of the Move List shows (12: the list has 12 lines).

sideToMoveTextdefault White
selectedTextdefault (empty)
lastFromTextdefault (empty)
lastToTextdefault (empty)
checkSquareTextdefault (empty)
enPassantSquareTextdefault (empty)
promotionSquareTextdefault (empty)
playerSideTextdefault White
fiftyMoveCountNumberdefault 0
isFlippedBooleandefault false
strengthTextdefault Casual
chosenSideTextdefault (empty)
chosenStrengthTextdefault (empty)
isShowingThreatsBooleandefault false
inspectedTextdefault (empty)
boardFinishTextdefault Walnut
pieceSetTextdefault Carved walnut
firstShownMoveNumberdefault 0
movesPerPageNumberdefault 12
Data StructureMove Notation

The words of one Move in the Game menu's Move List, as chess players write it. number: the full Move it belongs to (1 is the first). The other fields are the Move History's columns of the same names: letter (the Kind's letter, or O-O and O-O-O), fromFile and fromRank (only when needed), capture (x), square, promotion (=Q), checkMark (+ or #).

numberNumberdefault 1
letterTextdefault (empty)
fromFileTextdefault (empty)
fromRankTextdefault (empty)
captureTextdefault (empty)
squareTextdefault (empty)
promotionTextdefault (empty)
checkMarkTextdefault (empty)

Board State’s card opens with a long Description again, so read past it to the green lines. Board State gets two fields at the end. The first, firstShownMove, is the first full Move the page shows, counted from 0, so 0 is Move 1. The second, movesPerPage, is 12, one for each line of the list.

Move Notation holds the words of one Move: its number, and the Move History’s seven columns of the same names.

12.7.2 Move Words

ObjectMove Words
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 140, Y 26
UI Interaction
Element TypeText
GroupGame Menu
Text / UI
Text{number}. {letter}{fromFile}{fromRank}{capture}{square}{promotion}{checkMark}
Font Size18
EmphasisMedium
Color#503A2B
Text BoundsWrap to Width
Transform > Size X140
Data Structure
Data StructureMove Notation
Logic
Show Recorded Move

Move Words writes one Move. Its Text is a template, like the Hint Message’s in Chapter 8, and each {name} shows a field of its own Move Notation. For the game’s first Move, 1. e4, the number is 1, the letter is empty, and the square is e4. Its Text Bounds is Wrap to Width, 140 pixels. With it, the words start at the left edge of their box, like a column in a table.

12.7.3 Show Recorded Move

Logic ComponentShow Recorded MoveAttach to: Move Words

Shows one Move of the game in the Game menu's Move List, as chess players write it, read from its row of the Move History into this Object's own Move Notation, which its words show. Each line of the list is two placements, White's Move and Black's. When the page changes ("movePageChanged", from the Game Rules), the Move shown is the line's full Move on that page; a line past the newest Move shows nothing. line: the line of the list, 0 (top) to 11. isBlackMove: true for the placement that shows Black's Move of the line (false: White's, with the move number).

Attach toAny Object
DATA STRUCTURES
Move Notationself.moveNotation
COMPONENTS
self.uiUI Interaction
PER INSTANCE VARIABLES
NameTypeStarting Value
lineNumber0
isBlackMoveBooleanNo
On Move Page Changed
WhenmovePageChangedCustom Event
1Declare Variable
Name
row
Value
0
2Change Variable
Variable
row
Value
(other.boardState.firstShownMove + self.line) * 2
3Ifself.isBlackMove == true
Then
4Change Variable
Variable
row
Operator
+=
Value
1
5Ifrow < dataCount('Move History')
Then
6Change Component Value
Component Value
self.moveNotation.number
Value
objectComponentProperty("otherObject","boardState","firstShownMove") + instanceVar("self","line") + 1
7Change Component Value
Component Value
self.moveNotation.letter
Value
data('Move History', row, 'letter')
8Change Component Value
Component Value
self.moveNotation.fromFile
Value
data('Move History', row, 'fromFile')
9Change Component Value
Component Value
self.moveNotation.fromRank
Value
data('Move History', row, 'fromRank')
10Change Component Value
Component Value
self.moveNotation.capture
Value
data('Move History', row, 'capture')
11Change Component Value
Component Value
self.moveNotation.square
Value
data('Move History', row, 'square')
12Change Component Value
Component Value
self.moveNotation.promotion
Value
data('Move History', row, 'promotion')
13Change Component Value
Component Value
self.moveNotation.checkMark
Value
data('Move History', row, 'checkMark')
14Set UI Element Visibility
15Otherwise
16Set UI Element Visibility
Visible
No

Show Recorded Move fills one Move Words from the Move History. Each line of the list is two placements, White’s Move and Black’s. White moves first, so rows 0 and 1 are Move 1, rows 2 and 3 are Move 2, and so on.

So step 2 takes the page’s first Move and adds the line. Doubled, that’s White’s row. Step 4 adds one for Black. If that row exists, steps 6 to 13 copy it in, and the words show. A line past the newest Move hides.

Step 6 reads firstShownMove too, written the long way: objectComponentProperty("otherObject","boardState","firstShownMove") is other.boardState.firstShownMove. It’s only a longer spelling, so no rule was missed, and you can type it as the card shows it.

Steps 14 and 16 show and hide the words. The first Set UI Element Visibility keeps its starting Visible, on. The other takes No, as the card shows. The note uses them too.

Add Move Notation to its Data Structures, and UI Interaction to its Components. The Game Rules are its Other. They send movePageChanged and keep the page in Board State, ready for every line to read. Two Per Instance Variables tell the placements apart: line, 0 at the top to 11, and isBlackMove.

12.7.4 No Moves Note and Show No Moves Note

ObjectNo Moves Note
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 300, Y 26
UI Interaction
Element TypeText
GroupGame Menu
Text / UI
TextNo moves yet.
Font Size18
Font StyleItalic
Color#503A2B
AlignmentCenter
Logic
Show No Moves Note
Logic ComponentShow No Moves NoteAttach to: No Moves Note

Shows "No moves yet." in the Game menu's Move List while no Move has been made, and hides it once there is one, each time the page is drawn ("movePageChanged", from the Game Rules).

Attach toAny Object
COMPONENTS
self.uiUI Interaction
On Move Page Changed
WhenmovePageChangedCustom Event
1IfdataCount('Move History') == 0
Then
2Set UI Element Visibility
3Otherwise
4Set UI Element Visibility
Visible
No

A new game has an empty list. The No Moves Note says so, No moves yet., in italic. Show No Moves Note shows it while the Move History has no rows, and hides it once there’s one.

12.7.5 Show Page Button, Report Earlier Moves and Report Later Moves

Logic ComponentShow Page Button

Shows a page button of the Game menu's Move List (Earlier or Later) only when there is a page to turn to, each time the page is drawn ("movePageChanged", from the Game Rules, whose Board State holds the page shown and movesPerPage). direction: -1 on the Earlier Moves Button (the page before), 1 on the Later Moves Button (the page after).

Attach toAny Object
COMPONENTS
self.uiUI Interaction
SHARED VARIABLES
NameTypeKindStarting Value
directionNumberConstant1
On Move Page Changed
WhenmovePageChangedCustom Event
1Declare Variable
Name
pageFirstMove
Value
0
2Change Variable
Variable
pageFirstMove
Value
other.boardState.movesPerPage * @self.direction
3Change Variable
Variable
pageFirstMove
Operator
+=
Value
other.boardState.firstShownMove
4IfpageFirstMove >= 0 && (pageFirstMove * 2) < dataCount('Move History')
Then
5Set UI Element Visibility
6Otherwise
7Set UI Element Visibility
Visible
No
Logic ComponentReport Earlier Moves

What the Earlier button of the Move List does: it tells whoever listens (the Game Rules) with "earlierMovesPressed".

Attach toAny Object
On Hud Activated
WhenUI Activated
1Trigger Custom Event
Custom Event
earlierMovesPressed
Logic ComponentReport Later Moves

What the Later button of the Move List does: it tells whoever listens (the Game Rules) with "laterMovesPressed".

Attach toAny Object
On Hud Activated
WhenUI Activated
1Trigger Custom Event
Custom Event
laterMovesPressed

A long game has more than one page. Earlier and Later turn them, each through its own Report, and each one shows only when there’s a page to turn to.

Show Page Button goes on each page button’s variant, with its Report. Its direction is a constant Shared Variable: -1 for Earlier and 1 for Later. It works out where that page would start: movesPerPage steps back or forward from the page shown. Is that at Move 1 or later, and has its first Move been made? Then the button shows. Otherwise it hides.

12.7.6 Move Pages

Data StructureMove Pages Data

What Move Pages remembers on the Game Rules. newestMove: the newest full Move, counted from 0. newestPage: the page that holds it, counted from 0.

newestMoveNumberdefault 0
newestPageNumberdefault 0
Logic ComponentMove PagesAttach to: Game Rules

Chooses which full Moves the Game menu's Move List shows, movesPerPage at a time (Board State's firstShownMove): the page that holds the newest Move when the menu opens ("gameMenuOpened"), the page before when Earlier is pressed ("earlierMovesPressed"), and the page after when Later is pressed ("laterMovesPressed"). Each time it tells everyone "movePageChanged", so the list shows the page.

Attach toAny Object
DATA STRUCTURES
Board Stateself.boardState
Move Pages Dataself.movePagesData
On Game Menu Opened
WhengameMenuOpenedCustom Event
1Change Component Value
Component Value
self.boardState.firstShownMove
Value
0
2IfdataCount('Move History') > 0
Then
3Change Component Value
Component Value
self.movePagesData.newestMove
Value
floor((dataCount('Move History') - 1) / 2)
4Change Component Value
Component Value
self.movePagesData.newestPage
Value
floor(self.movePagesData.newestMove / self.boardState.movesPerPage)
5Change Component Value
Component Value
self.boardState.firstShownMove
Value
self.movePagesData.newestPage * self.boardState.movesPerPage
6Trigger Custom Event
Custom Event
movePageChanged
On Earlier Moves Pressed
WhenearlierMovesPressedCustom Event
1Change Component Value
Component Value
self.boardState.firstShownMove
Operator
-=
Value
self.boardState.movesPerPage
2Trigger Custom Event
Custom Event
movePageChanged
On Later Moves Pressed
WhenlaterMovesPressedCustom Event
1Change Component Value
Component Value
self.boardState.firstShownMove
Operator
+=
Value
self.boardState.movesPerPage
2Trigger Custom Event
Custom Event
movePageChanged

Move Pages keeps the page in Board State. Its newestMove and newestPage wait in Move Pages Data, added to its Data Structures as movePagesData. When the menu opens, it finds the page with the newest Move. Step 3 halves the last row, rounded down by floor, to get the newest full Move. Step 4 divides that by movesPerPage to get its page, and step 5 turns the page back into its first Move.

Earlier takes movesPerPage off, and Later adds it. Each Event ends with movePageChanged, and every line, the note and both buttons draw the page.

The Values read self.boardState.movesPerPage, the number of lines the page holds, as the card shows it.

Now attach Move Pages to the Game Rules, the last Logic Component it gets. Remember gameMenuOpened, from the Game menu? This is who it was for.

The last pair of buttons turns the pages, Earlier back and Later forward. Make their two variants from Panel Button before placing them. Each one adds two jobs. Its own Report sends the press, and Show Page Button shows it only with a page to turn to. Earlier sets the Shared Variable direction to -1, and Later keeps its 1. Their bases give them the tan.

Object variantEarlier Moves ButtonVariant of: Panel Button
Logic
Report Earlier Moves
Show Page Button
Shared Variables
direction-1
Object variantLater Moves ButtonVariant of: Panel Button
Logic
Report Later Moves
Show Page Button

Now place the Move List, the next twenty-nine lines of PLACE THESE. They’re back on the Set up card, from the first Move Words down to Later Moves Button. It’s the longest stretch of placing in the book, and it goes faster once you see the pattern.

The Move Words come in pairs, one pair for each line. White’s is at X -60, and Black’s at X 90. Each pair sits 26 pixels below the one before, from Y 260 down to -26. Each placement sets its line, from none on the first pair (it stays 0) to 11 on the last. White’s placements keep the Object’s words. Black’s type the same template without the number, and switch isBlackMove on. Type it once, then copy it and paste it into the rest of Black’s.

The No Moves Note goes in the spot of the first line, and two Panel Labels above, the headings White and Black. Run the game, and start a new game. Press ••• before you move, and No moves yet. sits under the headings. Close it, play three Moves, and open it again. Your Moves are there, numbered, the way a chess player would write them.

12.8 Playing From the Keyboard

Now the last piece: no mouse at all.

12.8.1 Focus Mark

ObjectFocus Mark
Transform
Bounding Box > SizeX 3.75, Y 3.75
Sprite
Scene Depth Draw Order13
SpriteFocus Outline
Transform > SizeX 3.75, Y 3.75
Data Structure
Data StructureSquare Info
Data Structure
From LogicKeyboard Focus
Data StructureKeyboard Focus Data
Logic
Keyboard Focus

The Focus Mark is an amber outline, one Square in size, 3.75 meters. Unlike the panels, it lives in the world, on the Board, at a Scene Depth Draw Order of 13.

It carries a Square Info, like every Square. That’s the trick of this part. To Select and Move, the Focus Mark looks like a Square. It says squareClicked, and Select and Move reads its name exactly as it reads a clicked Square’s.

12.8.2 Move The Focus Mark

FunctionMove The Focus Mark

Moves the Focus Mark to where its Square (its Square Info) is drawn now, as Place On Board moves a Piece (Square Position). focusMark: the Focus Mark. isFlipped: whether the Board is drawn turned over. squareMeters, boardLeft and boardBottom: the Board's size and corner, as Place On Board has them.

PARAMETERS
NameTypeStarts at
focusMarkObjectStructural
Required Components
Slot NamesquareInfo
Component TypeData Structure
Required SchemaSquare Info
isFlippedBooleanNo
squareMetersNumber3.75
boardLeftNumber0
boardBottomNumber4.375
ACTIONS
1Square PositionFunction
Action Name
focusedSquare
square
focusMark.squareInfo.name
isFlipped
isFlipped
squareMeters
squareMeters
boardLeft
boardLeft
boardBottom
boardBottom
2Set Position
Applies to
focusMark
X
focusedSquare.x
Y
focusedSquare.y

Move The Focus Mark puts the outline on its Square. Square Position, from Chapter 1, turns a Square’s name into a place on the Board, flipped or not. Set Position takes it there.

12.8.3 Step The Focus

FunctionStep The Focus

Moves the focus by a number of Squares on the screen, and stops at the Board's edges: the Focus Mark's Square becomes the one reached, the mark is shown, and it moves there (Move The Focus Mark). focusMark: the Focus Mark. fileStep: Squares to the right; rankStep: Squares up (negative: left, down). isFlipped: whether the Board is drawn turned over. squareMeters, boardLeft and boardBottom: the Board's size and corner.

PARAMETERS
NameTypeStarts at
focusMarkObjectStructural
Required Components
Slot NamesquareInfo
Component TypeData Structure
Required SchemaSquare Info
fileStepNumber0
rankStepNumber0
isFlippedBooleanNo
squareMetersNumber3.75
boardLeftNumber0
boardBottomNumber4.375
ACTIONS
1Declare Variable
Name
across
Value
0
2Declare Variable
Name
up
Value
0
3Declare Variable
Name
file
Value
0
4Declare Variable
Name
rank
Value
0
5Declare Variable
Name
row
Value
0
6Change Variable
Variable
across
Value
fileStep
7Change Variable
Variable
up
Value
rankStep
8IfisFlipped == true
Then
9Change Variable
Variable
across
Operator
*=
Value
-1
10Change Variable
Variable
up
Operator
*=
Value
-1
11Change Variable
Variable
file
Value
data('Position', focusMark.squareInfo.name, 'file')
12Change Variable
Variable
file
Operator
+=
Value
across
13Change Variable
Variable
file
Value
clamp(file, 1, 8)
14Change Variable
Variable
rank
Value
data('Position', focusMark.squareInfo.name, 'rank')
15Change Variable
Variable
rank
Operator
+=
Value
up
16Change Variable
Variable
rank
Value
clamp(rank, 1, 8)
17Change Variable
Variable
row
Value
(rank - 1) * 8 + (file - 1)
18Change Component Value
Component Value
focusMark.squareInfo.name
Value
dataRow('Position', row)
19Set Visible
Applies to
focusMark
Visible
true
20Move The Focus MarkFunction
focusMark
focusMark
isFlipped
isFlipped
squareMeters
squareMeters
boardLeft
boardLeft
boardBottom
boardBottom

Step The Focus moves the focus by a number of Squares, counted on the screen. Right is always right, the way you see it.

That’s why steps 6 to 10 come first, after the Declares. On a flipped Board, File a is on the right and Rank 1 at the top. So a step right on the screen is a step toward File a, and both steps turn round. Steps 9 and 10 multiply by -1 with the Operator *=, in the same list as = and +=.

Next, clamp keeps the new File and Rank between 1 and 8. That’s the Board’s edge. Press Left on File a, and the focus stays put. Step 17 turns File and Rank into a row of Position. Position’s rows run a1 to h1, then a2 to h2, eight to a Rank. So (rank - 1) * 8 counts the Ranks below, and file - 1 the steps along. Step 18 names the Square. Last, the outline shows and moves.

12.8.4 Keyboard Focus

Data StructureKeyboard Focus Data

What Keyboard Focus remembers on the Focus Mark. isFlipped: whether the Board is drawn turned over, so the arrow keys move the focus the way the screen shows.

isFlippedBooleandefault false
Logic ComponentKeyboard FocusAttach to: Focus Mark

Lets the Player play with the keyboard: keeps the focused Square (this Object's Square Info) and draws the Focus Mark on it. The arrow keys (Move Focus) move the focus one Square on the screen, Home and End (Focus Row Start, Focus Row End) to the ends of its row, always stopping at the Board's edges, and the way the Board is drawn turns them round ("boardFlipped", from the Game Rules). Enter or Space (Press Square) presses the focused Square as a click does ("squareClicked"), while the game is being played. The focus starts on the Square in front of the Player's King when each game begins ("gameStarted", from the Game Rules), and shows itself from the first key. These keys are the Input Context Default: while the Promotion choice is open they rest, and the focus stays where it is (Choose With Keys turns them off and the choice's own keys on). startFile: the File the focus starts on (5: File e). squareMeters, boardLeft, boardBottom: the Board as Place On Board draws it.

Attach toAny Object
DATA STRUCTURES
Square Infoself.squareInfo
Keyboard Focus Dataself.keyboardFocusData
SHARED VARIABLES
NameTypeKindStarting Value
squareMetersNumberConstant3.75
boardLeftNumberConstant0
boardBottomNumberConstant4.375
startFileNumberConstant5
On Game Started
WhengameStartedCustom Event
1Declare Variable
Name
row
Value
0
2Declare Variable
Name
rank
Value
0
3Change Component Value
Component Value
self.keyboardFocusData.isFlipped
Value
other.boardState.isFlipped
4Change Variable
Variable
rank
Value
data('Sides', other.boardState.playerSide, 'pawnRank')
5Change Variable
Variable
row
Value
(rank - 1) * 8 + (@self.startFile - 1)
6Change Component Value
Component Value
self.squareInfo.name
Value
dataRow('Position', row)
7Move The Focus MarkFunction
focusMark
self
isFlipped
self.keyboardFocusData.isFlipped
squareMeters
@self.squareMeters
boardLeft
@self.boardLeft
boardBottom
@self.boardBottom
On Board Flipped
WhenboardFlippedCustom Event
1Change Component Value
Component Value
self.keyboardFocusData.isFlipped
Value
other.boardState.isFlipped
2Move The Focus MarkFunction
focusMark
self
isFlipped
self.keyboardFocusData.isFlipped
squareMeters
@self.squareMeters
boardLeft
@self.boardLeft
boardBottom
@self.boardBottom
When Move Focus Left Is Pressed
When2D Direction PressedCommand: Move FocusDirection: Left
1Step The FocusFunction
focusMark
self
fileStep
-1
rankStep
0
isFlipped
self.keyboardFocusData.isFlipped
squareMeters
@self.squareMeters
boardLeft
@self.boardLeft
boardBottom
@self.boardBottom
When Move Focus Right Is Pressed
When2D Direction PressedCommand: Move FocusDirection: Right
1Step The FocusFunction
focusMark
self
fileStep
1
rankStep
0
isFlipped
self.keyboardFocusData.isFlipped
squareMeters
@self.squareMeters
boardLeft
@self.boardLeft
boardBottom
@self.boardBottom
When Move Focus Up Is Pressed
When2D Direction PressedCommand: Move FocusDirection: Up
1Step The FocusFunction
focusMark
self
fileStep
0
rankStep
1
isFlipped
self.keyboardFocusData.isFlipped
squareMeters
@self.squareMeters
boardLeft
@self.boardLeft
boardBottom
@self.boardBottom
When Move Focus Down Is Pressed
When2D Direction PressedCommand: Move FocusDirection: Down
1Step The FocusFunction
focusMark
self
fileStep
0
rankStep
-1
isFlipped
self.keyboardFocusData.isFlipped
squareMeters
@self.squareMeters
boardLeft
@self.boardLeft
boardBottom
@self.boardBottom
When Focus Row Start Is Pressed
WhenCommand PressedCommand: Focus Row Start
1Step The FocusFunction
focusMark
self
fileStep
-7
rankStep
0
isFlipped
self.keyboardFocusData.isFlipped
squareMeters
@self.squareMeters
boardLeft
@self.boardLeft
boardBottom
@self.boardBottom
When Focus Row End Is Pressed
WhenCommand PressedCommand: Focus Row End
1Step The FocusFunction
focusMark
self
fileStep
7
rankStep
0
isFlipped
self.keyboardFocusData.isFlipped
squareMeters
@self.squareMeters
boardLeft
@self.boardLeft
boardBottom
@self.boardBottom
When Press Square Is Pressed
WhenCommand PressedCommand: Press Square
1Check Game State
Action Name
isPlaying
Game State
Playing
2IfisPlaying.value == true
Then
3Set Visible
Visible
Yes
4Trigger Custom Event
Custom Event
squareClicked

Keyboard Focus remembers the Board’s direction in Keyboard Focus Data. Add it to Data Structures with the slot name keyboardFocusData, so the calls can read that direction. It has nine Events, and most are one call. When a game starts, the focus goes to File e of your Pawns’ Rank, in front of your King: e2 for White, e7 for Black. When the Board flips, it follows its Square to its new place.

Each arrow key is its own 2D Direction Pressed Event, for the Command Move Focus. Choose Move Focus from the Command list. The next window chooses the direction. Pick the card’s Left, Right, Up or Down, and that key gets its own Event. Each calls Step The Focus with one step. Home and End are Command Pressed Events, and they step seven Squares. A row has eight Squares, so seven steps always reach its end, and the clamp stops it there.

Enter or Space is Press Square. It asks first whether the game is being played. On the Computer’s Turn, or after the end, a key counts no more than a click would. Then it shows the outline and sends squareClicked.

One thing surprises people. The outline is hidden until you press a key. Then it appears and moves, both at once.

12.8.5 New Game

Logic ComponentNew GameAttach to: Game RulesAddDelete

Starts every game with the Side and the Strength the Player chose last, and lets the Player start a new game. When the game begins (Game Start, before the first Turn), it takes the choices saved on this device (the Strength through Use The Last Strength, which it uses again when a saved game has been brought back, "savedGameLoaded") (Persistent Values), when the game has them (the Sides and Strengths tables; otherwise, and the first time, Board State's own playerSide and strength), turns the Board over for a Player who plays Black, and tells everyone "gameStarted". When the Player presses New Game ("newGamePressed"), it opens the New Game panel, a menu that holds the game while it is open, showing the current choices as chosen and asking "Replace the current game?" when a game is in progress and has Moves. Each Side or Strength pressed ("sideChosen", "strengthChosen"; the button is its Other) becomes the chosen one. Play ("playPressed") saves the choices, forgets the saved game (the slot "auto"), and restarts the game, which starts again from the beginning with them.

Attach toAny Object
DATA STRUCTURES
Board Stateself.boardState
When the Game Starts
WhenGame Start
1Load Persistent Value
Action Name
savedSide
Key
"playerSide"
Default
self.boardState.playerSide
2Check Data Row Exists
Action Name
isKnownSide
Table
Sides
Row
savedSide.value
3IfisKnownSide.value == true
Then
4Change Component Value
Component Value
self.boardState.playerSide
Value
savedSide.value
5Use The Last StrengthFunction
gameRules
self
6Ifself.boardState.playerSide == "Black"
Then
7Change Component Value
Component Value
self.boardState.isFlipped
Value
true
8Trigger Custom Event
Custom Event
gameStarted
On New Game Pressed
WhennewGamePressedCustom Event
1Change Component Value
Component Value
self.boardState.chosenSide
Value
self.boardState.playerSide
2Change Component Value
Component Value
self.boardState.chosenStrength
Value
self.boardState.strength
3Control Menu
Menu Element
New Game Panel
4Set Menu Pause State
Menu Element
New Game Panel
5Check Game State
Action Name
isOver
Game State
Game Over
6Ifself.boardState.lastFrom != "" && isOver.value == false
Then
7Set UI Element Visibility
Element
Replace Question
8Otherwise
9Set UI Element Visibility
Element
Replace Question
Visible
No
10Trigger Custom Event
Custom Event
choiceChanged
On Side Chosen
WhensideChosenCustom Event
1Change Component Value
Component Value
self.boardState.chosenSide
Value
other.panelOption.option
2Trigger Custom Event
Custom Event
choiceChanged
On Strength Chosen
WhenstrengthChosenCustom Event
1Change Component Value
Component Value
self.boardState.chosenStrength
Value
other.panelOption.option
2Trigger Custom Event
Custom Event
choiceChanged
On Play Pressed
WhenplayPressedCustom Event
1Save Persistent Value
Action Name
persistentWriteResult
Key
"playerSide"
Value
self.boardState.chosenSide
2Save Persistent Value
Action Name
persistentWriteResult2
Key
"strength"
Value
self.boardState.chosenStrength
3Delete Save
Slot
"auto"
4Restart Game
On Saved Game Loaded
WhensavedGameLoadedCustom Event
1Use The Last StrengthFunction
gameRules
self

New Game gets one step at the end of When the Game Starts. Once your Side is known, gameStarted tells the Focus Mark which Square to start on, e2 or e7.

12.8.6 New Game Panel and Settings Panel

ObjectNew Game PanelAddDelete
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 600, Y 420
UI Interaction
Element TypeText
GroupNew Game
Cancel CommandCancel
Sprite
Scene Depth Draw Order30
SpriteSquare Highlight
Tint#EFE6CF
Transform > SizeX 600, Y 420
Text / UI
TextNew game
Font Size26
EmphasisSemibold
Color#503A2B
AlignmentCenter
Transform > PositionX 0, Y 170
ObjectSettings PanelAddDelete
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 600, Y 620
UI Interaction
Element TypeText
GroupSettings
Cancel CommandCancel
Sprite
Scene Depth Draw Order30
SpriteSquare Highlight
Tint#EFE6CF
Transform > SizeX 600, Y 620
Text / UI
TextSettings
Font Size26
EmphasisSemibold
Color#503A2B
AlignmentCenter
Transform > PositionX 0, Y 270

The two panels of earlier chapters get the Cancel Command too. Pick Cancel in each UI Interaction. Now Escape closes every panel in the game, as its Cancel or Done does.

12.8.7 Promotion Focus and Move The Promotion Focus

Data StructurePromotion ChoiceAddDelete

What one button of the Promotion panel stands for. kind: the Kind the Pawn becomes (Queen, Rook, Bishop, or Knight); empty for the button that cancels the Move. The Promotion Focus carries one too: the Piece the keys are on (Choose With Keys).

kindTextdefault (empty)
ObjectPromotion Focus
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 134, Y 158
UI Interaction
Element TypeText
GroupPromotion
Sprite
Scene Depth Draw Order22
SpritePromotion Outline
Transform > SizeX 134, Y 158
Data Structure
Data StructurePromotion Choice
Data Structure
From LogicChoose With Keys
Data StructureChoose With Keys Data
Logic
Choose With Keys
FunctionMove The Promotion Focus

Puts the Promotion Focus on the Piece at one place of the Promotion choice: its Promotion Choice becomes that Kind, and its outline is drawn over that Piece's button. promotionFocus: the Promotion Focus. place: 1 to 4, the Queen, Rook, Bishop and Knight, as their buttons stand from left to right. firstPieceX and pieceY: where the Queen's button stands, in screen pixels right of and above the middle of the screen; pieceSpacing: how far apart the buttons stand.

PARAMETERS
NameTypeStarts at
promotionFocusObjectStructural
Required Components
Slot NamepromotionChoice
Component TypeData Structure
Required SchemaPromotion Choice
placeNumber1
firstPieceXNumber-195
pieceYNumber66
pieceSpacingNumber130
ACTIONS
1Change Component Value
Component Value
promotionFocus.promotionChoice.kind
Value
dataRow('Kinds', place)
2Set Position
Applies to
promotionFocus
Position Relative To
Screen
X
firstPieceX + (place - 1) * pieceSpacing
Y
pieceY

The Promotion choice needs keys of its own. A Pawn reaches the last Rank, and four Pieces wait in a row. The Promotion Focus is a rounded outline around one of them, in the Promotion UI Group. It shows and hides with the choice. Its Element Type is Text, so a click on the Piece under it still reaches that Piece’s button.

It carries a Promotion Choice, like the four buttons, and its kind is the Piece it’s on. On Promotion Choice’s card, only the Description changes, to say so. Nothing reads a Description, so there’s nothing to build there.

Move The Promotion Focus puts it on one of four places, 1 for the Queen to 4 for the Knight. Its dataRow reads the Kinds table by number. Counted from Row 0, the way the card counts, rows 1 to 4 are Queen, Rook, Bishop and Knight, the buttons’ own order. In the editor’s numbers, that’s rows 2 to 5.

Then Set Position moves the outline on the screen, 130 pixels for each place. Its Position Relative To is a list. Pick Screen, so X and Y count in pixels from the middle of the screen, as the Description says.

12.8.8 Choose With Keys

Data StructureChoose With Keys Data

What Choose With Keys remembers on the Promotion Focus. place: which Piece of the Promotion choice the outline is on, 1 (the Queen) to 4.

placeNumberdefault 1
Logic ComponentChoose With KeysAttach to: Promotion Focus

Lets the Player choose the Promotion with the keyboard. While the Promotion choice is open the keys choose among its Pieces instead of playing on the Board: the Input Context Promotion Choice is on and Default (the Board's keys) is off, turned when the choice opens or closes and when a saved game comes back ("positionChanged", from the Game Rules). Left and Right (the Command Choose Piece) move this outline from Piece to Piece, from the Queen to the Knight; Enter or Space (Promote) promotes the Pawn to the Piece it is on: this Object carries that Kind in its Promotion Choice, so the Game Rules (Choose Promotion) hear "promotionChosen" from it as from a button. The outline starts on the Queen each time the choice opens. firstPieceX and pieceY: where the Queen's button stands, in screen pixels right of and above the middle of the screen; pieceSpacing: how far apart the buttons stand.

Attach toAny Object
DATA STRUCTURES
Promotion Choiceself.promotionChoice
Choose With Keys Dataself.chooseWithKeysData
SHARED VARIABLES
NameTypeKindStarting Value
firstPieceXNumberConstant-195
pieceYNumberConstant66
pieceSpacingNumberConstant130
On Position Changed
WhenpositionChangedCustom Event
1Check Game State
Action Name
isChoosing
Game State
Promotion
2IfisChoosing.value == true
Then
3Set Input Context Active
Input Context
Default
Active
No
4Set Input Context Active
Input Context
Promotion Choice
5Change Component Value
Component Value
self.chooseWithKeysData.place
Value
1
6Move The Promotion FocusFunction
promotionFocus
self
place
self.chooseWithKeysData.place
firstPieceX
@self.firstPieceX
pieceY
@self.pieceY
pieceSpacing
@self.pieceSpacing
7Otherwise
8Set Input Context Active
Input Context
Promotion Choice
Active
No
9Set Input Context Active
Input Context
Default
When Choose Piece Left Is Pressed
When2D Direction PressedCommand: Choose PieceDirection: Left
1Change Component Value
Component Value
self.chooseWithKeysData.place
Value
clamp(self.chooseWithKeysData.place - 1, 1, 4)
2Move The Promotion FocusFunction
promotionFocus
self
place
self.chooseWithKeysData.place
firstPieceX
@self.firstPieceX
pieceY
@self.pieceY
pieceSpacing
@self.pieceSpacing
When Choose Piece Right Is Pressed
When2D Direction PressedCommand: Choose PieceDirection: Right
1Change Component Value
Component Value
self.chooseWithKeysData.place
Value
clamp(self.chooseWithKeysData.place + 1, 1, 4)
2Move The Promotion FocusFunction
promotionFocus
self
place
self.chooseWithKeysData.place
firstPieceX
@self.firstPieceX
pieceY
@self.pieceY
pieceSpacing
@self.pieceSpacing
When Promote Is Pressed
WhenCommand PressedCommand: Promote
1Trigger Custom Event
Custom Event
promotionChosen

Choose With Keys switches the keys. Choose With Keys Data holds place, added to Data Structures as chooseWithKeysData. The button positions are constant Shared Variables. On every positionChanged, it asks whether the Promotion choice is open. If it is, Set Input Context Active turns Default off, then Promotion Choice on. Steps 4 and 9 have no Active line. Active starts on, and that’s what they need. The arrow keys now mean the four Pieces, and the outline starts on the Queen. When the choice closes, it switches back.

Left and Right step place, and clamp keeps it from 1 to 4, the Queen to the Knight. Enter or Space sends promotionChosen. Choose Promotion reads this Object as its other, so it gets the Kind the outline is on, as if you’d clicked that button.

12.8.9 Cancel With Escape

Logic ComponentCancel With EscapeAttach to: Cancel Promotion

Lets Escape (the Command Cancel Choice) cancel the Promotion choice, as a click on its Cancel button does: the button tells whoever listens (the Game Rules) "promotionChosen", and the listener reads its Promotion Choice, empty for Cancel, as Other. Cancel Choice is one of the Promotion choice's own keys, live only while the choice is open (Choose With Keys turns them on).

Attach toAny Object
When Cancel Choice Is Pressed
WhenCommand PressedCommand: Cancel Choice
1Trigger Custom Event
Custom Event
promotionChosen
ObjectCancel PromotionAddDelete
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 160, Y 40
UI Interaction
GroupPromotion
Sprite
Scene Depth Draw Order21
SpriteSquare Highlight
Tint#E2D5B4
Transform > SizeX 160, Y 40
Text / UI
TextCancel
Font Size18
EmphasisSemibold
Color#503A2B
AlignmentCenter
Data Structure
Data StructurePromotion Choice
Logic
Report Choice
Cancel With Escape

The Promotion choice isn’t a menu. It’s part of the game, so no Cancel Command closes it. Its Cancel button answers Escape itself. Cancel With Escape sends promotionChosen. The button’s Promotion Choice is empty, and Choose Promotion takes an empty Kind as Cancel. Attach it to Cancel Promotion.

Last, the two placements: the Focus Mark on e2, and the Promotion Focus on the Queen’s button. Both start hidden.

Run the game. Press New Game, choose White, and press Play. Now leave the mouse alone. Press Up. The amber outline appears on e3, one Square up from e2. Press Down, then Enter. Your e-Pawn’s Square turns gold, and its dots appear. Press Up twice, then Enter. The Pawn moves to e4.

Your game plays from the keyboard now, from the first Move to the last.

Play it!

Watch for each of these.

  • Press •••. The game dims, and the Game menu opens with the headings White and Black, and No moves yet.
  • Play a few Moves, then press ••• again. Each Move is written down, the number before White’s Move: 1. e4, with Black’s reply beside it.
  • Capture something with a Pawn. Its name has an x and its own File, such as exd5. Give a Check, and the Move ends in +.
  • Press Escape. The Game menu closes, as Done would. Escape closes New Game, Settings, How to play and Resign? the same way.
  • In the Game menu, press How to play. Three short paragraphs explain selecting a Piece, Threats mode, and how to play the whole game with the keyboard.
  • Press Resign, then Cancel, and the game goes on. Resign again, and confirm. You lose · Resignation appears, and Resign fades in the menu.
  • Start a new game, and press an arrow key. The outline appears, moving one Square from e2, and it stops at the Board’s edges. Home and End take it to the ends of its row.
  • Flip the Board. Right still moves the outline right on the screen.
  • Move a Pawn to its last Rank with the keys, and the outline waits on the Queen. Left and Right move it, and Enter promotes. Or press Escape instead, and the choice closes with the Pawn still selected.
How it works

The ••• button opens a menu that holds the game. Every Move is named as it’s made, before the Board changes, and its + or # is added when the next Turn starts. The Move List reads the names from the Move History, twelve full Moves to a page. The Focus Mark carries a Square Info and sends squareClicked, and two Input Contexts take turns with the keys.

Underneath, nothing in this chapter changed a rule. A key sends the message a click sends. Escape does what Cancel does, and Enter on the outline what a click on its button does. When a new way to play arrives, give it a door the game already has.

12.9 If It Didn’t Work

This chapter touches pieces from every part of the game. Run it after each part, and the trouble stays small.

The ••• button does nothing? Its placement should pick Game Menu Button, whose Logic is Report Game Menu. Is Game Menu attached to the Game Rules?

The Game menu opens, but the Board still takes clicks under it? Its Panel Backdrop needs the Group Game Menu, on its placement.

Resign never fades? Look at Ask To Resign’s On Position Changed. Can Resign and Show Button On Or Off both need joining, with canUse.value handed to isOn.

The list always says No moves yet.? Perhaps Move Pages isn’t attached, or Game Menu’s step 3 sends to another Object. It should go to its own, with Applies to left on Self.

Every line shows the same Move? Each pair of placements needs its own line, 1 to 11. A Black Move that starts with a number has White’s template, so type Black’s without {number}. and switch its isBlackMove on.

A Knight’s Move reads f3 with no N, or a name comes out empty? Look at the three Move makers. Record Move must come before Make Move. After the Move, from is an empty Square, and Name The Move finds no Piece there to name.

Record Move sits outside the Else in Select and Move? Cut that call. Right-click step 10’s Else, choose Paste, then join the call first on its line, before Make Move. The three steps should now match their card.

The arrow keys do nothing? Open the Input Manager. The five Commands must be in Default, spelled as the card has them. Perhaps a panel is still open, and keys rest while a menu holds the game.

Right moves left on a flipped Board? Look at steps 8 to 10 of Step The Focus, where both Changes multiply by -1 with the Operator *=.

The Promotion keys move across the Board instead? Promotion Choice needs its three Commands, and Choose With Keys must be on the Promotion Focus. If the outline sits beside the Pieces, compare firstPieceX, pieceY and pieceSpacing with where Chapter 4 placed the four buttons.

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 the finished game, if you’d like to compare.

Challenge

The recipe ends here, but your game doesn’t have to. What would you add to it? Perhaps a clock for each Side, counting down, or a row of captured Pieces beside the Board. Or a second Player at the same keyboard, with the Computer resting. Every one of those is built from the same blocks you’ve used for twelve chapters.

Or close this project and start a new one. A game no one has made yet, of your own. You know how to begin now: an empty page, one table, and the first piece of Logic.

Still stuck? Search the manual, or ask in the Myth Engine Discord (opens a new tab).

In Chapter 1, the page was empty. It was the color of paper, with nothing on it. Then you laid out a Board, Square by Square, and set thirty-two Pieces on it.

Since then, the game has learned whose Turn it is and which Moves are legal. It knows when a King is lost, and when nobody can win. It writes down every Move. The Computer’s thinking came from outside. Every rule that judges its Moves, and yours, you built with your own hands.

Play it to the end. When the last Checkmate comes, the game will say so under the Board, in the words you gave it.

Free demo

Free

  • No time limit
  • Build, save and playtest your games
  • Follow every game guide and build its game

Publishing needs the full version.

Try the free demo

Full version

$84.99 USD, once

No subscription, no paid upgrades, every update included.

Everything in the free demo, plus:

  • Publish your game as one HTML file, a web folder, or desktop and mobile projects you build and sign
  • Share it or sell it, with no royalties, however much it earns
  • Let players build their own version of your game, within the parts you allow (Builder Mode)
Buy Myth Engine — $84.99

Windows 10/11, 64-bit · One person, on computers you own or control · Checkout and downloads through itch.io · Made by 3D Mage