Build a GameCreating Sky Ace

6  Mission Timeline

Goal

The mission gets its shape. Four waves come down on a clock, and each one opens with a banner across the window: WAVE 1 - CORAL SEA PATROL first, WAVE 4 - HEAVY SQUADRON last. Zero Fighters arrive in Vs, in columns, in rows and in long slanting sweeps from the sides, each formation at its own second. By the end of this chapter, a mission is almost two minutes of flying.

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

This chapter builds on Chapter 5’s game. Starting here? The catch-up download in Chapter 5’s Goal is that game, finished, ready to start from.

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

Sky Ace, Chapter 6 finishedZip of a Myth project · 4.1 MB

To open it, right-click the downloaded file, choose Extract All... and then Extract. Start Myth Engine, choose File › Open Project... and pick the .mythproj file in the new folder. Beside it, OFL.txt is the license of the project’s font, Bebas Neue.

6.1 The Idea

So far a mission is one V. It comes down three seconds in, and after that the sky stays empty.

Now, a second into the mission, a dark strip appears across the window, with pale gold letters on it: WAVE 1 - CORAL SEA PATROL. At the top right, under the word STAGE, it says WAVE 1. The strip goes, and the V comes.

Two columns of Zero Fighters follow it, one down each side. Then a slanting line of planes sweeps in from the left edge and crosses the window as it falls. Two small Vs, a sweep from the right, a row of six, a wide V of seven. At 26 seconds the banner comes back: WAVE 2 - ACES HIGH.

That’s a wave: one of the mission’s four parts, each with its banner. Inside a wave, every group of planes still comes in a formation, the way the V did in Chapter 3. There are four kinds now. You know the V. The column, the row and the side sweep are new.

What brings them is the Mission Timeline from Chapter 3, grown to a row for each formation and its moment. But the way Chapter 3 waited has a catch. It set an alarm for the gap until the next row. A timer can only ring on a step of the game, so each ring comes a hair late, up to a sixtieth of a second. And each gap starts from that late ring.

Chain a gap for every row, and by the last V the hairs could add up to more than a third of a second. You’d hardly see that. But the table keeps growing, chapter by chapter, and every row should come when its time says. So this chapter gives the mission a clock.

Every step of play adds its own length to one number, the mission time. It works like the clock on a station wall. Every train has its time in the timetable, and it leaves when the station clock says so. A late train never makes the next one late, because nobody counts from the last train. Run Mission Timeline will read the timetable against the clock.

6.2 The Plan

Here’s how the pieces work together. Read each line from left to right: it starts with something that happens in the game.

  • Gameplay starts -> Mission Clock sets $missionTime to 0 -> every step after that adds the step’s own length.
  • A row’s time comes on the clock -> Run Mission Timeline’s alarm rings -> Make a Row Arrive reads the row -> the row’s formation picks the Function that makes the planes.
  • A wave’s time comes -> Run Waves sets $wave and $banner and sends waveStarted -> Show Banner shows the banner for a moment.
  • Whenever $wave changes -> the Wave Text, under STAGE, shows the new wave.
  • The mission fails -> nothing more arrives, and a banner that’s up goes away at once.

6.3 Set Up

This chapter adds three shared values and four placements. There are no new pictures.

Set upWhat this chapter adds
GLOBAL VARIABLES
$missionTimeNumberstarts at 0
$waveTextstarts at WAVE 1
$bannerTextstarts at
SCENE Gameplay: PLACE THESE
ObjectXY
Banner Strip0120hidden
Banner Text0118hidden
with Z-Index = 111
Wave Label250-76
with Z-Index = 120
Wave Text250-104
with Z-Index = 120

Each Global Variable is made where it’s first needed, with the + on the Globals card of a canvas. You’ll make $missionTime in the first part, on Mission Clock’s canvas, and the other two in the last part, on Run Waves’. PLACE THESE waits too.

One line on the card looks cut off. The line for $banner stops after starts at, because $banner starts empty. Nothing is missing.

6.4 A Clock for the Mission

First, the mission learns to count its own time.

6.4.1 Mission Clock

Mission Clock does one small thing, over and over: every step of the game, it adds that step’s length to $missionTime. That length is $deltaTime, about a sixtieth of a second, and Myth gives it fresh every step. So the mission time is the seconds you’ve flown so far.

Its first Event, When the Scene Starts, sets it back to 0. That Event runs every time Gameplay starts, FLY AGAIN too, before any placed Object runs its When Created. So every mission starts from zero, and the alarms that read the clock will find it there.

Why not use the time since the game started? Myth Engine keeps that one too, but it goes on counting while the game is paused. This clock doesn’t. A paused game runs no steps, so there’s nothing to add. In Chapter 10 the game learns to pause, and the mission time will wait with it.

Mission Clock’s card has no Variables of its own. It changes only a Global Variable, never its Object. So make $missionTime first. Press the + on the canvas’s Globals card and choose New Global…, as you did for the score in Chapter 3. Give it Name missionTime, Type Number and Default 0.

For the second Event, type Step into the Add Event window’s filter. Pick Step itself, at the top of the list, above Stepped on Cell and Begin Step.

Its Change Variable adds on. So its Operator is +=, not the = it starts with. Then type $deltaTime into the Value box, as the card has it. The box keeps it as you typed it.

Logic ComponentMission ClockAttach to: Game Rules

Counts the mission time ($missionTime): the seconds the mission has been played. A paused game runs no steps, so pauses are not counted.

Attach toAny Object
When the Scene Starts
WhenScene Start
1Change Variable
Variable
$missionTime
Value
0
Every Step
WhenStep
1Change Variable
Variable
$missionTime
Operator
+=
Value
$deltaTime

Attach Mission Clock to Game Rules. Nothing shows yet. Nobody playing Sky Ace ever sees the mission time, yet every plane from here on arrives by it.

You can watch it count, though, if you borrow the score for a minute. Open Score Text, the score’s number from Chapter 3, and type {$missionTime} over {$score} in its Text.

Save, and run the game. Where the score was, a number climbs, with a long tail of decimals that spills onto a second line. Sixtieths of a second never come out even. Then put {$score} back.

6.5 Three More Formations

Next, three new ways for planes to arrive.

Each formation is a Function like Spawn V Formation, with a Repeat that makes its planes one at a time. The column and the row make them above the top of the window, at entryY. So they slide into view as they fly down. Each plane comes from the enemy Parameter, a Thing Object, so the table can send any kind.

You’ve built one of these already, so these three go faster. Make each one’s PARAMETERS first, on its Start block: Caller, then enemy, then the numbers. In Create Instance, pick From a Value at the bottom of Object to Create, and type enemy in the box that opens. A Parameter’s Default box keeps three decimals, and the cards give each default that way.

6.5.1 Spawn Column

A column is planes in single file. The first starts at entryY, and each one after it starts gap meters higher, at the same x. So they come down the window one behind another.

FunctionSpawn Column

Creates a single-file line of enemies above the top edge at x, one every "gap" meters upward.

PARAMETERS
NameTypeStarts at
CallerObject
enemyThing Object
xNumber11.25
countNumber4
gapNumber2.813
entryYNumber35.938
ACTIONS
1Repeatcounttimes
Each time
2Create Instance
Applies To
Caller
Object to Create
enemy
X
x
Y
entryY + local.index * gap

6.5.2 Spawn Row

A row is planes side by side, across the whole window. Spawn Row spaces them evenly. With count planes, there are count plus one gaps, all the same size, so none touches a side. Plane 1 sits one gap in from the left, plane 2 two gaps in, and so on. That’s the card’s X.

FunctionSpawn Row

Creates a row of enemies spread evenly across the screen, just above the top edge.

PARAMETERS
NameTypeStarts at
CallerObject
enemyThing Object
countNumber4
widthNumber22.5
entryYNumber35.938
ACTIONS
1Repeatcounttimes
Each time
2Create Instance
Applies To
Caller
Object to Create
enemy
X
width * (local.index + 1) / (count + 1)
Y
entryY

6.5.3 Spawn Side Sweep

A side sweep comes in from the side, not the top. The planes start beyond one edge of the window, each one farther out and lower than the last. All of them fly across and down together, so they cross the window as a slanting line.

The side comes from edgeX. Its If asks whether edgeX is more than 0. If it is, the sweep starts past the right edge, 22.5 meters across, and flies left. If not, it comes from the left and flies right. The True line and the False line are the same moves, mirrored.

Fly Down, on the Zero Fighter, sends each plane straight down the moment it’s made. Set Velocity changes that once, right after: acrossSpeed sideways, 7.5 meters a second, and fallSpeed down, about three.

Build the True line first. The If’s Add inside Then gives it its Repeat, and the Repeat’s Add inside Repeat its two blocks. Then right-click the If and choose Add Else. The Else’s own Add inside Else adds the False line’s Repeat. The Create Instance inside that Repeat names its plane created2 by itself, in Created As, because the first one already took created. So the two Repeats never mix up their planes. Each Set Velocity you add after a Create Instance is already aimed at its plane.

FunctionSpawn Side Sweep

Creates a diagonal stream of enemies entering from beyond the left or right edge, flying across and down.

PARAMETERS
NameTypeStarts at
CallerObject
enemyThing Object
edgeXNumber0
countNumber5
widthNumber22.5
startOutNumber1.563
stepOutNumber2.344
startYNumber30.938
stepDownNumber1.406
acrossSpeedNumber7.5
fallSpeedNumber2.969
ACTIONS
1IfedgeX > 0
Then
2Repeatcounttimes
Each time
3Create Instance
Applies To
Caller
Object to Create
enemy
X
width + startOut + local.index * stepOut
Y
startY - local.index * stepDown
4Set Velocity
Applies To
created
X Velocity
-acrossSpeed
Y Velocity
-fallSpeed
5Otherwise
6Repeatcounttimes
Each time
7Create Instance
Applies To
Caller
Object to Create
enemy
X
-startOut - local.index * stepOut
Y
startY - local.index * stepDown
Created As
created2
8Set Velocity
Applies To
created2
X Velocity
acrossSpeed
Y Velocity
-fallSpeed

6.6 One Row Arrives

Now the table can choose among four formations.

6.6.1 Make a Row Arrive

Make a Row Arrive gets a row’s number and makes that row happen. It reads the row’s formation cell, and four Ifs ask which word it is.

V calls Spawn V Formation. Column calls Spawn Column, Row calls Spawn Row, and Side Sweep calls Spawn Side Sweep. Only one of the four is true. So only one formation comes.

Each call hands its Function only the cells it needs. Every call gets enemy, from the object column, and count. A V and a column get x and spacing too, a sweep gets only x, and a row needs neither. Two Functions have their own names for a cell: Spawn Column’s spacing is gap, and Spawn Side Sweep’s x is edgeX. Any field a call leaves out keeps the Function’s own default, as the sweep’s two speeds do.

Make its two PARAMETERS first, Caller and row. Each If’s condition is one box. Type it whole.

In a Function, every box reads what you type as a small formula. So a word needs its quotes: "V", as the card has it.

Each call goes on its If’s True line. Right-click the If, choose Add inside Then, and find the Function in the window’s Functions group. Join it with Connect to sequence. On the call’s block, Caller is a list, and it already holds Caller. The others are boxes, enemy too. Type the card’s expressions into them, and press Enter to keep each one.

The next If comes after the first, back on the main line, so the card gives it no indent. Add it from the Action List, and join it with Connect to sequence. It goes under the first If, not inside it. The other two follow.

FunctionMake a Row Arrive

Makes one Mission Timeline row arrive: the Object its object cell names, in the row's formation.

PARAMETERS
NameTypeStarts at
CallerObject
rowNumber0
ACTIONS
1Ifdata("Mission Timeline", row, "formation") == "V"
Then
2Spawn V FormationFunction
caller
Caller
enemy
data("Mission Timeline", row, "object")
x
data("Mission Timeline", row, "x")
count
data("Mission Timeline", row, "count")
spacing
data("Mission Timeline", row, "spacing")
3Ifdata("Mission Timeline", row, "formation") == "Column"
Then
4Spawn ColumnFunction
caller
Caller
enemy
data("Mission Timeline", row, "object")
x
data("Mission Timeline", row, "x")
count
data("Mission Timeline", row, "count")
gap
data("Mission Timeline", row, "spacing")
5Ifdata("Mission Timeline", row, "formation") == "Row"
Then
6Spawn RowFunction
caller
Caller
enemy
data("Mission Timeline", row, "object")
count
data("Mission Timeline", row, "count")
7Ifdata("Mission Timeline", row, "formation") == "Side Sweep"
Then
8Spawn Side SweepFunction
caller
Caller
enemy
data("Mission Timeline", row, "object")
edgeX
data("Mission Timeline", row, "x")
count
data("Mission Timeline", row, "count")

6.7 The Whole Mission

Now the timeline grows to the whole mission. And the planes come.

6.7.1 Mission Timeline

Twenty-three rows make the whole mission, Row 0 to Row 22, from the V at 3 seconds to a last V at 105. Most of the table is typing. It’s the longest typing of the book so far, so take it a wave at a time. Wave 1’s nine rows already use all four formations. The waves after it bring no new kind, only new times and places.

Each row’s name starts with its wave, so you can see where one wave ends. Type the names as the card has them.

The defaults do much of it. A new row starts with every column’s default: formation V, a Zero Fighter, x 11.25, count 5 and spacing 2.25. So each row needs only its name, its time, and what differs.

The card prints every cell, defaults too. Comparing them takes time, so type every cell if you like. A default typed over itself changes nothing.

What differs follows the kind of row. A V may change its x and count, and the wide Vs of seven their spacing. A column changes its formation, x, count and spacing, as the two at 6.5 seconds do: Column, their x, a count of 4 and a spacing of 2.8125. A side sweep’s x is the edge it comes from, 0 for the left and 22.5 for the right. Every row keeps its Zero Fighter.

The sweeps and the row have a spacing of 0. Nothing reads it for them, because a row spaces itself across the window and a sweep has numbers of its own. Type the 0 anyway, so your table matches the game’s.

Your first row is already there, with its old name. The card starts with its new name in green, Row 0: Wave 1: V at 3 s. Under it, red and struck, is the old one, Wave 1 V.

The unmarked values under those are the first row’s. They stay as they are. Double-click Wave 1 V in the Entry column and type the new name.

Add the others after it in the card’s order, which is time order. Run Mission Timeline reads the rows from the top. A row out of order would hold up every row after it, however early their times.

Data TableMission TimelineData Structure: Mission Timeline EntryAddDelete
Row 0Wave 1: V at 3 s
Row 0Wave 1 V
timeSeconds3
formationV
objectZero Fighter
x11.25
count5
spacing2.25
Row 1Wave 1: Column (left) at 6.5 s
timeSeconds6.5
formationColumn
objectZero Fighter
x5.3125
count4
spacing2.8125
Row 2Wave 1: Column (right) at 6.5 s
timeSeconds6.5
formationColumn
objectZero Fighter
x17.1875
count4
spacing2.8125
Row 3Wave 1: Side Sweep from the left at 10 s
timeSeconds10
formationSide Sweep
objectZero Fighter
x0
count5
spacing0
Row 4Wave 1: V (left) at 13 s
timeSeconds13
formationV
objectZero Fighter
x7.1875
count3
spacing2.25
Row 5Wave 1: V (right) at 13 s
timeSeconds13
formationV
objectZero Fighter
x15.3125
count3
spacing2.25
Row 6Wave 1: Side Sweep from the right at 16 s
timeSeconds16
formationSide Sweep
objectZero Fighter
x22.5
count5
spacing0
Row 7Wave 1: Row at 19 s
timeSeconds19
formationRow
objectZero Fighter
x11.25
count6
spacing0
Row 8Wave 1: V at 22 s
timeSeconds22
formationV
objectZero Fighter
x11.25
count7
spacing2
Row 9Wave 2: Column at 28 s
timeSeconds28
formationColumn
objectZero Fighter
x11.25
count3
spacing2.8125
Row 10Wave 2: V at 36 s
timeSeconds36
formationV
objectZero Fighter
x11.25
count5
spacing2.25
Row 11Wave 2: Side Sweep from the left at 40 s
timeSeconds40
formationSide Sweep
objectZero Fighter
x0
count4
spacing0
Row 12Wave 2: Side Sweep from the right at 40 s
timeSeconds40
formationSide Sweep
objectZero Fighter
x22.5
count4
spacing0
Row 13Wave 2: V (left) at 48 s
timeSeconds48
formationV
objectZero Fighter
x7.8125
count3
spacing2.25
Row 14Wave 2: V (right) at 48 s
timeSeconds48
formationV
objectZero Fighter
x14.6875
count3
spacing2.25
Row 15Wave 3: Column (left) at 58 s
timeSeconds58
formationColumn
objectZero Fighter
x2.8125
count3
spacing2.8125
Row 16Wave 3: Column (right) at 58 s
timeSeconds58
formationColumn
objectZero Fighter
x19.6875
count3
spacing2.8125
Row 17Wave 3: Side Sweep from the right at 68 s
timeSeconds68
formationSide Sweep
objectZero Fighter
x22.5
count5
spacing0
Row 18Wave 3: V at 76 s
timeSeconds76
formationV
objectZero Fighter
x11.25
count7
spacing2
Row 19Wave 4: Column (left) at 82 s
timeSeconds82
formationColumn
objectZero Fighter
x3.75
count3
spacing2.8125
Row 20Wave 4: Column (right) at 82 s
timeSeconds82
formationColumn
objectZero Fighter
x18.75
count3
spacing2.8125
Row 21Wave 4: Side Sweep from the left at 100 s
timeSeconds100
formationSide Sweep
objectZero Fighter
x0
count5
spacing0
Row 22Wave 4: V at 105 s
timeSeconds105
formationV
objectZero Fighter
x11.25
count5
spacing2.25

6.7.2 Run Mission Timeline

Run Mission Timeline still sets an alarm and waits. What’s new is how it sets it, and what it does when it rings.

The alarm is set by the clock now. When Created sets it for the first row’s time minus the mission time, so it rings when the clock reaches that row. Every later alarm is set the same way.

When it rings, Check Game State asks first whether the mission is still being played. If it is, a While takes over. A While runs its Actions again and again, as long as its condition holds. This one’s condition has two rows: there’s a row left, and that row’s time has come on the clock. Each pass through the While, Make a Row Arrive brings the row, and nextRow moves on to the next.

Follow it at 6.5 seconds. The alarm rings, and the While looks at row 1. Its time has come, so the left column arrives. Row 2’s has come too, and the right column arrives with it, side by side. Row 3 is at 10 seconds, not yet.

The While stops. Last, an If sets the alarm again, for 10 minus the clock’s 6.5, about three and a half seconds. Two rows with one time arrive together. And a ring that comes a hair late never makes the next one late.

Most of this card changes. Three of the four fields of Run Mission Timeline Data are struck. Open it from the Resources, and press each one’s Delete Field button, at its row’s end. Only nextRow stays.

Data StructureRun Mission Timeline DataAddDelete

Object Data of Logic "Run Mission Timeline" (its state that lasts between Events).

nextRowNumberdefault 0
gapSecondsNumberdefault 0
lastRowTimeNumberdefault 0
nextRowTimeNumberdefault 0

Back on the Logic’s canvas, in When Created, add the minus and $missionTime to the end of First Delay. On the card that line shows twice, the new one in green and the old one struck under it.

In the timer’s Event, delete the old blocks. Right-click a block and choose Delete. Deleting an If takes everything inside it along, so three deletes clear the Event: the first If, the Change Component Value and the last If. Changes cards has this too.

Now build the new steps, from Check Game State down. Check Game State already starts on Playing. The If after it is one box, and its condition is stillPlaying.value == true, as on the card.

The While goes on that If’s True line. Right-click the If, choose Add inside Then, pick While, and join it with Connect to sequence. A While’s condition is one box too, and this one asks two things at once, joined by &&, which means and. Type it whole, as the card has it. If, Else, Repeat and While has more on a While.

Two steps go inside the While. Right-click it and choose Add inside While for each, then join each with Connect to sequence. The call to Make a Row Arrive starts its Caller list on self, as the card has it. Type the card’s path into its Row box. Then Change Component Value moves nextRow on, with Plus in its Operator list, as in Chapter 3.

The last If goes after the While, on the first If’s True line. Right-click the first If, choose Add inside Then, and join it with Connect to sequence. It joins the end of that line, after the While. Its Start Recurring Timer goes on its own True line. The Timer Name takes timeline bare, and Ring Once is a list on Yes.

The order once more: Check Game State, the If, and on its True line the While with its two steps, then the last If with its timer.

Logic ComponentRun Mission TimelineAttach to: Game RulesAddDelete

Runs the Mission Timeline: each row's formation arrives at its mission time, in order.

Attach toAny Object
DATA STRUCTURES
Run Mission Timeline Dataself.runMissionTimelineData
When Created
WhenCreate
1Start Recurring Timer
Timer Name
timeline
First Delay (s)
data("Mission Timeline", self.runMissionTimelineData.nextRow, "timeSeconds") - $missionTime
First Delay (s)
data("Mission Timeline", self.runMissionTimelineData.nextRow, "timeSeconds")
Ring Once
Yes
On the Timeline Timer
WhenRecurring TimerTimer name: timeline
1Ifdata("Mission Timeline", self.runMissionTimelineData.nextRow, "formation") == "V"
Then
2Spawn V FormationFunction
caller
self
enemy
data("Mission Timeline", self.runMissionTimelineData.nextRow, "object")
x
data("Mission Timeline", self.runMissionTimelineData.nextRow, "x")
count
data("Mission Timeline", self.runMissionTimelineData.nextRow, "count")
spacing
data("Mission Timeline", self.runMissionTimelineData.nextRow, "spacing")
3Change Component Value
Component Value
self.runMissionTimelineData.nextRow
Operator
+=
Value
1
4Ifself.runMissionTimelineData.nextRow < dataCount("Mission Timeline")
Then
5Change Component Value
Component Value
self.runMissionTimelineData.lastRowTime
Value
data("Mission Timeline", self.runMissionTimelineData.nextRow - 1, "timeSeconds")
6Change Component Value
Component Value
self.runMissionTimelineData.nextRowTime
Value
data("Mission Timeline", self.runMissionTimelineData.nextRow, "timeSeconds")
7Change Component Value
Component Value
self.runMissionTimelineData.gapSeconds
Value
self.runMissionTimelineData.nextRowTime - self.runMissionTimelineData.lastRowTime
8Start Recurring Timer
Timer Name
timeline
First Delay (s)
self.runMissionTimelineData.gapSeconds
Ring Once
Yes
1Check Game State
Action Name
stillPlaying
Game State
Playing
2IfstillPlaying.value == true
Then
3Whileself.runMissionTimelineData.nextRow < dataCount("Mission Timeline") && data("Mission Timeline", self.runMissionTimelineData.nextRow, "timeSeconds") <= $missionTime
Each time
4Make a Row ArriveFunction
caller
self
row
self.runMissionTimelineData.nextRow
5Change Component Value
Component Value
self.runMissionTimelineData.nextRow
Operator
+=
Value
1
6Ifself.runMissionTimelineData.nextRow < dataCount("Mission Timeline")
Then
7Start Recurring Timer
Timer Name
timeline
First Delay (s)
data("Mission Timeline", self.runMissionTimelineData.nextRow, "timeSeconds") - $missionTime
Ring Once
Yes

Save, and run the game. The V comes at three seconds, as before. Keep watching. Two columns come down the sides, and a sweep slants in from the left. A minute later the planes are still coming, in every formation, until the last V at 105 seconds.

After it, the sky is quiet. There’s no banner yet, because the banners are the last part. No plane at all? Then the clock is the first place to look, in If it didn’t work.

That’s the biggest part of the chapter behind you. If you’d like a break, this is a good place for one.

6.8 Waves and Banners

Last, the mission gets its waves, and each one opens with its banner.

6.8.1 Waves

The waves have a table of their own. Waves has four rows, one for each wave: when it starts, the short label for the top bar, and the banner’s words.

Make the table first. It makes its own Data Structure, Waves Entry, and that’s the one its card names, so keep it this time. Open it, and add its three fields with Add Field. Each comes as a Number named localVariable, at 0, so type the card’s name over localVariable and pick its Type. For label and banner, pick Text and delete the 0, so they start empty, as the card has them.

Data StructureWaves Entry

One row of the "Waves" Data Table.

startSecondsNumberdefault 0
labelTextdefault (empty)
bannerTextdefault (empty)

Each banner has two spaces on either side of its dash, as the card shows. Type them that way, and your banners match the game’s.

Data TableWavesData Structure: Waves Entry
Row 0Wave 1
startSeconds1
labelWAVE 1
bannerWAVE 1 - CORAL SEA PATROL
Row 1Wave 2
startSeconds26
labelWAVE 2
bannerWAVE 2 - ACES HIGH
Row 2Wave 3
startSeconds52
labelWAVE 3
bannerWAVE 3 - DIVE BOMBERS
Row 3Wave 4
startSeconds80
labelWAVE 4
bannerWAVE 4 - HEAVY SQUADRON

6.8.2 Run Waves

At 26 seconds, two things change together. The top bar’s WAVE 1 turns to WAVE 2, and the strip comes back with ACES HIGH on it. One alarm does both. Run Waves is Run Mission Timeline’s twin, for the Waves table. Waves never share a time, so this one needs no While.

Each ring starts one wave. Its words go into two Global Variables. The short label goes into $wave, for the top bar, and the banner’s words into $banner. Then waveStarted goes out, and Show Banner hears it on both banner pieces. Last, if a wave is left, the alarm is set for it.

Before the first ring, When Created puts WAVE 1 in $wave, so the top bar reads it as every mission starts, FLY AGAIN too.

Make $wave and $banner first, with the + on Run Waves’ Globals card and New Global…, both Text. Pick Text in the window’s Type list first. The 0 the window started with stays in its Default box, so type WAVE 1 over it for $wave. For $banner, delete it and leave the box empty.

Last comes nextWave, which lasts from one ring to the next. Press the + on the Data Structures card and choose New Data Structure, as you did for Run Mission Timeline in Chapter 3. Give Run Waves Data its one field, nextWave, a Number at 0.

Data StructureRun Waves Data

Object Data of Logic "Run Waves" (its state that lasts between Events).

nextWaveNumberdefault 0

Go by the card for the boxes. Each Timer Name takes wave bare, and Ring Once is a list on Yes. Its first If is one box, stillPlaying.value == true, like Run Mission Timeline’s.

Steps 3 to 7 fill the first If’s True line. Right-click that If and choose Add inside Then for each, and join each with Connect to sequence. Step 8 sits alone on the second If’s True line. It comes from that If’s own Add inside Then.

Logic ComponentRun WavesAttach to: Game Rules

Starts each wave of the Waves table at its mission time: the HUD shows it and its banner is raised.

Attach toAny Object
DATA STRUCTURES
Run Waves Dataself.runWavesData
When Created
WhenCreate
1Change Variable
Variable
$wave
Value
data("Waves", self.runWavesData.nextWave, "label")
2Start Recurring Timer
Timer Name
wave
First Delay (s)
data("Waves", self.runWavesData.nextWave, "startSeconds") - $missionTime
Ring Once
Yes
On the Wave Timer
WhenRecurring TimerTimer name: wave
1Check Game State
Action Name
stillPlaying
Game State
Playing
2IfstillPlaying.value == true
Then
3Change Variable
Variable
$wave
Value
data("Waves", self.runWavesData.nextWave, "label")
4Change Variable
Variable
$banner
Value
data("Waves", self.runWavesData.nextWave, "banner")
5Trigger Custom Event
Custom Event
waveStarted
6Change Component Value
Component Value
self.runWavesData.nextWave
Operator
+=
Value
1
7Ifself.runWavesData.nextWave < dataCount("Waves")
Then
8Start Recurring Timer
Timer Name
wave
First Delay (s)
data("Waves", self.runWavesData.nextWave, "startSeconds") - $missionTime
Ring Once
Yes

6.8.3 Wave Label and Wave Text

The wave’s name needs a place in the top bar, at the right end, across from the score. The Wave Label is STAGE, in small gold letters. Under it, the Wave Text shows {$wave}, larger and white, so it reads WAVE 1 as a mission starts. They’re the twins of SCORE and its number. So Duplicate saves most of the work.

Right-click Score Label in the Resources, and choose its Duplicate line. Type Wave Label in the copy’s Name box, as in Chapter 5. Then type STAGE in its Text. Its Alignment is three small buttons with lines drawn on them, and each says its name when you hover over it. Press the last, Align Right.

Make the Wave Text from Score Text the same way, with {$wave} in its Text and Align Right pressed. Its Font Size is 32. That box is a list you can also type in, and it takes a typed size when you press Enter. The rest of each card matches its copy already.

ObjectWave Label
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorTop Center
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 48
Text / UI
TextSTAGE
FontBebas Neue
Font Size20
Color#F4C542
Letter Spacing1
AlignmentRight
Text BoundsWrap to Width
Transform > Size X200
ObjectWave Text
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorTop Center
Presentation > Render LayerUI
Bounding Box > SizeX 128, Y 48
Text / UI
Text{$wave}
FontBebas Neue
Font Size32
Letter Spacing1
AlignmentRight
Text BoundsWrap to Width
Transform > Size X200

Place both from PLACE THESE, at X 250, the right end of the bar, each with its Z-Index of 120.

6.8.4 Show Banner

Show Banner does the showing. Both banner pieces have it. When waveStarted arrives, it makes its piece visible and starts a timer named banner that rings once, bannerSeconds later. That’s 2.6 seconds, long enough to read the name of a wave. When it rings, the piece hides again.

Its third Event is On Game State Changed. If the mission fails while a banner is up, the banner goes at once, so it never hangs over the GAME OVER screen. Its Check Game State starts on Playing, so pick Mission Failed.

Make bannerSeconds first, a Constant under Shared Variables, and then go by the card for the boxes. The Timer Name takes banner bare, and Ring Once is a list on Yes. Repeat Every and First Delay both read @self.bannerSeconds, with its @.

This timer’s card has a Repeat Every line, and the timers in Run Mission Timeline and Run Waves don’t. A new timer’s Repeat Every starts at 1, and those two leave it there. A timer that rings once never repeats. It rings at its First Delay. Its Repeat Every only has to be above 0, so 1 and bannerSeconds both work.

Its first Event listens for waveStarted. It’s in the Add Event window’s list already, since Run Waves sends it. Find it with the filter.

For On the Banner Timer, Myth Engine asks which timer. Choose Type a timer name… and press OK. Then type banner in the box that comes next, bare again, because that box holds a name.

Logic ComponentShow BannerAttach to: Banner Strip, Banner Text

Shows this banner piece for a moment when a wave starts, while the mission is being played.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
bannerSecondsNumberConstant2.6
On Wave Started
WhenwaveStartedCustom Event
1Set Visible
Visible
Yes
2Start Recurring Timer
Timer Name
banner
Repeat Every (s)
@self.bannerSeconds
First Delay (s)
@self.bannerSeconds
Ring Once
Yes
On the Banner Timer
WhenRecurring TimerTimer name: banner
1Set Visible
Visible
No
On Game State Changed
WhenGame State Changed
1Check Game State
Action Name
missionFailed
Game State
Mission Failed
2IfmissionFailed.value == true
Then
3Set Visible
Visible
No

6.9 If It Didn’t Work

Something may be a little off the first time. That’s normal. This chapter is long, and most of it is typing, where one wrong number hides well. Run the game, watch what it does, and think it through from the clock to the planes.

No plane at all? Look at the clock first. Is Mission Clock attached to Game Rules, where Run Mission Timeline is? Is Every Step’s Operator +=, and its Value $deltaTime?

With = there, the mission time never gets past a sixtieth of a second. No row’s time ever comes.

Once the waves are in, the first banner still comes. Its alarm is a countdown, and a countdown runs out whatever the clock says. The planes wait for more. The While lets a row through only when the clock itself has reached the row’s time.

The game won’t start, and Myth says Can’t run yet? Its message names the Logic Component that’s wrong, and what’s wrong with it. Open that Logic, and the Errors bar under its canvas points at the block. Perhaps a box lost a quote or a bracket. Count them against the card.

Only the first V comes, or the rest come late? Look at the While’s condition. Its first half asks whether a row is left, and its second whether that row’s time has come on $missionTime. Look last at the second If’s Start Recurring Timer, whose First Delay ends in - $missionTime.

A formation comes in the wrong shape? Look at that row in Mission Timeline: its formation word must be spelled the way Make a Row Arrive compares it, V, Column, Row or Side Sweep. Then look at that If’s box. The word needs its quotes there.

A side sweep comes in from the wrong side, or flies off the wrong way? Look at Spawn Side Sweep’s two Set Velocities. The True line’s X Velocity is -acrossSpeed, and the False line’s is acrossSpeed. Each should be aimed at its own plane, created or created2.

The banner never shows? Look for Show Banner on both pieces, and waveStarted spelled the same in Run Waves and in Show Banner.

The banner shows but stays? Then the timer and its Event don’t share a name. Show Banner’s Start Recurring Timer names it banner, and so must the When bar of On the Banner Timer.

The banner’s words sit behind the strip? Give the Banner Text’s placement its Z-Index of 111, so the words draw on top.

A dark strip with no words lies across the window from the very start? A banner piece was placed visible. Turn off Visible at Game Start on both placements, and the strip waits for its wave.

The banner says WAVE 2, but the wave under STAGE still reads WAVE 1? Look at Run Waves’ step 3, which puts the wave’s label into $wave. Then look at the Wave Text’s Text. It should be {$wave}, braces and all.

A long number with a tail of decimals sits where the score should be? Score Text still holds {$missionTime}, from when you watched the clock. Type {$score} back into its Text.

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

Challenge

The mission is yours to rearrange now. One thing first: Chapter 7 starts from the cards’ tables. So note what you change, and put it back before you go on. Or start Chapter 7 from this chapter’s catch-up download.

Open Mission Timeline and move a row’s time, and watch its formation come sooner. Or add a row of your own: a column of seven down the middle, or two sweeps from both sides at once.

Or give the mission a fifth wave. It needs a row in Waves, with its own name on the banner, and a few rows in the timeline after it. What would you call it?

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

Four waves fly on a clock now, and every plane in them is a Zero Fighter. In Chapter 7, the banners keep their word: Red Aces, Dive Bombers and Heavy Bombers.