Build a GameCreating Pitch Shot

Appendix A — Logic Reference

Every Logic Component and Function in Pitch Shot, as it is in the finished game. Each entry stands on its own: read what it does, see what it needs, and build it from its card into your own game. A card’s Shared Variables and Per Instance Variables are the values you can change. A Shared Variable holds one value for the whole Object, under Variables in its Properties. A Per Instance Variable holds one for each placement in the Scene.

A.1 Backdrop Of The Place

Built in Chapter 1, A Stage Stands.

Logic ComponentBackdrop Of The PlaceAttach to: Backdrop

Shows the backdrop of the place of the stage being played: the Sprite its row of the Places table names.

Attach toAny Object
When Created
WhenCreate
1Declare Variable
Name
placeRow
Value
0
2Change Variable
Variable
placeRow
Value
dataFind("Places", "name", data("Stages", $stage - 1, "place"))
3Check Data Row Exists
Action Name
placeFound
Table
Places
Row
placeRow
4IfplaceFound.value == true
Then
5Set Sprite
Sprite
data("Places", placeRow, "backdrop")

A.2 Bob While Waiting

Built in Chapter 1, A Stage Stands.

Logic ComponentBob While WaitingAttach to: Singing Note

Moves this singing note gently up and down around where it was placed, each note starting at its own moment.

Attach toAny Object
DATA STRUCTURES
Note Stateself.noteState
SHARED VARIABLES
NameTypeKindStarting Value
bobMetersNumberConstant0.03
secondsPerSwingNumberConstant1.43
When Created
WhenCreate
1Change Component Value
Component Value
self.noteState.homeY
Value
self.transform.position.y
2Generate Random Number
Action Name
startOffset
Minimum
0
Maximum
1
3Change Component Value
Component Value
self.noteState.startDelay
Value
startOffset.value * @self.secondsPerSwing
4If$calmMotion == false
Then
5Start Recurring Timer
Timer Name
"bob"
Repeat Every (s)
@self.secondsPerSwing
First Delay (s)
self.noteState.startDelay
On the Bob Timer
WhenRecurring TimerTimer name: bob
1Tween
Value
self.transform.position.y
Target
self.noteState.homeY + @self.bobMeters * self.noteState.swingDirection
Duration
@self.secondsPerSwing
Ease
Quad in Out
2Change Component Value
Component Value
self.noteState.swingDirection
Value
-self.noteState.swingDirection
On Variable Changed · Calm Motion
WhenVariable ChangedGlobal Variable: calmMotion
1If$calmMotion == true
Then
2Stop Recurring Timer
Timer Name
"bob"
3Control Tween
Which
Value
Value
self.transform.position.y
4Set Position
X
self.transform.position.x
Y
self.noteState.homeY
5Otherwise
6Start Recurring Timer
Timer Name
"bob"
Repeat Every (s)
@self.secondsPerSwing
First Delay (s)
self.noteState.startDelay

A.3 Build A Floor (Function)

Built in Chapter 1, A Stage Stands.

FunctionBuild A Floor

Builds one floor of a tower from its material (a row of the Materials table): a support at each side, supportSpread from the middle of the tower, and a plank across them, standing on floorBottom (meters).

PARAMETERS
NameTypeStarts at
builderObject
towerNumber0
towerXNumber0
floorBottomNumber0
materialTextwood
floorHeightNumber1.34
supportSpreadNumber0.94
ACTIONS
1Declare Variable
Type
Text
Name
supportKind
2Declare Variable
Name
supportHeight
Value
0
3Declare Variable
Type
Text
Name
plankKind
4Declare Variable
Name
plankHeight
Value
0
5Change Variable
Variable
supportKind
Value
data("Materials", material, "support")
6Change Variable
Variable
supportHeight
Value
data("Block Kinds", supportKind, "height")
7Repeatdata("Materials", material, "supportsHigh")times
Each time
8Place A BlockFunction
x
towerX - supportSpread
y
floorBottom + supportHeight * (local.index + 0.5)
tower
tower
builder
builder
kind
supportKind
9Repeatdata("Materials", material, "supportsHigh")times
Each time
10Place A BlockFunction
x
towerX + supportSpread
y
floorBottom + supportHeight * (local.index + 0.5)
tower
tower
builder
builder
kind
supportKind
11Change Variable
Variable
plankKind
Value
data("Materials", material, "plank")
12Change Variable
Variable
plankHeight
Value
data("Block Kinds", plankKind, "height")
13Place A BlockFunction
x
towerX
y
floorBottom + floorHeight - plankHeight / 2
tower
tower
builder
builder
kind
plankKind

A.4 Build The Stage

Built in Chapter 1, A Stage Stands.

Logic ComponentBuild The StageAttach to: Game Rules

When the Field starts, builds the stage being played from the Stages, Tower Plans, Floors and Notes tables: every tower, floor by floor from the ground up, and every singing note where its pitch puts it.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
singingNoteObjectConstantNone
groundHeightNumberConstant1.3
floorHeightNumberConstant1.34
supportSpreadNumberConstant0.94
roofSpreadNumberConstant0.6
noteAboveFloorNumberConstant0.56
When the Scene Starts
WhenScene Start
1Declare Variable
Name
tower
Value
0
2Declare Variable
Name
towerRow
Value
0
3Declare Variable
Name
towerX
Value
0
4Declare Variable
Name
floorRow
Value
0
5Declare Variable
Name
floorBottom
Value
0
6Declare Variable
Type
Text
Name
roofKind
7Declare Variable
Name
row
Value
0
8Reset Data Table
Table
Towers
9Region
Label
"Towers"
Color
#C27A3A
10Repeatdata("Stages", $stage - 1, "towerCount")times
Each time
11Change Variable
Variable
tower
Value
local.index
12Change Variable
Variable
towerRow
Value
data("Stages", $stage - 1, "firstTower") + tower
13Change Variable
Variable
towerX
Value
data("Tower Plans", towerRow, "x")
14Change Variable
Variable
floorBottom
Value
@self.groundHeight
15Repeatdata("Tower Plans", towerRow, "floorCount")times
Each time
16Change Variable
Variable
floorRow
Value
data("Tower Plans", towerRow, "firstFloor") + local.index
17Build A FloorFunction
tower
tower
towerX
towerX
floorBottom
floorBottom
floorHeight
@self.floorHeight
supportSpread
@self.supportSpread
builder
self
material
data("Floors", floorRow, "material")
18Change Variable
Variable
floorBottom
Operator
+=
Value
@self.floorHeight
19Check Data Row Exists
Action Name
roofFound
Table
Materials
Row
data("Tower Plans", towerRow, "roof")
20IfroofFound.value == true
Then
21Change Variable
Variable
roofKind
Value
data("Materials", data("Tower Plans", towerRow, "roof"), "support")
22Place A BlockFunction
x
towerX - @self.roofSpread
y
floorBottom + data("Block Kinds", roofKind, "height") / 2
tower
tower
builder
self
kind
roofKind
23Place A BlockFunction
x
towerX + @self.roofSpread
y
floorBottom + data("Block Kinds", roofKind, "height") / 2
tower
tower
builder
self
kind
roofKind
24Region
Label
"Singing Notes"
Color
#E8B923
25Repeatdata("Stages", $stage - 1, "noteCount")times
Each time
26Change Variable
Variable
row
Value
data("Stages", $stage - 1, "firstNote") + local.index
27Where A Note SitsFunction
Action Name
noteSpot
noteRow
row
groundHeight
@self.groundHeight
floorHeight
@self.floorHeight
noteAboveFloor
@self.noteAboveFloor
28Set Data Cell
Table
Notes
Row
row
Column
"x"
Value
noteSpot.x
29Set Data Cell
Table
Notes
Row
row
Column
"y"
Value
noteSpot.y
30Create Instance
Object to Create
@self.singingNote
X
noteSpot.x
Y
noteSpot.y
Variable Name
newNote
31Change Variable
Variable
newNote.noteRow
Value
data("Stages", $stage - 1, "firstNote") + local.index
32Change Variable
Variable
newNote.turn
Value
local.index
33Trigger Custom Event on Object
Applies to
newNote
Custom Event
placed
34Trigger Custom Event
Custom Event
stageBuilt

A.5 Place A Block (Function)

Built in Chapter 1, A Stage Stands.

FunctionPlace A Block

Creates one block of a tower: the block Object named kind, its middle at x, y (meters). The new block is told its tower and its kind, and "placed" tells it to read its size and material.

PARAMETERS
NameTypeStarts at
builderObject
kindThing ObjectWood Post
xNumber0
yNumber0
towerNumber0
ACTIONS
1Create Instance
Applies to
builder
Object to Create
kind
X
x
Y
y
Variable Name
newBlock
2Change Variable
Variable
newBlock.tower
Value
tower
3Change Variable
Variable
newBlock.kind
Value
kind
4Trigger Custom Event on Object
Applies to
newBlock
Custom Event
placed

A.6 Where A Note Sits (Function)

Built in Chapter 1, A Stage Stands.

FunctionWhere A Note Sits

Works out where a singing note of the stage being played sits, from its pitch: a higher note sits higher. noteRow is its row of the Notes table; x and y are the middle of the note (meters).

PARAMETERS
NameTypeStarts at
noteRowNumber0
groundHeightNumber1.3
floorHeightNumber1.34
noteAboveFloorNumber0.56
RETURN TYPEWhere A Note Sits Result (a Data Structure)
ACTIONS
1Declare Variable
Name
pitch
Value
0
2Declare Variable
Name
lowestPitch
Value
0
3Declare Variable
Name
semitonesPerFloor
Value
1
4Declare Variable
Name
floorNumber
Value
0
5Declare Variable
Name
tower
Value
0
6Declare Variable
Name
towerRow
Value
0
7Declare Variable
Name
noteX
Value
0
8Declare Variable
Name
noteY
Value
0
9Change Variable
Variable
pitch
Value
data("Notes", noteRow, "midi")
10Change Variable
Variable
lowestPitch
Value
data("Notes", data("Stages", $stage - 1, "firstNote"), "midi")
11Change Variable
Variable
semitonesPerFloor
Value
data("Stages", $stage - 1, "semitonesPerFloor")
12Change Variable
Variable
floorNumber
Value
round((pitch - lowestPitch) / semitonesPerFloor)
13Change Variable
Variable
tower
Value
data("Notes", noteRow, "tower")
14Change Variable
Variable
towerRow
Value
data("Stages", $stage - 1, "firstTower") + tower
15Change Variable
Variable
noteX
Value
data("Tower Plans", towerRow, "x")
16Change Variable
Variable
noteY
Value
groundHeight + floorNumber * floorHeight + noteAboveFloor
17Return
x
noteX
y
noteY

A.7 Ask For The Call

Built in Chapter 2, Listening.

Logic ComponentAsk For The CallAttach to: Listen Button

The Hear it again button, and its key (the Hear It Again Command, Space): asks for the call to be played again.

Attach toAny Object
On Hud Activated
WhenUI Activated
1Trigger Custom Event
Custom Event
callRequested
When Hearitagain Is Pressed
WhenCommand PressedCommand: Hear It Again
1Trigger Custom Event
Custom Event
callRequested

A.8 Call A Note

Built in Chapter 2, Listening.

Logic ComponentCall A NoteAttach to: Game Rules

After the opening, says "Listen…" and chooses the call, one of the stage's singing notes at random: $calledPitch is its pitch. Repeat The Call plays it.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
secondsBeforeCallNumberConstant0.35
When the Scene Starts
WhenScene Start
1Change Variable
Variable
$calledPitch
Value
0
On Opening Finished
WhenopeningFinishedCustom Event
1Change Variable
Variable
$message
Value
'listen'
2Start Recurring Timer
Timer Name
"callNote"
Repeat Every (s)
@self.secondsBeforeCall
Ring Once
Yes
On the Call Note Timer
WhenRecurring TimerTimer name: callNote
1Declare Variable
Name
calledRow
Value
0
2Generate Random Integer
Action Name
calledTurn
Minimum
0
Maximum
data("Stages", $stage - 1, "noteCount") - 1
3Change Variable
Variable
calledRow
Value
data("Stages", $stage - 1, "firstNote") + calledTurn.value
4Change Variable
Variable
$calledPitch
Value
data("Notes", calledRow, "midi")
5Trigger Custom Event
Custom Event
callRequested

A.9 Make Way For The Notes

Built in Chapter 2, Listening.

Logic ComponentMake Way For The NotesAttach to: Game Rules

Keeps the music quiet under the notes ($musicLevel), fades it down while a note sings and brings it back afterwards, so the notes are always heard clearly.

Attach toAny Object
DATA STRUCTURES
Make Way For The Notes Dataself.makeWayForTheNotesData
SHARED VARIABLES
NameTypeKindStarting Value
holdSecondsNumberConstant1.6
secondsToFadeOutNumberConstant0.25
secondsToFadeInNumberConstant1.4
stepSecondsNumberConstant0.05
When the Scene Starts
WhenScene Start
1Change Component Value
Component Value
self.makeWayForTheNotesData.loudness
Value
1
2Change Component Value
Component Value
self.makeWayForTheNotesData.targetLoudness
Value
1
3Set Volume
Audio Bus
Music
Volume
$musicLevel
On Note Sung
WhennoteSungCustom Event
1Change Component Value
Component Value
self.makeWayForTheNotesData.targetLoudness
Value
0
2Start Recurring Timer
Timer Name
"musicBack"
Repeat Every (s)
@self.holdSeconds
Ring Once
Yes
3Start Recurring Timer
Timer Name
"fadeMusic"
Repeat Every (s)
@self.stepSeconds
First Delay (s)
@self.stepSeconds
On the Music Back Timer
WhenRecurring TimerTimer name: musicBack
1Change Component Value
Component Value
self.makeWayForTheNotesData.targetLoudness
Value
1
2Start Recurring Timer
Timer Name
"fadeMusic"
Repeat Every (s)
@self.stepSeconds
First Delay (s)
@self.stepSeconds
On the Fade Music Timer
WhenRecurring TimerTimer name: fadeMusic
1Ifself.makeWayForTheNotesData.loudness > self.makeWayForTheNotesData.targetLoudness
Then
2Change Component Value
Component Value
self.makeWayForTheNotesData.loudness
Value
max(self.makeWayForTheNotesData.targetLoudness, self.makeWayForTheNotesData.loudness - @self.stepSeconds / @self.secondsToFadeOut)
3Ifself.makeWayForTheNotesData.loudness < self.makeWayForTheNotesData.targetLoudness
Then
4Change Component Value
Component Value
self.makeWayForTheNotesData.loudness
Value
min(self.makeWayForTheNotesData.targetLoudness, self.makeWayForTheNotesData.loudness + @self.stepSeconds / @self.secondsToFadeIn)
5Set Volume
Audio Bus
Music
Volume
self.makeWayForTheNotesData.loudness * $musicLevel
6Ifself.makeWayForTheNotesData.loudness == self.makeWayForTheNotesData.targetLoudness
Then
7Stop Recurring Timer
Timer Name
"fadeMusic"

A.10 Play Piano Note (Function)

Built in Chapter 2, Listening.

FunctionPlay Piano Note

Plays the piano note of one pitch (a MIDI number: 53 is F3, 60 is middle C, 79 is G5), the Sound its row of the Pitches table names.

PARAMETERS
NameTypeStarts at
pitchNumber60
ACTIONS
1Check Data Row Exists
Action Name
pitchFound
Table
Pitches
Row
dataFind("Pitches", "midi", pitch)
2IfpitchFound.value == true
Then
3Control Sound
Sound
data("Pitches", dataFind("Pitches", "midi", pitch), "noteSound")
4Trigger Custom Event
Custom Event
noteSung

A.11 Play The Place’s Tune

Built in Chapter 2, Listening.

Logic ComponentPlay The Place's TuneAttach to: Game Rules

When a stage starts, crossfades to the tune of its place, the Sound its row of the Places table names (a tune already playing carries on). How loud the music is belongs to Make Way For The Notes.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
crossfadeSecondsNumberConstant1.5
When the Scene Starts
WhenScene Start
1Declare Variable
Name
placeRow
Value
0
2Change Variable
Variable
placeRow
Value
dataFind("Places", "name", data("Stages", $stage - 1, "place"))
3Check Data Row Exists
Action Name
placeFound
Table
Places
Row
placeRow
4IfplaceFound.value == true
Then
5Control Sound
Operation
Crossfade Music
Sound
data("Places", placeRow, "tune")
Crossfade Seconds
@self.crossfadeSeconds

A.12 Repeat The Call

Built in Chapter 2, Listening.

Logic ComponentRepeat The CallAttach to: Game Rules

Plays the call whenever it is asked for while the stage is being played, and again by itself after a quiet spell, at most twice in a row, never over the player's aim or a shot in the air.

Attach toAny Object
DATA STRUCTURES
Repeat The Call Dataself.repeatTheCallData
SHARED VARIABLES
NameTypeKindStarting Value
quietSecondsNumberConstant8
mostRepeatsNumberConstant2
waitSecondsNumberConstant1
On Call Requested
WhencallRequestedCustom Event
1Check Game State
Action Name
isPlaying
Game State
Playing
2IfisPlaying.value == true && $calledPitch > 0
Then
3Play Piano NoteFunction
pitch
$calledPitch
4Change Component Value
Component Value
self.repeatTheCallData.repeatsLeft
Value
@self.mostRepeats
5Start Recurring Timer
Timer Name
"repeatTheCall"
Repeat Every (s)
@self.quietSeconds
First Delay (s)
@self.quietSeconds
On the Repeat the Call Timer
WhenRecurring TimerTimer name: repeatTheCall
1Ifself.repeatTheCallData.isNoteWaiting == true
Then
2Play Piano NoteFunction
pitch
$calledPitch
3Change Component Value
Component Value
self.repeatTheCallData.repeatsLeft
Operator
+=
Value
-1
4Ifself.repeatTheCallData.repeatsLeft <= 0
Then
5Stop Recurring Timer
Timer Name
"repeatTheCall"
6Otherwise
7Start Recurring Timer
Timer Name
"repeatTheCall"
Repeat Every (s)
@self.quietSeconds
First Delay (s)
@self.waitSeconds
On Happy Note Loaded
WhenhappyNoteLoadedCustom Event
1Change Component Value
Component Value
self.repeatTheCallData.isNoteWaiting
Value
true
On Pull Started
WhenpullStartedCustom Event
1Change Component Value
Component Value
self.repeatTheCallData.isNoteWaiting
Value
false
On Pull Ended
WhenpullEndedCustom Event
1Change Component Value
Component Value
self.repeatTheCallData.isNoteWaiting
Value
true
On Happy Note Launched
WhenhappyNoteLaunchedCustom Event
1Change Component Value
Component Value
self.repeatTheCallData.isNoteWaiting
Value
false
On Shot Ended
WhenshotEndedCustom Event
1Check Game State
Action Name
isStillPlaying
Game State
Playing
2IfisStillPlaying.value == true
Then
3Start Recurring Timer
Timer Name
"repeatTheCall"
Repeat Every (s)
@self.quietSeconds
First Delay (s)
@self.quietSeconds
On Call Found
WhencallFoundCustom Event
1Stop Recurring Timer
Timer Name
"repeatTheCall"

A.13 Show The Message

Built in Chapter 2, Listening.

Logic ComponentShow The MessageAttach to: Message Pill

Shows the message named by $message (a row of the Messages table) for a few seconds, then clears it.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
showSecondsNumberConstant2.6
When Created
WhenCreate
1Change Variable
Variable
$message
Value
""
2Set Visible
Visible
No
On Variable Changed · Message
WhenVariable ChangedGlobal Variable: message
1If$message != ""
Then
2Set Visible
Visible
Yes
3Start Recurring Timer
Timer Name
"hideMessage"
Repeat Every (s)
@self.showSeconds
Ring Once
Yes
4Otherwise
5Set Visible
Visible
No
On the Hide Message Timer
WhenRecurring TimerTimer name: hideMessage
1Change Variable
Variable
$message
Value
""

A.14 Sing In The Opening

Built in Chapter 2, Listening.

Logic ComponentSing In The OpeningAttach to: Singing Note

Before the first call, the singing notes sing once from the lowest to the highest. Each note sings its own turn and swells while it sings. It reads noteRow and turn (its Note State), set by Build The Stage, when it creates the note.

Attach toAny Object
DATA STRUCTURES
Note Stateself.noteState
SHARED VARIABLES
NameTypeKindStarting Value
openingStartSecondsNumberConstant0.6
afterHowToPlaySecondsNumberConstant0.3
secondsBetweenNotesNumberConstant0.52
swellScaleNumberConstant1.32
swellSecondsNumberConstant0.45
pauseAfterOpeningSecondsNumberConstant0.75
On Placed
WhenplacedCustom Event
1Change Component Value
Component Value
self.noteState.pitch
Value
data("Notes", self.noteState.noteRow, "midi")
On Stage Built
WhenstageBuiltCustom Event
1If$howToPlaySeen == true
Then
2Start Recurring Timer
Timer Name
"singTurn"
Repeat Every (s)
@self.openingStartSeconds + self.noteState.turn * @self.secondsBetweenNotes
Ring Once
Yes
On How to Play Closed
WhenhowToPlayClosedCustom Event
1Start Recurring Timer
Timer Name
"singTurn"
Repeat Every (s)
@self.afterHowToPlaySeconds + self.noteState.turn * @self.secondsBetweenNotes
Ring Once
Yes
On the Sing Turn Timer
WhenRecurring TimerTimer name: singTurn
1Ifself.noteState.turn == 0
Then
2Change Variable
Variable
$message
Value
'lowToHigh'
3Ifself.noteState.turn == (data("Stages", $stage - 1, "noteCount") - 1)
Then
4Start Recurring Timer
Timer Name
"openingDone"
Repeat Every (s)
@self.pauseAfterOpeningSeconds
Ring Once
Yes
5Play Piano NoteFunction
pitch
self.noteState.pitch
6Tween
Value
self.transform.scale
Target
@self.swellScale
Duration
@self.swellSeconds / 2
Ease
Quad Out
7Start Recurring Timer
Timer Name
"swellFull"
Repeat Every (s)
@self.swellSeconds / 2
Ring Once
Yes
On the Swell Full Timer
WhenRecurring TimerTimer name: swellFull
1Tween
Value
self.transform.scale
Target
1
Duration
@self.swellSeconds / 2
Ease
Quad in
On the Opening Done Timer
WhenRecurring TimerTimer name: openingDone
1Trigger Custom Event
Custom Event
openingFinished

A.15 Aim At (Function)

Built in Chapter 3, Aiming.

FunctionAim At

Sets the aim ($aimX, $aimY): the point the happy note is pulled to, towards a point but never more than maxPull from home (the band point); and the speed it will leave at ($launchVX, $launchVY): launchPower times the pull, back towards home.

PARAMETERS
NameTypeStarts at
happyNoteObjectStructural
Required Components
Slot NameshotSums
Component TypeData Structure
Required SchemaShot Sums
homeXNumber0
homeYNumber0
pointXNumber0
pointYNumber0
maxPullNumber1.75
launchPowerNumber9.2
ACTIONS
1Change Component Value
Component Value
happyNote.shotSums.pullX
Value
pointX - homeX
2Change Component Value
Component Value
happyNote.shotSums.pullY
Value
pointY - homeY
3Change Component Value
Component Value
happyNote.shotSums.pullLength
Value
hypot(happyNote.shotSums.pullX, happyNote.shotSums.pullY)
4Change Component Value
Component Value
happyNote.shotSums.pullScale
Value
min(1, maxPull / happyNote.shotSums.pullLength)
5Change Variable
Variable
$aimX
Value
homeX + happyNote.shotSums.pullX * happyNote.shotSums.pullScale
6Change Variable
Variable
$aimY
Value
homeY + happyNote.shotSums.pullY * happyNote.shotSums.pullScale
7Change Variable
Variable
$launchVX
Value
(homeX - $aimX) * launchPower
8Change Variable
Variable
$launchVY
Value
(homeY - $aimY) * launchPower

A.16 Band At Rest

Built in Chapter 3, Aiming.

Logic ComponentBand At RestAttach to: Band Rest

The band hangs between the prongs while a happy note waits in it and nobody is pulling; it makes the stretching sound when a pull starts.

Attach toAny Object
When Created
WhenCreate
1Set Visible
Visible
No
On Happy Note Loaded
WhenhappyNoteLoadedCustom Event
1Set Visible
Visible
Yes
On Pull Started
WhenpullStartedCustom Event
1Set Visible
Visible
No
2Control Sound
Sound
Sound Stretch
On Pull Ended
WhenpullEndedCustom Event
1Set Visible
Visible
Yes
On Happy Note Launched
WhenhappyNoteLaunchedCustom Event
1Set Visible
Visible
No

A.17 Drop The Pull (Function)

Built in Chapter 3, Aiming.

FunctionDrop The Pull

Ends a pull with no shot: the happy note goes back to the band (home), and the band and the aiming dots rest.

PARAMETERS
NameTypeStarts at
happyNoteObject
homeXNumber0
homeYNumber0
ACTIONS
1Set Position
Applies to
happyNote
X
homeX
Y
homeY
2Trigger Custom Event
Custom Event
pullEnded

A.18 Load The Happy Note

Built in Chapter 3, Aiming.

Logic ComponentLoad The Happy NoteAttach to: Slingshot

Puts a happy note in the band when the opening is over, and again a moment after each shot ends, if none is there.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
happyNoteObjectConstantNone
bandOffsetXNumberConstant-0.01
bandOffsetYNumberConstant1.01
secondsAfterShotNumberConstant0.35
On Opening Finished
WhenopeningFinishedCustom Event
1Put A Note In The BandFunction
bandX
self.transform.position.x + @self.bandOffsetX
bandY
self.transform.position.y + @self.bandOffsetY
happyNote
@self.happyNote
slingshot
self
On Shot Ended
WhenshotEndedCustom Event
1Start Recurring Timer
Timer Name
"loadNext"
Repeat Every (s)
@self.secondsAfterShot
Ring Once
Yes
On the Load Next Timer
WhenRecurring TimerTimer name: loadNext
1Check Game State
Action Name
isPlaying
Game State
Playing
2IfisPlaying.value == true
Then
3Put A Note In The BandFunction
bandX
self.transform.position.x + @self.bandOffsetX
bandY
self.transform.position.y + @self.bandOffsetY
happyNote
@self.happyNote
slingshot
self

A.19 Make The Aiming Dots

Built in Chapter 3, Aiming.

Logic ComponentMake The Aiming DotsAttach to: Slingshot

When the slingshot is created, it makes its aiming dots: dotCount of them, numbered from 1 (nearest the band) out, each hidden until a pull starts.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
aimDotObjectConstantNone
dotCountNumberConstant33
When Created
WhenCreate
1Repeat@self.dotCounttimes
Each time
2Create Instance
Object to Create
@self.aimDot
X
self.transform.position.x
Y
self.transform.position.y
Variable Name
newDot
3Change Variable
Variable
newDot.dotNumber
Value
local.index + 1
4Trigger Custom Event on Object
Applies to
newDot
Custom Event
placed

A.20 Pull Back

Built in Chapter 3, Aiming.

Logic ComponentPull BackAttach to: Happy Note

Lets the player pull the waiting happy note back from the band, with the mouse (or a finger) or with the keys, and let go. A pull cut off by another window or by the device is dropped.

Attach toAny Object
DATA STRUCTURES
Shot Sumsself.shotSums
Pull Back Dataself.pullBackData
SHARED VARIABLES
NameTypeKindStarting Value
maxPullNumberConstant1.75
launchPowerNumberConstant9.2
reachNumberConstant2.6
reachLeftOfNumberConstant7
aimAreaTopNumberConstant8.8
startAngleNumberConstant40
startPullNumberConstant0.75
degreesPerSecondNumberConstant50
pullPerSecondNumberConstant0.5
lowestAngleNumberConstant-10
highestAngleNumberConstant80
leastPullNumberConstant0.2
stepSecondsNumberConstant0.02
shortestShotNumberConstant0.24
When Created
WhenCreate
1Change Component Value
Component Value
self.pullBackData.homeX
Value
self.transform.position.x
2Change Component Value
Component Value
self.pullBackData.homeY
Value
self.transform.position.y
When the Left Mouse Button Is Pressed
WhenMouse PressMouse button: left
1Declare Variable
Name
pointerDistance
Value
0
2Declare Variable
Name
pointerX
Value
0
3Declare Variable
Name
pointerY
Value
0
4Declare Variable
Type
Boolean
Name
isInReach
Value
false
5Change Variable
Variable
pointerX
Value
eventValue("position.x", 0)
6Change Variable
Variable
pointerY
Value
eventValue("position.y", 0)
7Change Variable
Variable
pointerDistance
Value
hypot(pointerX - self.pullBackData.homeX, pointerY - self.pullBackData.homeY)
8IfpointerDistance <= @self.reach || pointerX <= @self.reachLeftOf
Then
9Change Variable
Variable
isInReach
Value
true
10Otherwise
11Change Variable
Variable
isInReach
Value
false
12IfpointerY < @self.aimAreaTop && isInReach == true
Then
13Change Component Value
Component Value
self.pullBackData.isKeyAiming
Value
false
14Stop Recurring Timer
Timer Name
"steerAim"
15Change Component Value
Component Value
self.pullBackData.isPulled
Value
true
16Aim AtFunction
homeX
self.pullBackData.homeX
homeY
self.pullBackData.homeY
pointX
pointerX
pointY
pointerY
maxPull
@self.maxPull
launchPower
@self.launchPower
happyNote
self
17Set Position
X
$aimX
Y
$aimY
18Trigger Custom Event
Custom Event
pullStarted
While the Left Mouse Button Is Held
WhenMouse HeldMouse button: left
1Declare Variable
Name
pointerX
Value
0
2Declare Variable
Name
pointerY
Value
0
3Ifself.pullBackData.isPulled == true
Then
4Change Variable
Variable
pointerX
Value
eventValue("position.x", 0)
5Change Variable
Variable
pointerY
Value
eventValue("position.y", 0)
6Aim AtFunction
homeX
self.pullBackData.homeX
homeY
self.pullBackData.homeY
pointX
pointerX
pointY
pointerY
maxPull
@self.maxPull
launchPower
@self.launchPower
happyNote
self
7Set Position
X
$aimX
Y
$aimY
Aim 2D Axis Input
When2D Axis InputCommand: Aim
1Change Component Value
Component Value
self.pullBackData.turnKeys
Value
eventValue("axisVector.y", 0)
2Change Component Value
Component Value
self.pullBackData.pullKeys
Value
eventValue("axisVector.x", 0)
3Ifself.pullBackData.turnKeys != 0 || self.pullBackData.pullKeys != 0
Then
4Change Component Value
Component Value
self.pullBackData.isKeyHeld
Value
true
5Otherwise
6Change Component Value
Component Value
self.pullBackData.isKeyHeld
Value
false
7Ifself.pullBackData.isPulled == false && self.pullBackData.isKeyAiming == false && self.pullBackData.isKeyHeld == true
Then
8Change Component Value
Component Value
self.pullBackData.isKeyAiming
Value
true
9Change Component Value
Component Value
self.pullBackData.keyAngle
Value
@self.startAngle
10Change Component Value
Component Value
self.pullBackData.keyPull
Value
@self.startPull
11Trigger Custom Event
Custom Event
pullStarted
12Start Recurring Timer
Timer Name
"steerAim"
Repeat Every (s)
@self.stepSeconds
First Delay (s)
0
On the Steer Aim Timer
WhenRecurring TimerTimer name: steerAim
1Change Component Value
Component Value
self.pullBackData.keyAngle
Operator
+=
Value
self.pullBackData.turnKeys * @self.degreesPerSecond * @self.stepSeconds
2Change Component Value
Component Value
self.pullBackData.keyAngle
Value
clamp(self.pullBackData.keyAngle, @self.lowestAngle, @self.highestAngle)
3Change Component Value
Component Value
self.pullBackData.keyPull
Operator
+=
Value
self.pullBackData.pullKeys * @self.pullPerSecond * @self.stepSeconds
4Change Component Value
Component Value
self.pullBackData.keyPull
Value
clamp(self.pullBackData.keyPull, @self.leastPull, 1)
5Aim AtFunction
homeX
self.pullBackData.homeX
homeY
self.pullBackData.homeY
pointX
self.pullBackData.homeX - cos(degtorad(self.pullBackData.keyAngle)) * @self.maxPull * self.pullBackData.keyPull
pointY
self.pullBackData.homeY - sin(degtorad(self.pullBackData.keyAngle)) * @self.maxPull * self.pullBackData.keyPull
maxPull
@self.maxPull
launchPower
@self.launchPower
happyNote
self
6Set Position
X
$aimX
Y
$aimY
When Letgo Is Pressed
WhenCommand PressedCommand: Let Go
1Ifself.pullBackData.isKeyAiming == true
Then
2Change Component Value
Component Value
self.pullBackData.isKeyAiming
Value
false
3Stop Recurring Timer
Timer Name
"steerAim"
4Let GoFunction
homeX
self.pullBackData.homeX
homeY
self.pullBackData.homeY
shortestShot
@self.shortestShot
happyNote
self
When the Left Mouse Button Is Released
WhenMouse ReleaseMouse button: left
1Ifself.pullBackData.isPulled == true
Then
2Change Component Value
Component Value
self.pullBackData.isPulled
Value
false
3Let GoFunction
homeX
self.pullBackData.homeX
homeY
self.pullBackData.homeY
shortestShot
@self.shortestShot
happyNote
self
On Focus Lost
WhenFocus Lost
1Ifself.pullBackData.isPulled == true
Then
2Change Component Value
Component Value
self.pullBackData.isPulled
Value
false
3Drop The PullFunction
homeX
self.pullBackData.homeX
homeY
self.pullBackData.homeY
happyNote
self
On Touch Cancelled
WhenTouch Cancelled
1Ifself.pullBackData.isPulled == true
Then
2Change Component Value
Component Value
self.pullBackData.isPulled
Value
false
3Drop The PullFunction
homeX
self.pullBackData.homeX
homeY
self.pullBackData.homeY
happyNote
self

A.21 Show The Flight

Built in Chapter 3, Aiming.

Logic ComponentShow The FlightAttach to: Aim Dot

One of the white dots that show where the happy note will fly while it is pulled: dot number n is where the note will be n x secondsBetweenDots after it is let go. It reads dotNumber (its Dot State), set by Make The Aiming Dots, when the slingshot makes the dot.

Attach toAny Object
DATA STRUCTURES
Dot Stateself.dotState
SHARED VARIABLES
NameTypeKindStarting Value
secondsBetweenDotsNumberConstant0.055
firstDotScaleNumberConstant0.875
shrinkPerDotNumberConstant0.018
smallestDotScaleNumberConstant0.313
groundHeightNumberConstant1.3
screenRightNumberConstant19.2
highestShownNumberConstant12.8
When Created
WhenCreate
1Set Visible
Visible
No
On Placed
WhenplacedCustom Event
1Declare Variable
Name
dotScale
Value
1
2Change Variable
Variable
dotScale
Value
@self.firstDotScale - self.dotState.dotNumber * @self.shrinkPerDot
3Change Variable
Variable
dotScale
Value
max(@self.smallestDotScale, dotScale)
4Set Scale
Horizontal Scale
dotScale
Vertical Scale
dotScale
On Pull Started
WhenpullStartedCustom Event
1Switch Mode
Event
Every Step
Mode
Shown
On Pull Ended
WhenpullEndedCustom Event
1Set Visible
Visible
No
2Switch Mode
Event
Every Step
Mode
Hidden
Every Step
WhenStep
ModeHidden (Starting Mode)
(no Actions)
Every Step
WhenStep
ModeShown
1Declare Variable
Name
dotY
Value
0
2Declare Variable
Name
dotX
Value
0
3Declare Variable
Name
t
Value
0
4Change Variable
Variable
t
Value
self.dotState.dotNumber * @self.secondsBetweenDots
5Change Variable
Variable
dotX
Value
$aimX + $launchVX * t
6Change Variable
Variable
dotY
Value
$aimY + $launchVY * t - $gravity / 2 * t * t
7IfdotY > @self.groundHeight && dotX < @self.screenRight && dotY < @self.highestShown
Then
8Set Visible
Visible
Yes
9Set Position
X
dotX
Y
dotY
10Otherwise
11Set Visible
Visible
No

A.22 Stretch The Band

Built in Chapter 3, Aiming.

Logic ComponentStretch The BandAttach to: Band Piece

One side of the band: while the happy note is pulled it stretches from its prong (where it is placed) to the note.

Attach toAny Object
DATA STRUCTURES
Stretch The Band Dataself.stretchTheBandData
SHARED VARIABLES
NameTypeKindStarting Value
bandThicknessNumberConstant0.08
When Created
WhenCreate
1Change Component Value
Component Value
self.stretchTheBandData.prongX
Value
self.transform.position.x
2Change Component Value
Component Value
self.stretchTheBandData.prongY
Value
self.transform.position.y
3Set Visible
Visible
No
On Pull Started
WhenpullStartedCustom Event
1Set Visible
Visible
Yes
2Switch Mode
Event
Every Step
Mode
Stretched
On Pull Ended
WhenpullEndedCustom Event
1Set Visible
Visible
No
2Switch Mode
Event
Every Step
Mode
Slack
Every Step
WhenStep
ModeSlack (Starting Mode)
(no Actions)
Every Step
WhenStep
ModeStretched
1Set Position
X
(self.stretchTheBandData.prongX + $aimX) / 2
Y
(self.stretchTheBandData.prongY + $aimY) / 2
2Set Rotation
Degrees
radtodeg(atan2($aimY - self.stretchTheBandData.prongY, $aimX - self.stretchTheBandData.prongX))
3Set Scale
Horizontal Scale
hypot($aimX - self.stretchTheBandData.prongX, $aimY - self.stretchTheBandData.prongY) / @self.bandThickness
Vertical Scale
1

A.23 Ask Again

Built in Chapter 4, Flying.

Logic ComponentAsk AgainAttach to: Game Rules

After a shot that did not find the called note, tells the player and plays the call again: "Missed! Listen again…" when the shot reached no singing note, "Not that one. Listen again…" when it reached a wrong one, and after a few wrong notes which way the call is.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
secondsAfterMissNumberConstant0.6
secondsAfterWrongNoteNumberConstant1
hintAfterWrongNotesNumberConstant2
On Shot Ended
WhenshotEndedCustom Event
1If$aimedPitch == 0
Then
2Change Variable
Variable
$message
Value
'missed'
3Start Recurring Timer
Timer Name
"callAgain"
Repeat Every (s)
@self.secondsAfterMiss
Ring Once
Yes
On Wrong Note Counted
WhenwrongNoteCountedCustom Event
1If$wrongNotes >= @self.hintAfterWrongNotes
Then
2If$calledPitch > $aimedPitch
Then
3Change Variable
Variable
$message
Value
'hintHigher'
4Otherwise
5Change Variable
Variable
$message
Value
'hintLower'
6Trigger Custom Event
Custom Event
hintWanted
7Otherwise
8Change Variable
Variable
$message
Value
'notThatOne'
9Start Recurring Timer
Timer Name
"callAgain"
Repeat Every (s)
@self.secondsAfterWrongNote
Ring Once
Yes
On the Call Again Timer
WhenRecurring TimerTimer name: callAgain
1Trigger Custom Event
Custom Event
callRequested

A.24 Count The Shots

Built in Chapter 4, Flying.

Logic ComponentCount The ShotsAttach to: Game Rules

Counts the shots of this stage in $shots (the Shots Count at the top shows it), and how many of them reached a wrong note in $wrongNotes.

Attach toAny Object
When the Scene Starts
WhenScene Start
1Change Variable
Variable
$shots
Value
0
2Change Variable
Variable
$wrongNotes
Value
0
On Wrong Note Reached
WhenwrongNoteReachedCustom Event
1Change Variable
Variable
$wrongNotes
Operator
+=
Value
1
2Trigger Custom Event on Object
Custom Event
wrongNoteCounted
On Happy Note Launched
WhenhappyNoteLaunchedCustom Event
1Change Variable
Variable
$shots
Operator
+=
Value
1

A.25 Fly

Built in Chapter 4, Flying.

Logic ComponentFlyAttach to: Happy Note

Flings the happy note from the aim when it is launched, lets it fly, land and roll, and ends the shot when it has stood still for a moment, left the field or flown too long.

Attach toAny Object
DATA STRUCTURES
Shot Sumsself.shotSums
Fly Dataself.flyData
COMPONENTS
self.colliderCollider
SHARED VARIABLES
NameTypeKindStarting Value
stillSpeedNumberConstant0.25
stillSecondsNumberConstant0.8
longestFlightSecondsNumberConstant9
rollingHeightNumberConstant1.7
rollingSlowdownNumberConstant2.5
fieldLeftNumberConstant-1.2
fieldRightNumberConstant20.4
fieldBottomNumberConstant-1.2
checkSecondsNumberConstant0.05
groundHeightNumberConstant1.3
screenLeftNumberConstant0.4
screenRightNumberConstant18.8
dustBelowNoteNumberConstant0.2
dustLayerNumberConstant60
hitBounceNumberConstant0.15
springBackBounceNumberConstant0.4
nearRadiusNumberConstant1.2
On Happy Note Launched
WhenhappyNoteLaunchedCustom Event
1Set Logic State
Logic Component
Pull Back
State
Disable
2Change Component Value
Component Value
self.collider.fixed
Value
false
3Change Component Value
Component Value
self.transform.gravity
Value
true
4Set Velocity
X Velocity
$launchVX
Y Velocity
$launchVY
5Judge The ShotFunction
groundHeight
@self.groundHeight
fieldLeft
@self.fieldLeft
fieldRight
@self.fieldRight
shot
self
6If$aimedPitch == $calledPitch
Then
7Set Bounciness
Value
@self.hitBounce
8Switch Mode
Event
Every Step
Mode
Hard
9Otherwise
10Set Bounciness
Value
@self.springBackBounce
11Control Sound
Sound
Sound Launch
12Start Recurring Timer
Timer Name
"watchFlight"
Repeat Every (s)
@self.checkSeconds
First Delay (s)
@self.checkSeconds
Every Step
WhenStep
ModeGentle (Starting Mode)
(no Actions)
Every Step
WhenStep
ModeHard
1Fire Event In Radius
Event
shotNear
Radius
@self.nearRadius
On the Watch Flight Timer
WhenRecurring TimerTimer name: watchFlight
1Declare Variable
Name
speed
Value
0
2Change Component Value
Component Value
self.flyData.flightSeconds
Operator
+=
Value
@self.checkSeconds
3Change Variable
Variable
speed
Value
hypot(self.transform.velocity.x, self.transform.velocity.y)
4Ifspeed < @self.stillSpeed
Then
5Change Component Value
Component Value
self.flyData.stillFor
Operator
+=
Value
@self.checkSeconds
6Otherwise
7Change Component Value
Component Value
self.flyData.stillFor
Value
0
8Ifself.transform.position.y < @self.rollingHeight
Then
9Set Drag (Slow Down)
Amount
@self.rollingSlowdown
10Ifself.flyData.stillFor >= @self.stillSeconds || self.flyData.flightSeconds >= @self.longestFlightSeconds || self.transform.position.x < @self.fieldLeft || self.transform.position.x > @self.fieldRight || self.transform.position.y < @self.fieldBottom
Then
11Stop Recurring Timer
Timer Name
"watchFlight"
12Burst Particles
Particles
Landing Dust
Position Relative To
World
X
clamp(self.transform.position.x, @self.screenLeft, @self.screenRight)
Y
max(self.transform.position.y - @self.dustBelowNote, @self.groundHeight)
Z Index Offset
@self.dustLayer
13Trigger Custom Event
Custom Event
shotEnded
14Destroy Instance

A.26 Let Go (Function)

Built in Chapter 4, Flying.

FunctionLet Go

Ends a pull: a pull shorter than shortestShot puts the happy note back in the band; a longer one launches it.

PARAMETERS
NameTypeStarts at
happyNoteObject
homeXNumber0
homeYNumber0
shortestShotNumber0.24
ACTIONS
1Trigger Custom Event
Custom Event
pullEnded
2Ifhypot($aimX - homeX, $aimY - homeY) < shortestShot
Then
3Set Position
Applies to
happyNote
X
homeX
Y
homeY
4Otherwise
5Trigger Custom Event
Custom Event
happyNoteLaunched

A.27 Put A Note In The Band (Function)

Built in Chapter 4, Flying.

FunctionPut A Note In The Band

Puts a happy note at the band point, unless one is already there or flying.

PARAMETERS
NameTypeStarts at
slingshotObject
happyNoteObjectHappy Note
bandXNumber0
bandYNumber0
ACTIONS
1IfinstanceCount("Happy Note") == 0
Then
2Create Instance
Applies to
slingshot
Object to Create
happyNote
X
bandX
Y
bandY
Variable Name
newHappyNote
3Trigger Custom Event
Custom Event
happyNoteLoaded

A.28 Answer The Shot

Built in Chapter 5, Wrong Notes.

Logic ComponentAnswer The ShotAttach to: Singing Note

When the shot aimed at this singing note reaches it, the note answers: a wrong note sings its own pitch, shakes and says so; the called note bursts and plays its flourish. It reads pitch (its Note State), set by Sing In The Opening, when the note hears "placed".

Attach toAny Object
DATA STRUCTURES
Note Stateself.noteState
Answer The Shot Dataself.answerTheShotData
SHARED VARIABLES
NameTypeKindStarting Value
shakeMetersNumberConstant0.06
shakeSecondsNumberConstant0.5
shakeStepSecondsNumberConstant0.05
burstLayerNumberConstant60
When Created
WhenCreate
1Change Component Value
Component Value
self.answerTheShotData.homeX
Value
self.transform.position.x
On Happy Note Launched
WhenhappyNoteLaunchedCustom Event
1Switch Mode
Event
On Shot Arrived
Mode
Waiting
When Starting to Hit Happy Note
WhenCollision EnterObject: Happy Note
1Trigger Custom Event on Object
Custom Event
shotArrived
On Tower Struck
WhentowerStruckCustom Event
1Ifself.noteState.pitch != $calledPitch
Then
2Trigger Custom Event on Object
Custom Event
shotArrived
On Shot Ended
WhenshotEndedCustom Event
1Trigger Custom Event on Object
Custom Event
shotArrived
On Shot Arrived
WhenshotArrivedCustom Event
ModeWaiting (Starting Mode)
1Ifself.noteState.pitch == $aimedPitch
Then
2Switch Mode
Event
On Shot Arrived
Mode
Answered
3Ifself.noteState.pitch != $calledPitch
Then
4Play Piano NoteFunction
pitch
self.noteState.pitch
5Change Component Value
Component Value
self.answerTheShotData.shakeLeft
Value
@self.shakeSeconds
6Start Recurring Timer
Timer Name
"shake"
Repeat Every (s)
@self.shakeStepSeconds
First Delay (s)
0
7Trigger Custom Event
Custom Event
wrongNoteReached
8Otherwise
9Burst Particles
Particles
Note Burst
Position Relative To
World
X
self.transform.position.x
Y
self.transform.position.y
Z Index Offset
@self.burstLayer
10Play FlourishFunction
pitch
self.noteState.pitch
11Trigger Custom Event
Custom Event
callFound
12Destroy Instance
On Shot Arrived
WhenshotArrivedCustom Event
ModeAnswered
(no Actions)
On the Shake Timer
WhenRecurring TimerTimer name: shake
1Change Component Value
Component Value
self.answerTheShotData.shakeSide
Value
-self.answerTheShotData.shakeSide
2Change Component Value
Component Value
self.answerTheShotData.shakeLeft
Operator
+=
Value
-@self.shakeStepSeconds
3Ifself.answerTheShotData.shakeLeft > 0
Then
4Tween
Value
self.transform.position.x
Target
self.answerTheShotData.homeX + self.answerTheShotData.shakeSide * @self.shakeMeters
Duration
@self.shakeStepSeconds
5Otherwise
6Tween
Value
self.transform.position.x
Target
self.answerTheShotData.homeX
Duration
@self.shakeStepSeconds
7Stop Recurring Timer
Timer Name
"shake"

A.29 Judge The Shot (Function)

Built in Chapter 5, Wrong Notes.

FunctionJudge The Shot

Follows the path the aiming dots show, from the aim at the launch speed, and sets $aimedPitch to the pitch of the first singing note it comes within reach of (0 if it reaches none). A shot is judged as it leaves the slingshot.

PARAMETERS
NameTypeStarts at
shotObjectStructural
Required Components
Slot NameshotSums
Component TypeData Structure
Required SchemaShot Sums
reachNumber0.64
pathStepSecondsNumber0.004
longestPathSecondsNumber5
groundHeightNumber1.3
fieldLeftNumber-1.2
fieldRightNumber20.4
ACTIONS
1Change Variable
Variable
$aimedPitch
Value
0
2Change Component Value
Component Value
shot.shotSums.t
Value
0
3Repeatround(longestPathSeconds / pathStepSeconds)times
Each time
4Change Component Value
Component Value
shot.shotSums.t
Operator
+=
Value
pathStepSeconds
5Change Component Value
Component Value
shot.shotSums.pathX
Value
$aimX + $launchVX * shot.shotSums.t
6Change Component Value
Component Value
shot.shotSums.drop
Value
$gravity / 2 * shot.shotSums.t * shot.shotSums.t
7Change Component Value
Component Value
shot.shotSums.pathY
Value
$aimY + $launchVY * shot.shotSums.t - shot.shotSums.drop
8Repeatdata("Stages", $stage - 1, "noteCount")times
Each time
9Change Component Value
Component Value
shot.shotSums.noteRow
Value
data("Stages", $stage - 1, "firstNote") + local.index
10Change Component Value
Component Value
shot.shotSums.noteX
Value
data("Notes", shot.shotSums.noteRow, "x")
11Change Component Value
Component Value
shot.shotSums.noteY
Value
data("Notes", shot.shotSums.noteRow, "y")
12Change Component Value
Component Value
shot.shotSums.gapX
Value
shot.shotSums.pathX - shot.shotSums.noteX
13Change Component Value
Component Value
shot.shotSums.gapY
Value
shot.shotSums.pathY - shot.shotSums.noteY
14Change Component Value
Component Value
shot.shotSums.distanceToNote
Value
hypot(shot.shotSums.gapX, shot.shotSums.gapY)
15If$aimedPitch == 0 && shot.shotSums.distanceToNote < reach && shot.shotSums.pathY > groundHeight && shot.shotSums.pathX > fieldLeft && shot.shotSums.pathX < fieldRight
Then
16Change Variable
Variable
$aimedPitch
Value
data("Notes", shot.shotSums.noteRow, "midi")

A.30 Point To The Call

Built in Chapter 5, Wrong Notes.

Logic ComponentPoint To The CallAttach to: Hint Arrow

When a hint is wanted, shows this arrow beside the wrong note the shot reached, pointing up or down towards the called note, bobbing gently, for a few seconds.

Attach toAny Object
DATA STRUCTURES
Point To The Call Dataself.pointToTheCallData
SHARED VARIABLES
NameTypeKindStarting Value
besideMetersNumberConstant0.78
aboveMetersNumberConstant0.58
bobMetersNumberConstant0.08
secondsPerSwingNumberConstant0.52
showSecondsNumberConstant4.5
When Created
WhenCreate
1Set Visible
Visible
No
On Hint Wanted
WhenhintWantedCustom Event
1Declare Variable
Name
noteRow
Value
0
2Declare Variable
Name
noteX
Value
0
3Declare Variable
Name
noteY
Value
0
4Repeatdata("Stages", $stage - 1, "noteCount")times
Each time
5Change Variable
Variable
noteRow
Value
data("Stages", $stage - 1, "firstNote") + local.index
6Ifdata("Notes", noteRow, "midi") == $aimedPitch
Then
7Change Variable
Variable
noteX
Value
data("Notes", noteRow, "x")
8Change Variable
Variable
noteY
Value
data("Notes", noteRow, "y")
9If$calledPitch > $aimedPitch
Then
10Set Rotation
Degrees
0
11Change Component Value
Component Value
self.pointToTheCallData.baseY
Value
noteY + @self.aboveMeters
12Otherwise
13Set Rotation
Degrees
180
14Change Component Value
Component Value
self.pointToTheCallData.baseY
Value
noteY - @self.aboveMeters
15Set Position
X
noteX - @self.besideMeters
Y
self.pointToTheCallData.baseY
16Set Visible
Visible
Yes
17Start Recurring Timer
Timer Name
"bob"
Repeat Every (s)
@self.secondsPerSwing
First Delay (s)
0
18Start Recurring Timer
Timer Name
"hideHint"
Repeat Every (s)
@self.showSeconds
Ring Once
Yes
On the Bob Timer
WhenRecurring TimerTimer name: bob
1If$calmMotion == false
Then
2Tween
Value
self.transform.position.y
Target
self.pointToTheCallData.baseY + @self.bobMeters * self.pointToTheCallData.swingDirection
Duration
@self.secondsPerSwing
Ease
Quad in Out
3Change Component Value
Component Value
self.pointToTheCallData.swingDirection
Value
-self.pointToTheCallData.swingDirection
On Variable Changed · Calm Motion
WhenVariable ChangedGlobal Variable: calmMotion
1If$calmMotion == true
Then
2Control Tween
Which
Value
Value
self.transform.position.y
3Set Position
X
self.transform.position.x
Y
self.pointToTheCallData.baseY
On the Hide Hint Timer
WhenRecurring TimerTimer name: hideHint
1Stop Recurring Timer
Timer Name
"bob"
2Set Visible
Visible
No

A.31 Tell Of A Strike

Built in Chapter 5, Wrong Notes.

Logic ComponentTell Of A StrikeAttach to: Wood Post, Wood Plank, Stone Cube, Stone Plank, Ice Cube

When the happy note strikes this block, tells everyone that the shot has reached the towers.

Attach toAny Object
When Starting to Hit Happy Note
WhenCollision EnterObject: Happy Note
1Trigger Custom Event
Custom Event
towerStruck

A.32 Come Down When Struck

Built in Chapter 6, The Tower Comes Down.

Logic ComponentCome Down When StruckAttach to: Wood Post, Wood Plank, Stone Cube, Stone Plank, Ice Cube

A block stands until a shot at the called note strikes it, or a falling block knocks into it while a tower is coming down. Then it cuts its tower at its top, and every block of that tower at or above the cut comes loose and falls. It reads tower and kind (its Block State), set by Place A Block, when it creates the block.

Attach toAny Object
DATA STRUCTURES
Block Stateself.blockState
Come Down When Struck Dataself.comeDownWhenStruckData
COMPONENTS
self.colliderCollider
SHARED VARIABLES
NameTypeKindStarting Value
knockSpeedNumberConstant0.45
cutToleranceNumberConstant0.02
nearMetersNumberConstant0.33
lookAheadSecondsNumberConstant0.034
On Placed
WhenplacedCustom Event
1Change Component Value
Component Value
self.comeDownWhenStruckData.width
Value
data("Block Kinds", self.blockState.kind, "width")
2Change Component Value
Component Value
self.comeDownWhenStruckData.height
Value
data("Block Kinds", self.blockState.kind, "height")
When Starting to Hit Happy Note
WhenCollision EnterObject: Happy Note
1If$aimedPitch == $calledPitch
Then
2Trigger Custom Event on Object
Custom Event
struck
On Shot Near
WhenshotNearCustom Event
1Declare Variable
Name
gapY
Value
0
2Declare Variable
Name
gapX
Value
0
3Declare Variable
Name
reachAhead
Value
0
4Declare Variable
Name
otherSpeed
Value
0
5Change Variable
Variable
otherSpeed
Value
hypot(other.transform.velocity.x, other.transform.velocity.y)
6Change Variable
Variable
reachAhead
Value
@self.nearMeters + otherSpeed * @self.lookAheadSeconds
7Change Variable
Variable
gapX
Value
abs(other.transform.position.x - self.transform.position.x)
8Change Variable
Variable
gapY
Value
abs(other.transform.position.y - self.transform.position.y)
9IfgapX < (self.comeDownWhenStruckData.width / 2 + reachAhead) && gapY < (self.comeDownWhenStruckData.height / 2 + reachAhead)
Then
10Trigger Custom Event on Object
Custom Event
struck
When Starting to Hit Anything Tagged Block
WhenCollision EnterObject: tag:Block
1Declare Variable
Name
otherSpeed
Value
0
2Change Variable
Variable
otherSpeed
Value
hypot(other.transform.velocity.x, other.transform.velocity.y)
3If$towersFalling == true && otherSpeed > @self.knockSpeed
Then
4Trigger Custom Event on Object
Custom Event
struck
On Struck
WhenstruckCustom Event
1Declare Variable
Name
top
Value
0
2Change Component Value
Component Value
self.comeDownWhenStruckData.isStruck
Value
true
3Change Variable
Variable
top
Value
self.transform.position.y + self.comeDownWhenStruckData.height / 2
4Iftop < data("Towers", self.blockState.tower, "cut")
Then
5Set Data Cell
Table
Towers
Row
self.blockState.tower
Column
"cut"
Value
top
6Trigger Custom Event
Custom Event
towerCut
On Tower Cut
WhentowerCutCustom Event
1Declare Variable
Name
bottom
Value
0
2Change Variable
Variable
bottom
Value
self.transform.position.y - self.comeDownWhenStruckData.height / 2
3Ifself.comeDownWhenStruckData.isStruck == true || bottom >= (data("Towers", self.blockState.tower, "cut") - @self.cutTolerance)
Then
4Change Component Value
Component Value
self.blockState.isFalling
Value
true
5Change Component Value
Component Value
self.collider.fixed
Value
false
6Change Component Value
Component Value
self.transform.gravity
Value
true
7Trigger Custom Event on Object
Custom Event
cameLoose
8Set Logic State
Logic Component
Come Down When Struck
State
Disable

A.33 Fall With A Knock

Built in Chapter 6, The Tower Comes Down.

Logic ComponentFall With A KnockAttach to: Wood Post, Wood Plank, Stone Cube, Stone Plank, Ice Cube

Once a block has come loose: it knocks when it lands (wood, stone or ice), throws splinters or dust when it lands hard, and a block of ice shatters when it is hit or lands hard while a tower is coming down. A block that falls out of the field is removed. It reads kind and isFalling (its Block State), set by Place A Block (kind, when it creates the block) and Come Down When Struck (isFalling), on the same block.

Attach toAny Object
DATA STRUCTURES
Block Stateself.blockState
Fall With A Knock Dataself.fallWithAKnockData
COMPONENTS
self.colliderCollider
SHARED VARIABLES
NameTypeKindStarting Value
landingSpeedNumberConstant2.4
landingDropNumberConstant2.2
hardDropNumberConstant4.2
iceLandingSpeedNumberConstant4.8
iceLandingDropNumberConstant3
iceShotSpeedNumberConstant3.3
iceKnockSpeedNumberConstant5.2
fieldBottomNumberConstant-3
fieldLeftNumberConstant-3
fieldRightNumberConstant22.2
effectLayerNumberConstant60
On Placed
WhenplacedCustom Event
1Change Component Value
Component Value
self.fallWithAKnockData.material
Value
data("Block Kinds", self.blockState.kind, "material")
On Came Loose
WhencameLooseCustom Event
1Switch Mode
Event
Every Step
Mode
Falling
Every Step
WhenStep
ModeStanding (Starting Mode)
(no Actions)
Every Step
WhenStep
ModeFalling
1Change Component Value
Component Value
self.fallWithAKnockData.lastSpeed
Value
self.fallWithAKnockData.speed
2Change Component Value
Component Value
self.fallWithAKnockData.speed
Value
hypot(self.transform.velocity.x, self.transform.velocity.y)
3Ifself.fallWithAKnockData.lastSpeed > @self.landingSpeed && (self.fallWithAKnockData.lastSpeed - self.fallWithAKnockData.speed) > @self.landingDrop
Then
4Trigger Custom Event on Object
Custom Event
landed
5Ifself.transform.position.y < @self.fieldBottom || self.transform.position.x < @self.fieldLeft || self.transform.position.x > @self.fieldRight
Then
6Destroy Instance
On Landed
WhenlandedCustom Event
1Ifself.fallWithAKnockData.material == "ice" && $towersFalling == true && self.fallWithAKnockData.lastSpeed > @self.iceLandingSpeed && (self.fallWithAKnockData.lastSpeed - self.fallWithAKnockData.speed) > @self.iceLandingDrop
Then
2Trigger Custom Event on Object
Custom Event
shatter
3Otherwise
4Change Variable
Variable
$knockMaterial
Value
self.fallWithAKnockData.material
5Trigger Custom Event
Custom Event
blockKnocked
6If(self.fallWithAKnockData.lastSpeed - self.fallWithAKnockData.speed) > @self.hardDrop && self.fallWithAKnockData.material == "wood" && $calmMotion == false
Then
7Burst Particles
Particles
Wood Splinters
Position Relative To
World
X
self.transform.position.x
Y
self.transform.position.y
Z Index Offset
@self.effectLayer
8If(self.fallWithAKnockData.lastSpeed - self.fallWithAKnockData.speed) > @self.hardDrop && self.fallWithAKnockData.material == "stone" && $calmMotion == false
Then
9Burst Particles
Particles
Stone Dust
Position Relative To
World
X
self.transform.position.x
Y
self.transform.position.y
Z Index Offset
@self.effectLayer
When Starting to Hit Happy Note
WhenCollision EnterObject: Happy Note
1Declare Variable
Name
otherSpeed
Value
0
2Change Variable
Variable
otherSpeed
Value
hypot(other.transform.velocity.x, other.transform.velocity.y)
3Ifself.fallWithAKnockData.material == "ice" && self.blockState.isFalling == true && $towersFalling == true && otherSpeed > @self.iceShotSpeed
Then
4Trigger Custom Event on Object
Custom Event
shatter
When Starting to Hit Anything Tagged Block
WhenCollision EnterObject: tag:Block
1Declare Variable
Name
otherSpeed
Value
0
2Change Variable
Variable
otherSpeed
Value
hypot(other.transform.velocity.x, other.transform.velocity.y)
3Ifself.fallWithAKnockData.material == "ice" && self.blockState.isFalling == true && $towersFalling == true && otherSpeed > @self.iceKnockSpeed
Then
4Trigger Custom Event on Object
Custom Event
shatter
On Shatter
WhenshatterCustom Event
1Burst Particles
Particles
Ice Shatter
Position Relative To
World
X
self.transform.position.x
Y
self.transform.position.y
Z Index Offset
@self.effectLayer
2Change Variable
Variable
$knockMaterial
Value
'ice'
3Trigger Custom Event
Custom Event
blockKnocked
4Destroy Instance

A.34 Play Flourish (Function)

Built in Chapter 6, The Tower Comes Down.

FunctionPlay Flourish

Plays the short rising flourish of one pitch (a MIDI number), the sound of the called note found: the Sound its row of the Pitches table names.

PARAMETERS
NameTypeStarts at
pitchNumber60
ACTIONS
1Check Data Row Exists
Action Name
pitchFound
Table
Pitches
Row
dataFind("Pitches", "midi", pitch)
2IfpitchFound.value == true
Then
3Control Sound
Sound
data("Pitches", dataFind("Pitches", "midi", pitch), "flourishSound")
4Trigger Custom Event
Custom Event
noteSung

A.35 Slow The Moment

Built in Chapter 6, The Tower Comes Down.

Logic ComponentSlow The MomentAttach to: Game Rules

When the called note is found, slows the world for a moment and gives the camera a small shake.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
slowPaceNumberConstant0.3
easeSecondsNumberConstant0.05
slowSecondsNumberConstant0.55
shakeStrengthNumberConstant0.008
shakeSecondsNumberConstant0.35
On Call Found
WhencallFoundCustom Event
1If$calmMotion == false
Then
2Set Time Flow
Speed
@self.slowPace
Ease Seconds
@self.easeSeconds
Hold Seconds
@self.slowSeconds
3Camera Shake
Intensity
@self.shakeStrength
Seconds
@self.shakeSeconds

A.36 Sound The Fall

Built in Chapter 6, The Tower Comes Down.

Logic ComponentSound The FallAttach to: Game Rules

Plays the knock of each block that lands, the Sound its material's row of the Materials table names (never two closer than knockGapSeconds), and a crash that grows with the fall: a small crash once enough knocks come close together, a big crash if many more do.

Attach toAny Object
DATA STRUCTURES
Sound The Fall Dataself.soundTheFallData
SHARED VARIABLES
NameTypeKindStarting Value
knockGapSecondsNumberConstant0.045
fadePerSecondNumberConstant2.5
smallCrashKnocksNumberConstant3
bigCrashKnocksNumberConstant8
quietKnocksNumberConstant0.5
fadeStepSecondsNumberConstant0.05
On Block Knocked
WhenblockKnockedCustom Event
1Change Component Value
Component Value
self.soundTheFallData.crash
Operator
+=
Value
1
2Start Recurring Timer
Timer Name
"crashFade"
Repeat Every (s)
@self.fadeStepSeconds
First Delay (s)
@self.fadeStepSeconds
3Check Cooldown Ready
Action Name
knockReady
Cooldown Key
"knock"
4IfknockReady.value == true
Then
5Start Cooldown
Cooldown Key
"knock"
Seconds
@self.knockGapSeconds
6Check Data Row Exists
Action Name
materialFound
Table
Materials
Row
$knockMaterial
7IfmaterialFound.value == true
Then
8Control Sound
Sound
data("Materials", $knockMaterial, "knockSound")
On the Crash Fade Timer
WhenRecurring TimerTimer name: crashFade
1Change Component Value
Component Value
self.soundTheFallData.crash
Value
max(0, self.soundTheFallData.crash - @self.fadePerSecond * @self.fadeStepSeconds)
2Ifself.soundTheFallData.crash >= @self.bigCrashKnocks && self.soundTheFallData.crashLevel < 2
Then
3Change Component Value
Component Value
self.soundTheFallData.crashLevel
Value
2
4Control Sound
Sound
Sound Crash Big
5Ifself.soundTheFallData.crash >= @self.smallCrashKnocks && self.soundTheFallData.crashLevel < 1
Then
6Change Component Value
Component Value
self.soundTheFallData.crashLevel
Value
1
7Control Sound
Sound
Sound Crash Small
8Ifself.soundTheFallData.crash < @self.quietKnocks
Then
9Change Component Value
Component Value
self.soundTheFallData.crashLevel
Value
0
10Stop Recurring Timer
Timer Name
"crashFade"

A.37 Watch The Towers Fall

Built in Chapter 6, The Tower Comes Down.

Logic ComponentWatch The Towers FallAttach to: Game Rules

Keeps $towersFalling Yes from the moment a tower is cut until settleSeconds after the shot ends: while it is Yes, falling blocks knock standing blocks loose.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
settleSecondsNumberConstant2.5
When the Scene Starts
WhenScene Start
1Change Variable
Variable
$towersFalling
Value
false
On Tower Cut
WhentowerCutCustom Event
1Change Variable
Variable
$towersFalling
Value
true
2Stop Recurring Timer
Timer Name
"settle"
On Shot Ended
WhenshotEndedCustom Event
1If$towersFalling == true
Then
2Start Recurring Timer
Timer Name
"settle"
Repeat Every (s)
@self.settleSeconds
Ring Once
Yes
On the Settle Timer
WhenRecurring TimerTimer name: settle
1Change Variable
Variable
$towersFalling
Value
false

A.38 Bring Up The Card

Built in Chapter 7, Winning.

Logic ComponentBring Up The CardAttach to: Game Rules

When the stage is won, the card comes up cardAfterSeconds later, or later while blocks are still crashing, and at latestCardSeconds at the latest.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
cardAfterSecondsNumberConstant1.6
latestCardSecondsNumberConstant3.5
restSecondsNumberConstant0.4
On Call Found
WhencallFoundCustom Event
1Start Recurring Timer
Timer Name
"showCard"
Repeat Every (s)
@self.cardAfterSeconds
Ring Once
Yes
2Start Recurring Timer
Timer Name
"latestCard"
Repeat Every (s)
@self.latestCardSeconds
Ring Once
Yes
On Block Knocked
WhenblockKnockedCustom Event
1Start Cooldown
Cooldown Key
"stillCrashing"
Seconds
@self.restSeconds
On the Show Card Timer
WhenRecurring TimerTimer name: showCard
1Check Cooldown Ready
Action Name
isQuiet
Cooldown Key
"stillCrashing"
2IfisQuiet.value == true
Then
3Trigger Custom Event on Object
Custom Event
cardDue
4Otherwise
5Start Recurring Timer
Timer Name
"showCard"
Repeat Every (s)
@self.restSeconds
Ring Once
Yes
On the Latest Card Timer
WhenRecurring TimerTimer name: latestCard
1Trigger Custom Event on Object
Custom Event
cardDue
On Card Due
WhencardDueCustom Event
1Stop Recurring Timer
Timer Name
"showCard"
2Stop Recurring Timer
Timer Name
"latestCard"
3Set Input Context Active
Input Context
Field
Active
No
4Set Input Context Active
Input Context
Card
5Trigger Custom Event
Custom Event
cardShown

A.39 Fill The Bar

Built in Chapter 7, Winning.

Logic ComponentFill The BarAttach to: Card Bar

The bar on the card fills over fillSeconds; when it is full it says the card has had its time.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
fillSecondsNumberConstant2.4
On Card Shown
WhencardShownCustom Event
1Set Scale
Horizontal Scale
0
Vertical Scale
1
2Tween
Value
self.transform.scale.x
Target
1
Duration
@self.fillSeconds
3Start Recurring Timer
Timer Name
"barFull"
Repeat Every (s)
@self.fillSeconds
Ring Once
Yes
On the Bar Full Timer
WhenRecurring TimerTimer name: barFull
1Trigger Custom Event
Custom Event
cardTimeUp

A.40 Go On From The Card

Built in Chapter 7, Winning.

Logic ComponentGo On From The CardAttach to: Card Panel

Clicking or tapping the card asks to go on at once.

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

A.41 Go On To The Next Stage

Built in Chapter 7, Winning.

Logic ComponentGo On To The Next StageAttach to: Game Rules

From the card, the next stage starts: by itself when the card has had its time, or at once with Enter or a click. After the last stage the finale comes instead.

Attach toAny Object
On Card Time Up
WhencardTimeUpCustom Event
1Trigger Custom Event on Object
Custom Event
goOn
On Go on Wanted
WhengoOnWantedCustom Event
1Trigger Custom Event on Object
Custom Event
goOn
When Goon Is Pressed
WhenCommand PressedCommand: Go On
1Trigger Custom Event on Object
Custom Event
goOn
On Go on
WhengoOnCustom Event
1Set Logic State
Logic Component
Go On To The Next Stage
State
Disable
2If$stage >= dataCount("Stages")
Then
3Trigger Custom Event
Custom Event
finaleShown
4Otherwise
5Change Variable
Variable
$stage
Operator
+=
Value
1
6Restart Scene

A.42 Light A Star

Built in Chapter 7, Winning.

Logic ComponentLight A StarAttach to: Card Star

One of the three stars on the card (each placement has its starNumber): it shows lit when the stage earned at least that many stars.

Attach toAny Object
PER INSTANCE VARIABLES
NameTypeStarting Value
starNumberNumber1
On Card Shown
WhencardShownCustom Event
1If$starsWon >= self.starNumber
Then
2Set Frame
Frame
1
3Otherwise
4Set Frame
Frame
0

A.43 Show The Next Stage

Built in Chapter 7, Winning.

Logic ComponentShow The Next StageAttach to: Card Next

The card's last line, the number and name of the next stage: shown with the card when there is a next stage.

Attach toAny Object
When Created
WhenCreate
1Set Visible
Visible
No
On Finale Shown
WhenfinaleShownCustom Event
1Set Visible
Visible
No
On Card Shown
WhencardShownCustom Event
1If$stage < dataCount("Stages")
Then
2Set Visible
Visible
Yes

A.44 Show With The Card

Built in Chapter 7, Winning.

Logic ComponentShow With The CardAttach to: Card Panel, Card Message, Card Star, Card Bar Track, Card Bar

A part of the card that shows when a stage is won: hidden until then.

Attach toAny Object
When Created
WhenCreate
1Set Visible
Visible
No
On Card Shown
WhencardShownCustom Event
1Set Visible
Visible
Yes
On Finale Shown
WhenfinaleShownCustom Event
1Set Visible
Visible
No

A.45 Start The Stage Again

Built in Chapter 7, Winning.

Logic ComponentStart The Stage AgainAttach to: Restart Button

The Restart button: starts the stage being played again from the beginning (with a new call).

Attach toAny Object
On Hud Activated
WhenUI Activated
1Control Sound
Sound
Sound Click
2Restart Scene

A.46 Tell How It Was Found

Built in Chapter 7, Winning.

Logic ComponentTell How It Was FoundAttach to: Card Message

The card's message: how the called note was found, by how many wrong notes came first.

Attach toAny Object
On Card Shown
WhencardShownCustom Event
1Declare Variable
Type
Text
Name
wordsBefore
2Declare Variable
Type
Text
Name
wordsAfter
3If$wrongNotes <= 1
Then
4Set UI Text
Text
data("Found Words", $wrongNotes, "words")
5Otherwise
6Change Variable
Variable
wordsBefore
Value
data("Found Words", 2, "words")
7Change Variable
Variable
wordsAfter
Value
data("Found Words", 2, "wordsAfterNumber")
8Set UI Text
Text
text(wordsBefore, " ", $wrongNotes, " ", wordsAfter)

A.47 Win The Stage

Built in Chapter 7, Winning.

Logic ComponentWin The StageAttach to: Game Rules

Finding the called note wins the stage: the game is Stage Won, and the stage earns stars for listening. The Stages table keeps the best stars of each stage.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
twoStarWrongNotesNumberConstant2
When the Scene Starts
WhenScene Start
1Set Game State
Game State
Playing
2Set Input Context Active
Input Context
Field
3Set Input Context Active
Input Context
Card
Active
No
4Set Input Context Active
Input Context
Menus
Active
No
On Call Found
WhencallFoundCustom Event
1Set Game State
Game State
Stage Won
2If$wrongNotes == 0
Then
3Change Variable
Variable
$starsWon
Value
3
4Otherwise
5If$wrongNotes <= @self.twoStarWrongNotes
Then
6Change Variable
Variable
$starsWon
Value
2
7Otherwise
8Change Variable
Variable
$starsWon
Value
1
9If$starsWon > data("Stages", $stage - 1, "stars")
Then
10Set Data Cell
Table
Stages
Row
$stage - 1
Column
"stars"
Value
$starsWon
11Trigger Custom Event on Object
Custom Event
starsCounted

A.48 Belong To A Place

Built in Chapter 8, The Title and the Maps.

Logic ComponentBelong To A PlaceAttach to: Place Card, Place Picture, Place Name, Place Stars, Place Lock

One part of a place card: from its card number (cardIndex, 0 to 11) it keeps its place in placeIndex, and whether the place is open in isOpen (its first stage is open: it is stage 1, or the stage before it has a star). It reads cardIndex (its Map Spot), set by Lay Out The Places (the card) or Lay Out A Place Card (its other parts), when it makes the part.

Attach toAny Object
DATA STRUCTURES
Map Spotself.mapSpot
On Placed
WhenplacedCustom Event
1Declare Variable
Name
rowBefore
Value
0
2Change Component Value
Component Value
self.mapSpot.placeIndex
Value
self.mapSpot.cardIndex
3Change Variable
Variable
rowBefore
Value
self.mapSpot.placeIndex * $stagesPerPlace - 1
4Ifself.mapSpot.placeIndex == 0 || data("Stages", rowBefore, "stars") > 0
Then
5Change Component Value
Component Value
self.mapSpot.isOpen
Value
true
6Otherwise
7Change Component Value
Component Value
self.mapSpot.isOpen
Value
false

A.49 Belong To A Stage

Built in Chapter 8, The Title and the Maps.

Logic ComponentBelong To A StageAttach to: Stage Card, Stage Number, Stage Name, Stage Star, Stage Lock

One part of a stage card: from its card number (cardIndex, 0 to 9) its stage is cardIndex + 1 of the place shown, kept in stageNumber, and whether it is open, in isOpen. It reads cardIndex (its Map Spot), set by Lay Out The Stages (the card) or Lay Out A Stage Card (its other parts), when it makes the part.

Attach toAny Object
DATA STRUCTURES
Map Spotself.mapSpot
On Placed
WhenplacedCustom Event
1Declare Variable
Name
firstStage
Value
1
2Change Variable
Variable
firstStage
Value
floor(($stage - 1) / $stagesPerPlace) * $stagesPerPlace + 1
3Change Component Value
Component Value
self.mapSpot.stageNumber
Value
firstStage + self.mapSpot.cardIndex
4Ifself.mapSpot.stageNumber == 1 || data("Stages", self.mapSpot.stageNumber - 2, "stars") > 0
Then
5Change Component Value
Component Value
self.mapSpot.isOpen
Value
true
6Otherwise
7Change Component Value
Component Value
self.mapSpot.isOpen
Value
false

A.50 Choose The Next Stage

Built in Chapter 8, The Title and the Maps.

Logic ComponentChoose The Next StageAttach to: Places Director, Stages Director

When a map opens, $nextStage is the stage to play next: the first stage without stars, or the last stage when every stage has some (the maps highlight it). On the Place Map it also becomes $stage, so the map shows its place.

Attach toAny Object
PER INSTANCE VARIABLES
NameTypeStarting Value
selectItBooleanYes
When the Scene Starts
WhenScene Start
1Declare Variable
Name
rowWithoutStars
Value
-1
2Change Variable
Variable
rowWithoutStars
Value
dataFind("Stages", "stars", 0)
3IfrowWithoutStars >= 0
Then
4Change Variable
Variable
$nextStage
Value
rowWithoutStars + 1
5Otherwise
6Change Variable
Variable
$nextStage
Value
dataCount("Stages")
7Ifself.selectIt == true
Then
8Change Variable
Variable
$stage
Value
$nextStage

A.51 Count The Place’s Stars

How many of a place’s stars (3 for each of its $stagesPerPlace stages) have been earned, shown on its card (“ of 30”). It reads placeIndex (its Map Spot), set by Belong To A Place, attached first.

Built in Chapter 8, The Title and the Maps.

Logic ComponentCount The Place's StarsAttach to: Place Stars

How many of a place's stars (3 for each of its $stagesPerPlace stages) have been earned, shown on its card ("<n> of 30"). It reads placeIndex (its Map Spot), set by Belong To A Place, attached first.

Attach toAny Object
DATA STRUCTURES
Map Spotself.mapSpot
On Placed
WhenplacedCustom Event
1Declare Variable
Name
stageRow
Value
0
2Change Component Value
Component Value
self.mapSpot.starsEarned
Value
0
3Repeat$stagesPerPlacetimes
Each time
4Change Variable
Variable
stageRow
Value
self.mapSpot.placeIndex * $stagesPerPlace + local.index
5Change Component Value
Component Value
self.mapSpot.starsEarned
Operator
+=
Value
data("Stages", stageRow, "stars")

A.52 Go Back

Built in Chapter 8, The Title and the Maps.

Logic ComponentGo BackAttach to: Back Button, Map Button, Finale Button

The back arrow and the Map button (and Escape): go back one screen (Field to Stage Map, Stage Map to Place Map, Place Map to Title).

Attach toAny Object
On Hud Activated
WhenUI Activated
1Trigger Custom Event on Object
Custom Event
goBack
When Back Is Pressed
WhenCommand PressedCommand: Back
1Trigger Custom Event on Object
Custom Event
goBack
On Go Back
WhengoBackCustom Event
1Control Sound
Sound
Sound Click
2Previous Scene

A.53 Lay Out A Place Card

Built in Chapter 8, The Title and the Maps.

Logic ComponentLay Out A Place CardAttach to: Place Card

When the card is placed, makes the rest of it around its middle: the place's picture, its name, a star and the count of its stars, its lock and its keyboard ring, each told the card's number. It reads cardIndex (its Map Spot), set by Lay Out The Places, when it makes the card.

Attach toAny Object
DATA STRUCTURES
Map Spotself.mapSpot
SHARED VARIABLES
NameTypeKindStarting Value
placePictureObjectConstantNone
placeLockObjectConstantNone
placeRingObjectConstantNone
placeNameObjectConstantNone
placeStarObjectConstantNone
placeStarsObjectConstantNone
pictureAboveNumberConstant0.44
nameBelowNumberConstant0.62
starsBelowNumberConstant1.04
starLeftNumberConstant0.4
countRightNumberConstant0.5
On Placed
WhenplacedCustom Event
1Create Instance
Object to Create
@self.placePicture
X
self.transform.position.x
Y
self.transform.position.y + @self.pictureAbove
Variable Name
newPicture
2Change Variable
Variable
newPicture.cardIndex
Value
self.mapSpot.cardIndex
3Trigger Custom Event on Object
Applies to
newPicture
Custom Event
placed
4Create Instance
Object to Create
@self.placeLock
X
self.transform.position.x
Y
self.transform.position.y + @self.pictureAbove
Variable Name
newLock
5Change Variable
Variable
newLock.cardIndex
Value
self.mapSpot.cardIndex
6Trigger Custom Event on Object
Applies to
newLock
Custom Event
placed
7Create Instance
Object to Create
@self.placeRing
X
self.transform.position.x
Y
self.transform.position.y
Variable Name
newRing
8Change Variable
Variable
newRing.cardIndex
Value
self.mapSpot.cardIndex
9Trigger Custom Event on Object
Applies to
newRing
Custom Event
placed
10Create Instance
Object to Create
@self.placeName
X
0
Y
0
Variable Name
newName
11Set Position
Applies to
newName
X
self.transform.position.x
Y
self.transform.position.y - @self.nameBelow
12Change Variable
Variable
newName.cardIndex
Value
self.mapSpot.cardIndex
13Trigger Custom Event on Object
Applies to
newName
Custom Event
placed
14Create Instance
Object to Create
@self.placeStar
X
self.transform.position.x - @self.starLeft
Y
self.transform.position.y - @self.starsBelow
Variable Name
newStar
15Create Instance
Object to Create
@self.placeStars
X
0
Y
0
Variable Name
newStarCount
16Set Position
Applies to
newStarCount
X
self.transform.position.x + @self.countRight
Y
self.transform.position.y - @self.starsBelow
17Change Variable
Variable
newStarCount.cardIndex
Value
self.mapSpot.cardIndex
18Trigger Custom Event on Object
Applies to
newStarCount
Custom Event
placed

A.54 Lay Out A Stage Card

Built in Chapter 8, The Title and the Maps.

Logic ComponentLay Out A Stage CardAttach to: Stage Card

When the card is placed, makes the rest of it around its middle: the stage's number and name, its three stars, its lock and its keyboard ring, each told the card's number (and each star which it is). It reads cardIndex and starNumber (its Map Spot), set by Lay Out The Stages, when it makes the card.

Attach toAny Object
DATA STRUCTURES
Map Spotself.mapSpot
SHARED VARIABLES
NameTypeKindStarting Value
numberLabelObjectConstantNone
nameLabelObjectConstantNone
stageStarObjectConstantNone
stageLockObjectConstantNone
stageRingObjectConstantNone
numberAboveNumberConstant0.46
nameBelowNumberConstant0.66
starsBelowNumberConstant0.14
starSpacingNumberConstant0.44
On Placed
WhenplacedCustom Event
1Create Instance
Object to Create
@self.numberLabel
X
0
Y
0
Variable Name
newNumber
2Set Position
Applies to
newNumber
X
self.transform.position.x
Y
self.transform.position.y + @self.numberAbove
3Change Variable
Variable
newNumber.cardIndex
Value
self.mapSpot.cardIndex
4Trigger Custom Event on Object
Applies to
newNumber
Custom Event
placed
5Create Instance
Object to Create
@self.nameLabel
X
0
Y
0
Variable Name
newName
6Set Position
Applies to
newName
X
self.transform.position.x
Y
self.transform.position.y - @self.nameBelow
7Change Variable
Variable
newName.cardIndex
Value
self.mapSpot.cardIndex
8Trigger Custom Event on Object
Applies to
newName
Custom Event
placed
9Create Instance
Object to Create
@self.stageLock
X
self.transform.position.x
Y
self.transform.position.y - @self.starsBelow
Variable Name
newLock
10Change Variable
Variable
newLock.cardIndex
Value
self.mapSpot.cardIndex
11Trigger Custom Event on Object
Applies to
newLock
Custom Event
placed
12Create Instance
Object to Create
@self.stageRing
X
self.transform.position.x
Y
self.transform.position.y
Variable Name
newRing
13Change Variable
Variable
newRing.cardIndex
Value
self.mapSpot.cardIndex
14Trigger Custom Event on Object
Applies to
newRing
Custom Event
placed
15Repeat3times
Each time
16Create Instance
Object to Create
@self.stageStar
X
self.transform.position.x + (local.index - 1) * @self.starSpacing
Y
self.transform.position.y - @self.starsBelow
Variable Name
newStar
17Change Variable
Variable
newStar.cardIndex
Value
self.mapSpot.cardIndex
18Change Variable
Variable
newStar.starNumber
Value
local.index + 1
19Trigger Custom Event on Object
Applies to
newStar
Custom Event
placed

A.55 Lay Out The Places

Built in Chapter 8, The Title and the Maps.

Logic ComponentLay Out The PlacesAttach to: Places Director

When the Place Map is made, lays out a card for each place (each row of the Places table): columns cards to a row from the top left, each told its number (cardIndex). The Map Grid keeps how many cards there are and how many to a row, for the keys.

Attach toAny Object
DATA STRUCTURES
Map Gridself.mapGrid
SHARED VARIABLES
NameTypeKindStarting Value
placeCardObjectConstantNone
columnsNumberConstant6
firstCardXNumberConstant1.85
firstCardYNumberConstant7.35
acrossNumberConstant3.1
downNumberConstant3.1
When Created
WhenCreate
1Declare Variable
Name
cardX
Value
0
2Declare Variable
Name
cardY
Value
0
3Change Component Value
Component Value
self.mapGrid.cardCount
Value
dataCount("Places")
4Change Component Value
Component Value
self.mapGrid.cardsInARow
Value
@self.columns
5RepeatdataCount("Places")times
Each time
6Change Variable
Variable
cardX
Value
@self.firstCardX + mod(local.index, @self.columns) * @self.across
7Change Variable
Variable
cardY
Value
@self.firstCardY - floor(local.index / @self.columns) * @self.down
8Create Instance
Object to Create
@self.placeCard
X
cardX
Y
cardY
Variable Name
newCard
9Change Variable
Variable
newCard.cardIndex
Value
local.index
10Trigger Custom Event on Object
Applies to
newCard
Custom Event
placed

A.56 Lay Out The Stages

Built in Chapter 8, The Title and the Maps.

Logic ComponentLay Out The StagesAttach to: Stages Director

When the Stage Map is made, lays out a card for each stage of the place shown: columns cards to a row from the top left, each told its number (cardIndex). The Map Grid keeps how many cards there are and how many to a row, for the keys.

Attach toAny Object
DATA STRUCTURES
Map Gridself.mapGrid
SHARED VARIABLES
NameTypeKindStarting Value
stageCardObjectConstantNone
columnsNumberConstant5
firstCardXNumberConstant2.4
firstCardYNumberConstant6.9
acrossNumberConstant3.6
downNumberConstant2.6
When Created
WhenCreate
1Declare Variable
Name
cardX
Value
0
2Declare Variable
Name
cardY
Value
0
3Change Component Value
Component Value
self.mapGrid.cardCount
Value
$stagesPerPlace
4Change Component Value
Component Value
self.mapGrid.cardsInARow
Value
@self.columns
5Repeat$stagesPerPlacetimes
Each time
6Change Variable
Variable
cardX
Value
@self.firstCardX + mod(local.index, @self.columns) * @self.across
7Change Variable
Variable
cardY
Value
@self.firstCardY - floor(local.index / @self.columns) * @self.down
8Create Instance
Object to Create
@self.stageCard
X
cardX
Y
cardY
Variable Name
newCard
9Change Variable
Variable
newCard.cardIndex
Value
local.index
10Trigger Custom Event on Object
Applies to
newCard
Custom Event
placed

A.57 Light A Stage Star

Built in Chapter 8, The Title and the Maps.

Logic ComponentLight A Stage StarAttach to: Stage Star

One of the three stars on a stage card (its starNumber, 1 to 3, told by the card that made it): lit when the stage has earned at least that many stars. It reads stageNumber, starNumber and isOpen (its Map Spot), set by Belong To A Stage, attached first (starNumber by Lay Out A Stage Card, when it makes the star).

Attach toAny Object
DATA STRUCTURES
Map Spotself.mapSpot
On Placed
WhenplacedCustom Event
1Ifself.mapSpot.isOpen == false
Then
2Set Visible
Visible
No
3Ifdata("Stages", self.mapSpot.stageNumber - 1, "stars") >= self.mapSpot.starNumber
Then
4Set Frame
Frame
1
5Otherwise
6Set Frame
Frame
0

A.58 Open A Place

Built in Chapter 8, The Title and the Maps.

Logic ComponentOpen A PlaceAttach to: Place Card

One place card: highlighted when the stage to play next ($nextStage) is in its place, dim when the place is locked; clicking an open card opens the place's Stage Map. It reads cardIndex, placeIndex and isOpen (its Map Spot), set by Belong To A Place, attached first (cardIndex by Lay Out The Places, when it makes the card).

Attach toAny Object
DATA STRUCTURES
Map Spotself.mapSpot
SHARED VARIABLES
NameTypeKindStarting Value
fadeSecondsNumberConstant0.25
On Placed
WhenplacedCustom Event
1Ifself.mapSpot.isOpen == true
Then
2Iffloor(($nextStage - 1) / $stagesPerPlace) == self.mapSpot.placeIndex
Then
3Change Variable
Variable
$selectedCard
Value
self.mapSpot.cardIndex
4Set Frame
Frame
1
5Otherwise
6Set Frame
Frame
0
7Otherwise
8Set Frame
Frame
2
When Left Is Clicked
WhenMouse Pressed on ObjectMouse button: left
1Trigger Custom Event on Object
Custom Event
chosen
When Open Is Pressed
WhenCommand PressedCommand: Open
1Ifself.mapSpot.cardIndex == $selectedCard
Then
2Trigger Custom Event on Object
Custom Event
chosen
On Chosen
WhenchosenCustom Event
1Ifself.mapSpot.isOpen == true
Then
2Control Sound
Sound
Sound Click
3Change Variable
Variable
$stage
Value
self.mapSpot.placeIndex * $stagesPerPlace + 1
4Go to Scene
Scene
Stage Map
Transition
Fade
Transition Seconds
@self.fadeSeconds

A.59 Open A Stage

Built in Chapter 8, The Title and the Maps.

Logic ComponentOpen A StageAttach to: Stage Card

A stage card: highlighted when it is the stage to play next; clicking it starts that stage. It reads cardIndex, stageNumber and isOpen (its Map Spot), set by Belong To A Stage, attached first (cardIndex by Lay Out The Stages, when it makes the card).

Attach toAny Object
DATA STRUCTURES
Map Spotself.mapSpot
SHARED VARIABLES
NameTypeKindStarting Value
fadeSecondsNumberConstant0.25
On Placed
WhenplacedCustom Event
1Ifself.mapSpot.isOpen == true
Then
2Ifself.mapSpot.stageNumber == $nextStage
Then
3Change Variable
Variable
$selectedCard
Value
self.mapSpot.cardIndex
4Set Frame
Frame
1
5Otherwise
6Set Frame
Frame
0
7Otherwise
8Set Frame
Frame
2
When Left Is Clicked
WhenMouse Pressed on ObjectMouse button: left
1Trigger Custom Event on Object
Custom Event
chosen
When Open Is Pressed
WhenCommand PressedCommand: Open
1Ifself.mapSpot.cardIndex == $selectedCard
Then
2Trigger Custom Event on Object
Custom Event
chosen
On Chosen
WhenchosenCustom Event
1Ifself.mapSpot.isOpen == true
Then
2Control Sound
Sound
Sound Click
3Change Variable
Variable
$stage
Value
self.mapSpot.stageNumber
4Go to Scene
Scene
Field
Transition
Fade
Transition Seconds
@self.fadeSeconds

A.60 Open The Places

Built in Chapter 8, The Title and the Maps.

Logic ComponentOpen The PlacesAttach to: Play Button

The Play button, and Enter or Space on the Title (the Open Command): goes to the Place Map.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
fadeSecondsNumberConstant0.25
On Hud Activated
WhenUI Activated
1Trigger Custom Event on Object
Custom Event
opened
When Open Is Pressed
WhenCommand PressedCommand: Open
1Trigger Custom Event on Object
Custom Event
opened
On Opened
WhenopenedCustom Event
1Control Sound
Sound
Sound Click
2Go to Scene
Scene
Place Map
Transition
Fade
Transition Seconds
@self.fadeSeconds

A.61 Play The Title Tune

Built in Chapter 8, The Title and the Maps.

Logic ComponentPlay The Title TuneAttach to: Title Director, Places Director, Stages Director

When the Title starts, the title tune plays at the game's music level, and the menu keys work.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
crossfadeSecondsNumberConstant1.5
When the Scene Starts
WhenScene Start
1Set Input Context Active
Input Context
Menus
2Set Input Context Active
Input Context
Field
Active
No
3Set Input Context Active
Input Context
Card
Active
No
4Set Volume
Audio Bus
Music
Volume
$musicLevel
5Control Sound
Operation
Crossfade Music
Sound
Music Title
Crossfade Seconds
@self.crossfadeSeconds

A.62 Show The Place Picture

Built in Chapter 8, The Title and the Maps.

Logic ComponentShow The Place PictureAttach to: Place Picture

The picture of one place on its card (frame n is place n), dimmed when the place is locked. It reads placeIndex and isOpen (its Map Spot), set by Belong To A Place, attached first.

Attach toAny Object
DATA STRUCTURES
Map Spotself.mapSpot
SHARED VARIABLES
NameTypeKindStarting Value
lockedAlphaNumberConstant0.55
On Placed
WhenplacedCustom Event
1Set Frame
Frame
self.mapSpot.placeIndex
2Ifself.mapSpot.isOpen == false
Then
3Set Alpha
Alpha
@self.lockedAlpha

A.63 Choose With The Keys

Built in Chapter 9, Locks and Keys.

Logic ComponentChoose With The KeysAttach to: Places Director, Stages Director

The arrow keys (or W A S D, the Choose Command) move the selection one card at a time on a map of cards in rows; the selection ring shows from the first key press. It reads cardCount and cardsInARow (its Map Grid), set by Lay Out The Places or Lay Out The Stages, on the same Director, when the map is made.

Attach toAny Object
DATA STRUCTURES
Map Gridself.mapGrid
When the Scene Starts
WhenScene Start
1Change Variable
Variable
$selectedCard
Value
0
2Change Variable
Variable
$isChoosing
Value
false
When Choose Left Is Pressed
When2D Direction PressedCommand: ChooseDirection: Left
1Change Variable
Variable
$selectedCard
Value
max(0, $selectedCard - 1)
2Trigger Custom Event on Object
Custom Event
moved
When Choose Right Is Pressed
When2D Direction PressedCommand: ChooseDirection: Right
1Change Variable
Variable
$selectedCard
Value
min(self.mapGrid.cardCount - 1, $selectedCard + 1)
2Trigger Custom Event on Object
Custom Event
moved
When Choose Up Is Pressed
When2D Direction PressedCommand: ChooseDirection: Up
1If$selectedCard >= self.mapGrid.cardsInARow
Then
2Change Variable
Variable
$selectedCard
Operator
-=
Value
self.mapGrid.cardsInARow
3Trigger Custom Event on Object
Custom Event
moved
When Choose Down Is Pressed
When2D Direction PressedCommand: ChooseDirection: Down
1If($selectedCard + self.mapGrid.cardsInARow) < self.mapGrid.cardCount
Then
2Change Variable
Variable
$selectedCard
Operator
+=
Value
self.mapGrid.cardsInARow
3Trigger Custom Event on Object
Custom Event
moved
On Moved
WhenmovedCustom Event
1Change Variable
Variable
$isChoosing
Value
true
2Control Sound
Sound
Sound Click

A.64 Dim When Locked

Built in Chapter 9, Locks and Keys.

Logic ComponentDim When LockedAttach to: Stage Number, Stage Name

A part of a locked stage's card is dimmed to lockedAlpha. It reads isOpen (its Map Spot), set by Belong To A Stage, attached first.

Attach toAny Object
DATA STRUCTURES
Map Spotself.mapSpot
SHARED VARIABLES
NameTypeKindStarting Value
lockedAlphaNumberConstant0.5
On Placed
WhenplacedCustom Event
1Ifself.mapSpot.isOpen == false
Then
2Set Alpha
Alpha
@self.lockedAlpha

A.65 Show A Lock

Built in Chapter 9, Locks and Keys.

Logic ComponentShow A LockAttach to: Place Lock, Stage Lock

A lock on a card: shown only when its place or stage is locked. It reads isOpen (its Map Spot), set by Belong To A Place or Belong To A Stage, attached first.

Attach toAny Object
DATA STRUCTURES
Map Spotself.mapSpot
On Placed
WhenplacedCustom Event
1Ifself.mapSpot.isOpen == false
Then
2Set Visible
Visible
Yes
3Otherwise
4Set Visible
Visible
No

A.66 Show The Ring

Built in Chapter 9, Locks and Keys.

Logic ComponentShow The RingAttach to: Place Ring, Stage Ring

The selection ring of one card: shown on the selected card ($selectedCard) once the keys are used ($isChoosing). It reads cardIndex (its Map Spot), set by Lay Out A Place Card or Lay Out A Stage Card, when the card makes the ring.

Attach toAny Object
DATA STRUCTURES
Map Spotself.mapSpot
When Created
WhenCreate
1Set Visible
Visible
No
On Variable Changed · Selected Card
WhenVariable ChangedGlobal Variable: selectedCard
1Trigger Custom Event on Object
Custom Event
placeRing
On Variable Changed · Is Choosing
WhenVariable ChangedGlobal Variable: isChoosing
1Trigger Custom Event on Object
Custom Event
placeRing
On Place Ring
WhenplaceRingCustom Event
1If$isChoosing == true && self.mapSpot.cardIndex == $selectedCard
Then
2Set Visible
Visible
Yes
3Otherwise
4Set Visible
Visible
No

A.67 Close How To Play

Built in Chapter 10, Remembering, Settings and Finish.

Logic ComponentClose How To PlayAttach to: Got It Button

The Got it button (and Enter or Space): closes the How to play card for good on this device, and the stage begins.

Attach toAny Object
When Created
WhenCreate
1If$howToPlaySeen == false
Then
2Set Input Context Active
Input Context
Field
Active
No
3Set Input Context Active
Input Context
Menus
On Hud Activated
WhenUI Activated
1Trigger Custom Event on Object
Custom Event
gotIt
When Open Is Pressed
WhenCommand PressedCommand: Open
1Trigger Custom Event on Object
Custom Event
gotIt
On Got It
WhengotItCustom Event
1If$howToPlaySeen == false
Then
2Control Sound
Sound
Sound Click
3Change Variable
Variable
$howToPlaySeen
Value
true
4Save Persistent Value
Action Name
howToPlayKept
Key
"howToPlaySeen"
Value
1
5Set Input Context Active
Input Context
Menus
Active
No
6Set Input Context Active
Input Context
Field
7Trigger Custom Event
Custom Event
howToPlayClosed

A.68 Count All The Stars

Built in Chapter 10, Remembering, Settings and Finish.

Logic ComponentCount All The StarsAttach to: Finale Message

Counts the stars of every stage (the Stages table) for the finale: the text reads starsInAll.

Attach toAny Object
DATA STRUCTURES
Finale Starsself.finaleStars
On Finale Shown
WhenfinaleShownCustom Event
1Change Component Value
Component Value
self.finaleStars.starsInAll
Value
0
2RepeatdataCount("Stages")times
Each time
3Change Component Value
Component Value
self.finaleStars.starsInAll
Operator
+=
Value
data("Stages", local.index, "stars")

A.69 Keep The Stars

Built in Chapter 10, Remembering, Settings and Finish.

Logic ComponentKeep The StarsAttach to: Game Rules

When a stage is won, keeps its place's stars on the device (one number per place), so they survive closing the game.

Attach toAny Object
On Stars Counted
WhenstarsCountedCustom Event
1Declare Variable
Name
place
Value
0
2Declare Variable
Name
packed
Value
0
3Declare Variable
Name
stageRow
Value
0
4Change Variable
Variable
place
Value
floor(($stage - 1) / $stagesPerPlace)
5Change Variable
Variable
packed
Value
0
6Repeat$stagesPerPlacetimes
Each time
7Change Variable
Variable
stageRow
Value
place * $stagesPerPlace + local.index
8Change Variable
Variable
packed
Operator
+=
Value
data("Stages", stageRow, "stars") * pow(4, local.index)
9Save Persistent Value
Action Name
starsKept
Key
data("Places", place, "starsKey")
Value
packed

A.70 Read Back What Was Kept

Built in Chapter 10, Remembering, Settings and Finish.

Logic ComponentRead Back What Was KeptAttach to: Title Director

When the game opens, reads back once what this device kept: the stars (into the Stages table) and whether How to play was seen.

Attach toAny Object
When the Game Starts
WhenGame Start
1RepeatdataCount("Places")times
Each time
2Load Persistent Value
Action Name
keptStars
Key
data("Places", local.index, "starsKey")
Default
0
3Unpack A Place's StarsFunction
place
local.index
packed
keptStars.value
4Load Persistent Value
Action Name
keptHowToPlay
Key
"howToPlaySeen"
Default
0
5IfkeptHowToPlay.value == 1
Then
6Change Variable
Variable
$howToPlaySeen
Value
true
7Otherwise
8Change Variable
Variable
$howToPlaySeen
Value
false
9Load Persistent Value
Action Name
keptSound
Key
"soundOff"
Default
0
10IfkeptSound.value == 1
Then
11Change Variable
Variable
$soundOff
Value
true
12Otherwise
13Change Variable
Variable
$soundOff
Value
false
14Load Persistent Value
Action Name
keptMotion
Key
"calmMotion"
Default
0
15IfkeptMotion.value == 1
Then
16Change Variable
Variable
$calmMotion
Value
true
17Otherwise
18Change Variable
Variable
$calmMotion
Value
false

A.71 Show How To Play

Built in Chapter 10, Remembering, Settings and Finish.

Logic ComponentShow How To PlayAttach to: How To Play Panel, How To Play Text, Got It Button

A part of the How to play card: shown only the very first time a stage is played on this device, until "Got it".

Attach toAny Object
When Created
WhenCreate
1If$howToPlaySeen == true
Then
2Set Visible
Visible
No
3Otherwise
4Set Visible
Visible
Yes
On How to Play Closed
WhenhowToPlayClosedCustom Event
1Set Visible
Visible
No

A.72 Show The Choice (Function)

Built in Chapter 10, Remembering, Settings and Finish.

FunctionShow The Choice

Shows a choice on its button's icon: frame 1 when the choice is on, frame 0 when it is off.

PARAMETERS
NameTypeStarts at
buttonObject
isOnBooleanNo
ACTIONS
1IfisOn == true
Then
2Set Frame
Applies to
button
Frame
1
3Otherwise
4Set Frame
Applies to
button
Frame
0

A.73 Show With The Finale

Built in Chapter 10, Remembering, Settings and Finish.

Logic ComponentShow With The FinaleAttach to: Finale Panel, Finale Message, Finale Button, Finale Star

A part of the finale: hidden until the last stage is won.

Attach toAny Object
When Created
WhenCreate
1Set Visible
Visible
No
On Finale Shown
WhenfinaleShownCustom Event
1Set Visible
Visible
Yes

A.74 Sing The Finale

Built in Chapter 10, Remembering, Settings and Finish.

Logic ComponentSing The FinaleAttach to: Game Rules

After the last stage: every note of that stage sings once from low to high, then all of them together.

Attach toAny Object
DATA STRUCTURES
Sing The Finale Dataself.singTheFinaleData
SHARED VARIABLES
NameTypeKindStarting Value
secondsBetweenNotesNumberConstant0.16
firstNoteSecondsNumberConstant0.1
On Finale Shown
WhenfinaleShownCustom Event
1Change Component Value
Component Value
self.singTheFinaleData.turn
Value
0
2Change Component Value
Component Value
self.singTheFinaleData.firstNote
Value
data("Stages", $stage - 1, "firstNote")
3Start Recurring Timer
Timer Name
"finaleNote"
Repeat Every (s)
@self.secondsBetweenNotes
First Delay (s)
@self.firstNoteSeconds
On the Finale Note Timer
WhenRecurring TimerTimer name: finaleNote
1Ifself.singTheFinaleData.turn < data("Stages", $stage - 1, "noteCount")
Then
2Play Piano NoteFunction
pitch
data("Notes", self.singTheFinaleData.firstNote + self.singTheFinaleData.turn, "midi")
3Change Component Value
Component Value
self.singTheFinaleData.turn
Operator
+=
Value
1
4Otherwise
5Repeatdata("Stages", $stage - 1, "noteCount")times
Each time
6Play Piano NoteFunction
pitch
data("Notes", self.singTheFinaleData.firstNote + local.index, "midi")
7Stop Recurring Timer
Timer Name
"finaleNote"

A.75 Turn Calm Motion On And Off

Built in Chapter 10, Remembering, Settings and Finish.

Logic ComponentTurn Calm Motion On And OffAttach to: Motion Button

The Motion button: turns calm motion on or off (no slow motion, camera shake, bobbing or flying bits); its icon shows which (frame 1 is calm), and the choice is kept on the device.

Attach toAny Object
When Created
WhenCreate
1Trigger Custom Event on Object
Custom Event
showChoice
On Hud Activated
WhenUI Activated
1If$calmMotion == true
Then
2Change Variable
Variable
$calmMotion
Value
false
3Save Persistent Value
Action Name
keptNo
Key
"calmMotion"
Value
0
4Otherwise
5Change Variable
Variable
$calmMotion
Value
true
6Save Persistent Value
Action Name
keptYes
Key
"calmMotion"
Value
1
7Control Sound
Sound
Sound Click
On Variable Changed · Calm Motion
WhenVariable ChangedGlobal Variable: calmMotion
1Trigger Custom Event on Object
Custom Event
showChoice
On Show Choice
WhenshowChoiceCustom Event
1Show The ChoiceFunction
isOn
$calmMotion
button
self

A.76 Turn The Sound On And Off

Built in Chapter 10, Remembering, Settings and Finish.

Logic ComponentTurn The Sound On And OffAttach to: Sound Button

The Sound button: turns all sound off or on; its icon shows which (frame 1 is off), and the choice is kept on the device.

Attach toAny Object
When Created
WhenCreate
1Trigger Custom Event on Object
Custom Event
showChoice
On Hud Activated
WhenUI Activated
1If$soundOff == true
Then
2Change Variable
Variable
$soundOff
Value
false
3Save Persistent Value
Action Name
keptNo
Key
"soundOff"
Value
0
4Otherwise
5Change Variable
Variable
$soundOff
Value
true
6Save Persistent Value
Action Name
keptYes
Key
"soundOff"
Value
1
7Control Sound
Sound
Sound Click
On Variable Changed · Sound Off
WhenVariable ChangedGlobal Variable: soundOff
1Trigger Custom Event on Object
Custom Event
showChoice
On Show Choice
WhenshowChoiceCustom Event
1Show The ChoiceFunction
isOn
$soundOff
button
self
2If$soundOff == true
Then
3Set Volume
Volume
0
4Otherwise
5Set Volume
Volume
1

A.77 Unpack A Place’s Stars (Function)

Built in Chapter 10, Remembering, Settings and Finish.

FunctionUnpack A Place's Stars

Writes the stars of a place's stages ($stagesPerPlace of them) into the Stages table from one number kept on the device (base 4: the place's stage k is digit k).

PARAMETERS
NameTypeStarts at
placeNumber0
packedNumber0
ACTIONS
1Repeat$stagesPerPlacetimes
Each time
2Set Data Cell
Table
Stages
Row
place * $stagesPerPlace + blockLocal("index")
Column
"stars"
Value
mod(floor(packed / pow(4, blockLocal("index"))), 4)