- Learn
- Build a Game
- Sky Ace
- 7 Other Enemies
7 Other Enemies
The banners keep their word. Red Aces sway down the window and fire three rounds at a time. Dive Bombers stop in the air, then dive at you. Heavy Bombers crawl down firing fans of five, and when one goes down, the camera shakes. By the end of this chapter, the mission is 46 rows long, and every kind of enemy flies in it but one.
The game as it is at the end of this chapter. Click the game to play.
This chapter builds on Chapter 6’s game. Starting here? The catch-up download in Chapter 6’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 8 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. Beside it, OFL.txt is the license of the project’s font, Bebas Neue.
7.1 The Idea
The banner comes up across the window: WAVE 2 - ACES HIGH. Then come the planes. They’re Zero Fighters, pale gray-green, the same as every plane before them. The banner promised aces.
This chapter brings the planes the banners named. A Red Ace is bright red, with yellow wingtips. It sways from side to side as it falls, and fires three rounds at a time, fanned out around you.
A Dive Bomber is sand-colored. It comes down, stops in the air, then dives at you. A Heavy Bomber is olive-green, with an engine on each wing. It crawls down the window, firing fans of rounds below it and single shots from its wings.
Three new planes sounds like three times the work. It isn’t.
Think about what a Red Ace shares with a Zero Fighter. It flies down. It takes hits. It goes down in smoke, and the score climbs. All of that is the shared part from Chapter 3: Logic Components any plane can carry, and the Tag every enemy wears, Enemy Aircraft.
So a Red Ace starts as a copy of the Zero Fighter. It gets a new picture, a row of its own in Enemy Types, and the few pieces that make it different. So do the two bombers.
Two of those pieces need names. The Red Ace’s sway, from side to side as it falls, is its weave. And its three rounds are a spread: rounds fanned out over an angle, its arc. Picture a hand of playing cards, held open. The cards are the rounds, and the arc is how wide the hand opens.
7.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.
- A Red Ace appears -> Fly Down pulls it down, and Weave sways it from side to side.
- A Red Ace reaches its firing band, the stretch of sky where enemies fire -> Red Ace Guns aims at the Fighter -> Fire a Spread throws three rounds around the aim.
- A Dive Bomber reaches its stopping height -> Dive Attack slows it to a hover -> a moment later, it dives at the Fighter.
- A Heavy Bomber reaches its firing band -> Heavy Bomber Guns fires a fan of five rounds -> its wing turrets take turns firing at the Fighter, left, then right.
- An enemy is shot down -> Shot Down reads its bigExplosion -> only a Heavy Bomber goes in a big explosion.
- A row’s time comes -> Make a Row Arrive passes on the row’s starting height, entryY, too -> a single plane can start higher above the window.
7.3 Set Up
This chapter uses six more pictures, the three planes and their shadows, and they’re already in your project, from the Starter Kit. The Game Settings don’t change. Nothing new is placed, either, because every enemy arrives from the Mission Timeline.
7.4 Three New Rows
First, the new enemies get their numbers.
7.4.1 Enemy Stats
Enemy Stats gets one more field, bigExplosion. It says whether a plane goes down in a big explosion. Only the Heavy Bomber does.
Open Enemy Stats and press Add Field, and a new field appears: a Number named localVariable. Type bigExplosion over its name, and pick Boolean in its Type list. Its Value turns into a small switch that reads No.
The card writes that default as false. It’s the same answer. Myth shows true and false as Yes and No beside that switch.
What every enemy carries; each enemy takes the values from its own row of Enemy Types.
7.4.2 Enemy Types
Enemy Types gets the new field too, as a column, all by itself, because its rows are Enemy Stats. Until now its one row was the Zero Fighter, from Chapter 3. Three join it. They’re the Red Ace, the Dive Bomber and the Heavy Bomber. Name each row exactly as its Object will be. That’s how a plane finds its row.
A Red Ace flies a little slower than a Zero Fighter, and takes five hits. A Dive Bomber takes six. A Heavy Bomber crawls along at under two meters a second. It takes 36 hits, and it’s worth 2000 points.
Open Enemy Types, and bigExplosion is there, at the right end of the grid. In each row, its cell is a small switch that reads Off.
False, No and Off all mean no here. On is Yes.
Now the rows. Press Add Row three times, under the grid. Myth names each new row Row. Double-click that name in the Entry column, type the plane’s name, and give the row the card’s numbers. Only one switch goes On, the Heavy Bomber’s.
On the card, the Zero Fighter’s No is a green line under its other three values. The three new rows are green, every line of them.
5.93752100No4.68755300No4.3756350No1.71875362000Yes7.5 The Red Ace
Now the first of them takes off.
7.5.1 Red Ace Shadow and Red Ace
Every plane casts a shadow. Chapter 5 said how a new kind gets one. Its shadow is an Object that wears the Tag Plane Shadow and carries Shadow on Clouds, and the plane carries Cast Shadow. The Red Ace Shadow is the Zero Fighter Shadow with another picture.
So right-click Zero Fighter Shadow in the Resources, and choose its Duplicate line. Myth opens the copy, named Zero Fighter Shadow2. Type Red Ace Shadow in its Name box, and pick Red Ace Shadow Art in its Sprite box. Its Tag and its Logic came with the copy. On the card, that Sprite line is the only one that differs from the Zero Fighter Shadow’s.
X 3, Y 3-12Red Ace Shadow ArtX 3, Y 3SensorX 3, Y 3Collide Only WithTagged CloudPlane ShadowShadow on CloudsShadow on Clouds DataThe Red Ace starts as a copy of the Zero Fighter. The copy wears Enemy Aircraft and carries all of the Zero Fighter’s Logic, so it already flies down, takes hits and goes down. Its Data Structure lines come along too. They find its row in Enemy Types by its name. So duplicate the Zero Fighter, type Red Ace in the Name box, and give it Red Ace Art.
Four things differ. Its Scene Depth Draw Order is 21, one above the Zero Fighter’s 20, so where the two cross, the Red Ace flies on top. Its Collider is a little wider and longer, to fit the red wings. Under its Shared Variables, pick Red Ace Shadow for shadow. The offsets stay.
And its guns are its own. Switch to its Logic, and take Zero Fighter Guns off with the red button at the right end of its row. The Shared Variables it brought go with it, round and fighter among them. Weave and Red Ace Guns, on its card, come next.
Once they’re on, your Attached Logic will list them last, under the Logic the copy brought. The card lists them first. That’s all right. Their place in the list changes nothing here.
X 3, Y 3Off21Red Ace ArtX 3, Y 3X 1.563, Y 1.188Collide Only WithFighter, Tagged Fighter RoundEnemy StatsData TableEnemy TypesEnemy AircraftExpressionobjectComponentProperty("self","dataStruct","health")ExpressionobjectComponentProperty("self","dataStruct","health")Red Ace Shadow0.75-1.125Enemy RoundFighterYou can see it already, if you borrow the first V. Open Mission Timeline. In its first row, Wave 1: V at 3 s, pick Red Ace in the object cell’s list. There’s no need to put it back later. The last part of this chapter makes the table new.
Save, and run the game. At three seconds, five red planes come down where the gray V was. They fall straight for now, and each one takes five hits.
7.5.2 Weave
A Red Ace doesn’t fall straight. It drifts right, slows, drifts left, slows, and drifts right again, all the way down, like a leaf falling. Weave makes that sway.
It changes only the sideways speed, while Fly Down still pulls the plane down. Weave’s Set Velocity has an X Velocity and an empty Y Velocity, and an empty box changes nothing. So the two pieces never fight over the plane.
The sideways speed follows a slow wave. That’s what cos does. Hand it a number that keeps growing, and it swings back and forth between plus one and minus one, again and again. Weave hands it the seconds the plane has flown, times weaveRate, and multiplies the swing by weaveSpeed: 6.563 meters a second at the widest. One whole sway takes a little over two and a half seconds.
Where on the wave does a plane start? At random. When Created rolls a number from 0 to 6.28, one whole turn of the wave, as phaseRoll, and keeps it in weavePhase. So five Red Aces in a V never sway in step.
Every Step adds the step’s length to secondsFlown, the way Mission Clock does in Chapter 6. Pick Plus in the Operator list, and type $deltaTime. A paused game runs no steps, so the weave waits too.
Weave keeps four numbers. Two never change, weaveSpeed and weaveRate, so they’re its SHARED VARIABLES, both Constants. The other two belong to each plane and change as it flies. So they live in a Data Structure of the Logic’s own, as Shadow on Clouds’ do in Chapter 5. Press the + on the Data Structures card and choose New Data Structure. Myth names it Weave Data. Give it the card’s two fields, weavePhase and secondsFlown, each a Number at 0.
The blocks reach those fields by their path. Change Component Value’s Component Value takes self.weaveData.weavePhase, typed as the card spells it. Type phaseRoll over the name in the Generate Random Number’s Action Name box, and 6.28 in its Maximum. Minimum stays as it starts.
For the second Event, type Step into the Add Event window’s filter, and pick Step itself, the first in the list. In Set Velocity, type the card’s X Velocity, and leave Y Velocity empty, as it starts.
Weaves from side to side on the way down: the sideways speed follows a slow wave, starting at a random point of it.
Any Objectself.weaveData- Action Name
phaseRoll- Maximum
6.28
- Component Value
self.weaveData.weavePhase- Value
phaseRoll.value
- Component Value
self.weaveData.secondsFlown- Operator
+=- Value
$deltaTime
- X Velocity
cos(@self.weaveRate * self.weaveData.secondsFlown + self.weaveData.weavePhase) * @self.weaveSpeed
Attach Weave to the Red Ace. Save, and run the game. The red V comes down swaying, each plane on its own beat.
7.5.3 Fire a Spread
A Red Ace fires three rounds at a time, fanned out around its aim. So does a Dive Bomber as it dives. A Heavy Bomber fires five. One Function lays out every one of those fans.
Fire a Spread makes count rounds from Caller, one each pass through its Repeat. The rounds spread evenly over arc degrees, centered on direction. With three rounds over 28 degrees, one flies along direction and one on either side.
How does each round find its angle? Inside the Repeat, local.index counts the rounds from 0. The first round starts half the arc to one side of direction. Each one after it turns a little farther, the same step each time, until the last is half the arc to the other side. That’s the card’s Direction on the Else line.
A single round has no fan to spread, and dividing by count minus one would mean dividing by 0. So when count is 1, the If sends the round straight along direction.
Last, Set Speed sends each round off at speed. The last two PARAMETERS, muzzleY and muzzleX, say where the rounds start, measured from the shooter’s middle. That’s how a wing turret fires from its wing.
Make its PARAMETERS first, with the + beside Parameters on its Start block: Caller, then round, then the six Numbers. The round Parameter asks only for a Transform, as on Fire a Volley in Chapter 2.
The Repeat holds three steps: Create Instance, the If, and Set Speed. Right-click the Repeat and choose Add inside Repeat for each, in that order, and join each one with Connect to sequence. Inside the If, Add inside Then adds the Then line’s Set Direction. Add Else makes the Else, and its own Add inside Else adds the Else line’s.
Create Instance’s Applies To starts on Caller, the first Object Parameter, as in Fire a Volley. In its Object to Create list, pick round.
Its Position Relative To starts at World. Pick Self, and the rounds start at the shooter, wherever it has flown.
Set Speed starts on created already. The two Set Directions sit inside the If, so pick created in each one’s Applies To. In the Else’s Direction, type the card’s formula as it is.
Creates count rounds from the caller, fanned evenly over arc degrees around direction, each flying at speed.
transformTransformcounttimes- Applies To
Caller- Object to Create
round- Position Relative To
Self- X
muzzleX- Y
muzzleY
count == 1- Applies To
created- Direction
direction
- Applies To
created- Direction
direction - arc / 2 + arc * local.index / (count - 1)
- Applies To
created- Speed
speed
7.5.4 Red Ace Guns
Red Ace Guns works like Zero Fighter Guns from Chapter 4, with a spread where one round was.
A Red Ace appears. It picks a first delay at random, between 0.4 and 1 second, as firstShot. Then it asks Wait for the Firing Band how long until it’s inside its firing band, the stretch of sky from bandTop down to bandBottom. Only there does an enemy fire. Red Ace Guns is the first of two guns that Chapter 4 said would ask it.
The answer, firstBurstWait.value, is the First Delay of the burst timer. After that the timer rings every shotGap, 1.7 seconds. A timer that repeats keeps its own time, so nothing ever sets it again.
Make it in the order Zero Fighter Guns took. First come its SHARED VARIABLES, all Constants. The first two, round and fighter, are Objects, and their Starting Value stays at None. The Red Ace picks them. Then the numbers, in the card’s order. Then press the + on the Data Structures card, and pick Enemy Stats under Existing Data Structures.
Next, its two Events: When Created, and the burst timer’s. That one is a Recurring Timer. Myth Engine asks which timer, so choose Type a timer name…, press OK, and type burst. Last, their Actions.
Each Timer Name takes burst bare, in Start and in Stop Recurring Timer.
This timer’s card has a Repeat Every line and no Ring Once line. Leave Ring Once as it starts, on No. That keeps the timer ringing.
Fires an aimed burst of three rounds every shotGap seconds while inside the firing band.
Any Objectself.enemyStats- Action Name
firstShot- Minimum
@self.firstShotMin- Maximum
@self.firstShotMax
- Action Name
firstBurstWait- caller
self- bandTop
@self.bandTop- speed
self.enemyStats.speed- delay
firstShot.value
- Timer Name
burst- Repeat Every (s)
@self.shotGap- First Delay (s)
firstBurstWait.value
Each ring asks two things, the way Still Firing? does on the Zero Fighter. Is the mission still being played, and is the plane still above bandBottom? If both are yes, it fires.
Aim Down at the Fighter gives fighterAim.value, the direction to the Fighter, held between aimMin and aimMax, 200 and 340. Those are the directions below the plane, either side of 270, straight down. Fire a Spread throws burstCount rounds around it, over burstArc. Then the flash, and Enemy Guns.
If either answer is no, the Else’s Stop Recurring Timer ends the timer, and that plane’s guns are done for good. Add Else, on the If’s right-click menu, makes the Else line.
Its If is one box, with both questions joined by &&, and. Type it whole. Check Game State starts on Playing, the one it needs. The call to Fire a Spread has fields named for the Function’s Parameters, and its caller list starts on self. In its round list, pick @self.round. The muzzleX field isn’t on the card, and left empty, it keeps the Function’s own 0.
- Action Name
stillPlaying- Game State
Playing
stillPlaying.value == true && self.transform.position.y > @self.bandBottom- Action Name
fighterAim- caller
self- fighter
@self.fighter- aimMin
@self.aimMin- aimMax
@self.aimMax
- caller
self- round
@self.round- count
@self.burstCount- direction
fighterAim.value- arc
@self.burstArc- speed
@self.roundSpeed- muzzleY
@self.muzzleY
- Particles
"Enemy Muzzle Flash"- Y
@self.muzzleY- Count
@self.enemyMuzzleFlashCount- Z Index Offset
2
- Sound
"Enemy Guns"
- Timer Name
burst
Attach Red Ace Guns to the Red Ace. Its round and fighter join the Red Ace’s Shared Variables, at None. Pick Enemy Round for round and Fighter for fighter.
Save, and run the game. The red V sways down. As each plane drops into the window, a spark flashes at its nose. Three rounds fan out toward you. That’s a good place to stop for a break, if you’d like one.
7.6 The Dive Bomber
Next comes the Dive Bomber.
7.6.1 Dive Bomber Shadow and Dive Bomber
Make both the way you made the Red Ace and its shadow: duplicate the Zero Fighter Shadow and the Zero Fighter, name each copy, then pick its picture. Again, only the shadow card’s Sprite line is new. The Dive Bomber’s Draw Order is 22, so it flies over every other plane. Its Collider fits its sand-colored wings.
Under its Shared Variables, pick Dive Bomber Shadow for shadow. Its shadow falls a little farther out, so type the two offsets from the card. Take Zero Fighter Guns off the copy too, since its one Logic of its own is Dive Attack, below. As on the Red Ace, the order of its Attached Logic changes nothing.
X 3, Y 3-12Dive Bomber Shadow ArtX 3, Y 3SensorX 3, Y 3Collide Only WithTagged CloudPlane ShadowShadow on CloudsShadow on Clouds DataX 3, Y 3Off22Dive Bomber ArtX 3, Y 3X 1.813, Y 1.375Collide Only WithFighter, Tagged Fighter RoundEnemy StatsData TableEnemy TypesEnemy AircraftExpressionobjectComponentProperty("self","dataStruct","health")ExpressionobjectComponentProperty("self","dataStruct","health")Dive Bomber Shadow0.844-1.219Enemy RoundFighter7.6.2 Dive Attack
A Dive Bomber falls like any enemy at first. Part way down, it almost stops. It hangs there for 0.7 seconds. Then it turns toward you and dives, as fast as your Fighter flies, and three rounds spread from its nose.
Each of those moments is a timer. When Created works out when the first one rings. The bomber picks a height to stop at: stopHeight, less a random amount up to stopRange, 5 meters. That’s stopY. Its height above stopY, divided by its speed, is how many seconds it falls before it gets there, descentSeconds.
A plane that starts below stopY would get a time under 0, so the If makes it 0, and the timer rings at once.
Why not look at the bomber’s height every step? One timer, set once, rings the moment it gets there. Nothing has to keep checking.
Make its SHARED VARIABLES first, all Constants, with round and fighter at None. Then Enemy Stats, from the + on the Data Structures card. stopY and descentSeconds are made by When Created itself. Its first two steps are Declare Variables, each a Number. Their Value boxes start empty, so type the card’s 0.
In the Generate Random Number, type stopBelow over its Action Name, and @self.stopRange in Maximum. Each timer’s Event is a Recurring Timer, made the way the burst timer’s was. Each Timer Name takes its name bare, descent or hover, and both timers ring once, so Ring Once is a list: Yes.
The card’s last step, Start Recurring Timer, has no indent. It sits on the main line, after the If, not inside it. Inside the If, the timer would start only for a plane that begins below stopY. Every other Dive Bomber would fall straight through.
So once the If’s own step is in, add Start Recurring Timer from the Action List, and join it with Connect to sequence. It goes under the If, above End. If, Else, Repeat and While shows the same move.
Descends to a random height, hangs there for a moment, then dives at the Fighter and drops a spread of three rounds (once the mission is over it dives straight down).
Any Objectself.enemyStats- Name
descentSeconds- Value
0
- Name
stopY- Value
0
- Action Name
stopBelow- Maximum
@self.stopRange
- Variable
stopY- Value
@self.stopHeight - stopBelow.value
- Variable
descentSeconds- Value
(self.transform.position.y - stopY) / self.enemyStats.speed
descentSeconds < 0- Variable
descentSeconds- Value
0
- Timer Name
descent- First Delay (s)
descentSeconds- Ring Once
Yes
The descent timer rings. Set Speed drops the bomber’s speed to hoverSpeed, a slow drift down, so it seems to stop in the air. Then the hover timer starts, for hoverSeconds.
- Speed
@self.hoverSpeed
- Timer Name
hover- First Delay (s)
@self.hoverSeconds- Ring Once
Yes
The hover timer rings, and the bomber dives. While the mission is being played, it aims down at the Fighter, as diveAim, and turns along that line. Fire a Spread drops spreadCount rounds along the dive, over spreadArc. Then the flash, and Enemy Guns.
Once the mission is over, the Fighter may be gone, with nothing to aim at. So the Else turns the bomber straight down, 270, instead. Either way, the last step sends it off at diveSpeed.
That last step sits on the main line too, after the If and its Else. Add it as you added the descent timer’s start.
- Action Name
stillPlaying- Game State
Playing
stillPlaying.value == true- Action Name
diveAim- caller
self- fighter
@self.fighter- aimMin
@self.aimMin- aimMax
@self.aimMax
- Direction
diveAim.value
- caller
self- round
@self.round- count
@self.spreadCount- direction
diveAim.value- arc
@self.spreadArc- speed
@self.roundSpeed- muzzleY
@self.muzzleY
- Particles
"Enemy Muzzle Flash"- Y
@self.muzzleY- Count
@self.enemyMuzzleFlashCount- Z Index Offset
2
- Sound
"Enemy Guns"
- Direction
270
- Speed
@self.diveSpeed
Attach Dive Attack to the Dive Bomber, and pick Enemy Round and Fighter under its Shared Variables. Now lend it the first V: pick Dive Bomber in that row’s object cell.
Save, and run the game. Five sand-colored planes come down, stop one by one at their own heights, hang, and dive at you.
7.7 The Heavy Bomber
Last comes the heaviest.
7.7.1 Heavy Bomber Shadow and Heavy Bomber
Make these two the same way, but this time the Draw Orders go lower. The Heavy Bomber’s is 19, under the Zero Fighter’s 20, so the other planes fly over it. Its shadow’s is -13, under the other planes’ shadows. On the shadow’s card, that Draw Order and the Sprite line are the only changes.
Its picture fills the same 3-meter square as every plane’s. So its Size stays 3. What makes it heavy is its row in Enemy Types. It crawls, and takes 36 hits.
Its Collider is the widest of all. Under its Shared Variables, pick Heavy Bomber Shadow for shadow, and type the card’s offsets, which put its shadow farthest out. Take Zero Fighter Guns off this copy too, because its guns are Heavy Bomber Guns, next.
X 3, Y 3-13Heavy Bomber Shadow ArtX 3, Y 3SensorX 3, Y 3Collide Only WithTagged CloudPlane ShadowShadow on CloudsShadow on Clouds DataX 3, Y 3Off19Heavy Bomber ArtX 3, Y 3X 2.625, Y 1.875Collide Only WithFighter, Tagged Fighter RoundEnemy StatsData TableEnemy TypesEnemy AircraftExpressionobjectComponentProperty("self","dataStruct","health")ExpressionobjectComponentProperty("self","dataStruct","health")Heavy Bomber Shadow1.031-1.594Enemy RoundFighter7.7.2 Heavy Bomber Guns
A Heavy Bomber has two kinds of gun. Under its nose, it fires a fan: five rounds at once, over 60 degrees, straight down the middle. From its wings, it fires single rounds at you, one wing and then the other.
Each gun has its own timer, and both repeat. When Created asks Wait for the Firing Band how long until the bomber reaches its band, with no delay of its own. That’s the second gun that Chapter 4 said would ask it. The fan timer first rings fanFirst seconds after that, then every fanGap, and the wing timer wingFirst seconds after it, then every wingGap.
Build it in the order Zero Fighter Guns took: Shared Variables and Enemy Stats, Events and Modes, switches, Actions. The cards come in another order, so read on to the wing timer before you add the first card’s Actions. Each Timer Name takes its name bare here too, fan or wingShot.
Inside its firing band the Heavy Bomber fires a five-round fan every 1.8 s and an aimed round from alternating wing turrets every 1.1 s.
Any Objectself.enemyStats- Action Name
bandWait- caller
self- bandTop
@self.bandTop- speed
self.enemyStats.speed- delay
0
- Timer Name
fan- Repeat Every (s)
@self.fanGap- First Delay (s)
bandWait.value + @self.fanFirst
- Timer Name
wingShot- Repeat Every (s)
@self.wingGap- First Delay (s)
bandWait.value + @self.wingFirst
The fan works like the Red Ace’s burst, with no aim: Fire a Spread throws fanCount rounds around 270, straight down, over fanArc. The call’s muzzleX is 0 on the card, the Function’s own value. Type it anyway, so the call matches its card. Once the mission is over, or the bomber is below bandBottom, the Else stops the timer.
- Action Name
stillPlayingForFan- Game State
Playing
stillPlayingForFan.value == true && self.transform.position.y > @self.bandBottom- caller
self- round
@self.round- count
@self.fanCount- direction
270- arc
@self.fanArc- speed
@self.fanSpeed- muzzleX
0- muzzleY
@self.fanY
- Particles
"Enemy Muzzle Flash"- Y
@self.fanY- Count
@self.enemyMuzzleFlashCount- Z Index Offset
2
- Sound
"Enemy Guns"
- Timer Name
fan
The wing turrets take turns. The wing timer’s Event is Combined, with three Modes: Still Firing?, Left Wing and Right Wing. Still Firing? and Left Wing answer from the start. Right Wing waits.
Each ring, Still Firing? goes first. If the mission is over, or the bomber is below its band, it stops the timer. Return ends the ring right there, for the whole Event.
Otherwise the wing that’s on fires one round at the Fighter, from wingOffset off center. Then it trades places with the other wing. Turn Off Mode takes it out, and Turn On Mode puts the other wing in. The swap counts from the next ring, so the other wing fires then. Left, right, left, right.
Why not one Mode, with an If for the side? Then a Variable would have to remember which wing fires next, and both wings’ steps would share one line. With two Modes, each wing’s steps sit on a line of their own. The wing that’s on is the wing whose turn it is, so nothing else has to remember.
In Chapter 4, a Zero Fighter whose pilot aims swaps Shoot Straight for Shoot Aimed once, as it appears. These wings swap at every ring.
The wing timer’s new Event starts with one Mode, Mode 1. Rename it Still Firing?, and add Left Wing and Right Wing with New Mode….
Pick Combined, and turn on On at start on Still Firing? and Left Wing. Right Wing’s stays off. Turn Off Mode and Turn On Mode name no Event, so they work on the Current Event, where their Event list starts. Their Mode list holds this Event’s three Modes.
The two wings are mirror images. Left Wing’s muzzleX is -@self.wingOffset, and Right Wing’s is @self.wingOffset, the same distance the other way.
- Action Name
stillPlayingForWings- Game State
Playing
stillPlayingForWings.value == false || self.transform.position.y <= @self.bandBottom- Timer Name
wingShot
- Action Name
leftWingAim- caller
self- fighter
@self.fighter- aimMin
@self.aimMin- aimMax
@self.aimMax
- caller
self- round
@self.round- count
1- direction
leftWingAim.value- arc
0- speed
@self.wingRoundSpeed- muzzleX
-@self.wingOffset- muzzleY
@self.wingY
- Particles
"Enemy Muzzle Flash"- X
-@self.wingOffset- Y
@self.wingY- Count
@self.enemyMuzzleFlashCount- Z Index Offset
2
- Sound
"Enemy Guns"
- Mode
Left Wing
- Mode
Right Wing
- Action Name
rightWingAim- caller
self- fighter
@self.fighter- aimMin
@self.aimMin- aimMax
@self.aimMax
- caller
self- round
@self.round- count
1- direction
rightWingAim.value- arc
0- speed
@self.wingRoundSpeed- muzzleX
@self.wingOffset- muzzleY
@self.wingY
- Particles
"Enemy Muzzle Flash"- X
@self.wingOffset- Y
@self.wingY- Count
@self.enemyMuzzleFlashCount- Z Index Offset
2
- Sound
"Enemy Guns"
- Mode
Right Wing
- Mode
Left Wing
Attach Heavy Bomber Guns to the Heavy Bomber, and pick Enemy Round and Fighter under its Shared Variables, as on the other two. Lend it the first V, too. Pick Heavy Bomber in that row’s object cell, and type 1 in its count.
Save, and run the game. One olive-green bomber crawls down the middle, firing fans of five, and single rounds from each wing in turn. It takes 36 hits. For now it goes down the way a Zero Fighter does. Shot Down changes that next.
7.7.3 Shot Down
A Heavy Bomber deserves a bigger ending. When one goes down, it goes the way your Fighter does on its last medkit, in Chapter 4. The Big Explosion bursts, smoke rolls out, Explosion Large sounds, and the camera shakes.
Shot Down already knows how a plane goes down, and every plane carries it, the three copies too. Now it asks the plane first: is your bigExplosion on? If yes, the big show, and if no, the small one, as before. Only the Heavy Bomber’s row says yes.
To read that field, Shot Down needs the plane’s Enemy Stats. Every plane already carries them. So press the + on Shot Down’s Data Structures card, and pick Enemy Stats under Existing Data Structures.
Then add the four new Shared Variables, all Constants. Each new row lands under the old ones, while the card shows them above. The order doesn’t matter.
On the card, the struck lines come first: the three old blocks, two Burst Particles and a Control Sound. Under them comes the If, in green. Everything inside it is new, the four blocks on its paler Then panel too. Right-click each old block and choose Delete.
The If goes between Trigger Custom Event and Destroy Instance. Connect to sequence always joins the end of the line, so take Destroy Instance off it first. Right-click it and choose Disconnect from flow. It waits beside the line. Now add an If from the Action List and join it. Then right-click Destroy Instance and choose Connect to sequence, and it joins the end again, after the If. Type the If’s condition whole, in its one box.
Its True line gets the big show, four blocks. Right-click the If and choose Add inside Then for each, and join each one with Connect to sequence. Then choose Add Else on the same menu. On the Else, Add inside Else takes the small show’s three blocks. They’re the three you deleted, with their old values.
When this enemy has taken as many hits as its health it tells Game Rules (enemyShotDown), explodes and is removed.
Any Objectself.enemyStats- Custom Event
enemyShotDown
- Particles
"Plane Explosion"- Count
@self.explosionCount- Z Index Offset
2
- Particles
"Smoke Puff"- Count
@self.smokeCount- Z Index Offset
2
- Sound
"Explosion Small"
self.enemyStats.bigExplosion == true- Particles
"Big Explosion"- Count
@self.bigExplosionCount- Z Index Offset
2
- Particles
"Smoke Puff"- Count
@self.bigSmokeCount- Z Index Offset
2
- Sound
"Explosion Large"
- Intensity
@self.shakeStrength- Seconds
@self.shakeSeconds
- Particles
"Plane Explosion"- Count
@self.explosionCount- Z Index Offset
2
- Particles
"Smoke Puff"- Count
@self.smokeCount- Z Index Offset
2
- Sound
"Explosion Small"
Save, and run the game again. The bomber still has the first V to itself, so it comes down alone. Bring it down. The camera shakes. This is another good place to stop for a break, if you’d like one.
7.8 The Whole Mission
Now the new enemies join the mission.
7.8.1 Mission Timeline
The Mission Timeline grows to 46 rows. In Chapter 6 you typed its rows, but this time a file brings them, with Import CSV.
It gets one new field, entryY, the height a row’s planes start at. Most rows keep 35.9375, out of sight above the window. A few single planes start higher, so they come into view a moment later.
There’s one catch. Import CSV adds every row whose name the table doesn’t have yet, and it adds them at the end. So if you kept your old rows, they’d stay at the top. The new rows would land after your last V. By then their times would be long past, so every one of them would arrive at once, the moment that V came.
So the old rows go first. Under the grid, press Clear All Rows, and Myth Engine asks first, in a window: Clear every row? The columns and their defaults stay in place, so press Clear Rows.
Next comes the new field. Open Mission Timeline Entry, press Add Field, and give the field the card’s name and default: entryY, a Number, 35.9375. The table gets its entryY column by itself. Make it before you import, so each row’s entryY has a place to go.
Download the file from the card’s File line, then press Import CSV, under the grid, and pick it. Myth Engine asks first: Import CSV Into Mission Timeline? This merge will apply 46 new rows, 0 existing rows. Press Import CSV again. Your first row is the Zero Fighters’ V again, so the borrowed V is gone too.
3VZero Fighter11.2552.2535.93756.5ColumnZero Fighter5.312542.812535.93756.5ColumnZero Fighter17.187542.812535.937510Side SweepZero Fighter05013VZero Fighter7.187532.2513VZero Fighter15.312532.2516Side SweepZero Fighter22.55019RowZero Fighter11.256022VZero Fighter11.257228ColumnZero Fighter11.2532.812536VZero Fighter11.2552.2540Side SweepZero Fighter04040Side SweepZero Fighter22.54048VZero Fighter7.812532.2548VZero Fighter14.687532.2558ColumnZero Fighter2.812532.812558ColumnZero Fighter19.687532.812568Side SweepZero Fighter22.55076VZero Fighter11.257282ColumnZero Fighter3.7532.812582ColumnZero Fighter18.7532.8125100Side SweepZero Fighter050105VZero Fighter11.2552.257.8.2 Make a Row Arrive
Make a Row Arrive passes each row’s entryY on. The calls to Spawn V Formation, Spawn Column and Spawn Row each get one more field. Spawn Side Sweep has its own starting height, so its call stays as it is.
Open each of the first three calls. Its entryY box is empty, and an empty field keeps the Function’s own entryY. Type the card’s expression into it, as each green line on the card shows, and press Enter.
Makes one Mission Timeline row arrive: the Object its object cell names, in the row's formation.
data("Mission Timeline", row, "formation") == "V"- 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")- entryY
data("Mission Timeline", row, "entryY")
data("Mission Timeline", row, "formation") == "Column"- 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")- entryY
data("Mission Timeline", row, "entryY")
data("Mission Timeline", row, "formation") == "Row"- caller
Caller- enemy
data("Mission Timeline", row, "object")- count
data("Mission Timeline", row, "count")- entryY
data("Mission Timeline", row, "entryY")
data("Mission Timeline", row, "formation") == "Side Sweep"- caller
Caller- enemy
data("Mission Timeline", row, "object")- edgeX
data("Mission Timeline", row, "x")- count
data("Mission Timeline", row, "count")
Save, and run the game. Let the mission run.
With ACES HIGH, red planes join the gray ones. With DIVE BOMBERS, rows of sand-colored bombers stop in the air and dive. And with HEAVY SQUADRON, a Heavy Bomber crawls down the middle. That’s your mission, nearly whole.
Watch for each of these.
- In Wave 1, the Zero Fighters come alone, as they did before.
- When ACES HIGH comes up, two single Red Aces fly in, one on each side of a column of Zero Fighters.
- Each Red Ace sways on its own beat, and fires three rounds at a time: one at you, one on each side.
- A Red Ace takes five hits, and it’s worth 300 points.
- When DIVE BOMBERS comes up, a row of sand-colored bombers comes down. Each stops at its own height and hangs there, then dives at you with three rounds.
- When HEAVY SQUADRON comes up, one Heavy Bomber crawls down the middle. It fires fans of five rounds, and single rounds from each wing in turn.
- Hit it 36 times. It goes down in a big explosion, and the camera shakes.
- Where planes cross, the Dive Bomber flies over the rest, and the Heavy Bomber under them.
- Every new plane casts a shadow, which shows on the clouds.
Three new enemies, and most of each was already built. Each began as a copy of the Zero Fighter, so it wears Enemy Aircraft and carries the Logic that flies it down, counts its hits and brings it down. Each finds its numbers in its own row of Enemy Types. Each casts its shadow with Cast Shadow. What’s new is what makes it different: the Red Ace’s weave and burst, the Dive Bomber’s stop and dive, the Heavy Bomber’s fan and wings.
Underneath it is one idea. Build what’s shared once, and give each one only what’s its own. One Function lays out every fan in this chapter. Two from Chapter 4 aim at the Fighter and wait for the firing band. A new enemy is mostly old pieces.
7.9 If It Didn’t Work
Something may be a little off the first time. That’s normal. This chapter has three new planes. Run the game, find the one that misbehaves, and watch what it does.
No red plane at all? It may be there, out of sight. Is there a row in Enemy Types named Red Ace, exactly as the Object is? A plane with no row of its own gets the starting speed, 0. It waits above the window.
While you borrow the first V, look at the object in Mission Timeline’s first row too. It should say Red Ace. After the last part, that row is the Zero Fighters’ again, and the Red Aces come with ACES HIGH. The file names them Red Ace, so your Object needs that name, spelled the same way.
The Red Aces slide sideways but stop falling? Look at Weave’s Set Velocity. Its Y Velocity box must be empty, since a 0 there sets the fall to nothing, every step.
The Red Aces fall straight, with no sway? Is Weave attached to the Red Ace?
Each Red Ace slides off to one side and leaves the window? Look at the Operator in Weave’s Every Step. It should be Plus, the card’s +=. With a plain =, secondsFlown is only ever one step long, so the wave never moves on. Each plane holds its first sideways speed.
The three rounds fly out as one, on a single line? Look at the Else line’s Set Direction in Fire a Spread. Its Direction ends in local.index / (count - 1). The If above it compares count with 1.
Rounds appear at the middle of the window, or nowhere, though the plane flashes at its nose? In Fire a Spread, Create Instance’s Applies To should be Caller, and its Position Relative To should be Self. Left at World, the rounds start far from the plane, out of sight. The two Set Directions’ Applies To should be created.
A Red Ace never fires? Is Red Ace Guns on the Red Ace, with Enemy Round and Fighter under its Shared Variables? Its timer is named burst, bare, in both Start and Stop Recurring Timer, and in the box Myth asked for when you made On the Burst Timer.
A Dive Bomber never stops? Look first at When Created’s Start Recurring Timer. It belongs on the main line, under the If. Inside the If, it starts only for a plane already below stopY, and the rest fall straight through. After that, look at the timer itself: First Delay holds descentSeconds, and the Timer Name is descent, bare, the name its Event waits for.
It stops but never dives? The hover timer works the same way, and Set Speed with diveSpeed is on the main line, after the Else.
The Heavy Bomber fires from one wing only? Look at Left Wing’s last two steps: Turn Off Mode Left Wing, then Turn On Mode Right Wing. Right Wing’s are the mirror. And Right Wing’s On at start should be off.
The Heavy Bomber goes down like a Zero Fighter? Look in Enemy Types: its switch in the bigExplosion column should be On, not Off.
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 name is spelled another way than on the card, or a quote mark or a bracket went missing along the way.
Nothing new comes until after the last V, and then every plane at once? Your table kept its old rows, and the new ones came in after them, with times long past. Press Clear All Rows, as in the last part, and import the file again.
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.
One thing first. Chapter 8 starts from the cards’ tables, so save your project.
Choose File > Save as… next, and give the copy a new name. Myth goes on in the copy, and your chapter’s project stays as it was. Or start Chapter 8 from this chapter’s catch-up download.
Now make an enemy of your own. Duplicate the Red Ace, and give it a row in Enemy Types with your own speed, health and points. Give it new weave numbers under its Shared Variables, weaveSpeed and weaveRate: a wide, slow sway, or a quick shiver. It can borrow a picture for now.
Send it in by borrowing a row of the Mission Timeline, the way you borrowed the first V. A row added at the end would come only after the mission’s last row. What would you call your enemy?
Still stuck? Search the manual, or ask in the Myth Engine Discord (opens a new tab).
Every kind of enemy flies in your mission now but one. In Chapter 8, a plane you shoot down leaves something behind.
