- Learn
- Build a Game
- Pitch Shot
- 5 Wrong Notes
5 Wrong Notes
By the end of this chapter, every shot is judged as it leaves the slingshot. A wrong note shakes and sings its own pitch, so you can hear it beside the call, and the pill says “Not that one. Listen again…”. The towers stand firm and throw a wrong shot back. After two wrong notes, a gold arrow points the way.
The game as it is at the end of this chapter. Click the game to play.
If your game and this chapter part ways, here is the chapter’s finished project. Unzip it first. Then open it and compare, or start Chapter 6 from it.
To open it, right-click the downloaded file, choose Extract All... and then Extract. Start Myth Engine, choose File › Open Project... and pick the .mythproj file in the new folder. Nunito-OFL.txt beside it comes with the game.
5.1 The Idea
Pull back, let go, and the happy note sails into the tower. It knocks against a post, drops and rolls. And the pill says what it has said every time since Chapter 4: Missed! Listen again…
Even when you heard the call right. Even when the note flew straight at it.
That’s because the game can’t yet tell which singing note you were after. And it’s harder than it sounds. A shot rarely meets its note cleanly. It may clip a post on the way, or a plank, and spring back before it ever touches the note it was flying at. Who decides what that shot was for?
Think of a game of pool. A good player calls the pocket before the shot, and the call stands, whatever the ball bumps on the way. Pitch Shot does the same, for you. The moment the note leaves the band, the game follows the path the dots have been drawing and finds the first singing note it comes near. That note is the aimed note. Its pitch goes into $aimedPitch, and a shot that comes near no note gets 0.
After that, the flight only decides when the answer comes. The aimed note answers once, when the shot touches it, strikes the tower, or ends. A wrong note, one that isn’t the call, shakes. And it sings its own pitch, so you can hear it beside the call and compare the two.
5.2 The Plan
Here’s how the pieces work together. A name in bold is a piece you’ll make, and a name in plain text is a Custom Event.
- The stage is built -> Build The Stage writes down where each note sits.
- You let go -> happyNoteLaunched -> Fly asks Judge The Shot ->
$aimedPitch, and Fly picks how bouncy the note is. - The happy note strikes a block -> Tell Of A Strike, on each block -> towerStruck.
- The happy note touches a singing note, or towerStruck, or shotEnded -> Answer The Shot, on every singing note -> only the aimed one answers. A wrong note sings, shakes, and sends wrongNoteReached.
- Each wrongNoteReached -> Count The Shots counts it -> wrongNoteCounted -> Ask Again says Not that one. Listen again…, or, from the second, gives a hint -> hintWanted -> Point To The Call shows the Hint Arrow.
- When
$aimedPitchis 0, shotEnded -> Ask Again says Missed! Listen again…, as before.
You’ll build it in that order: first where the notes sit, then the judging, then the answer, the words and the arrow.
5.3 Set Up
ART names the arrow’s picture, which the Starter Kit already brought.
GLOBAL VARIABLES has two. $aimedPitch is the aimed note’s pitch, and $wrongNotes counts the wrong notes of the stage. Both are Numbers that start at 0. Add them from the canvas’s Globals card, as you made $shots.
PLACE THESE waits for the Hint Arrow, and the chapter comes back to it at the end.
5.4 Where Every Note Sits
To follow a path and see which note it passes, the game has to know where every singing note is. Build The Stage works that out already, note by note, with Where A Note Sits. It uses the answer once, to make the note. And then it forgets it.
So now it writes each spot down, in the Notes table, where Judge The Shot and the arrow can read it later.
Nothing new shows in this part, or the next. The first answer comes when the singing notes learn to speak.
5.4.1 Note Spot, Changed
One singing note of a stage: the pitch it sings and the tower it sits in, and where it sits.
Add the two new fields at the bottom of the list, x and y, both of them Numbers.
5.4.2 The Notes Table, Changed
F353000F465000F sharp354000There’s nothing to type here, and nothing to import again. Notes is shaped by Note Spot, so the two new fields are two new columns already, and every cell starts at 0. That’s right. The table is a plan, and a plan doesn’t need to know where its notes will stand. Build The Stage fills them in while the game runs.
5.4.3 Build The Stage, Changed
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.
Any Object- Name
tower- Value
0
- Name
towerRow- Value
0
- Name
towerX- Value
0
- Name
floorRow- Value
0
- Name
floorBottom- Value
0
- Type
Text- Name
roofKind
- Name
row- Value
0
- Label
"Towers"- Color
#C27A3A
data("Stages", $stage - 1, "towerCount")times- Variable
tower- Value
local.index
- Variable
towerRow- Value
data("Stages", $stage - 1, "firstTower") + tower
- Variable
towerX- Value
data("Tower Plans", towerRow, "x")
- Variable
floorBottom- Value
@self.groundHeight
data("Tower Plans", towerRow, "floorCount")times- Variable
floorRow- Value
data("Tower Plans", towerRow, "firstFloor") + local.index
- towerX
towerX- floorBottom
floorBottom- floorHeight
@self.floorHeight- supportSpread
@self.supportSpread- builder
self- material
data("Floors", floorRow, "material")
- Variable
floorBottom- Operator
+=- Value
@self.floorHeight
- Action Name
roofFound- Table
Materials- Row
data("Tower Plans", towerRow, "roof")
roofFound.value == true- Variable
roofKind- Value
data("Materials", data("Tower Plans", towerRow, "roof"), "support")
- x
towerX - @self.roofSpread- y
floorBottom + data("Block Kinds", roofKind, "height") / 2- builder
self- kind
roofKind
- x
towerX + @self.roofSpread- y
floorBottom + data("Block Kinds", roofKind, "height") / 2- builder
self- kind
roofKind
- Label
"Singing Notes"- Color
#E8B923
data("Stages", $stage - 1, "noteCount")times- Variable
row- Value
data("Stages", $stage - 1, "firstNote") + local.index
- Action Name
noteSpot- noteRow
row- groundHeight
@self.groundHeight- floorHeight
@self.floorHeight- noteAboveFloor
@self.noteAboveFloor
- Table
Notes- Row
row- Column
"x"- Value
noteSpot.x
- Table
Notes- Row
row- Column
"y"- Value
noteSpot.y
- Object to Create
@self.singingNote- X
noteSpot.x- Y
noteSpot.y- Variable Name
newNote
- Variable
newNote.noteRow- Value
data("Stages", $stage - 1, "firstNote") + local.index
- Variable
newNote.turn- Value
local.index
- Applies to
newNote- Custom Event
placed
- Custom Event
stageBuilt
Two new steps go between Where A Note Sits and Create Instance. Each is a Set Data Cell, which writes into one cell of a table while the game runs. It’s one of the Advanced Mode Actions, and it has a box for each of the card’s lines: Table, Row, Column and Value. The first writes noteSpot.x into the x column of this note’s row, and the second writes noteSpot.y into the y column.
Pick Notes in its Table list. Its Column box takes "x" or "y", with quotes, as the card shows. The running game’s copy changes. The table saved in your project keeps the 0s you gave it.
The two steps go in the middle of a line, so use Disconnect Incoming on Create Instance, as Actions, one at a time shows near its end.
5.5 Calling the Shot
Now the judging. It happens in one moment, as the note leaves the band.
5.5.1 Shot Sums, Changed
The working values of the Functions that aim the happy note: the pull (Aim At), and the path it will fly (Judge The Shot).
Ten new Numbers, all starting at 0. They’re Judge The Shot’s working values, kept on the happy note, the way Aim At keeps its own there.
5.5.2 Judge The Shot
Picture the dots again, the flip-book of Chapter 3. Thirty-three pages, a little apart. Judge The Shot reads the same flight, but it turns the pages much faster: every pathStepSeconds, 0.004 seconds of flight, up to longestPathSeconds, 5 seconds in all. At each page, it asks one question of every singing note in the stage. Am I near you?
Each page is a point on the path, worked out by the dots’ own sum. For each note, the page asks the Notes table where it sits, which is what Build The Stage wrote down. The straight line from the point to the note is distanceToNote. The rest are steps on the way.
A note is near when distanceToNote is under reach, 0.64 meters. That number isn’t a guess. The happy note’s Collider is a circle with a Radius of 0.3 meters, and the singing note’s will have 0.34. Add them, and 0.64 is the gap at which the two circles touch.
The If at the end joins five checks in one Condition box. Each keeps out a wrong answer. The first, $aimedPitch == 0, means the first note found wins, and no note further along can take its place. The other four ask that the note is within reach, and that the point is still above the grass and inside the field. A path that has already hit the ground or left the screen finds nothing more.
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.
shotSumsData StructureShot Sums- Variable
$aimedPitch- Value
0
- Component Value
shot.shotSums.t- Value
0
round(longestPathSeconds / pathStepSeconds)times- Component Value
shot.shotSums.t- Operator
+=- Value
pathStepSeconds
- Component Value
shot.shotSums.pathX- Value
$aimX + $launchVX * shot.shotSums.t
- Component Value
shot.shotSums.drop- Value
$gravity / 2 * shot.shotSums.t * shot.shotSums.t
- Component Value
shot.shotSums.pathY- Value
$aimY + $launchVY * shot.shotSums.t - shot.shotSums.drop
data("Stages", $stage - 1, "noteCount")times- Component Value
shot.shotSums.noteRow- Value
data("Stages", $stage - 1, "firstNote") + local.index
- Component Value
shot.shotSums.noteX- Value
data("Notes", shot.shotSums.noteRow, "x")
- Component Value
shot.shotSums.noteY- Value
data("Notes", shot.shotSums.noteRow, "y")
- Component Value
shot.shotSums.gapX- Value
shot.shotSums.pathX - shot.shotSums.noteX
- Component Value
shot.shotSums.gapY- Value
shot.shotSums.pathY - shot.shotSums.noteY
- Component Value
shot.shotSums.distanceToNote- Value
hypot(shot.shotSums.gapX, shot.shotSums.gapY)
$aimedPitch == 0 && shot.shotSums.distanceToNote < reach && shot.shotSums.pathY > groundHeight && shot.shotSums.pathX > fieldLeft && shot.shotSums.pathX < fieldRight- Variable
$aimedPitch- Value
data("Notes", shot.shotSums.noteRow, "midi")
Make it with Add > Function. Its shot is like Aim At’s happyNote: Object at the end of the Type list. Open its pencil on Start, and add Shot Sums under Required Components, with the Slot Name shotSums. Its working values live on shot.
There are two Repeats, one inside the other, like Build The Stage’s towers and floors. The outer one walks the path. The inner one goes through the notes at each point. The If at step 15 belongs inside the inner one, with its five checks joined by && in the Condition box.
5.5.3 Fly, Changed
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.
Any Objectself.shotSumsself.flyDataCollider- Logic Component
Pull Back- State
Disable
- Component Value
self.collider.fixed- Value
false
- Component Value
self.transform.gravity- Value
true
- X Velocity
$launchVX- Y Velocity
$launchVY
- groundHeight
@self.groundHeight- fieldLeft
@self.fieldLeft- fieldRight
@self.fieldRight- shot
self
$aimedPitch == $calledPitch- Value
@self.hitBounce
- Value
@self.springBackBounce
- Sound
Sound Launch
- Timer Name
"watchFlight"- Repeat Every (s)
@self.checkSeconds- First Delay (s)
@self.checkSeconds
- Name
speed- Value
0
- Component Value
self.flyData.flightSeconds- Operator
+=- Value
@self.checkSeconds
- Variable
speed- Value
hypot(self.transform.velocity.x, self.transform.velocity.y)
speed < @self.stillSpeed- Component Value
self.flyData.stillFor- Operator
+=- Value
@self.checkSeconds
- Component Value
self.flyData.stillFor- Value
0
self.transform.position.y < @self.rollingHeight- Amount
@self.rollingSlowdown
self.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- Timer Name
"watchFlight"
- 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
- Custom Event
shotEnded
Fly calls Judge The Shot the moment it sets the note’s speed. Nothing else has happened yet. Then it picks a bounce. A shot at the call keeps hitBounce, 0.15, and settles softly against its tower. Every other shot gets springBackBounce, 0.4, so it springs back off the towers. The towers won’t have it.
Set Bounciness changes the Collider’s Bounciness while the game runs, and its one box, Value, takes the Shared Variable. Add hitBounce and springBackBounce under the Shared Variables card. Both live there.
Steps 5 to 9 go between Set Velocity and Control Sound. So use Disconnect Incoming on Control Sound first. On the Judge The Shot block, shot is a list, so pick self. Its groundHeight, fieldLeft and fieldRight take Fly’s Shared Variables, with @self. before each name, and the Else at step 8 belongs to the If at step 6.
Run the game, and shoot at the tower. It leaves the same way. But when it hits a post, it springs back farther than it used to. The pill still says Missed! every time. The game has called the shot. Nobody answers yet.
5.6 A Wrong Note Answers
Now the singing notes learn to hear the shot.
5.6.1 One Tag for Every Block
A shot can strike any of the five kinds of block. Each should ring the same bell. They already share the Tag Block, from Chapter 1. Each will carry Tell Of A Strike, so every block can report a touch in the same way.
5.6.2 Tell Of A Strike
When the happy note first touches a block, the block rings one bell: towerStruck. That’s all it does.
When the happy note strikes this block, tells everyone that the shot has reached the towers.
Any Object- Custom Event
towerStruck
Make it, and attach it to each of the five blocks: Wood Post, Wood Plank, Stone Cube, Stone Plank and Ice Cube. Its Event is a Collision Enter, which runs once, the moment two bodies first touch. Its Collision Target, on the Event’s own bar, is Happy Note, so a block touching another block rings nothing. Events: the When bars has it in the paragraph that begins From Chapter 5. The heading When Starting to Hit Happy Note is Myth’s own name for it.
5.6.3 The Five Blocks, Changed
X 0.24, Y 1.12On0.35X 0.24, Y 1.120.040.75On30Wood Post ArtX 0.24, Y 1.12BlockThe Wood Post now carries Tell Of A Strike. Its Tag stays Block. Attach the Logic to the other four kinds too, so every post, plank and cube can report a touch.
The other four cards differ only in their names and numbers. Here’s the Ice Cube’s.
X 0.56, Y 0.560.7On0.2X 0.56, Y 0.560.080.2On30Ice Cube ArtX 0.56, Y 0.56Block5.6.4 The Singing Note, Changed
X 0.84, Y 0.83OffSensorCircle0.3435Singing Note ArtX 0.84, Y 0.83Answer The Shot, Bob While Waiting, Sing In The OpeningBob While Waiting, Sing In The OpeningNote StateAnswer The ShotAnswer The Shot DataThe singing note gets a body too, a circle with a Radius of 0.34 meters. Attach a Collider from Physics, pick Circle in its Shape list, and type the Radius.
Its Collision is three buttons at the top of the Collider, above Shape and Transform: Solid, Sensor and Off. Pick Sensor. A sensor feels a touch, but it never pushes back. So the happy note passes right through a singing note, and the note still knows it was touched. Leave Physics Object Off under its Transform. Logic moves this note, so physics mustn’t push it away from its spot.
You’ll attach Answer The Shot at the end of the next part, once it’s made. It uses Note State, which the note already carries. It also brings Answer The Shot Data. Their From Logic lines fill in when you attach the Logic to the note.
5.6.5 Answer The Shot
Every singing note in the stage hears about every shot, but only one should answer, the aimed one, and only once.
A shot can reach its note three ways. It can touch it. It can strike the tower first and spring back. Or it can end somewhere else. Answer The Shot listens for all three, and turns each into one message to the note itself, shotArrived. So there’s one answer, whichever way the shot came.
That answer is an Event with two Modes, Waiting and Answered. Each new shot sets it to Waiting. In Waiting, the note asks: is my pitch the aimed one? Its pitch in Note State is the note’s midi number, the same kind of number as $aimedPitch, so the two compare. If not, the shot wasn’t for me, and I do nothing. If it is, I switch to Answered at once, so a second touch in the same shot is ignored.
And if this note isn’t the call, it answers out loud. It sings its own pitch with Play Piano Note, and it shakes, 0.06 meters to each side, every 0.05 seconds, for half a second. Last, it sends wrongNoteReached.
And if it is the call? For now it switches to Answered, and that’s all. The card’s description mentions Step 06. That’s this book’s Chapter 6, where the called note gets its answer.
The shake is a timer. Each time shake rings, the note flips to its other side, and Tween glides it there, over 0.05 seconds. shakeLeft counts the time down from shakeSeconds. When it’s used up, the note glides home, to homeX, the spot it remembered when it was made, and the timer stops.
Answer The Shot Data keeps the note’s home and the shake between timer rings. Make it before the Logic, then pick it beside Note State on the Data Structures card.
Object Data of Logic "Answer The Shot" (its state that lasts between Events).
When the shot reaches this singing note and the shot was judged to be aimed at it, the note answers: it sings its own pitch and shakes, and if it is not the call it says so. (Step 06 adds what the called note does.) It reads pitch (its Note State), set by Sing In The Opening, when the note hears "placed".
Any Objectself.noteStateself.answerTheShotData- Component Value
self.answerTheShotData.homeX- Value
self.transform.position.x
- Event
On Shot Arrived- Mode
Waiting
- Custom Event
shotArrived
- Custom Event
shotArrived
- Custom Event
shotArrived
self.noteState.pitch == $aimedPitch- Event
On Shot Arrived- Mode
Answered
self.noteState.pitch != $calledPitch- pitch
self.noteState.pitch
- Component Value
self.answerTheShotData.shakeLeft- Value
@self.shakeSeconds
- Timer Name
"shake"- Repeat Every (s)
@self.shakeStepSeconds- First Delay (s)
0
- Custom Event
wrongNoteReached
- Component Value
self.answerTheShotData.shakeSide- Value
-self.answerTheShotData.shakeSide
- Component Value
self.answerTheShotData.shakeLeft- Operator
+=- Value
-@self.shakeStepSeconds
self.answerTheShotData.shakeLeft > 0- Value
self.transform.position.x- Target
self.answerTheShotData.homeX + self.answerTheShotData.shakeSide * @self.shakeMeters- Duration
@self.shakeStepSeconds
- Value
self.transform.position.x- Target
self.answerTheShotData.homeX- Duration
@self.shakeStepSeconds
- Timer Name
"shake"
Make it with Add > Logic Component. Its Data Structures card lists Note State and Answer The Shot Data. The Shared Variables hold its shake and timing, on the Singing Note. Its Declare Variables last for one Event run.
Build the shotArrived Event and its two Modes before the happyNoteLaunched Event. That Event’s Switch Mode picks Waiting from a list. Waiting comes first, and Answered stays empty. The card draws shotArrived twice, but it’s one Event, as the band’s Step was in Chapter 3.
Three Events send shotArrived. Each is a Trigger Custom Event on Object with no Applies To, so the note sends it to itself and no other note hears. Tween’s Value is self.transform.position.x, the note’s place across.
Now attach Answer The Shot to the Singing Note.
Run the game, and shoot at the note that isn’t the call. It shakes, and you hear its pitch, right after the shot gets there. Shoot at the other one, and it stays still. That’s the call. The pill still says Missed! after both. The words are next.
5.7 The Right Words
5.7.1 The Messages Table, Changed
Low to high…Listen…Missed! Listen again…Not that one. Listen again…Listen: the note you want is higher.Listen: the note you want is lower.Three new rows. Copy and paste the words from this page. notThatOne ends with the same … as missed, one character.
5.7.2 Count The Shots, Changed
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.
Any Object- Variable
$shots- Value
0
- Variable
$wrongNotes- Value
0
- Variable
$wrongNotes- Operator
+=- Value
1
- Custom Event
wrongNoteCounted
- Variable
$shots- Operator
+=- Value
1
Count The Shots now counts wrong notes too. $wrongNotes goes back to 0 when the Field starts, and each wrongNoteReached adds one.
Next it rings a bell of its own, wrongNoteCounted, with Trigger Custom Event on Object and no Applies To, so only Game Rules hears it. Why not let Ask Again listen for wrongNoteReached itself? It needs the new count. If both heard wrongNoteReached at once, Ask Again might look before the count went up. This way, the counting comes first, and the words after it.
5.7.3 Ask Again, Changed
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.
Any Object- Variable
$message- Value
'missed'
- Timer Name
"callAgain"- Repeat Every (s)
@self.secondsAfterMiss- Ring Once
Yes
$aimedPitch == 0- Variable
$message- Value
'missed'
- Timer Name
"callAgain"- Repeat Every (s)
@self.secondsAfterMiss- Ring Once
Yes
$wrongNotes >= @self.hintAfterWrongNotes$calledPitch > $aimedPitch- Variable
$message- Value
'hintHigher'
- Variable
$message- Value
'hintLower'
- Custom Event
hintWanted
- Variable
$message- Value
'notThatOne'
- Timer Name
"callAgain"- Repeat Every (s)
@self.secondsAfterWrongNote- Ring Once
Yes
- Custom Event
callRequested
Ask Again has two kinds of miss to answer now, and it tells them apart.
When shotEnded comes, it looks at $aimedPitch first. Is it 0? Then the shot went near no note, and it’s Missed! Listen again…, as before. If not, a singing note has the answer, and Ask Again leaves it to that note.
When wrongNoteCounted comes, it’s a wrong note. On the first, the pill says Not that one. Listen again… From the second wrong note on, hintAfterWrongNotes, 2, it gives a hint instead of those words. Is the call higher than the note you reached? The pill says the note you want is higher, and if not, lower. And it sends hintWanted, for the arrow.
Either way, the call sings again secondsAfterWrongNote later, 1 second, a little longer than after a miss. You hear the wrong note’s pitch first, and then the call.
In the first Event, delete the old steps, and build the new If in their place, then the two steps inside it.
In the second Event, there’s an If inside an If. Follow the card’s bars for the nesting. The pitch check belongs inside the hint-count check, with its own Else. Use Add inside Then and Add inside Else. The callAgain timer belongs after the outer If, on the Event’s main line.
Run the game. Shoot at the wrong note. It shakes and sings, and the pill says Not that one. Listen again… A second later, the call. Now you can hear them side by side.
5.8 An Arrow That Points
5.8.1 The Hint Arrow
X 0.6, Y 0.755Hint Arrow ArtX 0.6, Y 0.7Point To The CallPoint To The Call DataThe Hint Arrow is a gold arrow, pointing up, made as an Empty Object with its Sprite and sizes. Its Scene Depth Draw Order of 55 draws it in front of the notes and the dots.
5.8.2 Point To The Call
The arrow is placed once, and it hides until it’s wanted. When hintWanted comes, it goes looking for the wrong note you reached.
It reads the Notes table, as Judge The Shot did, and goes through the stage’s notes until it finds the row whose midi is $aimedPitch. That row’s x and y are where the wrong note sits.
Then it turns. A higher note always sits higher in its tower, since Chapter 1. So if the call is higher, the arrow points up, at 0 degrees, and sits above the note. If it’s lower, the arrow turns to 180, upside down, and sits below. Either way it goes besideMeters, 0.78 meters, to the left of the note, and shows itself.
It bobs while it shows, up and down by 0.08 meters, one swing every 0.52 seconds, the way the singing notes bob. After showSeconds, 4.5 seconds, a second timer stops the bob and hides it.
Point To The Call Data keeps the bob’s center and direction between swings, as Stretch The Band Data kept its prong. Make it first; the Logic brings it to the arrow when attached.
Object Data of Logic "Point To The Call" (its state that lasts between Events).
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.
Any Objectself.pointToTheCallData- Visible
No
- Name
noteRow- Value
0
- Name
noteX- Value
0
- Name
noteY- Value
0
data("Stages", $stage - 1, "noteCount")times- Variable
noteRow- Value
data("Stages", $stage - 1, "firstNote") + local.index
data("Notes", noteRow, "midi") == $aimedPitch- Variable
noteX- Value
data("Notes", noteRow, "x")
- Variable
noteY- Value
data("Notes", noteRow, "y")
$calledPitch > $aimedPitch- Degrees
0
- Component Value
self.pointToTheCallData.baseY- Value
noteY + @self.aboveMeters
- Degrees
180
- Component Value
self.pointToTheCallData.baseY- Value
noteY - @self.aboveMeters
- X
noteX - @self.besideMeters- Y
self.pointToTheCallData.baseY
- Visible
Yes
- Timer Name
"bob"- Repeat Every (s)
@self.secondsPerSwing- First Delay (s)
0
- Timer Name
"hideHint"- Repeat Every (s)
@self.showSeconds- Ring Once
Yes
- Value
self.transform.position.y- Target
self.pointToTheCallData.baseY + @self.bobMeters * self.pointToTheCallData.swingDirection- Duration
@self.secondsPerSwing- Ease
Quad in Out
- Component Value
self.pointToTheCallData.swingDirection- Value
-self.pointToTheCallData.swingDirection
- Timer Name
"bob"
- Visible
No
You’ve built this before. The bob works like Bob While Waiting, Tween with Ease Quad in Out, and swingDirection flips each time. Set Visible has a Yes / No list, as before. Set Rotation has one box, Degrees. The If at step 9 comes after the Repeat, outside it. Join it on the Event’s main line.
Point To The Call brings its own Data Structure to the Hint Arrow. Its Shared Variables set the bob and its timing; the Declare Variables find the note for this one hint.
Attach it to the Hint Arrow, and then PLACE THESE. Drag the Hint Arrow onto the Field at 9.6 and 5.4. It moves itself before it shows, so the spot only matters for the moment before.
Run the game. Shoot at a wrong note twice. The second time, a gold arrow appears beside it, bobbing, pointing toward the call, and the pill tells you which way to listen.
Listen, and watch, for each of these.
- Shoot at the wrong note. It shakes side to side for half a second and sings its own pitch. The pill says Not that one. Listen again…, and a second later the call sings.
- Listen to the two together. The wrong note, then the call, close enough to compare.
- The happy note springs back off the tower, farther than in Chapter 4. Every block stays where it stood.
- Clip a post on the way to the wrong note. The wrong note still answers, the moment the post is struck.
- Shoot at the wrong note again. Now a gold arrow bobs beside it, pointing up or down toward the call, and the pill says Listen: the note you want is higher. or …lower. After 4.5 seconds, the arrow is gone.
- Shoot where no note is, high over the tower. Missed! Listen again…, and the call 0.6 seconds after the dust puffs, as before.
- Shoot at the call itself. The happy note settles softly against the tower, and nothing answers yet. The call comes back after its quiet spell.
The stage writes down where its notes sit. You let go, and Fly asks Judge The Shot to call the shot along the dots’ path. The aimed note’s pitch goes into $aimedPitch, and then the flight plays out. A block it strikes rings towerStruck. Every singing note hears the shot arrive, but only the aimed one answers, and only once. A wrong note sings and shakes. Count The Shots counts it, and Ask Again finds the words and, from the second, the arrow.
Underneath it is one idea: decide early, answer later. The shot is judged in one moment, from the path, before the note has flown a meter. After that, nothing the note bumps into can change what it was for. The answer only waits for its moment.
That’s why a shot that clips the tower still finds its note. Like a called pocket in pool, the call stands.
5.9 If It Didn’t Work
This chapter judges in one place and answers in another, so a slip can hide between them. Watch which half goes quiet. If no note ever answers, look at the judging. If the wrong one does, look at the answer.
No note ever answers? Perhaps $aimedPitch never leaves 0. Look at Build The Stage’s two Set Data Cells. Is Notes picked in Table, and is Column "x" or "y", with quotes? Then look at Fly. Is Judge The Shot joined into its line, between Set Velocity and Control Sound, and not left Unattached?
Every note shakes, or the wrong one? Look at the first If of Answer The Shot’s Waiting. It compares self.noteState.pitch with $aimedPitch, and the If inside it compares it with $calledPitch, with != between them.
A note answers twice in one shot? Look at step 2 of Waiting. It should switch On Shot Arrived to Answered, in its second list.
The happy note bumps a singing note like a wall? Its Collision is Solid. Pick Sensor.
A wrong note shakes, but the pill still says Missed!? Look at Ask Again’s first Event. Its steps sit inside an If that asks $aimedPitch == 0.
The arrow never shows? Is the Hint Arrow placed in the Field? Is hintWanted spelled the same in Ask Again and in Point To The Call’s When bar? Or perhaps the arrow points the wrong way. Look at its two Set Rotations, 0 under the If and 180 under the Else.
Each of these is one small fix. Make it, run the game, and listen again. And if you’d like to compare, the catch-up download in the Goal is this chapter’s game, finished.
The hints are yours to tune. Under Variables on Game Rules, change hintAfterWrongNotes from 2 to 1, and the arrow comes after the first wrong note. On the Singing Note, change shakeMeters under Variables from 0.06 to 0.15. A wrong note shakes its head harder. Or change springBackBounce under the Happy Note’s Variables from 0.4 to 0.8, and the tower throws a wrong shot back across the meadow. Which feels kindest to someone still learning to listen? Put everything back before Chapter 6.
Still stuck? Search the manual, or ask in the Myth Engine Discord (opens a new tab).
A wrong note answers, and the right one waits. In Chapter 6, the tower comes down.
