- Learn
- Build a Game
- Pacific Wings
- 4 Enemy Fire and Lost Planes
4 Enemy Fire and Lost Planes
Nothing in the sky can hurt your Fighter yet. By the end of this chapter, the Enemy Fighters shoot back. A red tracer costs you a plane. So does an enemy you fly into. Small cream planes under the score count the ones in reserve. The next one flies up from below the screen, blinking, and nothing can hurt it while it blinks. Lose the last plane, and the screen says MISSION FAILED.
The game as it is at the end of this chapter. Click the game to play.
If your game and this chapter part ways, here is the chapter’s finished project. Open it and compare, or start Chapter 5 from it.
To open it, start Myth Engine, choose File › Open Project... and pick the downloaded file.
4.1 The Idea
An Enemy Fighter slides into the top of the view. A moment later a spark flashes at its nose, and a red tracer drops toward you. Then the next plane fires, and the next, each on a beat of its own.
Until now, nothing could hurt you. Enemies rode on your nose, and nothing happened. That changes here.
Fly into a red tracer, or into an enemy, and your plane is lost. It breaks up in a big explosion. The camera shakes, and the screen flashes a warm white. You start with three planes: the one flying and two in reserve. Two seconds after a loss, the next one flies up from below the screen, blinking. While it blinks, nothing can hurt it.
Lose the last one, and the world stops. MISSION FAILED and your final score hang over the frozen sky, above a PLAY AGAIN button. That button does nothing until Chapter 5 gives it its job.
New ideas carry all of this.
Everything that can cost you a plane wears one Tag, Enemy Threat. The enemies wear it, and so do their tracers. Your Fighter needs to ask one question only: did anything tagged Enemy Threat touch me?
An enemy fires when an alarm rings. A Recurring Timer is that alarm. Chapter 2’s cooldown was a stopwatch the guns kept looking at, to see whether their wait was over. A Recurring Timer rings by itself, and its ringing is an Event. Each enemy sets its own.
A plane flying in mustn’t steer, fire, or be lost. Its Events still happen: your keys are held, an enemy touches it. They only answer differently. Each way of answering is a Mode, and one Event can have several. It works like a phone set to ring or to silent. The call still comes. The setting decides what happens.
And the mission itself has a state now. A Game State says what the mission is doing: Playing, and then, if it goes wrong, Mission Failed.
4.2 The Plan
Here’s how the pieces work together, one chain of events to a line. Most of these names are new. Each is a piece this chapter builds. Glance at the plan now, and come back to it as you go.
- An Enemy Fighter comes into view -> Fire When Seen starts its enemyFire timer.
- The timer rings -> Fire From Muzzle sends an Enemy Tracer south -> the timer starts again, for a random wait.
- Something tagged Enemy Threat touches the Fighter -> Crashes Into Fighter bursts it into flak and removes it -> Lost on Hit breaks the Fighter up and sends fighterLost.
- Every step of the game -> Track the View, on the camera, writes the middle of the view into $viewMiddleX and $viewMiddleY.
- Lost on Hit sends fighterLost -> Planes, on Game Rules, takes one plane from $planes.
- Planes are left -> launchReserve rings 2 seconds later -> a new Fighter appears below the screen and hears startReturnFlight.
- The new plane hears it -> Return Flight flies it up, blinking and protected.
- No planes are left -> Planes sets the Game State to Mission Failed.
- The Game State changes -> Score stops counting at once -> Mission Failed Screen waits 3 seconds, then shows the screen and pauses the world.
- The Global $planes changes -> each Reserve Plane Icon shows or hides.
4.3 Turn on Advanced Mode
One Action in this chapter stays hidden until you ask for it. Tween Property glides a value from where it is to where you want it, over a set time. Return Flight uses it to fly a new plane up from below the screen. Myth Engine keeps a few Actions like it out of the Action List at first. The list stays short while you learn.
Choose Settings > Advanced Mode at the top of the editor. The line at the bottom of the editor says Advanced mode enabled. Your game stays exactly as it was. Only the editor shows more.
4.4 Set Up
Three pictures and three sounds from the Starter Kit join the game. All six are in your project already. The pictures are the Enemy Tracer Art, the Reserve Plane Icon Art and the Mission Failed Panel. The sounds are Enemy Guns, Fighter Lost and Reserve Plane Arrives.
Playing, Mission FailedGLOBAL VARIABLES has four this time. Make them the way you made $score: open any Logic Component, Score will do, press the + on its Globals card, and choose New Global…. Type each name without the $, and its starting number into the Default. $planes starts at 3. $scrollSpeed starts at 2.25. That’s the camera’s speed from Chapter 1. It’s kept in one place now, where two pieces of Logic can read it. $viewMiddleX and $viewMiddleY start at 0. Later in this chapter, they’ll always hold where the middle of the view is.
GAME SETTINGS > General > Game State lists the states a mission can be in. Open Game Settings and choose General. Under Game State, the Available Game States list shows Playing already. Every new project starts with that state. Press the + under it, Add Game State. A small window asks for the Game State Name: type Mission Failed, and press the window’s own Add Game State.
The SCENE block says Route is changed. Its camera, its view and its Ocean are the same as before. What’s new rides on the camera. It’s a Logic Component, Track the View, and you’ll make it and put it there in the Reserve planes part.
PLACE THESE waits for its Objects. The icons and the screen come late in the chapter.
4.5 Enemy Fire
Now the enemies get their guns.
Each kind of enemy fires on its own beat. So three numbers join Enemy Stats: when the first shot comes, and the shortest and longest waits between shots after it.
What every enemy carries. Each enemy kind takes its values from its own row of Enemy Types.
Open Enemy Stats and press Add Field three times, as you did for its first three. The card’s defaults go into each Value: 1, 1 and 2.
3.711001.151.42.5Open Enemy Types, and it has six columns already, one for each field. The new ones start at 1, 1 and 2, and the Enemy Fighter’s row keeps its other numbers.
Double-click each new cell and type the card’s value. An Enemy Fighter fires its first shot 1.15 seconds after it comes into view. Each later shot comes 1.4 to 2.5 seconds after the last. No two waits are quite the same.
An enemy’s tracer is a rod of red light with a gold end.
X 0.68, Y 0.6850Enemy Tracer ArtX 0.68, Y 0.68Z -180SensorCapsuleX 0.154, Y 0.499Enemy ThreatMake it a 2D Object named Enemy Tracer. Go down its card from the top, as you did for the Fighter Tracer. Like the enemies’ planes, its picture turns -180 to face south. Its Collision is Sensor, like your tracer’s.
Its Tag is the new one. Attach Tags from the Data group, choose Create New Tag… in its list, and press the + beside it. Type Enemy Threat in the Create Tag window. From now on, Enemy Threat waits in the list for the next Object that needs it.
Its two Logic Components are what every threat does: it crashes into the Fighter, and it’s removed once it leaves the view. Remove When Out of View is Chapter 2’s, so attach it now. Crashes Into Fighter comes later in this chapter.
Each enemy shot comes with a small flash of its own, Enemy Gun Muzzle.
8pointmin 70, max 170min 0.938, max 3.594min -110, max -70Multiple Colors#FFF8D2, #FFD166, #FF9F431.2start 0.58, end 00.35Random Spin OnMake it the way you made Gun Muzzle. Its card is the same in every line but one, the angle. These sparks fly south, so the dial’s Min and Max are below zero. Here’s the rest again: Emit Shape goes to point, and with three colors you press Add Color once.
4.5.1 Fire From Muzzle
An enemy fires the way your Fighter does. A tracer appears at a muzzle, already flying, with a small flash. That’s two pieces of Logic doing the same three things. So the three things become one Function, Fire From Muzzle, and both the Fighter’s guns and the enemies’ call it.
The Function is handed everything that differs: who shoots, what, from which muzzle, how fast, how many sparks, which way, and which flash. Its direction is the angle the tracer flies: 90 is north, and -90 is south.
The middle step turns the tracer to face its flight. Every tracer picture points north. One flying north, at 90, needs no turn. One flying south needs -180, the same turn as the enemies’ pictures. Set Rotation turns it by direction - 90, which gives both. Flying north, 90 - 90 is 0. Flying south, -90 - 90 is -180.
The shooter creates one tracer at its muzzle Coordinate, flying in direction at tracerSpeed and turned to face that way, with a muzzle flash.
- Applies to
shooter- Object to Create
tracer- Position Relative To
Self- Self Position
Coordinate- Coordinate
muzzle- Launch Speed
tracerSpeed- Launch Angle
direction
- Applies to
created- Degrees
direction - 90
- Applies to
shooter- Particles
flash- Position Relative To
Coordinate- Coordinate
muzzle- Count
flashParticles- Z Index Offset
2
Make it with Add > Function, named Fire From Muzzle. Its Parameters go on the Start block, with the + there, as Tint Sprite’s did. shooter and tracer are Objects, the one at the very end of the Type list. The muzzle Parameter is a Text with the Default Center Muzzle, typed without quote marks. The three Numbers come next.
The last one, flash, is a Particles Parameter. That kind is among the ones that run from A to Z, lower in the Type list. It’s what the card’s Thing Particle means. Its Default is a list of your particle effects, starting on None. Pick Gun Muzzle.
Now the three Actions, each joined as it lands. Create Instance comes first. Pick shooter in its Applies to and tracer in Object to Create. Set Position Relative To to Self and Self Position to Coordinate, and a Coordinate box appears. A Function can’t list anyone’s Coordinates, because it doesn’t know whose muzzle it will be handed. So type muzzle into it, the Parameter’s name. Launch Speed is tracerSpeed, and Launch Angle is direction.
Set Rotation arrives with Applies to on created, the tracer Create Instance made. Leave it there, and type direction - 90 into Degrees.
Burst Particles arrives on created too, so pick shooter in its Applies to. Pick flash in its Particles list. Position Relative To goes to Coordinate, and its Coordinate box takes muzzle as well. The Count is flashParticles, and the Z Index Offset is 2.
Now your Fighter’s guns can call it.
While Fire is held, fires a Fighter Tracer north from the Center Muzzle every fireRateSeconds.
Any Object- Action Name
fireRateReady- Cooldown Key
"fireRate"
fireRateReady.value == true- Object to Create
@self.tracer- Position Relative To
Self- Self Position
Coordinate- Coordinate
Center Muzzle- Launch Speed
@self.tracerSpeed- Launch Angle
90
- Particles
Gun Muzzle- Position Relative To
Coordinate- Coordinate
Center Muzzle- Count
@self.muzzleFlashParticles- Z Index Offset
2
- shooter
self- tracer
@self.tracer- muzzle
"Center Muzzle"- tracerSpeed
@self.tracerSpeed- flashParticles
@self.muzzleFlashParticles
- Sound
Machine Guns
- Cooldown Key
"fireRate"- Seconds
@self.fireRateSeconds
Two things change on this card. First, Create Instance and Burst Particles are struck, and Fire From Muzzle takes their place, before Control Sound. Threading a block into the middle of an If’s line takes care. Rebuilding the end of the line is quicker. So delete four blocks: Create Instance, Burst Particles, Control Sound and Start Cooldown. Right-click each, and choose Delete, until the True line under the If is empty.
Right-click the If and choose Add Inside Then. Type Fire From Muzzle into the window’s filter, pick it, and join it with Connect to Sequence. Its boxes start on the Function’s Defaults, with self as the shooter. Check each one against the card, and type the card’s values over the rest. The card leaves out direction and flash, so they keep those Defaults: north, and Gun Muzzle. Then Add Inside Then twice more, for Control Sound with Machine Guns and Start Cooldown with "fireRate" and @self.fireRateSeconds, each joined in turn.
Second, the Event gains a second Mode. On the card, its When bar is drawn twice, once above each Mode. It’s still one Event. Right-click the Mode block beside the Event, the one named Mode 1, and choose Rename Mode…. Name it Fire the Guns. Then right-click the Event’s block, choose New Mode…, and name the new one Holding Fire. It stays empty. The card marks Fire the Guns as the Starting Mode, the one the Event starts with. Nothing switches to Holding Fire yet. Return Flight will do that, near the end of this chapter, when a new plane flies in.
Run the game and hold Space. Nothing looks different. Your guns fire through Fire From Muzzle now, exactly as before.
The enemies need a muzzle of their own, and more.
X 2.48, Y 2.4830Enemy Fighter ArtX 2.48, Y 2.48Z -180EllipseX 1.453, Y 1.046Enemy StatsData TableEnemy TypesEnemy FighterGun MuzzleX 0, Y -0.94Enemy Aircraft, Enemy ThreatEnemy AircraftEnemy TracerExpressionobjectComponentProperty("self","enemyStats","firstShotSeconds")ExpressionobjectComponentProperty("self","enemyStats","shotSecondsMin")ExpressionobjectComponentProperty("self","enemyStats","shotSecondsMax")ExpressionobjectComponentProperty("self","enemyStats","speed")Open Enemy Fighter and click Coordinate in the toolbox’s Core group, as you did for the Center Muzzle. Name it Gun Muzzle. Its Y is -0.94, south of the plane’s middle, at the nose of a plane that faces south.
Yes, the flash on your own Fighter’s guns is called Gun Muzzle too, from Chapter 2. One is a point on a plane. The other is a spray of sparks. A muzzle box asks for a point, and a flash list holds sparks, so the two never mix.
Select its Tags, pick Enemy Threat in the list, and press the +. The plane wears two Tags now. The rest of its card waits for Fire When Seen and Crashes Into Fighter.
4.5.2 Fire When Seen
An enemy holds its fire until you can see it.
When it comes into view, Enter View sets the enemyFire timer to ring once, after firstShotSeconds. When it rings, the timer’s own Event runs. Fire From Muzzle sends one Enemy Tracer south, at 7.7 meters a second, slower than yours. Enemy Guns plays. Last, a random number between shotSecondsMin and shotSecondsMax sets the timer again. So each enemy fires on an uneven beat of its own. A group of them never fires in step.
Once in view, fires its tracer south from the Gun Muzzle, after firstShotSeconds and then every shotSecondsMin to shotSecondsMax seconds.
Any Object- Timer Name
"enemyFire"- Repeat Every (s)
@self.firstShotSeconds- Ring Once
Yes
- shooter
self- tracer
@self.tracer- muzzle
"Gun Muzzle"- tracerSpeed
@self.tracerSpeed- flashParticles
@self.muzzleFlashParticles- direction
-90- flash
'Enemy Gun Muzzle'
- Sound
Enemy Guns
- Action Name
nextShotSeconds- Minimum
@self.shotSecondsMin- Maximum
@self.shotSecondsMax
- Timer Name
"enemyFire"- Repeat Every (s)
nextShotSeconds.value- Ring Once
Yes
Make it as an Empty Logic Component, and add its six Shared Variables from the card, each a Constant. The first, tracer, is an Object, starting at None. Each Enemy Fighter picks its own.
In the canvas, add Enter View, then join Start Recurring Timer to it. Type "enemyFire" into its Timer Name, @self.firstShotSeconds into Repeat Every (s), and pick Yes in Ring Once. Ring Once makes the alarm ring one time. It waits to be set again.
The timer’s own Event is next, from Add Event’s Recurring Timer. Its second window can’t list a timer you made up. Choose Type a timer name… and press OK, and a small window asks for the name: type enemyFire.
Fire From Muzzle comes first under it. Its shooter is self already, so type the card’s values over the rest. This muzzle is Gun Muzzle, the point on the enemy’s nose. The direction is -90, and the flash is 'Enemy Gun Muzzle', quote marks and all: the southward sparks.
Control Sound plays Enemy Guns. Generate Random Number hands back a number between its Minimum and Maximum. Type nextShotSeconds into its Action Name. The last Start Recurring Timer reads that answer, nextShotSeconds.value.
Now attach Fire When Seen to the Enemy Fighter, where it joins the end of the Attached Logic. Its Shared Variables arrive under Variables. Press tracer’s None button and pick Enemy Tracer. The three timings come from the plane’s own row of Enemy Types, the way its speed does. So set each one’s Kind to Expression, and type the card’s line into its box. Each kind of enemy now fires on the beat in its own row.
Save, and run the game. The Enemy Fighters come into view, and a moment later the first red tracers leave their noses. They pass straight through your plane, because nothing listens for that yet.
4.6 Lost Planes
Now the tracers can hurt you.
4.6.1 Crashes Into Fighter
A threat that reaches your plane is used up in the crash. Crashes Into Fighter is one Event, Collision Enter with the Fighter: a burst of flak opens, and the threat is gone. It earns no points. Only a shoot-down does.
Destroys this Object with a flak burst when it touches the Fighter.
Any Object- Particles
Flak Burst- Count
@self.crashParticles- Z Index Offset
2
Make it as an Empty Logic Component, with the Shared Variable crashParticles. Add Collision Enter, and pick Fighter in its Collision Target list. Burst Particles takes Flak Burst and @self.crashParticles. Destroy Instance comes last.
The card names two Objects to carry it. Attach it to the Enemy Tracer. On the Enemy Fighter, it goes after Fire When Seen. Then the Enemy Fighter’s card shows Remove When Out of View struck and added again, at the end of the list. Delete it with the red trash button, and attach it once more, so your list runs in the card’s order.
4.6.2 Lost on Hit
What happens to the plane is the Fighter’s own business.
When anything tagged Enemy Threat touches it, the plane is lost, and the rest of the game needs to hear about it. So Lost on Hit sends its message first. Then comes everything you see and hear. A crack, a jolt of the camera, a warm white flash. The plane breaks up in a big burst of flame, and it’s gone.
Two names here look alike. The message is fighterLost, one word, for other Logic to listen for. The sound is Fighter Lost, from the Starter Kit.
This Event has two Modes. Lost is the one it starts with, and does all of that. Protected has no Actions at all. While Protected answers, a touch does nothing to the plane. The threat still bursts, because Crashes Into Fighter belongs to the threat, not to the plane.
When an enemy or enemy tracer touches the Fighter, the Fighter is lost: it explodes and reports fighterLost.
Any Object- Custom Event
fighterLost
- Sound
Fighter Lost
- Intensity
@self.shakeIntensity- Seconds
@self.shakeSeconds
- Color
@self.flashColor- Seconds
@self.flashSeconds
- Particles
Plane Explosion- Count
@self.explosionParticles- Z Index Offset
2
Make it as an Empty Logic Component, with five Shared Variables. The one named flashColor is a Color. Pick Color in its Type, and the Starting Value shows a white swatch with #FFFFFF in the box beside it. Type #FFF1BD there, the warm white of the flash.
Add Collision Enter, and open its Collision Target list. Your Tag is in it now, under Tags, because two Objects wear it: pick Tagged Enemy Threat. That counts for every enemy and every enemy tracer.
Six Actions go under it, in the card’s order. Camera Shake and Camera Flash take their numbers from the Shared Variables, so type each one with its @self. in front. Destroy Instance comes last, with nothing to set. It’s the quiet one. It removes the plane from the sky.
With all six joined, it’s time to name the two Modes of this Event. Rename Mode 1 to Lost, then make a New Mode… on the Event’s block, named Protected. Adding the Actions first keeps them on Lost’s line.
When all of that is in, attach Lost on Hit to the Fighter.
Run the game, and fly into a red tracer. Your plane breaks up with a crack, the camera jolts, and the sky flashes. Then nothing. No plane comes to take its place. That’s next.
4.7 Reserve Planes
Game Rules counts the planes. The count belongs to the whole mission. First, though, the game needs to know where the view is, so a new plane can start a little below it.
4.7.1 Track the View
The camera moves north all game long. Track the View rides on the camera, and at the start of every step, it writes down where the middle of the view is: $viewMiddleX and $viewMiddleY. Any Logic that needs the view reads those two. Nobody will ever see this piece. Planes and Return Flight would be lost without it, though, because neither knows where the camera has got to.
Runs on the Main Camera. Each Begin Step it writes where the view is, in Globals that Logic on other Objects reads to place planes, enemies, pickups and scenery relative to the view.
Camera- Variable
$viewMiddleX- Value
self.transform.position.x
- Variable
$viewMiddleY- Value
self.transform.position.y
Make it as an Empty Logic Component. Click the Logic Component card at the top left of its canvas, and it folds open. Its Attach to list starts on Any Object. Pick Camera, under Special Objects, and now this Logic can only go on a camera.
Add Begin Step, an Event that runs at the start of every step of the game. Two Change Variables go under it. Type $viewMiddleX into the first one’s Variable, and self.transform.position.x into its Value. Here, self is the camera. The second does the same for Y, with $viewMiddleY and self.transform.position.y.
Now put it on the camera. Open the Route Scene. In the Scene Explorer on the right, click Main Camera. Its Properties fill the left, and at the bottom is a Logic section. Pick Track the View in its list, and press the blue + beside it, Attach Logic Component. Track the View joins the camera’s Attached Logic. That’s the change the Set up card’s SCENE block meant, when it said Route is changed.
4.7.2 Planes
At the start, Planes sets $planes to startingPlanes, 3, counting the one flying. When fighterLost arrives, it first checks that the mission is still being played. A hit after the mission has ended changes nothing. Then it takes one plane away.
If any are left, it sets an alarm, launchReserve, to ring once after reserveDelaySeconds: 2 seconds to catch your breath. If none are left, the mission has failed, and Planes says so with Set Game State.
When launchReserve rings, Planes makes a new Fighter 17.5 meters below the middle of the view, out of sight under the screen. That middle is $viewMiddleX and $viewMiddleY, from Track the View. Then Planes rings a bell on that one plane alone. Trigger Custom Event on Object sends startReturnFlight to the new Fighter, and Reserve Plane Arrives plays.
Counts the planes left; after a loss, launches a reserve plane if one is left.
Any Object- Variable
$planes- Value
@self.startingPlanes
- Action Name
isPlaying- Game State
Playing
isPlaying.value == true- Variable
$planes- Operator
-=- Value
1
$planes > 0- Timer Name
"launchReserve"- Repeat Every (s)
@self.reserveDelaySeconds- Ring Once
Yes
- Game State
Mission Failed
- Object to Create
@self.fighter- X
$viewMiddleX- Y
$viewMiddleY - @self.reserveStartBelowMiddle
- Applies to
created- Custom Event
startReturnFlight
- Sound
Reserve Plane Arrives
Make it as an Empty Logic Component, with its four Shared Variables. The first, fighter, is an Object starting at None. Game Rules picks the Fighter for it.
Game Start is in the Add Event list, and it runs once, when the game begins. Under it, Change Variable sets $planes to @self.startingPlanes.
The fighterLost message is in the list too, because Lost on Hit sends it. Type its name into the filter and pick it. Check Game State asks whether the mission is in one state. Name its answer isPlaying, and leave its Game State on Playing, which the list marks Initial.
Next comes an If with another If inside it. The outer one asks isPlaying.value == true, and its True line takes Change Variable, $planes -= 1. Then Add Inside Then again, and pick If. The inner If asks $planes > 0. Its True line starts the launchReserve timer, so a new plane comes after a short wait. For the card’s Otherwise, right-click the inner If and choose Add Else. Then right-click the Else that appears beside it, choose Add Inside Else, and pick Set Game State. Its list holds your two states: pick Mission Failed.
The launchReserve timer’s Event is typed in, like enemyFire. Under it, Create Instance makes @self.fighter, with Position Relative To left on World. Its X and Y take the card’s two lines. Trigger Custom Event on Object arrives with Applies to on created, the new plane, so leave it. Type startReturnFlight into its Custom Event box, and Control Sound plays Reserve Plane Arrives.
FighterAttach Planes to Game Rules. Its fighter Value is a None button: press it and pick Fighter. The card’s other new line, Mission Failed Screen, waits for the end of this chapter, where you make it.
4.7.3 A Quiet Mode
A new plane flies itself into place. While it does, it can’t steer, fire, or be lost. Three Events must answer with nothing, each with an empty Mode. You’ve made two of them: Holding Fire on Fighter Guns, and Protected on Lost on Hit. The third belongs to Vertical Shooter Controls, on its steering Event.
Flies the Fighter: steers it at moveSpeed with the Move Command, carries it and the camera north at scrollSpeed, keeps it inside the camera view (and topSafeInset meters below its top edge), and tilts it bankAngle degrees toward the side it moves to.
Any ObjectIts Events came built, but you can give one a Mode. Open Vertical Shooter Controls. The first Event, the one that steers the Fighter, is Move 2D Axis Input on the card. Your editor calls it Self 2D Axis Input. That’s the name its Starter gave it, and its Mode is named Mode 1. Rename it Vertical Shooter Controls. That’s the name Return Flight looks for. Then make a New Mode… on the same Event, named Returning (no steering). Like Holding Fire, it stays empty.
4.7.4 Return Flight
Now the flight itself.
When startReturnFlight arrives, Return Flight switches the three Events to their empty Modes. Then Tween Property glides the plane’s Y up to the middle of the view, over returnSeconds, 1.2 seconds. The camera keeps moving north during the flight, so the target is where the middle will be when the plane arrives: $viewMiddleY, plus $scrollSpeed times returnSeconds.
Three timers start with it. The arrived timer rings once, when the flight is over, and gives back the steering and the guns. The protectionOver timer rings once, 2 seconds after that. Lost on Hit goes back to Lost, the blinking stops, and the plane is fully seen. The blink timer rings every 0.1 seconds the whole time, and each ring flips the plane between dim and bright.
How does it know which way to flip? It keeps one field of its own, isDimmed, which is true or false, dim or bright. Each blink asks it, flips the picture, and flips the field.
Object Data of Logic "Return Flight" (its state that lasts between Events).
Flies a reserve plane up from below the screen to the middle, protected and blinking, then gives back its controls and guns.
Any Objectself.returnFlightData- Event
Move 2D Axis Input · Fighter- Mode
Returning (no steering)
- Event
While Fire Is Held · Fighter- Mode
Holding Fire
- Event
When Starting to Hit Anything Tagged Enemy Threat · Fighter- Mode
Protected
- Property
Y- Target Value
$viewMiddleY + $scrollSpeed * @self.returnSeconds- Seconds
@self.returnSeconds- Ease
Smooth
- Timer Name
"arrived"- Repeat Every (s)
@self.returnSeconds- Ring Once
Yes
- Timer Name
"protectionOver"- Repeat Every (s)
@self.returnSeconds + @self.protectionSeconds- Ring Once
Yes
- Timer Name
"blink"- Repeat Every (s)
@self.blinkSeconds
- Event
Move 2D Axis Input · Fighter- Mode
Vertical Shooter Controls
- Event
While Fire Is Held · Fighter- Mode
Fire the Guns
- Event
When Starting to Hit Anything Tagged Enemy Threat · Fighter- Mode
Lost
- Timer Name
"blink"
- Component Value
self.returnFlightData.isDimmed- Value
false
self.returnFlightData.isDimmed == true- Component Value
self.returnFlightData.isDimmed- Value
false
- Component Value
self.returnFlightData.isDimmed- Value
true
- Alpha
@self.dimAlpha
Make it as an Empty Logic Component, with its four Shared Variables. Its DATA STRUCTURES line is new. It’s a Data Structure of the Logic’s own, where Return Flight keeps isDimmed between one blink and the next. Press the + on the Data Structures card and choose New Data Structure. Myth names it after the Logic, Return Flight Data, and opens it. Add one field, isDimmed, a Boolean. It reads No. The sentence under its name on the card is its Description, if you’d like to type it in.
In the canvas, add startReturnFlight from the list, since Planes sends it.
Switch Mode switches an Event to another of its Modes. Its Event list names every Event in your project, each beside its Object, so pick the Fighter’s. The first is the steering Event, Self 2D Axis Input · Fighter in your list. Pick Returning (no steering) in the Mode list after it. The second is While Fire Is Held · Fighter, with Holding Fire, and the third is When Starting to Hit Anything Tagged Enemy Threat · Fighter, with Protected.
Tween Property’s Property list starts on Alpha. Pick Y. Its Ease is Smooth: the flight starts gently and lands gently. The three Timer Names take their quote marks, as on the card. Ring Once is Yes for the first two. The blink timer keeps Ring Once on No, so it rings again and again.
The other three Events are the timers, each typed in: arrived, protectionOver and blink. Their Switch Modes switch back. Steering and guns go back to Vertical Shooter Controls and Fire the Guns, and the touch goes back to Lost. Stop Recurring Timer ends blink. Type "blink" into its Timer Name. Change Component Value sets self.returnFlightData.isDimmed to false, and Set Alpha with nothing to set means 1, fully seen.
The blink Event’s If asks self.returnFlightData.isDimmed == true. Its True line sets isDimmed to false and the Alpha to 1. Its Otherwise, from Add Else, sets isDimmed to true and the Alpha to @self.dimAlpha, a quarter seen. Add Inside Then and Add Inside Else put each step on its line.
X 2.88, Y 2.8840Fighter ArtX 2.88, Y 2.88CapsuleX 0, Y -0.09X 0.698, Y 1.733Center MuzzleX 0, Y 1.193Return FlightReturn Flight Data7.8Expression$scrollSpeed2.25Fighter TracerAttach Return Flight to the Fighter. Two lines arrive with it. Return Flight Data joins the Fighter’s components, from the Logic, so there’s nothing to do there. And one line changes: Vertical Shooter Controls’ scrollSpeed. Under Variables, set its Kind to Expression, and type $scrollSpeed into its box. The camera’s speed is kept in one place now, where Return Flight reads it too.
Run the game and fly into a tracer. Two seconds after the crash, the next plane rises from below the screen, blinking, and settles in the middle of the view. Your keys and guns come back as it arrives. For 2 seconds more it blinks, and anything enemy that touches it bursts without costing a plane. Lose all three, and nothing more comes. The mission has failed, though nothing says so yet.
4.8 The Planes Left
The planes in reserve show under the score, one small cream plane each.
There’s one Object, Reserve Plane Icon, placed five times, and each placement has its own slot, 1 to 5. An icon shows while $planes is greater than its slot. The plane you’re flying counts in $planes, but it isn’t in reserve. So with 3 planes, icons 1 and 2 show.
Window / UIUIX 32, Y 32Reserve Plane Icon ArtX 22, Y 22Make it a Screen UI Object, and give it a Sprite, the Reserve Plane Icon Art, 22 pixels square. It has no UI Interaction on its card, so remove that, as you did for Score Text.
4.8.1 Match Icon to Planes
An icon asks one question: is $planes greater than my slot? Yes, and it shows. No, and it hides. Set Alpha with nothing to set shows it, and Set Alpha 0 makes it vanish.
Shows the icon while more than slot planes are left, and hides it otherwise (the plane flying is not in reserve).
$planes > slot- Applies to
icon
- Applies to
icon- Alpha
0
Make it with Add > Function. Its Object Parameter is the icon it works on, named icon, so pick icon in each Set Alpha’s Applies to. The If asks $planes > slot, and Add Else makes the Otherwise.
4.8.2 Show While in Reserve
That question gets asked in two moments: when the icon is created, as the game starts, and whenever $planes changes. Show While in Reserve asks it in both.
Shows this icon only while the reserve plane it stands for is left.
Any Object- icon
self- slot
self.slot
- icon
self- slot
self.slot
The slot is a Per Instance Variable, a number each placed icon keeps for itself. Press the + on the Per Instance Variables card, and name it slot, a Number starting at 1. Its Events are Create and Variable Changed. The second window of Variable Changed lists your Globals, so pick planes. Each Event calls Match Icon to Planes, with icon on self and slot typed as self.slot. Attach it to Reserve Plane Icon.
Now place the five, from PLACE THESE. Each goes on the screen like Score Text, with its Screen Offset (px) and its Z-Index. The first keeps the slot it starts with, 1, so its card has no slot line. The others each have a with Per Instance Variables > Slot line. Near the bottom of the placement’s Properties, under Logic, Show While in Reserve has a Slot box. Type the card’s number into it.
Run the game. Two small cream planes sit near the top left, under the score. Lose a plane, and one of them goes.
4.9 Mission Failed
Last comes a mission that goes wrong.
The MISSION FAILED screen is three Objects: the title, the final score and the PLAY AGAIN panel. All three sit at the middle of the screen, and they share a menu group, missionFailed, so they show and hide together.
Window / UICenterUIX 32, Y 32MISSION FAILED38Bold#FF9B73CenterWrap to Width560TextmissionFailedmenuChoiceWindow / UICenterUIX 32, Y 32FINAL SCORE {$score}22Bold#FFCA75CenterTextmissionFailedmenuChoiceWindow / UICenterUIX 268, Y 60-1Mission Failed PanelX 268, Y 60PLAY AGAIN20Bold#FFCA75CentermissionFailedEach is a Screen UI Object with Text / UI, made the way you made Score Text. One line is new: Screen Anchor Center. In the Transform’s Presentation section, Screen Anchor is a grid of nine squares. Click the middle one, Center.
UI Interaction stays this time, because the cards list it. Its Group is missionFailed. The menu keeps Button, the Element Type it starts with.
The title and the score are Text elements, and each has the Event menuChoice on its card. Why would words that nobody can press send a message? They don’t. Only a button is ever pressed, so a Text element’s Event never goes anywhere. The game keeps the name, so the cards do too. The button has no Event yet. Chapter 5 gives it one, with Logic that listens for it.
The panel’s picture sits behind its words. That’s the card’s Z Index Within Object, -1: type it into Z Index (Within Object), below Scene Depth (Draw Order). And FINAL SCORE has two spaces before {$score}, as on its card.
Place the three from PLACE THESE, on the screen and hidden, each with its Z-Index.
4.9.1 Mission Failed Screen
When the Game State changes to Mission Failed, Game Rules waits 3 seconds, so the last explosion can play out. Then it shows the menu and pauses the world behind it.
Game State Changed runs after every change of state, and it can’t be told which one to wait for. So an If asks whether event.current is "mission-failed". That’s the state’s own name, the one Myth made from Mission Failed, in lower case with a hyphen.
Shows MISSION FAILED, with the final score, a moment after the mission fails, and pauses the world.
Any Objectevent.current == "mission-failed"- Timer Name
"showScreen"- Repeat Every (s)
@self.screenDelaySeconds- Ring Once
Yes
- Menu Element
Mission Failed Menu
- Menu Element
Mission Failed Menu
Make it as an Empty Logic Component. Its one Shared Variable is screenDelaySeconds. The If’s True line starts the showScreen timer, to ring once after @self.screenDelaySeconds. That timer’s Event is typed in, like enemyFire. The screen comes under it. Control Menu shows a menu: pick Mission Failed Menu in its Menu Element slot. Set Menu Pause State pauses the world behind the same menu, so pick Mission Failed Menu there too. Attach it to Game Rules.
4.9.2 Score
Once the mission has failed, the score is final. A tracer still in the air shouldn’t add to it.
Adds the points of every enemy shot down to $score.
Any Object- Variable
$score- Operator
+=- Value
other.enemyStats.points
event.current == "mission-failed"- Logic Component
Score- State
Disable
Score gets a Game State Changed of its own, with the same If. On the If’s True line, Set Logic State turns a whole Logic Component on or off: pick Score in its Logic Component slot, and pick Disable.
Run the game one last time. Lose all three planes, and three seconds after the last explosion, MISSION FAILED appears over the frozen sky.
Your Fighter can be lost now, and the mission can end.
Watch for each of these, one at a time.
- A moment after an Enemy Fighter comes into view, a red tracer leaves its nose, heading south, with a small flash and the sound of Enemy Guns.
- Each enemy fires on its own uneven beat. No two fire in step for long.
- Two small cream planes sit near the top left: your reserves.
- Fly into a red tracer. Your plane breaks up, the camera shakes, and the screen flashes. The tracer bursts into flak, and one cream plane goes.
- Two seconds later, the next plane rises from below the screen and stops in the middle, blinking. Your keys work again when it stops.
- While it blinks, fly into a red tracer on purpose: it bursts, and the plane flies on.
- Lose your last plane, and three seconds later the world stops under MISSION FAILED, FINAL SCORE and PLAY AGAIN.
Enemies that fire on their own uneven beat. A threat that bursts. A plane that breaks up and reports its own loss to anyone listening. A count of planes. A new plane that flies itself in, blinking, safe until it stops. A screen for a mission that goes wrong.
Most of this chapter is the same few pieces seen from different sides. A message, fighterLost, lets the Fighter say what happened without knowing who listens. Timers ring by themselves. Nothing has to check the clock at every step. And Modes let one Event answer in different ways, so a plane flying in is never told “don’t” in a dozen places. Its Events are switched to answers that do nothing, and switched back when the flight is over.
4.10 If It Didn’t Work
A chapter this long has many places for a small slip, and finding one is part of the work. Run the game and watch what happens.
Press Play, and a window called Can’t run yet opens instead? Its message names the piece with the slip, and what’s wrong with it. Fix it and press Play again.
The enemies never fire? Look for Fire When Seen on the Enemy Fighter, with Enemy Tracer as its tracer and its three timings as Expressions. Then look for a Coordinate named Gun Muzzle on the Enemy Fighter, spelled exactly so.
Their tracers fly north, or sideways? Fire When Seen’s Fire From Muzzle needs -90 in its direction box, where the Function’s Default is 90.
A red tracer passes through you, and nothing happens? Perhaps the Enemy Tracer isn’t wearing its Tag. Select its Tags component and look for Enemy Threat in its Object Tags. Then look for Lost on Hit on the Fighter, with Tagged Enemy Threat on its Event’s block.
The plane breaks up, but no new one comes? Look in Planes for the launchReserve timer, typed the same in both places, and for startReturnFlight typed the same in Planes and Return Flight.
The new plane never comes into view? Perhaps Track the View isn’t on the camera. Select Main Camera in the Route Scene, and look under Logic. Then look at Return Flight’s Tween Property, where the Property should be Y, not Alpha.
The new plane comes, but it steers or fires while it flies in, or it’s lost at once? Look at Return Flight’s three Switch Mode steps, and the Mode each one picks.
Five cream planes sit under the score instead of two? Each placement needs its own slot, 1 to 5, in its Slot box. Left alone, every Slot box reads 1.
Each of these is one small 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.
The numbers of danger are yours to tune. Give the Enemy Fighter’s row a shorter wait between shots, and the sky fills with red. Give Planes a startingPlanes of 5, and watch four cream planes line up. Make protectionSeconds longer, and a new plane has more time to find its feet before anything can hurt it. Then put everything back the way the cards have it before Chapter 5.
Still stuck? Search the manual, or ask in the Myth Engine Discord (opens a new tab).
The enemies shoot back, and a mission can be lost. In Chapter 5, it gets a front door: a title screen, a pause, and a PLAY AGAIN that works.
