Build a GameCreating Pacific Wings

4  Enemy Fire and Lost Planes

Goal

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.

Pacific Wings, Chapter 4 finishedMyth project · 1.4 MB

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.

Set upWhat this chapter adds
ART (sprites, from the starter kit)
Enemy Tracer Art
Reserve Plane Icon Art
Mission Failed Panel
SOUNDS (from the starter kit)
Enemy Guns
Fighter Lost
Reserve Plane Arrives
GLOBAL VARIABLES
$planesNumberstarts at 3
$scrollSpeedNumberstarts at 2.25
$viewMiddleXNumberstarts at 0
$viewMiddleYNumberstarts at 0
GAME SETTINGS > General > Game State
Available Game StatesPlaying, Mission Failed
SCENERoute (changed)
Camera Main CameraX 10, Y 7.5, view 20 x 15 m
View Main View640 x 480 pixels, Left 0, Bottom 288, camera Main Camera
BackgroundOcean
SCENE Route: PLACE THESE
ObjectXY
Reserve Plane Icon27-48
with Z-Index = 10002
Reserve Plane Icon52-48
with Z-Index = 10002
with Per Instance Variables > Slot = 2
Reserve Plane Icon77-48
with Z-Index = 10002
with Per Instance Variables > Slot = 3
Reserve Plane Icon102-48
with Z-Index = 10002
with Per Instance Variables > Slot = 4
Reserve Plane Icon127-48
with Z-Index = 10002
with Per Instance Variables > Slot = 5
Mission Failed Title080hidden
with Z-Index = 10002
Mission Failed Score024hidden
with Z-Index = 10002
Mission Failed Menu0-40hidden
with Z-Index = 10002

GLOBAL 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.

Data StructureEnemy StatsAddDelete

What every enemy carries. Each enemy kind takes its values from its own row of Enemy Types.

speedNumberdefault 0
healthNumberdefault 1
pointsNumberdefault 0
firstShotSecondsNumberdefault 1
shotSecondsMinNumberdefault 1
shotSecondsMaxNumberdefault 2

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.

Data TableEnemy TypesData Structure: Enemy StatsAddDelete
Row 0Enemy Fighter
speed3.7
health1
points100
firstShotSeconds1.15
shotSecondsMin1.4
shotSecondsMax2.5

Open 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.

ObjectEnemy Tracer
Transform
Bounding Box > SizeX 0.68, Y 0.68
Sprite
Scene Depth Draw Order50
SpriteEnemy Tracer Art
Transform > SizeX 0.68, Y 0.68
Transform > Rotation (deg)Z -180
Collider
CollisionSensor
Shape and Transform > ShapeCapsule
Shape and Transform > SizeX 0.154, Y 0.499
Tags
Object TagsEnemy Threat
Logic
Crashes Into Fighter
Remove When Out of View

Make 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.

Particle EffectEnemy Gun Muzzle
Emitter
Emission > Burst Count8
Emitter Shape > Emit Shapepoint
Motion
Lifecycle > Each Particle Lives (ms)min 70, max 170
Motion > Speed (m/s)min 0.938, max 3.594
Motion > Angle (Deg)min -110, max -70
Appearance
Appearance > Color SourceMultiple Colors
Appearance > Multiple Colors#FFF8D2, #FFD166, #FF9F43
Appearance > Glow1.2
Appearance Over Life > Scalestart 0.58, end 0
Appearance Over Life > Size Variation (0–1)0.35
Appearance Over Life > Starting RotationRandom Spin On

Make 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.

FunctionFire From Muzzle

The shooter creates one tracer at its muzzle Coordinate, flying in direction at tracerSpeed and turned to face that way, with a muzzle flash.

PARAMETERS
NameTypeStarts at
shooterObject
tracerObject
muzzleTextCenter Muzzle
tracerSpeedNumber17.5
flashParticlesNumber5
directionNumber90
flashThing ParticleGun Muzzle
ACTIONS
1Create Instance
Applies to
shooter
Object to Create
tracer
Position Relative To
Self
Self Position
Coordinate
Coordinate
muzzle
Launch Speed
tracerSpeed
Launch Angle
direction
2Set Rotation
Applies to
created
Degrees
direction - 90
3Burst Particles
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.

Logic ComponentFighter GunsAttach to: FighterAddDelete

While Fire is held, fires a Fighter Tracer north from the Center Muzzle every fireRateSeconds.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
tracerObjectConstantNone
fireRateSecondsNumberConstant0.14
tracerSpeedNumberConstant17.5
muzzleFlashParticlesNumberConstant5
While Fire Is Held
WhenCommand HeldCommand: Fire
ModeFire the Guns (Starting Mode)
1Check Cooldown Ready
Action Name
fireRateReady
Cooldown Key
"fireRate"
2IffireRateReady.value == true
Then
3Create Instance
Object to Create
@self.tracer
Position Relative To
Self
Self Position
Coordinate
Coordinate
Center Muzzle
Launch Speed
@self.tracerSpeed
Launch Angle
90
4Burst Particles
Particles
Gun Muzzle
Position Relative To
Coordinate
Coordinate
Center Muzzle
Count
@self.muzzleFlashParticles
Z Index Offset
2
3Fire From MuzzleFunction
shooter
self
tracer
@self.tracer
muzzle
"Center Muzzle"
tracerSpeed
@self.tracerSpeed
flashParticles
@self.muzzleFlashParticles
4Control Sound
Sound
Machine Guns
5Start Cooldown
Cooldown Key
"fireRate"
Seconds
@self.fireRateSeconds
While Fire Is Held
WhenCommand HeldCommand: Fire
ModeHolding Fire
(no Actions)

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.

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
Data Structure
Data StructureEnemy Stats
Input SourceData Table
Data TableEnemy Types
RowEnemy Fighter
Coordinate
NameGun Muzzle
Local PositionX 0, Y -0.94
Tags
Object TagsEnemy Aircraft, Enemy Threat
Object TagsEnemy Aircraft
Logic
Fly South When Seen
Remove When Out of View
Takes Hits
Shot Down
Fire When Seen
Crashes Into Fighter
Remove When Out of View
Shared Variables
tracerEnemy Tracer
firstShotSeconds > KindExpression
firstShotSeconds > ExpressionobjectComponentProperty("self","enemyStats","firstShotSeconds")
shotSecondsMin > KindExpression
shotSecondsMin > ExpressionobjectComponentProperty("self","enemyStats","shotSecondsMin")
shotSecondsMax > KindExpression
shotSecondsMax > ExpressionobjectComponentProperty("self","enemyStats","shotSecondsMax")
speed > KindExpression
speed > 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.

Logic ComponentFire When SeenAttach to: Enemy Fighter

Once in view, fires its tracer south from the Gun Muzzle, after firstShotSeconds and then every shotSecondsMin to shotSecondsMax seconds.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
tracerObjectConstantNone
tracerSpeedNumberConstant7.7
firstShotSecondsNumberConstant1.15
shotSecondsMinNumberConstant1.4
shotSecondsMaxNumberConstant2.5
muzzleFlashParticlesNumberConstant5
When Entering the View
WhenEnter View
1Start Recurring Timer
Timer Name
"enemyFire"
Repeat Every (s)
@self.firstShotSeconds
Ring Once
Yes
On the Enemy Fire Timer
WhenRecurring TimerTimer name: enemyFire
1Fire From MuzzleFunction
shooter
self
tracer
@self.tracer
muzzle
"Gun Muzzle"
tracerSpeed
@self.tracerSpeed
flashParticles
@self.muzzleFlashParticles
direction
-90
flash
'Enemy Gun Muzzle'
2Control Sound
Sound
Enemy Guns
3Generate Random Number
Action Name
nextShotSeconds
Minimum
@self.shotSecondsMin
Maximum
@self.shotSecondsMax
4Start Recurring Timer
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.

Logic ComponentCrashes Into FighterAttach to: Enemy Fighter, Enemy Tracer

Destroys this Object with a flak burst when it touches the Fighter.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
crashParticlesNumberConstant30
When Starting to Hit Fighter
WhenCollision EnterObject: Fighter
1Burst Particles
Particles
Flak Burst
Count
@self.crashParticles
Z Index Offset
2
2Destroy Instance

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.

Logic ComponentLost on HitAttach to: Fighter

When an enemy or enemy tracer touches the Fighter, the Fighter is lost: it explodes and reports fighterLost.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
explosionParticlesNumberConstant88
shakeIntensityNumberConstant0.032
shakeSecondsNumberConstant0.48
flashColorColorConstant#fff1bd
flashSecondsNumberConstant0.16
When Starting to Hit Anything Tagged Enemy Threat
WhenCollision EnterObject: tag:Enemy Threat
ModeLost (Starting Mode)
1Trigger Custom Event
Custom Event
fighterLost
2Control Sound
Sound
Fighter Lost
3Camera Shake
Intensity
@self.shakeIntensity
Seconds
@self.shakeSeconds
4Camera Flash
Color
@self.flashColor
Seconds
@self.flashSeconds
5Burst Particles
Particles
Plane Explosion
Count
@self.explosionParticles
Z Index Offset
2
6Destroy Instance
When Starting to Hit Anything Tagged Enemy Threat
WhenCollision EnterObject: tag:Enemy Threat
ModeProtected
(no Actions)

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.

Logic ComponentTrack the View

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.

Attach toCamera
On Begin Step
WhenBegin Step
1Change Variable
Variable
$viewMiddleX
Value
self.transform.position.x
2Change Variable
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.

Logic ComponentPlanesAttach to: Game Rules

Counts the planes left; after a loss, launches a reserve plane if one is left.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
fighterObjectConstantNone
startingPlanesNumberConstant3
reserveDelaySecondsNumberConstant2
reserveStartBelowMiddleNumberConstant17.5
When the Game Starts
WhenGame Start
1Change Variable
Variable
$planes
Value
@self.startingPlanes
On Fighter Lost
WhenfighterLostCustom Event
1Check Game State
Action Name
isPlaying
Game State
Playing
2IfisPlaying.value == true
Then
3Change Variable
Variable
$planes
Operator
-=
Value
1
4If$planes > 0
Then
5Start Recurring Timer
Timer Name
"launchReserve"
Repeat Every (s)
@self.reserveDelaySeconds
Ring Once
Yes
6Otherwise
7Set Game State
Game State
Mission Failed
On the Launch Reserve Timer
WhenRecurring TimerTimer name: launchReserve
1Create Instance
Object to Create
@self.fighter
X
$viewMiddleX
Y
$viewMiddleY - @self.reserveStartBelowMiddle
2Trigger Custom Event on Object
Applies to
created
Custom Event
startReturnFlight
3Control Sound
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.

ObjectGame RulesAddDelete
Collider(as it is added)
Logic
Score
Planes
Mission Failed Screen
Shared Variables
fighterFighter

Attach 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.

Logic ComponentVertical Shooter ControlsAttach to: Fighter

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.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
moveSpeedNumberConstant6.875
scrollSpeedNumberConstant2.813
bankAngleNumberConstant7
topSafeInsetNumberConstant0
Built in: this Logic Component comes whole from the engine's template.
You add it and set its Variables on the Object; you do not build its Events.
Move 2D Axis Input
When2D Axis InputCommand: Move
ModeReturning (no steering)
(no Actions)

Its 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.

Data StructureReturn Flight Data

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

isDimmedBooleandefault false
Logic ComponentReturn FlightAttach to: Fighter

Flies a reserve plane up from below the screen to the middle, protected and blinking, then gives back its controls and guns.

Attach toAny Object
DATA STRUCTURES
Return Flight Dataself.returnFlightData
SHARED VARIABLES
NameTypeKindStarting Value
returnSecondsNumberConstant1.2
protectionSecondsNumberConstant2
blinkSecondsNumberConstant0.1
dimAlphaNumberConstant0.25
On Start Return Flight
WhenstartReturnFlightCustom Event
1Switch Mode
Event
Move 2D Axis Input · Fighter
Mode
Returning (no steering)
2Switch Mode
Event
While Fire Is Held · Fighter
Mode
Holding Fire
3Switch Mode
Event
When Starting to Hit Anything Tagged Enemy Threat · Fighter
Mode
Protected
4Tween Property
Property
Y
Target Value
$viewMiddleY + $scrollSpeed * @self.returnSeconds
Seconds
@self.returnSeconds
Ease
Smooth
5Start Recurring Timer
Timer Name
"arrived"
Repeat Every (s)
@self.returnSeconds
Ring Once
Yes
6Start Recurring Timer
Timer Name
"protectionOver"
Repeat Every (s)
@self.returnSeconds + @self.protectionSeconds
Ring Once
Yes
7Start Recurring Timer
Timer Name
"blink"
Repeat Every (s)
@self.blinkSeconds
On the Arrived Timer
WhenRecurring TimerTimer name: arrived
1Switch Mode
Event
Move 2D Axis Input · Fighter
Mode
Vertical Shooter Controls
2Switch Mode
Event
While Fire Is Held · Fighter
Mode
Fire the Guns
On the Protection Over Timer
WhenRecurring TimerTimer name: protectionOver
1Switch Mode
Event
When Starting to Hit Anything Tagged Enemy Threat · Fighter
Mode
Lost
2Stop Recurring Timer
Timer Name
"blink"
3Change Component Value
Component Value
self.returnFlightData.isDimmed
Value
false
4Set Alpha
On the Blink Timer
WhenRecurring TimerTimer name: blink
1Ifself.returnFlightData.isDimmed == true
Then
2Change Component Value
Component Value
self.returnFlightData.isDimmed
Value
false
3Set Alpha
4Otherwise
5Change Component Value
Component Value
self.returnFlightData.isDimmed
Value
true
6Set Alpha
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.

ObjectFighterAddDelete
Transform
Bounding Box > SizeX 2.88, Y 2.88
Sprite
Scene Depth Draw Order40
SpriteFighter Art
Transform > SizeX 2.88, Y 2.88
Collider
Shape and Transform > ShapeCapsule
Shape and Transform > PositionX 0, Y -0.09
Shape and Transform > SizeX 0.698, Y 1.733
Coordinate
NameCenter Muzzle
Local PositionX 0, Y 1.193
Data Structure
From LogicReturn Flight
Data StructureReturn Flight Data
Logic
Vertical Shooter Controls
Fighter Guns
Lost on Hit
Return Flight
Shared Variables
moveSpeed7.8
scrollSpeed > KindExpression
scrollSpeed > Expression$scrollSpeed
scrollSpeed2.25
tracerFighter Tracer

Attach 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.

ObjectReserve Plane Icon
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
Sprite
SpriteReserve Plane Icon Art
Transform > SizeX 22, Y 22
Logic
Show While in Reserve

Make 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.

FunctionMatch Icon to Planes

Shows the icon while more than slot planes are left, and hides it otherwise (the plane flying is not in reserve).

PARAMETERS
NameTypeStarts at
iconObject
slotNumber1
ACTIONS
1If$planes > slot
Then
2Set Alpha
Applies to
icon
3Otherwise
4Set Alpha
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.

Logic ComponentShow While in ReserveAttach to: Reserve Plane Icon

Shows this icon only while the reserve plane it stands for is left.

Attach toAny Object
PER INSTANCE VARIABLES
NameTypeStarting Value
slotNumber1
When Created
WhenCreate
1Match Icon to PlanesFunction
icon
self
slot
self.slot
On Variable Changed · Planes
WhenVariable ChangedGlobal Variable: planes
1Match Icon to PlanesFunction
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.

ObjectMission Failed Title
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
Text / UI
TextMISSION FAILED
Font Size38
EmphasisBold
Color#FF9B73
AlignmentCenter
Text BoundsWrap to Width
Transform > Size X560
UI Interaction
Element TypeText
GroupmissionFailed
EventmenuChoice
ObjectMission Failed Score
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
Text / UI
TextFINAL SCORE {$score}
Font Size22
EmphasisBold
Color#FFCA75
AlignmentCenter
UI Interaction
Element TypeText
GroupmissionFailed
EventmenuChoice
ObjectMission Failed Menu
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 268, Y 60
Sprite
Z Index Within Object-1
SpriteMission Failed Panel
Transform > SizeX 268, Y 60
Text / UI
TextPLAY AGAIN
Font Size20
EmphasisBold
Color#FFCA75
AlignmentCenter
UI Interaction
GroupmissionFailed

Each 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.

Logic ComponentMission Failed ScreenAttach to: Game Rules

Shows MISSION FAILED, with the final score, a moment after the mission fails, and pauses the world.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
screenDelaySecondsNumberConstant3
On Game State Changed
WhenGame State Changed
1Ifevent.current == "mission-failed"
Then
2Start Recurring Timer
Timer Name
"showScreen"
Repeat Every (s)
@self.screenDelaySeconds
Ring Once
Yes
On the Show Screen Timer
WhenRecurring TimerTimer name: showScreen
1Control Menu
Menu Element
Mission Failed Menu
2Set Menu Pause State
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.

Logic ComponentScoreAttach to: Game RulesAddDelete

Adds the points of every enemy shot down to $score.

Attach toAny Object
On Enemy Shot Down
WhenenemyShotDownCustom Event
1Change Variable
Variable
$score
Operator
+=
Value
other.enemyStats.points
On Game State Changed
WhenGame State Changed
1Ifevent.current == "mission-failed"
Then
2Set Logic State
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.

Play it!

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.
How it works

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.

Challenge

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.