Build a GameCreating Crystal Cascade

9  Countdown and Pause

Goal

Give your well a breath before play begins, and a pause whenever you need one.

Click the game, then press Enter. Choose a mode, watch the countdown, and press Escape or P to pause.

Use this project for comparison.

Crystal Cascade, Chapter 9 finishedZip of a Myth project · 4.6 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. Nunito-OFL.txt beside it comes with the game.

9.1 The Idea

The glass well waits. READY sits above it, and a number fills its middle. The count falls from three to one, with a chime on each beat. GO! A piece falls.

Until now, entering Gameplay started its clocks and invited the first piece at once. This time the Scene can arrive before play begins. One message, playStarted, opens that gate for the piece and its clocks.

The other quiet moment comes under your hand. Press Escape and the crystals stop where they are. A glass panel covers the well, offering RESUME, RESTART and MAIN MENU.

This is the engine’s pause. Timers wait with the piece, while the menu can still listen. The clock keeps its place too. Think of a bookmark held between two stretches of play.

Zen finally gets its way home. Earn a score above its saved best. If the well fills, Zen clears it and that score keeps growing. RESTART discards this attempt’s score and begins again. MAIN MENU keeps that better score as your record, ready for the next time you play. It returns you to the choices over the sky.

9.2 The Plan

  • Count Down holds Play’s controls -> playStarted lets Deal Pieces send the first piece.
  • The same message starts Time The Game and Ultra’s finishing timer. The countdown pictures give way to GO!.
  • Pause The Game asks Myth to pause -> the panel opens and Menus keeps listening.
  • RESUME returns to the waiting piece. RESTART begins this mode again; MAIN MENU leaves it, giving Zen a chance to save.

9.3 Set Up

Continue your completed Chapter 8 project, or open Chapter 8 finished. This is the starting project, with its menu already working. Keep its choosing Logic, prepared panel declarations, Fade Out Message and game clocks. This chapter uses those pieces again.

Check for Panel State, Choose Panel Choice, Panel Choices, Panel Choice and Show When Panel Choice. Their reference below gives their jobs and complete cards. For now, check that all five resources exist. Leave the complete cards as a reference unless a piece is missing. Missing any of them? Open Chapter 8 finished before continuing, keeping its existing resources together. That download also brings the earlier Functions and messages these cards call, including the Main Menu’s help responses.

These are existing resources to compare, rather than another set to add. Keep one of each. The pause will give their choosing work a new home.

9.3.1 Panel State

A panel remembers whether it is open and which button has the glow. Panel State keeps that memory. Its chosen field counts from 0, the first choice. isOpen keeps closed panels from answering keys. Each button adds itself to choiceCount when created, so navigation knows where to wrap.

Data StructurePanel State

What a panel of choices keeps: chosen, the choice chosen now (0 = the top one); isOpen, the panel is open and its choices can be chosen. choiceCount: how many choices it has (each choice adds itself when created).

chosenNumberdefault 0
isOpenBooleandefault false
choiceCountNumberdefault 0

9.3.2 Choose Panel Choice

Moving the glow needs one shared announcement. Choose Panel Choice changes the remembered choice and tells the pictures to look again. Its panel Parameter identifies the panel carrying that memory.

FunctionChoose Panel Choice

Makes choice the chosen choice of a panel (its Panel State chosen) and tells the highlights. The only writer of chosen.

PARAMETERS
NameTypeStarts at
panelObjectStructural
Required Components
Slot NamepanelState
Component TypeData Structure
Required SchemaPanel State
choiceNumber0
ACTIONS
1Change Component Value
Component Value
panel.panelState.chosen
Value
choice
2Trigger Custom Event
Custom Event
panelChoiceChanged

9.3.3 Panel Choices

The panel opens and closes on messages. While open, it lets Up and Down move the choice around. Panel Choices finds that memory through self.panelState, the component on its own Object. Give Pause Panel that component before attaching this Logic below. Closing resets the choice.

Logic ComponentPanel ChoicesAttach to: Results Panel, Main Menu Flow, Pause Panel

A panel of choices: opens on its chosen choice when told (panelOpened; the top one unless the Logic that opens it chose another), closes when told (panelClosed), going back to its top choice, and while open Up / Down choose the choice above or below, going round at either end, with Menu Bubble.

Attach toAny Object
DATA STRUCTURES
Panel Stateself.panelState
On Panel Opened
WhenpanelOpenedCustom Event
1Change Component Value
Component Value
self.panelState.isOpen
Value
true
2Choose Panel ChoiceFunction
panel
self
choice
self.panelState.chosen
On Panel Closed
WhenpanelClosedCustom Event
1Change Component Value
Component Value
self.panelState.isOpen
Value
false
2Change Component Value
Component Value
self.panelState.chosen
Value
0
3Trigger Custom Event
Custom Event
panelChoiceChanged
When Menu Navigate Up Is Pressed
When2D Direction PressedCommand: Menu NavigateDirection: Up
ModeChoose The One Above (Starting Mode)
1Ifself.panelState.isOpen == true
Then
2Choose Panel ChoiceFunction
panel
self
choice
mod(self.panelState.chosen - 1 + self.panelState.choiceCount, self.panelState.choiceCount)
3Control Sound
Sound
Menu Bubble
When Menu Navigate Down Is Pressed
When2D Direction PressedCommand: Menu NavigateDirection: Down
ModeChoose The One Below (Starting Mode)
1Ifself.panelState.isOpen == true
Then
2Choose Panel ChoiceFunction
panel
self
choice
mod(self.panelState.chosen + 1, self.panelState.choiceCount)
3Control Sound
Sound
Menu Bubble
On How to Play Opened
WhenhowToPlayOpenedCustom Event
1Switch Mode
Event
When Menu Navigate Up Is Pressed
Mode
While Help Is Open
2Switch Mode
Event
When Menu Navigate Down Is Pressed
Mode
While Help Is Open
On How to Play Closed
WhenhowToPlayClosedCustom Event
1Switch Mode
Event
When Menu Navigate Up Is Pressed
Mode
Choose The One Above
2Switch Mode
Event
When Menu Navigate Down Is Pressed
Mode
Choose The One Below
WhenWhen Menu Navigate Up Is Pressed(the same Event)
ModeWhile Help Is Open (no blocks: it does nothing)
WhenWhen Menu Navigate Down Is Pressed(the same Event)
ModeWhile Help Is Open (no blocks: it does nothing)

9.3.4 Panel Choice

Each button needs to know which panel it belongs to. Its Shared Variable panel points there. The other Shared Variable, choice, identifies this button within that panel. Panel Choice lets the keyboard and mouse choose the same button. Confirm sends choiceRun to the button.

Logic ComponentPanel ChoiceAttach to: PLAY AGAIN Button, MARATHON Button, SPRINT 40 Button, ULTRA Button, ZEN Button, HOW TO PLAY Button, QUIT Button, BACK TO MENU Button, RESUME Button, RESTART Button, MAIN MENU Button

One choice of a panel: while the panel is open, Confirm runs it when it is the chosen choice; the mouse over it chooses it, and a click on it runs it. Running it plays Menu Select and tells its own button (choiceRun), whose other Logic does the work of the choice. While the How to Play panel covers the Main Menu, the choices do nothing, and Confirm on the chosen one closes it.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
panelObjectConstantNone
choiceNumberConstant0
OBJECT KINDS
panelObjects with Panel State
When Created
WhenCreate
1Change Component Value
Component Value
@self.panel.panelState.choiceCount
Operator
+=
Value
1
When Confirm Is Pressed
WhenCommand PressedCommand: Confirm
ModeRun If Chosen (Starting Mode)
1If@self.panel.panelState.isOpen == true && @self.panel.panelState.chosen == @self.choice
Then
2Control Sound
Sound
Menu Select
3Trigger Custom Event on Object
Custom Event
choiceRun
On Mouse Enter
WhenMouse Enter
ModeChoose This One (Starting Mode)
1If@self.panel.panelState.chosen != @self.choice
Then
2Choose Panel ChoiceFunction
panel
@self.panel
choice
@self.choice
3Control Sound
Sound
Menu Bubble
When Left Is Clicked
WhenMouse Pressed on ObjectMouse button: left
ModeRun This One (Starting Mode)
1Choose Panel ChoiceFunction
panel
@self.panel
choice
@self.choice
2Control Sound
Sound
Menu Select
3Trigger Custom Event on Object
Custom Event
choiceRun
On How to Play Opened
WhenhowToPlayOpenedCustom Event
1Switch Mode
Event
When Confirm Is Pressed
Mode
While Help Is Open
2Switch Mode
Event
On Mouse Enter
Mode
While Help Is Open
3Switch Mode
Event
When Left Is Clicked
Mode
While Help Is Open
On How to Play Closed
WhenhowToPlayClosedCustom Event
1Switch Mode
Event
When Confirm Is Pressed
Mode
Run If Chosen
2Switch Mode
Event
On Mouse Enter
Mode
Choose This One
3Switch Mode
Event
When Left Is Clicked
Mode
Run This One
When Confirm Is Pressed
WhenCommand PressedCommand: Confirm
ModeWhile Help Is Open
1If@self.panel.panelState.chosen == @self.choice
Then
2Close How To PlayFunction
WhenOn Mouse Enter(the same Event)
ModeWhile Help Is Open (no blocks: it does nothing)
WhenWhen Left Is Clicked(the same Event)
ModeWhile Help Is Open (no blocks: it does nothing)

9.3.5 Show When Panel Choice

The brighter picture listens for a changed choice. Show When Panel Choice compares its Per Instance Variable choice with the panel’s memory. Both must match. The panel must be open too. Its Shared Variable panel points to the same panel as the button underneath. The button keeps choice on its Object, while each brighter picture placement can carry its own choice override.

Logic ComponentShow When Panel ChoiceAttach to: PLAY AGAIN Highlight, MARATHON Highlight, SPRINT 40 Highlight, ULTRA Highlight, ZEN Highlight, HOW TO PLAY Highlight, QUIT Highlight, Start Level Label, Start Level Left Key, Start Level Value, Start Level Right Key, BACK TO MENU Highlight, Menu Best Marathon, Menu Best Ultra, Menu Best Zen, RESUME Highlight, RESTART Highlight, MAIN MENU Highlight

The highlight over one choice of a panel: shown while its panel is open and its choice is the chosen one, hidden otherwise.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
panelObjectConstantNone
PER INSTANCE VARIABLES
NameTypeStarting Value
choiceNumber0
OBJECT KINDS
panelObjects with Panel State
When Created
WhenCreate
1Trigger Custom Event on Object
Custom Event
panelChoiceChanged
On Panel Choice Changed
WhenpanelChoiceChangedCustom Event
1If@self.panel.panelState.isOpen == true && @self.panel.panelState.chosen == self.choice
Then
2Set Visible
Visible
Yes
3Otherwise
4Set Visible
Visible
No

Chapter 8 finished includes all these declarations and the behavior that makes its existing menus work. Keep the prepared panel references: they expose Panel State’s fields. If rebuilding earlier chapters, Chapter 6’s panel passage supplies the declaration pack and its installation. The pack prepares declarations only; these cards give the behavior. Keep your finished choosing Logic.

The extra help Modes belong to the Main Menu you already made. Leave them in place. The pause sends panelOpened and panelClosed, so it uses the ordinary choosing responses.

Add Pause as a Button Command in its new Pause context. The card gives that Command two keys, so either can ask the well to wait. Leave that context Inactive at Start; Gameplay will activate it.

Menus needs another permission. Turn its Works While Paused switch On, so its Commands can reach the panel while the rest of play waits. Keep Play and Pause without that permission. Selecting a context for editing still doesn’t activate it.

Add countdown to Globals. Its text will read the number directly. The placement list has two groups: the countdown first, then the pause panel. Make each Object before returning to place it.

Set upWhat this chapter adds
SOUNDS (from the starter kit)
Countdown Beep
Countdown Go
Pause Chime
COMMANDS (Game Settings > Input Manager)
PauseButton
KeybindingsEscape, P
INPUT CONTEXTS (Game Settings > Input Manager)
PauseInactive at Start(new)
CommandsPause
Menus(changed)
Works While PausedOn
GLOBAL VARIABLES
$countdownNumberstarts at 0
SCENE Gameplay: PLACE THESE
ObjectXY
Ready0-345
with Z-Index = 130
Countdown045
with Z-Index = 130
Go045
with Z-Index = 130
with Per Instance Variables > Show Seconds = 0.7
with Per Instance Variables > Fade Seconds = 0.4
Pause Veil00
with Per Instance Variables > Shown Alpha = 0.6
Pause Panel00
Pause Title0-345
with Z-Index = 165
RESUME Button063
RESUME Label061.5
with Z-Index = 168
RESTART Button0-42
RESTART Label0-43.5
with Z-Index = 168
MAIN MENU Button0-147
MAIN MENU Label0-148.5
with Z-Index = 168
Pause Hint Enter Key-183.11300
Pause Hint CONFIRM-72.55298.5
with Z-Index = 166
Pause Hint Esc Key72.82300
Pause Hint RESUME166.13298.5
with Z-Index = 166
RESUME Highlight063
RESTART Highlight0-42
with Per Instance Variables > Choice = 1
MAIN MENU Highlight0-147
with Per Instance Variables > Choice = 2

9.4 A Well That Waits

The first piece has to wait for its invitation.

9.4.1 Count Down

Count Down owns the wait. It sets the opening number, keeps Play’s controls off, and starts a beat that lowers the number each second. The first beep waits for the first frame, so loading the Scene doesn’t stretch that first beat.

The count starts at 3. Each ring takes one away. While a number remains, another beep sounds; at zero, the timer stops and the invitation goes out. Nothing else needs its own countdown.

Make this Logic and attach it to Game Rules after Count Pieces. Its shared countdownSeconds keeps the starting count. Its card supplies the exact Events and Actions that turn those waiting seconds into a beginning.

Logic ComponentCount DownAttach to: Game Rules

Counts down before play: $countdown from countdownSeconds to 1, one a second, each with Countdown Beep; then Countdown Go, the play controls on, and playStarted to everyone.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
countdownSecondsNumberConstant3
When the Scene Starts
WhenScene Start
1Set Input Context Active
Input Context
Play
Active
No
2Change Variable
Variable
$countdown
Value
@self.countdownSeconds
3Start Recurring Timer
Timer Name
"countdownBegins"
First Delay (s)
0
Ring Once
Yes
On the Countdown Begins Timer
WhenRecurring TimerTimer name: countdownBegins
1Control Sound
Sound
Countdown Beep
2Start Recurring Timer
Timer Name
"countdownTick"
On the Countdown Tick Timer
WhenRecurring TimerTimer name: countdownTick
1Change Variable
Variable
$countdown
Operator
-=
Value
1
2If$countdown > 0
Then
3Control Sound
Sound
Countdown Beep
4Otherwise
5Stop Recurring Timer
Timer Name
"countdownTick"
6Control Sound
Sound
Countdown Go
7Set Input Context Active
Input Context
Play
8Trigger Custom Event
Custom Event
playStarted

9.4.2 Deal Pieces

The queue shuffles ahead. Remove nextPieceDue from When Created and send it from On Play Started instead. The bags wait, ready. Only When Created and On Play Started change here. Keep the other Events.

Logic ComponentDeal PiecesAttach to: Piece QueueAddDelete

Keeps the Queue table full of pieces from shuffled bags of seven: deals two bags at the start, takes the first piece off whenever one is dealt, and adds a bag whenever fewer than seven are left.

Attach toAny Object
DATA STRUCTURES
Deal Pieces Dataself.dealPiecesData
When the Scene Starts
WhenScene Start
1Reset Data Table
Table
Queue
When Created
WhenCreate
1Change Component Value
Component Value
self.dealPiecesData.queueLength
Value
0
2Repeat2times
Each time
3Add A Shuffled BagFunction
firstPlace
self.dealPiecesData.queueLength
4Change Component Value
Component Value
self.dealPiecesData.queueLength
Operator
+=
Value
dataCount('Piece Kinds')
5Trigger Custom Event
Custom Event
nextPieceDue
On Piece Dealt
WhenpieceDealtCustom Event
1Declare Variable
Name
placeRow
Value
0
2Change Variable
Variable
placeRow
Value
0
3WhileplaceRow < (self.dealPiecesData.queueLength - 1)
Each time
4Declare Variable
Name
placeKind
Value
data('Queue', placeRow + 1, 'piece')
5Set Data Cell
Table
Queue
Row
placeRow
Column
"piece"
Value
placeKind
6Change Variable
Variable
placeRow
Operator
+=
Value
1
7Set Data Cell
Table
Queue
Row
placeRow
Column
"piece"
8Change Component Value
Component Value
self.dealPiecesData.queueLength
Operator
-=
Value
1
9Ifself.dealPiecesData.queueLength < dataCount('Piece Kinds')
Then
10Add A Shuffled BagFunction
firstPlace
self.dealPiecesData.queueLength
11Change Component Value
Component Value
self.dealPiecesData.queueLength
Operator
+=
Value
dataCount('Piece Kinds')
12Trigger Custom Event
Custom Event
queueChanged
On Play Started
WhenplayStartedCustom Event
1Trigger Custom Event
Custom Event
nextPieceDue

9.4.3 Show Piece Crystal

Before the invitation, no falling crystal should be waiting in the middle of the screen. The new Create Event hides both the piece’s crystals and its ghost. pieceMoved will place them. Only the marked Create Event is new here. Leave the remaining Events in place; they still draw and dim the moving crystals.

Logic ComponentShow Piece CrystalAttach to: Falling Crystal, Ghost CrystalAddDelete

One crystal of the falling piece: whenever the piece moves, it goes to its cell (or, with showsLanding, to its cell in the landing row: the ghost) and shows the piece's color; it hides in the two hidden rows, and the piece's own crystals fade while it rests before locking.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
pieceObjectConstantNone
dimmedAlphaNumberConstant0.55
PER INSTANCE VARIABLES
NameTypeStarting Value
crystalNumber1
showsLandingBooleanNo
OBJECT KINDS
pieceFalling Piece
On Piece Moved
WhenpieceMovedCustom Event
1Control Tween
Which
Value
Value
self.transform.opacity
2Set Alpha
3Crystal CellFunction
Action Name
thisCrystal
kind
@self.piece.piece.kind
rotation
@self.piece.piece.rotation
crystal
self.crystal
4Declare Variable
Name
cellColumn
Value
@self.piece.piece.column + thisCrystal.column
5Declare Variable
Name
cellRow
Value
@self.piece.piece.row + thisCrystal.row
6Ifself.showsLanding == true
Then
7Change Variable
Variable
cellRow
Value
@self.piece.piece.landingRow + thisCrystal.row
8Cell MiddleFunction
Action Name
thisCellMiddle
column
cellColumn
row
cellRow
9Set Position
X
thisCellMiddle.x
Y
thisCellMiddle.y
10Set Frame
Frame
data('Piece Kinds', @self.piece.piece.kind - 1, 'frame')
11IfcellRow < data('Well Layout', 0, 'visibleRows')
Then
12Set Visible
Visible
Yes
13Otherwise
14Set Visible
Visible
No
On Lock Delay Started
WhenlockDelayStartedCustom Event
1Ifself.showsLanding == false
Then
2Piece Fits HereFunction
Action Name
roomBelowDimmingPiece
piece
@self.piece
columnShift
0
rowShift
-1
3IfroomBelowDimmingPiece.value == false
Then
4Tween
Value
self.transform.opacity
Target
@self.dimmedAlpha
Duration
@self.piece.piece.lockDelaySeconds
On Game Over
WhengameOverCustom Event
1Set Visible
Visible
No
When Created
WhenCreate
1Set Visible
Visible
No

The game now has a beginning it can wait for. Give that wait its words.

9.5 READY, Then GO!

Now the wait has words that the player can watch above the empty glass well.

9.5.1 Show During Countdown

READY gives the changing number a place to belong. Their shared Logic keeps that little announcement together, until GO! takes its place. The number follows countdown through its text template; it needs no updating Event.

Logic ComponentShow During CountdownAttach to: Ready, Countdown

A text of the countdown (READY, the number): shown from the start of the game until play begins (playStarted).

Attach toAny Object
When Created
WhenCreate
1Set Visible
Visible
Yes
On Play Started
WhenplayStartedCustom Event
1Set Visible
Visible
No
ObjectReady
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorTop Center
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 48
Text / UI
TextREADY
FontNunito
Font Size51
EmphasisBold
Color#BFEAFF
Letter Spacing1.5
AlignmentCenter
Text BoundsWrap to Width
Transform > Size X450
Logic
Show During Countdown
ObjectCountdown
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 48
Text / UI
Text{$countdown}
FontNunito
Font Size165
EmphasisBold
Letter Spacing1.5
AlignmentCenter
Text BoundsWrap to Width
Transform > Size X450
Logic
Show During Countdown

9.5.2 Show Go

The last beep becomes a different chime. Show Go asks the familiar Fade Out Message to reveal GO!, then let it fade. Its short life belongs to that placement, leaving other announcements alone.

Logic ComponentShow GoAttach to: Go

Shows "GO!" when play begins (Fade Out Message on the same text hides it again).

Attach toAny Object
On Play Started
WhenplayStartedCustom Event
1Trigger Custom Event on Object
Custom Event
messageShown
ObjectGo
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 48
Text / UI
TextGO!
FontNunito
Font Size165
EmphasisBold
Color#FFF3B0
Letter Spacing1.5
AlignmentCenter
Text BoundsWrap to Width
Transform > Size X600
Logic
Fade Out Message
Show Go

Place Ready, Countdown and Go from the first group in Set up. Keep their anchors as well as their offsets. GO! stays for 0.7 seconds and fades over its final 0.4 seconds, a brief welcome to the falling piece.

Wait to test this beginning until Open Results is updated below. Play still has a competing activation. The clocks also start early. We’ll remove that competing activation and give the clocks the same invitation.

9.6 Time Belongs to Play

The countdown shouldn’t spend any of Ultra’s time.

9.6.1 Time The Game

At Scene Start the clock is held at zero. playStarted begins the first live stretch. Later, pausing stores that stretch in clockHeld and turns clockOn off. Resuming starts a new stretch and keeps the stored time, and the clock adds them together. Changing clockStart marks the new beginning; it leaves clockHeld alone.

The first pause needs care. You can pause before the count finishes, when no playing time exists yet. The empty Clock Not Running Modes protect that beginning. Make both responses for each pause Event before choosing them in On Play Started.

Keep Scoring State on Game Rules named scoring. This Logic still reads that same component; its ending calculation stays in place. Change the marked Scene Start Actions and add the new listeners from the card.

Logic ComponentTime The GameAttach to: Game RulesAddDelete

Times the game: the clock the stats panel shows ($clockStart, $clockOn, $clockHeld: the time played is ($playTime - $clockStart) x $clockOn + $clockHeld, standing still while the game is paused and after the end) and the time played kept for the results.

Attach toAny Object
DATA STRUCTURES
Scoring Stateself.scoring
When the Scene Starts
WhenScene Start
1Change Variable
Variable
$clockStart
Value
$playTime
1Change Variable
Variable
$clockOn
Value
0
Value
1
2Change Variable
Variable
$clockHeld
Value
0
On Game Over
WhengameOverCustom Event
1Time PlayedFunction
Action Name
playedAtTheEnd
2Change Component Value
Component Value
self.scoring.playedSeconds
Value
playedAtTheEnd.value
3Ifdata('Modes', global('mode') - 1, 'timeLimit') > 0 && self.scoring.playedSeconds > data('Modes', global('mode') - 1, 'timeLimit')
Then
4Change Component Value
Component Value
self.scoring.playedSeconds
Value
data('Modes', global('mode') - 1, 'timeLimit')
5Change Variable
Variable
$clockHeld
Value
self.scoring.playedSeconds
6Change Variable
Variable
$clockOn
Value
0
On Play Started
WhenplayStartedCustom Event
1Change Variable
Variable
$clockStart
Value
$playTime
2Change Variable
Variable
$clockOn
Value
1
3Switch Mode
Event
On Game Paused
Mode
Stop The Clock
4Switch Mode
Event
On Game Resumed
Mode
Start The Clock Again
On Game Paused
WhengamePausedCustom Event
ModeClock Not Running (Starting Mode)
(no Actions)
On Game Paused
WhengamePausedCustom Event
ModeStop The Clock
1Time PlayedFunction
Action Name
playedBeforeThePause
2Change Variable
Variable
$clockHeld
Value
playedBeforeThePause.value
3Change Variable
Variable
$clockOn
Value
0
On Game Resumed
WhengameResumedCustom Event
ModeClock Not Running (Starting Mode)
(no Actions)
On Game Resumed
WhengameResumedCustom Event
ModeStart The Clock Again
1Change Variable
Variable
$clockStart
Value
$playTime
2Change Variable
Variable
$clockOn
Value
1

9.6.2 Finish The Mode

Ultra’s deadline needs the same beginning as its visible clock. Its Actions stay. Change the starting Event to playStarted, so the deadline begins with the first piece. Pause holds that timer too.

Logic ComponentFinish The ModeAttach to: Game RulesAddDelete

Finishes the mode at its goal lines or when its time limit is up (Modes): Game Over, Victory Jingle, Crystal Fountain and Sparkle Shower, modeFinished and gameOver.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
wellObjectConstantNone
sparkleCountNumberConstant80
fountainCountNumberConstant120
fountainRowNumberConstant-0.813
OBJECT KINDS
wellGlass Well
On Play Started
WhenplayStartedCustom Event
When the Scene Starts
WhenScene Start
1Ifdata('Modes', global('mode') - 1, 'timeLimit') > 0
Then
2Start Recurring Timer
Timer Name
"timeUp"
Repeat Every (s)
data('Modes', global('mode') - 1, 'timeLimit')
Ring Once
Yes
On Lines Cleared
WhenlinesClearedCustom Event
1Ifdata('Modes', global('mode') - 1, 'goalLines') > 0 && $lines >= data('Modes', global('mode') - 1, 'goalLines')
Then
2Trigger Custom Event on Object
Custom Event
goalReached
On the Time Up Timer
WhenRecurring TimerTimer name: timeUp
1Trigger Custom Event on Object
Custom Event
goalReached
On Goal Reached
WhengoalReachedCustom Event
1Trigger Custom Event on Object
Applies to
@self.well
Custom Event
settleClear
2Set Game State
Game State
Game Over
3Control Sound
Sound
Victory Jingle
4Cell MiddleFunction
Action Name
finishMiddle
column
(data('Well Layout', 0, 'columns') - 1) / 2
row
(data('Well Layout', 0, 'visibleRows') - 1) / 2
5Burst Particles
Particles
Sparkle Shower
Position Relative To
World
X
finishMiddle.x
Y
finishMiddle.y
Count
@self.sparkleCount
Z Index Offset
7
6Cell MiddleFunction
Action Name
finishFloor
column
(data('Well Layout', 0, 'columns') - 1) / 2
row
@self.fountainRow
7Burst Particles
Particles
Crystal Fountain
Position Relative To
World
X
finishFloor.x
Y
finishFloor.y
Count
@self.fountainCount
Z Index Offset
7
8Trigger Custom Event
Custom Event
modeFinished
9Trigger Custom Event
Custom Event
gameOver
On Game Over
WhengameOverCustom Event
1Set Logic State
Logic Component
Finish The Mode
State
Disable

The number on the panel and the deadline now count the same play. Neither spends the countdown.

9.7 A Panel Over the Well

The waiting piece remains where you left it, behind a panel with three ways onward.

9.7.1 Show While Paused

The veil leaves the well faintly visible behind glass. The title and buttons stay bright. Show While Paused gives them one shared opening and closing, with shownAlpha deciding how much each picture shows.

Declare shownAlpha as the Per Instance Variable on its card. It starts at 1. The veil’s placement changes only its own value, so the words keep their full brightness.

Logic ComponentShow While PausedAttach to: Pause Veil, Pause Panel, Pause Title, RESUME Button, RESUME Label, RESTART Button, RESTART Label, MAIN MENU Button, MAIN MENU Label, Pause Hint Enter Key, Pause Hint CONFIRM, Pause Hint Esc Key, Pause Hint RESUME

One part of the pause panel: hidden while the game is played, shown at shownAlpha while it is paused.

Attach toAny Object
PER INSTANCE VARIABLES
NameTypeStarting Value
shownAlphaNumber1
When Created
WhenCreate
1Set Visible
Visible
No
On Game Paused
WhengamePausedCustom Event
1Set Alpha
Alpha
self.shownAlpha
2Set Visible
Visible
Yes
On Game Resumed
WhengameResumedCustom Event
1Set Visible
Visible
No
ObjectPause Veil
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 128
Sprite
Scene Depth Draw Order160
SpriteWhite Pixel
Tint#03213F
Transform > SizeX 1920, Y 1080
Logic
Show While Paused
ObjectPause Panel
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 128
Sprite
Scene Depth Draw Order161
SpriteInfo Glass Panel
Transform > SizeX 690, Y 570
Data Structure
Data StructurePanel State
Logic
Show While Paused
Panel Choices
ObjectPause Title
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorTop Center
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 48
Text / UI
TextPAUSED
FontNunito
Font Size78
EmphasisBold
Letter Spacing1.5
AlignmentCenter
Text BoundsWrap to Width
Transform > Size X600
Logic
Show While Paused

Give Pause Panel one plain Panel State component. Keep its component name as Panel State, whose expression name is panelState. Panel Choices goes second. Its existing choosing work will serve this new panel.

Place Pause Veil, Pause Panel and Pause Title from Set up. The veil’s Shown Alpha is 0.6, enough to leave the stopped well behind it. The pictures stay hidden for now.

9.7.2 Resume The Game

Resuming should return your keys to the well. This Function closes the menu’s input context and ends the engine’s pause. Myth then announces gameResumed to the waiting listeners.

Make the Function before building the responses that call it. Its Actions give both Escape and the RESUME button the same return.

FunctionResume The Game

Goes on from the pause: the menu controls go off and Set Game Paused ends the pause (the engine then sends gameResumed).

ACTIONS
1Set Input Context Active
Input Context
Menus
Active
false
2Set Game Paused
Paused (1 pause / 0 resume)
0

9.7.3 Pause The Game

Escape has two jobs now. During play it opens the panel; while paused it resumes. Separate input contexts keep those jobs apart, and Back’s Modes keep this Logic silent outside the pause.

Declare pausePanel as a Shared Variable: Type Object, Kind Constant. The card permits Objects with Panel State; choose the concrete Pause Panel as Object Kind here. That broader card wording describes which Objects qualify. Pause Panel is your editor choice; this Logic only sends it messages. Choose its value on Game Rules later.

Make both Back Modes before the Switch Mode Actions. While Playing starts empty. gamePaused chooses Resume and opens the panel, while gameResumed closes it and restores the empty response. The ending disables Pause.

Logic ComponentPause The GameAttach to: Game Rules

Pauses the game with Set Game Paused when Pause is pressed (during the countdown or play, not after the end), with Pause Chime and the menu controls; Back resumes it.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
pausePanelObjectConstantNone
OBJECT KINDS
pausePanelObjects with Panel State
When the Scene Starts
WhenScene Start
1Set Input Context Active
Input Context
Pause
When Pause Is Pressed
WhenCommand PressedCommand: Pause
1Set Game Paused
2Control Sound
Sound
Pause Chime
3Set Input Context Active
Input Context
Menus
On Game Paused
WhengamePausedCustom Event
1Switch Mode
Event
When Back Is Pressed
Mode
Resume
2Trigger Custom Event on Object
Applies to
@self.pausePanel
Custom Event
panelOpened
On Game Resumed
WhengameResumedCustom Event
1Switch Mode
Event
When Back Is Pressed
Mode
While Playing
2Trigger Custom Event on Object
Applies to
@self.pausePanel
Custom Event
panelClosed
When Back Is Pressed
WhenCommand PressedCommand: Back
ModeWhile Playing (Starting Mode)
(no Actions)
When Back Is Pressed
WhenCommand PressedCommand: Back
ModeResume
1Control Sound
Sound
Menu Select
2Resume The GameFunction
On Game Over
WhengameOverCustom Event
1Set Input Context Active
Input Context
Pause
Active
No

Attach Pause The Game after Count Down on Game Rules. Set pausePanel to Pause Panel in its Shared Variables. Keep its other references and components in place; the Changes card shows what joins them.

ObjectGame RulesAddDelete
Data Structure
Data StructureScoring State
Data Structure
From LogicCount Level
Data StructureCount Level Data
Logic
Count Lines
Score Points
Count Combo
Count Level
Keep Bests
Check Top Out
Open Results
Count Clears
Time The Game
Game Music
Finish The Mode
Start Afresh
Count Pieces
Count Down
Pause The Game
Shared Variables
wellGlass Well
pieceFalling Piece
resultsPanelResults Panel
pausePanelPause Panel

9.7.4 Open Results

Both panels use Back, but only one should answer it. Open Results now starts with an empty While The Results Are Closed Mode. The results-delay timer selects Back To The Menu only when those results open.

Make both Modes before changing the timer’s Switch Mode. Remove its old Scene Start activation of Play too. Count Down now owns that opening, so the results Logic must leave it waiting.

Logic ComponentOpen ResultsAttach to: Game RulesAddDelete

Opens the results panel resultsDelaySeconds after the game ends (resultsShown).

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
resultsDelaySecondsNumberConstant1.6
resultsPanelObjectConstantNone
OBJECT KINDS
resultsPanelObjects with Panel State
When the Scene Starts
WhenScene Start
1Set Input Context Active
Input Context
Play
1Set Input Context Active
Input Context
Menus
Active
No
On Game Over
WhengameOverCustom Event
1Start Recurring Timer
Timer Name
"resultsDelay"
Repeat Every (s)
@self.resultsDelaySeconds
Ring Once
Yes
2Set Input Context Active
Input Context
Play
Active
No
On the Results Delay Timer
WhenRecurring TimerTimer name: resultsDelay
1Switch Mode
Event
When Back Is Pressed
Mode
Back To The Menu
2Set Input Context Active
Input Context
Menus
3Set Input Context Active
Input Context
Play
Active
No
4Trigger Custom Event on Object
Applies to
@self.resultsPanel
Custom Event
panelOpened
5Trigger Custom Event
Custom Event
resultsShown
When Back Is Pressed
WhenCommand PressedCommand: Back
ModeBack To The Menu
1Control Sound
Sound
Menu Back
2Back To The MenuFunction
When Back Is Pressed
WhenCommand PressedCommand: Back
ModeWhile The Results Are Closed (Starting Mode)
(no Actions)

Escape can now open and close the pause. The panel still needs its choices.

9.8 Three Ways Onward

The first choice returns to the piece exactly where it waited.

9.8.1 Go On Playing

RESUME uses the same Function as Back. Panel Choice supplies choiceRun when the selected button is confirmed or clicked. Go On Playing gives that choice its meaning.

Logic ComponentGo On PlayingAttach to: RESUME Button

What the RESUME choice does: goes on from the pause (Resume The Game).

Attach toAny Object
On Choice Run
WhenchoiceRunCustom Event
1Resume The GameFunction
ObjectRESUME Button
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 128
Sprite
Scene Depth Draw Order166
SpriteAero Button
Transform > SizeX 492, Y 86.4
Collider
CollisionSensor
Shape and Transform > SizeX 468, Y 65.4
Logic
Show While Paused
Panel Choice
Go On Playing
Shared Variables
panelPause Panel
ObjectRESUME Label
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 48
Text / UI
TextRESUME
FontNunito
Font Size42
EmphasisBold
Letter Spacing1.5
AlignmentCenter
Text BoundsWrap to Width
Transform > Size X492
Logic
Show While Paused

Reuse the prepared Panel Choice declaration from earlier chapters. Point panel at Pause Panel, whose existing choosing Logic will keep these new buttons together. RESUME keeps choice at its starting value, while the later buttons choose their own numbers. Their Collider sensors hear the mouse beneath the labels.

9.8.2 Restart The Mode

The next countdown needs a running Scene. End the pause first. Then the new Scene can count before inviting its first piece. Your chosen mode stays the same.

Logic ComponentRestart The ModeAttach to: RESTART Button

What the RESTART choice does: starts the same mode again from the pause: ends the pause, then starts a new game (Start A New Game).

Attach toAny Object
On Choice Run
WhenchoiceRunCustom Event
1Set Game Paused
Paused (1 pause / 0 resume)
0
2Start A New GameFunction
ObjectRESTART Button
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 128
Sprite
Scene Depth Draw Order166
SpriteAero Button
Transform > SizeX 492, Y 86.4
Collider
CollisionSensor
Shape and Transform > SizeX 468, Y 65.4
Logic
Show While Paused
Panel Choice
Restart The Mode
Shared Variables
panelPause Panel
choice1
ObjectRESTART Label
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 48
Text / UI
TextRESTART
FontNunito
Font Size42
EmphasisBold
Letter Spacing1.5
AlignmentCenter
Text BoundsWrap to Width
Transform > Size X492
Logic
Show While Paused

9.8.3 Leave For The Menu

MAIN MENU returns to the choices over the sky. Before leaving, settle any clear that was waiting beneath the pause. That reward is yours.

Declare well with Type Object, Kind Constant and Object Kind Glass Well. Set that reference to Glass Well on MAIN MENU Button after attaching the Logic. It gives settleClear the well to finish.

gameLeft announces the departure before the pause ends and the Scene changes. Zen will listen here. Other modes keep the completion and loss rules you built before.

Logic ComponentLeave For The MenuAttach to: MAIN MENU Button

What the MAIN MENU choice of the pause does: leaves the game: ends the pause, then goes back to the Main Menu (Back To The Menu).

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
wellObjectConstantNone
OBJECT KINDS
wellGlass Well
On Choice Run
WhenchoiceRunCustom Event
1Trigger Custom Event on Object
Applies to
@self.well
Custom Event
settleClear
2Trigger Custom Event
Custom Event
gameLeft
3Set Game Paused
Paused (1 pause / 0 resume)
0
4Back To The MenuFunction
ObjectMAIN MENU Button
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 128
Sprite
Scene Depth Draw Order166
SpriteAero Button
Transform > SizeX 492, Y 86.4
Collider
CollisionSensor
Shape and Transform > SizeX 468, Y 65.4
Logic
Show While Paused
Panel Choice
Leave For The Menu
Shared Variables
wellGlass Well
panelPause Panel
choice2
ObjectMAIN MENU Label
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 48
Text / UI
TextMAIN MENU
FontNunito
Font Size42
EmphasisBold
Letter Spacing1.5
AlignmentCenter
Text BoundsWrap to Width
Transform > Size X492
Logic
Show While Paused

9.8.4 Keep Bests

Zen’s well never has to end. Its record therefore needs this deliberate departure. Move the Keep A Zen Best Mode from On Game Over to On Game Left, keeping its score comparison and persistent write together.

On Game Left starts in the empty Nothing To Keep Mode. Make that Mode too, then update When Created to select Keep A Zen Best for Zen. The other modes leave this Event silent. No new-best notice is needed on a panel you’re leaving.

Logic ComponentKeep BestsAttach to: Game RulesAddDelete

Each mode's best: reads the four kept bests when a game begins (Read The Bests) and keeps a new best of the mode played: the highest score (Marathon and Ultra when the game ends, Zen when it is left) or the fastest finished time (Sprint 40).

Attach toAny Object
DATA STRUCTURES
Scoring Stateself.scoring
When the Scene Starts
WhenScene Start
1Read The BestsFunction
When Created
WhenCreate
1Ifdata('Modes', global('mode') - 1, 'bestKey') == "bestMarathon"
Then
2Switch Mode
Event
On Game Over
Mode
Keep A Marathon Best
3Ifdata('Modes', global('mode') - 1, 'bestKey') == "bestSprint"
Then
4Switch Mode
Event
On Mode Finished
Mode
Keep A Sprint Best
5Ifdata('Modes', global('mode') - 1, 'bestKey') == "bestUltra"
Then
6Switch Mode
Event
On Game Over
Mode
Keep An Ultra Best
7Ifdata('Modes', global('mode') - 1, 'bestKey') == "bestZen"
Then
8Switch Mode
Event
On Game Left
Event
On Game Over
Mode
Keep A Zen Best
On Game Over
WhengameOverCustom Event
ModeKeep A Marathon Best
1If$score > $bestMarathonScore
Then
2Change Variable
Variable
$bestMarathonScore
Value
$score
3Save Persistent Value
Action Name
bestMarathonWrite
Key
"bestMarathon"
Value
global('bestMarathonScore')
4Change Component Value
Component Value
self.scoring.isNewBest
Value
true
On Game Over
WhengameOverCustom Event
ModeKeep An Ultra Best
1If$score > $bestUltraScore
Then
2Change Variable
Variable
$bestUltraScore
Value
$score
3Save Persistent Value
Action Name
bestUltraWrite
Key
"bestUltra"
Value
global('bestUltraScore')
4Change Component Value
Component Value
self.scoring.isNewBest
Value
true
On Game Over
WhengameOverCustom Event
ModeKeep A Zen Best
1If$score > $bestZenScore
Then
2Change Variable
Variable
$bestZenScore
Value
$score
3Save Persistent Value
Action Name
bestZenWrite
Key
"bestZen"
Value
global('bestZenScore')
4Change Component Value
Component Value
self.scoring.isNewBest
Value
true
On Mode Finished
WhenmodeFinishedCustom Event
ModeKeep A Sprint Best
1Time PlayedFunction
Action Name
sprintTime
2If$bestSprintTime == 0 || sprintTime.value < $bestSprintTime
Then
3Change Variable
Variable
$bestSprintTime
Value
sprintTime.value
4Save Persistent Value
Action Name
bestSprintWrite
Key
"bestSprint"
Value
global('bestSprintTime')
5Change Component Value
Component Value
self.scoring.isNewBest
Value
true
On Game Left
WhengameLeftCustom Event
ModeKeep A Zen Best
1If$score > $bestZenScore
Then
2Change Variable
Variable
$bestZenScore
Value
$score
3Save Persistent Value
Action Name
bestZenWrite
Key
"bestZen"
Value
global('bestZenScore')
WhenOn Game Over(the same Event)
ModeNo Score Best (Starting Mode) (no blocks: it does nothing)
WhenOn Mode Finished(the same Event)
ModeNo Time Best (Starting Mode) (no blocks: it does nothing)
WhenOn Game Left(the same Event)
ModeNothing To Keep (Starting Mode) (no blocks: it does nothing)

Place each button and label from the setup list. The footer has familiar key pictures and words, with their own positions beside the screen edge. They share Show While Paused, but their Bottom Center anchors belong to the screen edge.

ObjectPause Hint Enter Key
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorBottom Center
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 128
Sprite
Scene Depth Draw Order165
SpriteKey Enter
Transform > SizeX 77.52, Y 40.8
Logic
Show While Paused
ObjectPause Hint CONFIRM
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorBottom Center
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 48
Text / UI
TextCONFIRM
FontNunito
Font Size24
EmphasisBold
Letter Spacing1.5
AlignmentCenter
Text BoundsWrap to Width
Transform > Size X144
Logic
Show While Paused
ObjectPause Hint Esc Key
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorBottom Center
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 128
Sprite
Scene Depth Draw Order165
SpriteKey Esc
Transform > SizeX 57.12, Y 40.8
Logic
Show While Paused
ObjectPause Hint RESUME
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorBottom Center
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 48
Text / UI
TextRESUME
FontNunito
Font Size24
EmphasisBold
Letter Spacing1.5
AlignmentCenter
Text BoundsWrap to Width
Transform > Size X130.5
Logic
Show While Paused

The brighter button pictures reuse Show When Panel Choice. Set panel to Pause Panel on each brighter picture Object. Compare choice on each placement: it matches the button below, while the Sprite and depth stay the same.

ObjectRESUME Highlight
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 128
Sprite
Scene Depth Draw Order167
SpriteAero Button Lit
Transform > SizeX 492, Y 86.4
Logic
Show When Panel Choice
Shared Variables
panelPause Panel
ObjectRESTART Highlight
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 128
Sprite
Scene Depth Draw Order167
SpriteAero Button Lit
Transform > SizeX 492, Y 86.4
Logic
Show When Panel Choice
Shared Variables
panelPause Panel
ObjectMAIN MENU Highlight
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 128
Sprite
Scene Depth Draw Order167
SpriteAero Button Lit
Transform > SizeX 492, Y 86.4
Logic
Show When Panel Choice
Shared Variables
panelPause Panel

Finish the setup list with those bright pictures. Their placement choices select the glow, while each button’s Shared Variable selects its action. Keep both sets matched.

The panel has its ways onward. A held key needs one last kindness before returning to play.

9.9 Let the Keys Rest Too

A key may be released during the pause, when its ordinary listening context is asleep.

9.9.1 Read The Move Keys

An arrow held before pausing shouldn’t carry on moving after you return. gameResumed clears that memory. Your next press can make a fresh choice. Add On Game Resumed; leave the existing press and release Events in place.

Logic ComponentRead The Move KeysAttach to: Falling PieceAddDelete

Hears Move Left and Move Right: keeps the piece's moveDirection (the key pressed last wins) and asks for one move (moveOnce) at a press and again and again while the key is held (auto-repeat). It stays on between pieces, so a key let go then is heard too.

Attach toAny Object
DATA STRUCTURES
Pieceself.piece
Read The Move Keys Dataself.readTheMoveKeysData
SHARED VARIABLES
NameTypeKindStarting Value
autoRepeatDelaySecondsNumberConstant0.15
autoRepeatSecondsNumberConstant0.03
When Move Left Is Pressed
WhenCommand PressedCommand: Move Left
1Change Component Value
Component Value
self.readTheMoveKeysData.isLeftHeld
Value
true
2Change Component Value
Component Value
self.piece.moveDirection
Value
-1
3Trigger Custom Event on Object
Custom Event
moveOnce
4Start Recurring Timer
Timer Name
"autoRepeat"
Repeat Every (s)
@self.autoRepeatSeconds
First Delay (s)
@self.autoRepeatDelaySeconds
When Move Right Is Pressed
WhenCommand PressedCommand: Move Right
1Change Component Value
Component Value
self.readTheMoveKeysData.isRightHeld
Value
true
2Change Component Value
Component Value
self.piece.moveDirection
Value
1
3Trigger Custom Event on Object
Custom Event
moveOnce
4Start Recurring Timer
Timer Name
"autoRepeat"
Repeat Every (s)
@self.autoRepeatSeconds
First Delay (s)
@self.autoRepeatDelaySeconds
When Move Left Is Released
WhenCommand ReleasedCommand: Move Left
1Change Component Value
Component Value
self.readTheMoveKeysData.isLeftHeld
Value
false
2Ifself.piece.moveDirection == (-1) && self.readTheMoveKeysData.isRightHeld == true
Then
3Change Component Value
Component Value
self.piece.moveDirection
Value
1
4Start Recurring Timer
Timer Name
"autoRepeat"
Repeat Every (s)
@self.autoRepeatSeconds
First Delay (s)
@self.autoRepeatDelaySeconds
5Otherwise
6Ifself.piece.moveDirection == (-1)
Then
7Change Component Value
Component Value
self.piece.moveDirection
Value
0
8Stop Recurring Timer
Timer Name
"autoRepeat"
When Move Right Is Released
WhenCommand ReleasedCommand: Move Right
1Change Component Value
Component Value
self.readTheMoveKeysData.isRightHeld
Value
false
2Ifself.piece.moveDirection == 1 && self.readTheMoveKeysData.isLeftHeld == true
Then
3Change Component Value
Component Value
self.piece.moveDirection
Value
-1
4Start Recurring Timer
Timer Name
"autoRepeat"
Repeat Every (s)
@self.autoRepeatSeconds
First Delay (s)
@self.autoRepeatDelaySeconds
5Otherwise
6Ifself.piece.moveDirection == 1
Then
7Change Component Value
Component Value
self.piece.moveDirection
Value
0
8Stop Recurring Timer
Timer Name
"autoRepeat"
On the Auto Repeat Timer
WhenRecurring TimerTimer name: autoRepeat
1Trigger Custom Event on Object
Custom Event
moveOnce
On Game Resumed
WhengameResumedCustom Event
1Change Component Value
Component Value
self.readTheMoveKeysData.isLeftHeld
Value
false
2Change Component Value
Component Value
self.readTheMoveKeysData.isRightHeld
Value
false
3Change Component Value
Component Value
self.piece.moveDirection
Value
0
4Stop Recurring Timer
Timer Name
"autoRepeat"

9.9.2 Soft Drop Piece

Down needs that kindness too, because it can be released while ordinary input is asleep. If soft drop was held, gameResumed asks for fallNormally. Gravity returns to its ordinary pace until you press Down again.

Logic ComponentSoft Drop PieceAttach to: Falling PieceAddDelete

While Soft Drop is held, the falling piece falls speedUp times faster (at least one row every slowestSeconds); letting go returns it to its normal fall.

Attach toAny Object
DATA STRUCTURES
Pieceself.piece
Soft Drop Piece Dataself.softDropPieceData
SHARED VARIABLES
NameTypeKindStarting Value
speedUpNumberConstant20
slowestSecondsNumberConstant0.05
When Soft Drop Is Pressed
WhenCommand PressedCommand: Soft Drop
1Change Component Value
Component Value
self.softDropPieceData.isSoftDropping
Value
true
2Trigger Custom Event on Object
Custom Event
fallFaster
When Soft Drop Is Released
WhenCommand ReleasedCommand: Soft Drop
1Trigger Custom Event on Object
Custom Event
fallNormally
On Fall Normally
WhenfallNormallyCustom Event
1Change Component Value
Component Value
self.softDropPieceData.isSoftDropping
Value
false
2Start Recurring Timer
Timer Name
"gravity"
Repeat Every (s)
self.piece.fallSeconds
On Spawn Piece
WhenspawnPieceCustom Event
1Ifself.softDropPieceData.isSoftDropping == true
Then
2Trigger Custom Event on Object
Custom Event
fallFaster
On Fall Faster
WhenfallFasterCustom Event
1Declare Variable
Name
fasterSeconds
Value
0
2Change Variable
Variable
fasterSeconds
Value
self.piece.fallSeconds / @self.speedUp
3IffasterSeconds > @self.slowestSeconds
Then
4Change Variable
Variable
fasterSeconds
Value
@self.slowestSeconds
5Start Recurring Timer
Timer Name
"gravity"
Repeat Every (s)
fasterSeconds
On Piece Fell
WhenpieceFellCustom Event
1Ifself.softDropPieceData.isSoftDropping == true
Then
2Trigger Custom Event
Custom Event
softDropRow
On Game Resumed
WhengameResumedCustom Event
1Ifself.softDropPieceData.isSoftDropping == true
Then
2Trigger Custom Event on Object
Custom Event
fallNormally

Run your game again. The piece waits when you ask, and moves when you choose.

9.10 Play It!

  • Enter Gameplay from the menu. Watch READY and the count, with no falling piece before GO!. The elapsed clock begins with play.
  • Pause during the countdown, wait, then resume with Escape. The count continues.
  • Hold an arrow, pause with P, release the arrow, then resume. It stays at that column. Repeat that hold, pause and release with Down, watching whether gravity returns at its ordinary pace.
  • Pause during Ultra. Compare TIME LEFT before and after waiting; the pause spends none of its remaining time.
  • Move through RESUME, RESTART and MAIN MENU with Up and Down. The glow wraps, Enter runs the choice, and reopening selects RESUME.
  • Hover each pause button and click it. RESTART returns to READY in the same mode; MAIN MENU returns to the six choices.
  • In Zen, earn a score above its saved best, pause, and choose MAIN MENU. Its PERSONAL BEST now shows that score. Start again and compare the saved best beside the well with the record you left on the menu.
  • Top out in a score mode. The ending keeps Pause closed, even when Escape is pressed before its results arrive. Once results appear, Back returns to the Main Menu.

9.11 How It Works

The Scene arrives. The count finishes. One message starts the piece and the clocks together. A pause holds their work while its own controls keep listening.

Resuming keeps this attempt. Restarting begins again from the countdown, while leaving tells the record before changing Scenes. Those different intentions have different messages, even when the same panel offers them together.

9.12 If It Didn’t Work

The first piece arrives under READY? Check Deal Pieces for the removed nextPieceDue in When Created. Move the invitation to On Play Started, where the finished count can reach it. Let the count invite the piece.

The pause opens but its keys do nothing? Compare the Menus context’s Works While Paused switch with the new setting on the setup card. Pause The Game also activates that context when pausing. Restore both settings and resume.

The clock includes the countdown? Compare Scene Start with On Play Started in Time The Game. Their jobs differ. Restore those separate beginnings and watch another count.

Escape leaves the waiting piece behind? Check Open Results starts Back in While The Results Are Closed. Its timer makes the switch later. Restore the empty starting response, then pause during play and use Escape to resume that same piece.

The panel opens without a glow? Compare panel on the buttons and bright pictures with Pause Panel. Keep the existing prepared declarations. Then check the placement’s choice against its button and reopen the panel.

Zen’s best disappears after leaving? Look in Keep Bests, at When Created and its Zen Switch Mode. It chooses On Game Left’s saving Mode. Leave For The Menu must send gameLeft before changing Scenes. Restore those connections, earn a higher score, and return through MAIN MENU again.

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

9.13 Challenge

What would your well offer while it waits? Try your own countdown words, a different pause layout, or another choice you’d like to build. Keep a working copy beside the experiment. The next game can begin with your idea.

In the first chapter, the well was an empty glass box. Now it catches crystals, shatters lines, keeps your records and waits for your return. Play it from your Title screen. This is the game you built.

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