Build a GameCreating Pacific Wings

7  The Route

Goal

The sea below fills up. A gray carrier, a jungle atoll, a coral reef and a bank of white cloud slide by under the Fighter. Each one comes around again ahead, so the sea never runs out. Hidden milestones move the mission on, stage by stage. Reinforcements join the waves.

The game as it is at the end of this chapter. Click the game, then press Enter to start.

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

Pacific Wings, Chapter 7 finishedMyth project · 1.6 MB

To open it, start Myth Engine, choose File › Open Project... and pick the downloaded file.

7.1 The Idea

Since Chapter 1, your Fighter has flown over open water, deep blue at the top and lighter below. Nothing else. The enemies come down in their waves, and between them the route is empty.

Now picture it full. A long gray carrier sits low on the water as the mission begins. It slides down the screen and out of sight. A round island goes by, with palm trees and a sandy beach. Then a ring of coral around a blue lagoon, and a white bank of cloud that drifts slowly sideways. A little later, the carrier is back, ahead of you, somewhere new.

It’s the same carrier. There are only four pieces of scenery in the whole game. When one passes below the view, it’s picked up and set down again ahead. It’s like crossing a stream on four stepping stones: you lift the one behind you and put it down in front.

The route gains a second thing you can’t see. Three milestones wait along it, markers that report when the camera reaches them. Each one moves the mission on a stage. Stage 1 is the start, and every milestone adds one.

The stage decides the reinforcements, planes that join the placed waves from above. Pairs of Enemy Fighters come from the start. Aces join them at stage 2, and the slow Heavy Bombers at stage 3. When the last milestone is gone, they stop. Something big is coming, and the Fighter will meet it alone. That waits for Chapter 11.

7.2 The Plan

Here’s how the pieces work together, one chain to a line. The message names are new, and each comes back in its own part. Skim them now, and look again at the end.

  • A piece of scenery leaves the view -> Move Ahead When Passed sets it down ahead, and sends movedAhead to its own piece.
  • The Cloud Bank is made, or moved ahead -> Drift Sideways sends startDrifting, and the cloud drifts toward its far side.
  • The route begins -> Stages sets $stage to 1 and sends stageReached.
  • A milestone comes into view -> Report Milestone sends milestoneReached, and removes itself. Stages adds one to $stage and sends stageReached.
  • stageReached arrives at a Squadron whose stage it is -> Reinforcements starts its timer, and each ring sends a group of planes.
  • The last milestone is gone -> Stages shakes the camera and sends commandBomberApproaching. Every Squadron stops.

7.3 Set Up

Four pictures join the game this chapter: the carrier, the atoll, the reef and the cloud bank. The fifth, Hit Area Marker, is the milestones’ picture for now. All five are in your project already.

Set upWhat this chapter adds
ART (sprites, from the starter kit)
Hit Area Marker
Aircraft Carrier Art
Tropical Atoll Art
Coral Reef Art
Cloud Bank Art
GLOBAL VARIABLES
$stageNumberstarts at 0
$furthestSceneryYNumberstarts at 0
SCENE Route: PLACE THESE
ObjectXY
Milestone1038.375
Milestone1066.188
Milestone10109
Squadron00
Squadron00
with Per Instance Variables > Kind = Enemy Ace
Squadron00
with Per Instance Variables > Kind = Heavy Bomber
Aircraft Carrier4.8447.5
Tropical Atoll15.15615.625
Cloud Bank5.46924.375
Coral Reef14.68833.125

GLOBAL VARIABLES has two new rows. Make them the way you made $planes, from the Globals card of any Logic Component, with New Global…. Both are Numbers that start at 0, so all you type is the name: stage for the first, furthestSceneryY for the second.

PLACE THESE waits until its Objects exist, and each part of this chapter places its own.

7.4 Scenery

The first job is the sea.

7.4.1 Move Ahead When Passed

From a piece of scenery’s point of view, there’s one moment that matters: the moment it leaves the view at the bottom. Chapter 2’s tracers met the same moment, and Leave View cleared them away. Leave View runs only once the whole piece is out of the view, so the cloud’s sideways drift never sets it off. Scenery isn’t cleared away. It’s moved ahead, to the far side of the view.

Where, exactly? Two rules decide. It must land well past the top of the view, so you never see it arrive. And it must land beyond the piece that’s furthest ahead. Two pieces never pile up in one spot.

The first rule is a spot in the sky, 17.5 meters past the middle of the view. The piece works that spot out for itself, and keeps it in leadY, a value that lasts one run of the Event. The second rule needs a number every piece can read: how far north the furthest piece is. That’s $furthestSceneryY, one of the two new Globals.

The piece starts from $furthestSceneryY. But if leadY is further north, leadY wins, and the piece goes from there instead. That’s the If. $furthestSceneryY starts at 0 and learns only of pieces that have moved, so the first time, leadY wins. By then it’s already further north than every piece you placed. The piece adds a random gap, picks a random spot across the route, and it’s there, all at once. Then it becomes the furthest piece itself, and last of all, it tells its own Object movedAhead. Nothing on the carrier listens. The cloud will.

Logic ComponentMove Ahead When PassedAttach to: Aircraft Carrier, Tropical Atoll, Coral Reef, Cloud Bank

When this piece of scenery has passed below the view, moves it ahead again: gapMin to gapMax meters beyond the scenery furthest ahead, and at least leadMeters above the middle of the view.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
leadMetersNumberConstant17.5
gapMinNumberConstant10.6
gapMaxNumberConstant13.1
xMinNumberConstant4.4
xMaxNumberConstant15.6
When Leaving the View
WhenLeave View
1Declare Variable
Name
leadY
Value
0
2Change Variable
Variable
leadY
Value
$viewMiddleY + @self.leadMeters
3If$furthestSceneryY < leadY
Then
4Change Variable
Variable
$furthestSceneryY
Value
leadY
5Generate Random Number
Action Name
gap
Minimum
@self.gapMin
Maximum
@self.gapMax
6Change Variable
Variable
$furthestSceneryY
Operator
+=
Value
gap.value
7Generate Random Number
Action Name
newX
Minimum
@self.xMin
Maximum
@self.xMax
8Set Position
X
newX.value
Y
$furthestSceneryY
9Trigger Custom Event on Object
Custom Event
movedAhead

Make it as an Empty Logic Component, with its five Shared Variables. The middle of the view comes from $viewMiddleY, the Global Track the View keeps for you since Chapter 4.

Leave View comes from Add Event, as on Remove When Out of View. Its first step is a Declare Variable, as in Chapter 6: the Name leadY, the Value 0. The Change Variable after it sets leadY. The If after that asks $furthestSceneryY < leadY, and its one step goes on its True line with Add Inside Then.

The rest go after the whole If, on the main line. Here’s how they get there. A block you add from the Action List never lands inside an If. It lands beside the main line, and Connect to Sequence joins it to the end of that line, below the If, where the True line comes back. Only the If’s own menu puts a step inside. So add the rest from the Action List.

Type gap and newX over the two Action Names of Generate Random Number. The second Change Variable for $furthestSceneryY, the one after the If, wants += · Add in its Operator list. Set Position moves an Object at once, with no glide: it has an X box and a Y box, and it starts on World, which is what the card wants. Last, Trigger Custom Event on Object. It starts on Self, so type movedAhead into its Custom Event box.

7.4.2 The Carrier, the Atoll, the Reef and the Cloud

Now the four pieces.

ObjectAircraft Carrier
Transform
Bounding Box > SizeX 7.8, Y 7.8
Physics > Physics ObjectOff
Sprite
Scene Depth Draw Order-20
SpriteAircraft Carrier Art
Transform > SizeX 7.8, Y 7.8
Collider
CollisionOff
Shape and Transform > ShapeSprite
Shape and Transform > SizeX 7.8, Y 7.8
Logic
Move Ahead When Passed
ObjectTropical Atoll
Transform
Bounding Box > SizeX 7, Y 7
Physics > Physics ObjectOff
Sprite
Scene Depth Draw Order-30
SpriteTropical Atoll Art
Transform > SizeX 7, Y 7
Collider
CollisionOff
Shape and Transform > ShapeSprite
Shape and Transform > SizeX 7, Y 7
Logic
Move Ahead When Passed
ObjectCoral Reef
Transform
Bounding Box > SizeX 7.2, Y 7.2
Physics > Physics ObjectOff
Sprite
Scene Depth Draw Order-40
SpriteCoral Reef Art
Transform > SizeX 7.2, Y 7.2
Collider
CollisionOff
Shape and Transform > ShapeSprite
Shape and Transform > SizeX 7.2, Y 7.2
Logic
Move Ahead When Passed
ObjectCloud Bank
Transform
Bounding Box > SizeX 7.4, Y 7.4
Physics > Physics ObjectOff
Sprite
Scene Depth Draw Order10
SpriteCloud Bank Art
Transform > SizeX 7.4, Y 7.4
Collider
CollisionOff
Shape and Transform > ShapeSprite
Shape and Transform > SizeX 7.4, Y 7.4
Data Structure
From LogicDrift Sideways
Data StructureDrift Sideways Data
Logic
Drift Sideways
Move Ahead When Passed

Each has a Collider, so each is a 2D Object. Go down its card from the top.

Look at the Scene Depth numbers. The carrier, the atoll and the reef are all below zero, so they lie under everything else, flat on the sea. The reef is lowest of all. The Cloud Bank is at 10. It floats above the islands, but under the planes at 30, so your Fighter flies over it.

The Collider has a new Shape, Sprite: the shape follows the picture. With Collision Off, nothing bumps into an island. The Collider stays only to give the piece its size. Up on the Transform, Physics > Physics Object is Off, so nothing can shove a piece. Its own Logic can still move it, as the cloud’s will.

Each piece carries Move Ahead When Passed, so attach it to all four. The Cloud Bank’s card names one more, Drift Sideways, and a Data Structure that comes with it. That’s next.

7.4.3 Drift Sideways

The cloud bank does one more thing. It drifts sideways, at 0.4 meters a second, so slowly you might miss it, and turns back at each side.

Here’s the trick. The cloud never checks where it is while it drifts. It works out how long the trip will take, and sets a timer for that moment. When the timer rings, it has arrived, so it turns back.

There are two kinds of trip. The first goes from wherever the cloud is now to the far side. The ones after go all the way across, from leftX to rightX and back. So the first ring comes after distanceToGo / driftSpeed seconds, and every ring after it is the time to cross.

When does a first trip start? Twice. Once when the cloud is made, and again each time Move Ahead When Passed sets it down somewhere new. Both send the same message to the cloud itself, startDrifting, so the work is written once.

Data StructureDrift Sideways Data

Object Data of Logic "Drift Sideways" (its state that lasts between Events).

driftSideNumberdefault 1
distanceToGoNumberdefault 0
Logic ComponentDrift SidewaysAttach to: Cloud Bank

Drifts sideways at driftSpeed between leftX and rightX, turning back at each on the driftTurn timer. It starts at Create and again whenever the Object is moved ahead.

Attach toAny Object
DATA STRUCTURES
Drift Sideways Dataself.driftSidewaysData
SHARED VARIABLES
NameTypeKindStarting Value
driftSpeedNumberConstant0.4
leftXNumberConstant3.1
rightXNumberConstant16.9
When Created
WhenCreate
1Trigger Custom Event on Object
Custom Event
startDrifting
On Moved Ahead
WhenmovedAheadCustom Event
1Trigger Custom Event on Object
Custom Event
startDrifting
On Start Drifting
WhenstartDriftingCustom Event
1Ifself.transform.position.x < ((@self.leftX + @self.rightX) / 2)
Then
2Change Component Value
Component Value
self.driftSidewaysData.driftSide
Value
1
3Change Component Value
Component Value
self.driftSidewaysData.distanceToGo
Value
@self.rightX - self.transform.position.x
4Otherwise
5Change Component Value
Component Value
self.driftSidewaysData.driftSide
Value
-1
6Change Component Value
Component Value
self.driftSidewaysData.distanceToGo
Value
self.transform.position.x - @self.leftX
7Set Velocity
X Velocity
@self.driftSpeed * self.driftSidewaysData.driftSide
8Start Recurring Timer
Timer Name
"driftTurn"
Repeat Every (s)
(@self.rightX - @self.leftX) / @self.driftSpeed
First Delay (s)
self.driftSidewaysData.distanceToGo / @self.driftSpeed
On the Drift Turn Timer
WhenRecurring TimerTimer name: driftTurn
1Change Component Value
Component Value
self.driftSidewaysData.driftSide
Operator
*=
Value
-1
2Set Velocity
X Velocity
@self.driftSpeed * self.driftSidewaysData.driftSide

Make it with its three Shared Variables. Its Data Structure comes from New Data Structure on the Data Structures card, as Weave Data did. Drift Sideways Data has two Number fields this time. driftSide’s Value is 1, and distanceToGo’s stays 0.

It has four Events. Create runs once, when the cloud comes into being, as on Show While in Reserve. Its one step sends startDrifting, typed in. In the Add Event list, movedAhead is there already, since Move Ahead When Passed sends it. startDrifting is there too, because the step you made a moment ago sends it.

Under startDrifting, the If has a True line and an Else line, each with two Change Component Value steps. Set Velocity and Start Recurring Timer go after the whole If, on the main line, from the Action List as before. Type "driftTurn" into Timer Name, with its quote marks. The old timer may still be running when the cloud is moved ahead. That’s fine. Starting a timer by a name that’s already running starts it over, with the new time. For the last Event, pick Recurring Timer in Add Event, choose Type a timer name…, and type driftTurn.

When that timer rings, the cloud turns around. Its Change Component Value’s Operator is *= · Multiply, as in Weave, with -1 in the Value. Times -1 turns 1 into -1, and -1 back into 1.

Attach Drift Sideways to the Cloud Bank, after Move Ahead When Passed. Drift Sideways Data arrives with it. Its Shared Variables need nothing typed: each starts at the Logic’s own value.

7.4.4 Four Pieces on the Sea

Open Route and place the four, from PLACE THESE: the Aircraft Carrier, the Tropical Atoll, the Cloud Bank and the Coral Reef, each at its World Position.

Run the game, and press Enter. The carrier is right there, beside your Fighter, long and gray. It slides away down the screen. The atoll follows it, then the cloud, sliding sideways as it goes. Keep flying. Some time after the carrier leaves the bottom of the view, it comes back in at the top, somewhere new.

7.5 Milestones

Now the route learns to count.

7.5.1 Report Milestone

A milestone is a marker with one job. When the camera reaches it, it says so, and then it’s gone.

It doesn’t know which stage it starts. It doesn’t need to. It only shouts milestoneReached, and Game Rules decides what that means.

There’s one small catch. In the Scene, you want to see the markers, so you can place them. In play, you don’t. Hiding the picture won’t work, because Myth’s Enter View looks at the picture an Object shows, and a hidden one never enters the view. So the marker goes see-through instead: the moment it’s made, Set Alpha sets its Alpha to 0. Invisible. Still there.

Logic ComponentReport MilestoneAttach to: Milestone

A marker placed along the route: when it comes into view it tells Game Rules milestoneReached, then removes itself.

Attach toAny Object
When Created
WhenCreate
1Set Alpha
Alpha
0
When Entering the View
WhenEnter View
1Trigger Custom Event
Custom Event
milestoneReached
2Destroy Instance

Make it as an Empty Logic Component. It needs no Shared Variables at all. Its two Events and three steps are all on the card.

ObjectMilestone
Transform
Bounding Box > SizeX 0.6975, Y 1.7325
Sprite
Scene Depth Draw Order90
Z Index Within Object1
SpriteHit Area Marker
Transform > SizeX 0.6975, Y 1.7325
Logic
Report Milestone

The Milestone has a picture and no Collider. So make it an Empty Object, and click Sprite in the toolbox’s Rendering group. Its picture is the Hit Area Marker, a small pale capsule that the Fighter will put to other work in Chapter 10. Here it marks a spot. Copy its Z Index Within Object, 1, from the card. With one picture, it changes nothing you’ll see. Attach Report Milestone in Logic.

7.5.2 Stages

Stages sits on Game Rules, and it keeps $stage.

Think of $stage as a page number. The route opens on page 1, and each milestone turns one page. Each time, Stages tells everyone, with stageReached.

The last part is the one to watch. How does Game Rules know that the last of the milestones has gone? It doesn’t count them. Myth has an Event for exactly this, No Instances Left. It runs by itself when the last Milestone in the game is removed. Place three markers, or ten. The last one is always the warning.

That warning is a light shiver of the camera, 0.012 for 0.35 seconds, and a message, commandBomberApproaching. Nothing in the game has a Command Bomber yet. But the Squadrons will hear the message, and stop.

Logic ComponentStagesAttach to: Game Rules

Starts $stage at 1 when the route begins and raises it by one at each milestone, announcing stageReached each time; when no milestones are left it shakes the camera lightly and announces commandBomberApproaching.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
milestoneObjectConstantNone
shakeIntensityNumberConstant0.012
shakeSecondsNumberConstant0.35
When the Scene Starts
WhenScene Start
1Change Variable
Variable
$stage
Value
1
2Trigger Custom Event
Custom Event
stageReached
On Milestone Reached
WhenmilestoneReachedCustom Event
1Change Variable
Variable
$stage
Operator
+=
Value
1
2Trigger Custom Event
Custom Event
stageReached
On No Instances Left · Milestone
WhenNo Instances LeftObject: Milestone
1Camera Shake
Intensity
@self.shakeIntensity
Seconds
@self.shakeSeconds
2Trigger Custom Event
Custom Event
commandBomberApproaching

Its milestone is a Shared Variable, an Object starting at None, and the two Numbers follow it. No step reads milestone. It’s there so that anyone who opens Stages sees, in its Shared Variables, which Object it watches. The watching itself is done by the Event.

Scene Start is in the Add Event list. It runs each time the route begins. milestoneReached is in the list already, since Report Milestone sends it. Its Change Variable wants += · Add again. For No Instances Left, Add Event opens no second window. Its Object is a list on the Event’s own block, so pick Milestone there.

ObjectGame RulesAddDelete
Collider(as it is added)
Logic
Score
Planes
Mission Failed Screen
Mission Start
Pause
Best Score
Play Again
Stages
Shared Variables
fighterFighter
milestoneMilestone

Attach Stages to Game Rules. Under Variables, its milestone Value is a button that reads None until you press it. Press it, and pick Milestone.

Open Route and place the three Milestones from PLACE THESE. In the Scene, each one is a pale capsule standing on the route. In play, they’re gone.

You won’t see much yet, so run the game and fly on. The stages go by in silence. Nothing reads $stage yet. The first milestone comes into view with the first Aces of Wave 2. The second comes with the Heavy Bomber at the heart of Wave 3, and the last waits past the final approach, beyond the last bomber. When it comes, the screen shivers. The route has been counting, quietly, from the moment you took off.

7.6 Reinforcements

Now the stages bring planes.

7.6.1 Reinforcement Orders

Each kind of enemy joins in its own way. Enemy Fighters come often, in pairs. Aces come one at a time, from stage 2, and Heavy Bombers rarely, from stage 3. Every number for that goes in one table.

Data StructureReinforcement Orders Entry

One row of the "Reinforcement Orders" Data Table.

fromStageNumberdefault 0
firstSecondsNumberdefault 0
secondsMinNumberdefault 0
secondsMaxNumberdefault 0
capNumberdefault 0
perWaveNumberdefault 0
xMinNumberdefault 0
xMaxNumberdefault 0
laneStepMetersNumberdefault 0
Data TableReinforcement OrdersData Structure: Reinforcement Orders Entry
Row 0Enemy Fighter
fromStage1
firstSeconds0.75
secondsMin3.8
secondsMax5
cap14
perWave2
xMin2.5
xMax8.1
laneStepMeters9.4
Row 1Enemy Ace
fromStage2
firstSeconds0.35
secondsMin7.2
secondsMax9
cap10
perWave1
xMin2.8
xMax17.2
laneStepMeters0
Row 2Heavy Bomber
fromStage3
firstSeconds0.45
secondsMin10
secondsMax13
cap5
perWave1
xMin3.75
xMax16.25
laneStepMeters0

This table keeps the Data Structure it makes. Make the table, Reinforcement Orders, and it makes Reinforcement Orders Entry under Data Structures. Leave its Entry Type on that Entry. Open the Entry, and add its nine fields from its card, each a Number at 0. Each field becomes a column of the table.

Add Row three times. Then double-click each row’s name in the Entry column, and type its own. Use Enemy Types’ very names: Enemy Fighter, Enemy Ace, Heavy Bomber. Both tables are read with one name, so one wrong letter, and that kind never comes.

7.6.2 Reinforcements

A Squadron has no picture. It’s a sender. It waits for its stage, then sends planes on a timer until it’s told to stop.

Which planes? The answer is small. There’s one Reinforcements, and three Squadrons in the Scene. Each Squadron’s placement says which enemy it sends, by name, in its kind. That name is the Object to make, and the row to read in both tables. One piece of Logic, three jobs.

Picture the Enemy Fighters’ Squadron. The route begins, and stageReached arrives at every Squadron at once. This one’s row says fromStage 1. Its turn. So it starts its reinforcements timer, set to ring once, very soon.

The timer rings, and a pair of Enemy Fighters goes out. Each plane goes only if there’s room, with fewer of its kind in the sky than its row allows. Each gets a lane, a random spot across the route. The second of the pair comes in 9.4 meters further across, so the two fly side by side. All of those numbers are columns of the Squadron’s row.

Each plane is made aboveCameraMeters above the middle of the view, 11.25 meters, out of sight. It’s launched south at its own speed from Enemy Types. By the time you see it, it’s already flying. The Squadron picks a random wait from its row, and starts the timer again.

When commandBomberApproaching arrives, the timer stops. That’s all.

Data StructureReinforcements Data

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

laneXNumberdefault 0
launchSpeedNumberdefault 0
Logic ComponentReinforcementsAttach to: Squadron

Sends one enemy kind in from above the view on the reinforcements timer, from the stage in its Reinforcement Orders row until the Command Bomber approaches; each one only while fewer than cap of that kind are alive.

Attach toAny Object
DATA STRUCTURES
Reinforcements Dataself.reinforcementsData
SHARED VARIABLES
NameTypeKindStarting Value
aboveCameraMetersNumberConstant11.25
PER INSTANCE VARIABLES
NameTypeStarting Value
kindTextEnemy Fighter
On Stage Reached
WhenstageReachedCustom Event
1If$stage == data('Reinforcement Orders', self.kind, 'fromStage')
Then
2Start Recurring Timer
Timer Name
"reinforcements"
Repeat Every (s)
data('Reinforcement Orders', self.kind, 'firstSeconds')
Ring Once
Yes
On the Reinforcements Timer
WhenRecurring TimerTimer name: reinforcements
1Declare Variable
Name
waitSeconds
Value
0
2Repeatdata('Reinforcement Orders', self.kind, 'perWave')times
Each time
3Check Instance Count
Action Name
roomForMore
Object
self.kind
Operator
<
Value
data('Reinforcement Orders', self.kind, 'cap')
4IfroomForMore.value == true
Then
5Generate Random Number
Action Name
laneRoll
Minimum
data('Reinforcement Orders', self.kind, 'xMin')
Maximum
data('Reinforcement Orders', self.kind, 'xMax')
6Change Component Value
Component Value
self.reinforcementsData.laneX
Value
laneRoll.value
7Change Component Value
Component Value
self.reinforcementsData.laneX
Operator
+=
Value
local.index * data('Reinforcement Orders', self.kind, 'laneStepMeters')
8Change Component Value
Component Value
self.reinforcementsData.launchSpeed
Value
data('Enemy Types', self.kind, 'speed')
9Create Instance
Object to Create
self.kind
X
self.reinforcementsData.laneX
Y
$viewMiddleY + @self.aboveCameraMeters
Launch Speed
self.reinforcementsData.launchSpeed
Launch Angle
-90
10Generate Random Number
Action Name
waitRoll
Minimum
data('Reinforcement Orders', self.kind, 'secondsMin')
Maximum
data('Reinforcement Orders', self.kind, 'secondsMax')
11Change Variable
Variable
waitSeconds
Value
waitRoll.value
12Start Recurring Timer
Timer Name
"reinforcements"
Repeat Every (s)
waitSeconds
Ring Once
Yes
On Command Bomber Approaching
WhencommandBomberApproachingCustom Event
1Stop Recurring Timer
Timer Name
"reinforcements"

Make it as an Empty Logic Component. Its one Shared Variable is aboveCameraMeters. Its kind is a Per Instance Variable, a Text starting at Enemy Fighter: each placed Squadron keeps its own.

Reinforcements Data comes from New Data Structure, with two Number fields at 0, laneX and launchSpeed. The wait, waitSeconds, lasts one run of the timer’s Event, so it’s a Declare Variable at the start of that Event.

stageReached is in the Add Event list already. Its If’s condition is typed as the card has it, data() and all. data() reads one cell of a Data Table. It takes the table’s name first, then the row, then the column. Here the row is self.kind. Each Squadron reads its own. The reinforcements timer’s Event is a Recurring Timer, with reinforcements typed as its timer name. A named timer in Myth is always a Recurring Timer. Ring Once Yes makes it ring a single time, then stop, until something starts it again.

Under it, after the Declare Variable, comes a Repeat. Its Count box is on the block. Right-click the Repeat and choose Add Inside Repeat for Check Instance Count, and again for the If after it. Inside that If go the next five steps, each from the If’s Add Inside Then. local.index counts the times round the Repeat, from 0. So the first plane of a pair is 0 steps across, and the second is one step.

Check Instance Count’s Object is self.kind, the Squadron’s own name for its enemy. So is Create Instance’s Object to Create. Create Instance starts on World, so type its X and Y, then Launch Speed and Launch Angle.

The last three steps go after the whole Repeat, on the main line. A Repeat works like an If here. Add each from the Action List, and Connect to Sequence joins it below the whole Repeat, never inside it. Their Applies to starts on Self, the Squadron, which is what the card wants. The Create Instance before them is inside the Repeat, not on their line, so it doesn’t count. The timer belongs to the Squadron, not to a plane it sent.

Last comes the commandBomberApproaching Event. Its Stop Recurring Timer takes "reinforcements", with its quote marks, like every Timer Name.

ObjectSquadron
Data Structure
From LogicReinforcements
Data StructureReinforcements Data
Logic
Reinforcements

Squadron is an Empty Object, with Reinforcements in its Logic. Reinforcements Data arrives with it. Its kind waits for the placements.

7.6.3 Three Squadrons

Open Route, and place three Squadrons from PLACE THESE, each at 0, 0. A Squadron has no picture, so it’s hard to click in the Scene. Click it in the Scene Explorer on the right instead, where the three are listed. Set up each one before you place the next.

The card’s with lines are each placement’s own values, as with the Reserve Plane Icons’ slots in Chapter 4. They’re in the Properties, near the bottom, under Logic, in Reinforcements’ Per Instance Variables. The Kind box shows Enemy Fighter already. That’s right for the first, so its card has no with line. Type Enemy Ace over it on the second, and Heavy Bomber on the third, spelled exactly as the Objects are named.

7.6.4 Room for Everyone

From now on, planes come in crowds. A new Enemy Fighter can arrive right where a placed one is flying, and two solid planes would shove each other off course. So each enemy learns to pass through the others.

The change is the same on all three planes, in the Collider’s Tags and Interactions. Pick Never Collide With in its Interactions list. Then press Search to add…, and pick Tagged Enemy Aircraft. Now every plane that wears that Tag passes straight through the others, as if they were cloud. Your Fighter’s tracers still hit them, and they still hit you. Only enemies ignore each other.

On the three cards below, look for the marked lines. They’re the only new ones. The rest is each plane as you left it in Chapter 6.

ObjectEnemy FighterAddDelete
Transform
Bounding Box > SizeX 2.48, Y 2.48
Sprite
Scene Depth Draw Order30
SpriteEnemy Fighter Art
Transform > SizeX 2.48, Y 2.48
Transform > Rotation (deg)Z -180
Collider
Shape and Transform > ShapeEllipse
Shape and Transform > SizeX 1.453, Y 1.046
Tags and Interactions > InteractionsNever Collide With
Tags and Interactions > Never Collide WithTagged Enemy Aircraft
Data Structure
Data StructureEnemy Stats
Input SourceData Table
Data TableEnemy Types
RowEnemy Fighter
Data Structure
From LogicFire When Seen
Data StructureFire When Seen Data
Coordinate
NameGun Muzzle
Local PositionX 0, Y -0.94
Tags
Object TagsEnemy Aircraft, Enemy Threat
Logic
Fly South When Seen
Takes Hits
Shot Down
Fire When Seen
Crashes Into Fighter
Remove When Out of View
Shared Variables
tracerEnemy Tracer
tracerSpeed > KindExpression
tracerSpeed > ExpressionobjectComponentProperty("self","enemyStats","tracerSpeed")
firstShotSeconds > KindExpression
firstShotSeconds > ExpressionobjectComponentProperty("self","enemyStats","firstShotSeconds")
shotSecondsMin > KindExpression
shotSecondsMin > ExpressionobjectComponentProperty("self","enemyStats","shotSecondsMin")
shotSecondsMax > KindExpression
shotSecondsMax > ExpressionobjectComponentProperty("self","enemyStats","shotSecondsMax")
fighterFighter
aimConeDegrees > KindExpression
aimConeDegrees > ExpressionobjectComponentProperty("self","enemyStats","aimConeDegrees")
speed > KindExpression
speed > ExpressionobjectComponentProperty("self","enemyStats","speed")
ObjectEnemy AceAddDelete
Transform
Bounding Box > SizeX 2.56, Y 2.56
Sprite
Scene Depth Draw Order30
SpriteEnemy Ace Art
Transform > SizeX 2.56, Y 2.56
Transform > Rotation (deg)Z -180
Collider
Shape and Transform > ShapeEllipse
Shape and Transform > SizeX 1.6, Y 1.04
Tags and Interactions > InteractionsNever Collide With
Tags and Interactions > Never Collide WithTagged Enemy Aircraft
Coordinate
NameGun Muzzle
Local PositionX 0, Y -0.94
Data Structure
Data StructureEnemy Stats
Input SourceData Table
Data TableEnemy Types
RowEnemy Ace
Data Structure
From LogicWeave
Data StructureWeave Data
Data Structure
From LogicFire When Seen
Data StructureFire When Seen Data
Tags
Object TagsEnemy Aircraft, Enemy Threat
Logic
Weave
Fly South When Seen
Takes Hits
Shot Down
Fire When Seen
Crashes Into Fighter
Remove When Out of View
Shared Variables
tracerEnemy Tracer
tracerSpeed > KindExpression
tracerSpeed > ExpressionobjectComponentProperty("self","enemyStats","tracerSpeed")
firstShotSeconds > KindExpression
firstShotSeconds > ExpressionobjectComponentProperty("self","enemyStats","firstShotSeconds")
shotSecondsMin > KindExpression
shotSecondsMin > ExpressionobjectComponentProperty("self","enemyStats","shotSecondsMin")
shotSecondsMax > KindExpression
shotSecondsMax > ExpressionobjectComponentProperty("self","enemyStats","shotSecondsMax")
fighterFighter
aimConeDegrees > KindExpression
aimConeDegrees > ExpressionobjectComponentProperty("self","enemyStats","aimConeDegrees")
weaveSpeed > KindExpression
weaveSpeed > ExpressionobjectComponentProperty("self","enemyStats","weaveSpeed")
weaveSeconds > KindExpression
weaveSeconds > ExpressionobjectComponentProperty("self","enemyStats","weaveSeconds")
weaveAngle > KindExpression
weaveAngle > ExpressionobjectComponentProperty("self","enemyStats","weaveAngle")
speed > KindExpression
speed > ExpressionobjectComponentProperty("self","enemyStats","speed")
ObjectHeavy BomberAddDelete
Transform
Bounding Box > SizeX 3.36, Y 3.36
Sprite
Scene Depth Draw Order30
SpriteHeavy Bomber Art
Transform > SizeX 3.36, Y 3.36
Transform > Rotation (deg)Z -180
Collider
Shape and Transform > ShapeEllipse
Shape and Transform > SizeX 2.468, Y 1.733
Tags and Interactions > InteractionsNever Collide With
Tags and Interactions > Never Collide WithTagged Enemy Aircraft
Coordinate
NameGun Muzzle
Local PositionX 0, Y -0.932
Data Structure
Data StructureEnemy Stats
Input SourceData Table
Data TableEnemy Types
RowHeavy Bomber
Data Structure
From LogicWeave
Data StructureWeave Data
Data Structure
From LogicFire When Seen
Data StructureFire When Seen Data
Tags
Object TagsEnemy Aircraft, Enemy Threat
Logic
Weave
Fly South When Seen
Takes Hits
Shot Down
Fire When Seen
Crashes Into Fighter
Remove When Out of View
Shared Variables
tracerEnemy Tracer
tracerSpeed > KindExpression
tracerSpeed > ExpressionobjectComponentProperty("self","enemyStats","tracerSpeed")
firstShotSeconds > KindExpression
firstShotSeconds > ExpressionobjectComponentProperty("self","enemyStats","firstShotSeconds")
shotSecondsMin > KindExpression
shotSecondsMin > ExpressionobjectComponentProperty("self","enemyStats","shotSecondsMin")
shotSecondsMax > KindExpression
shotSecondsMax > ExpressionobjectComponentProperty("self","enemyStats","shotSecondsMax")
fighterFighter
aimConeDegrees > KindExpression
aimConeDegrees > ExpressionobjectComponentProperty("self","enemyStats","aimConeDegrees")
weaveSpeed > KindExpression
weaveSpeed > ExpressionobjectComponentProperty("self","enemyStats","weaveSpeed")
weaveSeconds > KindExpression
weaveSeconds > ExpressionobjectComponentProperty("self","enemyStats","weaveSeconds")
weaveAngle > KindExpression
weaveAngle > ExpressionobjectComponentProperty("self","enemyStats","weaveAngle")
speed > KindExpression
speed > ExpressionobjectComponentProperty("self","enemyStats","speed")

Save, and run the game.

The carrier slides away beside you as you climb north. Two Enemy Fighters drop in from the top, side by side, and then two more. Fly on past the first Aces, and single red-orange Aces start arriving too. Later come the slow bombers, rocking as they crawl. Near the end, the screen shivers. Then the sky goes quiet.

Play it!

Watch for each of these, one at a time.

  • The Aircraft Carrier sits beside your Fighter as the mission begins. It slides down and away.
  • Each piece that leaves the bottom of the view comes back at the top, somewhere new across the route. You never see one appear.
  • The Cloud Bank drifts sideways, slowly, at 0.4 meters a second, and turns back at the sides. It floats over the islands and under your Fighter.
  • From the start, Enemy Fighters arrive in pairs, side by side, on top of the placed waves.
  • Once Wave 2’s first Aces are in view, single Aces start arriving too. Once Wave 3’s Heavy Bomber is in view, Heavy Bombers join them.
  • After the last milestone, the camera shivers once. No more reinforcements come.
  • Enemies fly right through each other, with never a bump between them.
How it works

Four stones on the water, and three markers along the route. Three Squadrons share one piece of Logic.

The scenery is placed once, and set down ahead again and again. The milestones are placed once, and each removes itself when its job is done. Only the reinforcements are new planes, and each Squadron sends only what its row says, while there’s room.

And nobody counts anything they don’t own. A milestone reports. Game Rules decides what the report means. When the last one goes, Myth itself notices, with No Instances Left. One piece of Logic, three Squadrons: the Scene says which is which, and the table says how.

7.7 If It Didn’t Work

This chapter has many pieces, and most of them work out of sight. So run the game, and watch the sea first. Then the sky.

Press Play, and a window called Can’t run yet opens? Its message names the piece and what’s wrong with it, so fix that, and press Play again.

A piece of scenery leaves and never comes back? Open that piece and pick Logic. Move Ahead When Passed should be in its Attached Logic.

The scenery comes back too close, or piles up? Look at the If in Move Ahead When Passed, where the condition compares $furthestSceneryY with leadY, with a < between them.

The cloud doesn’t drift? Look for Drift Sideways in the Cloud Bank’s Logic, and check startDrifting, spelled the same in all three places.

The cloud drifts off one side and never comes back? Look at the two timer names. Start Recurring Timer’s driftTurn and the Event’s driftTurn must match, letter for letter.

Pale capsules float by while you fly? Those are the milestones. Look at Report Milestone’s Create Event, where Set Alpha should hold 0.

No reinforcements at all? Click each Squadron in the Scene Explorer. Its Kind must be spelled like a row in Reinforcement Orders, and like the Object it sends. Last, Stages belongs on Game Rules. Its stageReached starts everything.

The first group of reinforcements comes, and then no more? Look at the last three steps of the reinforcements timer’s Event. They belong below the whole Repeat, not inside it, and Start Recurring Timer’s Applies to should read Self.

Enemy Fighters come, but never Aces or bombers? Perhaps the Milestones aren’t placed, or not where the card says they go. Each one has to come into view for the stage to rise.

Planes shove each other sideways, or bounce? Look at their Colliders’ Tags and Interactions, on all three kinds.

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

Challenge

Make the sea your own. Place a second Tropical Atoll the way you placed the first, anywhere ahead. Move Ahead When Passed takes care of it, with no new Logic. Or open Reinforcement Orders, and give Enemy Ace a fromStage of 1, so Aces come from the very start. How does the mission feel now? Put the row back, and take the extra atoll out, before Chapter 8.

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

Your route is a long way from an empty sea. It counts its stages, sends its reinforcements, and keeps the islands coming, one stepping stone at a time. In Chapter 8, the sky starts leaving gifts behind.