Build a GameCreating Shatterfield

9  Screens

Goal

Until now, your game started the moment you ran it, and it never really ended. By the end of this chapter, it opens on a title over drifting rocks, with PRESS ENTER TO START blinking. Enter starts a game, Esc holds it under PAUSED, and the last Ship lost brings GAME OVER with your final score. Then the title comes back, and your high score is kept for next time.

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

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

Shatterfield, Chapter 9 finishedZip of a Myth project · 5.0 MB

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

9.1 The Idea

Six Large rocks drift across a dark screen. Over them, in tall white letters that nearly span the screen from side to side, it says SHATTERFIELD. Under that, in cyan, CLEAR THE FIELD. SURVIVE THE SAUCERS. Music plays. Lower down, PRESS ENTER TO START blinks in gold, on and off, on and off.

Press Enter. The rocks are gone at once, without a spark. A short sound plays, your Ship appears in the middle, and WAVE 1 comes up.

That’s the front door. The game has a way home too. In Chapter 5, after your last crash, the rocks drifted on alone and nothing said it was over. Now GAME OVER comes up in pink-red, with your final score under it. A little later the game offers you another try, and if you don’t take it, the title comes back.

All of this rests on a new idea. The game is always in exactly one Game State, like a traffic light that’s always one color. This game has four: Title, Playing, Game Over and Play Again. Logic can change the Game State, and whenever it changes, every piece of Logic listening hears it, the way every driver at the crossing sees the light change.

The second idea follows from the first. Some Logic only makes sense during play: the waves, the lives, the saucers. So that Logic gets switched off when no game is being played, and switched on when one starts. Switched-off Logic hears nothing at all. One new Logic Component, Play Switch, does the switching.

This is the longest chapter in the book, though most of its pieces are ones your hands know: words on the screen, messages, timers, Ifs. Take it a part at a time, and run the game at the end of each.

9.2 The Plan

Here’s how the pieces work together, read from left to right. Most of the names are new, and the parts below make them one at a time. Come back to this list whenever you lose your place.

  • The game opens on the Title Game State -> Title Screen sends itself showTitle -> space is cleared, six Title Asteroids drift in, the title shows, the prompt blinks, the music plays.
  • Enter is pressed on the title -> Start Game clears space and sets the Game State to Playing.
  • The Game State changes to Playing -> Play Switch switches on Lives and Respawn, Waves, Extra Ships, Saucer Spawner and Pause -> each one starts its part of a new game.
  • Esc is pressed -> Pause tells the whole game gamePaused and sends showPausedMenu -> Menu Pause Lifecycle shows PAUSED and holds the game.
  • Esc or Enter on PAUSED -> the menu sends gameResumed -> Pause sends hideMenu, and the game goes on.
  • The last Ship is lost -> Lives and Respawn sets the Game State to Game Over -> Play Switch switches them all off and sends playStopped.
  • The Game State changes to Game Over -> Game Over Screen shows GAME OVER and the final score, and Score saves the high score.
  • Two seconds later -> Play Again. Twelve seconds after that -> Title again.

9.3 Set Up

This chapter adds two sounds, two Commands, a second Input Context and the Game States. Space Theme is the title’s music. The sound called Start is the short one a game begins with. One of the Commands is named Start too, so this chapter always says which one it means.

The Commands go into the Input Manager as before, with one new step. The card lists them first, with Start on top. Build them in the order below instead. The Start Command goes into an Input Context you haven’t made yet.

The Input Manager’s Input Contexts list already holds one, Default, with its switch on Active at Start. A new Command goes into the context selected in that list, and Default is selected when you open it. So add the Pause Command there.

The Pause Command takes two keys, Escape and P, and Escape needs a small trick. On a key row, a single Escape cancels the recording. So click the row and press Escape twice, quickly, and it reads Escape. Add Keybinding gives a second row, for P.

Next, press Add Input Context, and type Menus into the window that asks for its name. The new context arrives selected, and its switch reads Inactive at Start. Click it. Now it reads Active at Start, like Default’s. Each row has a second switch, Works While Paused. Switched on, it lets that context’s Commands reach your Logic while the game is held. Leave it off on both. PAUSED doesn’t need it. While it’s up, the menu listens for its own two Commands, the ones you’ll pick in its fields later in this chapter. Then add the Start Command here, in Menus, with Enter and Space.

Why a second Input Context? A key can feed only one Command in each Input Context, and Space is already Fire. In Menus, Space can be Start too.

On the card, (changed) beside Default means its list of Commands changed, now that Pause is in it. Its switch stays as it was. (new) beside Menus is the context you made.

The Game States are in Game Settings, on the General page, in its Game State section. Available Game States starts with one, Playing, marked Initial. Press Add Game State, type Title into its window, and press the window’s own Add Game State button. Do the same for Game Over and Play Again. Your list keeps Playing first, and that’s fine, since the order is only how the list reads. Last, pick Title in Initial Game State, and the Initial mark moves to it.

Leave the card’s three SCENE blocks for now. Each word goes into Space as soon as you’ve made it. The Ship’s placement comes out once something else can bring the Ship.

Set upWhat this chapter adds
SOUNDS (from the starter kit)
Space Theme
Start
COMMANDS (Game Settings > Input Manager)
StartButton
KeybindingsEnter, Space
PauseButton
KeybindingsEscape, P
INPUT CONTEXTS (Game Settings > Input Manager)
DefaultActive at Start(changed)
CommandsRotate-and-thrust Controls, Fire, Hyperspace, Pause
MenusActive at Start(new)
CommandsStart
GAME SETTINGS > General > Game State
Available Game StatesTitle, Playing, Game Over, Play Again
Initial Game StateTitle
SCENE Space: PLACE THESE
ObjectXY
Title0150
Title Tagline082
Title Prompt0-40hidden
Title High Score0-100
Title Controls046
Game Over064hidden
Final Score0-8hidden
Play Again Prompt0-66hidden
Paused024hidden
Paused Help0-40hidden
SCENE Space: CHANGE THESE PLACEMENTS
Score Displaymake it hidden
High Score Displaymake it hidden
Wave Displaymake it hidden
SCENE Space: REMOVE THESE PLACEMENTS
Ship1612

Run the game now, and nothing looks different. It opens on Title, but nothing listens for that yet.

9.4 A Field That Can Be Emptied

First, space learns to empty itself.

9.4.1 Leave When Cleared

When a game starts, or the title comes back, whatever is out there has to go: rocks, saucers, shots of every kind. But not by breaking. A broken rock leaves smaller rocks, sparks and points. Here, things need to leave and take nothing with them.

So there’s a new message, clearField. Leave When Cleared listens for it, and its one Action is Destroy Instance. No sparks, no points, nothing left behind.

Logic ComponentLeave When ClearedAttach to: Shot, Asteroid Large, Asteroid Medium, Asteroid Small, Saucer Orb, Saucer Lance, Saucer Large, Saucer Small, Title Asteroid

This Object leaves when space is cleared for a new game or the title screen.

Attach toAny Object
On Clear Field
WhenclearFieldCustom Event
1Destroy Instance

Make it with Add > Logic Component, as an Empty Logic Component. Its message, clearField, is new, so make its Event with Add Custom Event…, the way you made hit in Chapter 4. Destroy Instance goes in from Mode 1’s right-click and joins the line the usual way.

Attach it to eight Objects now. Its card names a ninth, Title Asteroid, which comes in the next part as a copy and brings Leave When Cleared along.

A new attachment joins the bottom of an Object’s Attached Logic, and that’s where every card here has it. Each card below is the whole Object. Look for the one green line at the bottom of each.

ObjectShotAddDelete
Transform
Bounding Box > SizeX 0.8125, Y 0.8125
Collider
Shape and Transform > ShapeCircle
Shape and Transform > Radius0.156
Tags and Interactions > InteractionsCollide Only With
Tags and Interactions > Collide Only WithTagged Asteroid, Tagged Saucer
Sprite
Scene Depth Draw Order15
SpriteShot Sprite
Transform > SizeX 0.8125, Y 0.8125
Logic
Shot Lifetime
Wrap Around World
Motion Facing
Shot Impact
Leave When Cleared
Shared Variables
facingOffset-90
ObjectAsteroid LargeAddDelete
Transform
Bounding Box > SizeX 3.875, Y 3.875
Physics > Allow RotationOn
Collider
CollisionSensor
Shape and Transform > ShapeCircle
Shape and Transform > Radius1.5
Sprite
Scene Depth Draw Order10
SpriteAsteroid Standard
Transform > SizeX 3.875, Y 3.875
Tags
Object TagsAsteroid
Logic
Asteroid Material
Asteroid Drift
Break Apart
Wrap Around World
Leave When Cleared
Shared Variables
fragmentAsteroid Medium
wave > KindExpression
wave > Expression$wave
ObjectAsteroid MediumAddDelete
Transform
Bounding Box > SizeX 2.0625, Y 2.0625
Physics > Allow RotationOn
Collider
CollisionSensor
Shape and Transform > ShapeCircle
Shape and Transform > Radius0.781
Sprite
Scene Depth Draw Order10
SpriteAsteroid Standard
Transform > SizeX 2.0625, Y 2.0625
Tags
Object TagsAsteroid
Logic
Asteroid Material
Asteroid Drift
Break Apart
Wrap Around World
Leave When Cleared
Shared Variables
points50
sparkCount22
shake0.006
breakSoundExplosionSmall
fragmentAsteroid Small
wave > KindExpression
wave > Expression$wave
minSpeed2.5
maxSpeed4.219
ObjectAsteroid SmallAddDelete
Transform
Bounding Box > SizeX 1.125, Y 1.125
Physics > Allow RotationOn
Collider
CollisionSensor
Shape and Transform > ShapeCircle
Shape and Transform > Radius0.406
Sprite
Scene Depth Draw Order10
SpriteAsteroid Standard
Transform > SizeX 1.125, Y 1.125
Tags
Object TagsAsteroid
Logic
Asteroid Material
Asteroid Drift
Break Apart
Wrap Around World
Leave When Cleared
Shared Variables
points100
sparkCount14
shake0
breakSoundAsteroid Break
fragmentAsteroid Small
fragments0
wave > KindExpression
wave > Expression$wave
minSpeed3.75
maxSpeed6.094
ObjectSaucer OrbAddDelete
Transform
Bounding Box > SizeX 1.625, Y 1.625
Collider
Shape and Transform > ShapeCircle
Shape and Transform > Radius0.313
Tags and Interactions > InteractionsCollide Only With
Tags and Interactions > Collide Only WithShip, Tagged Asteroid
Sprite
Scene Depth Draw Order15
SpriteSaucer Orb Sprite
Transform > SizeX 1.625, Y 1.625
Tags
Object TagsSaucer Shot
Logic
Saucer Shot Flight
Wrap Around World
Leave When Cleared
Shared Variables
shipShip
ObjectSaucer LanceAddDelete
Transform
Bounding Box > SizeX 2.375, Y 1.1875
Collider
Shape and Transform > ShapeCircle
Shape and Transform > Radius0.234
Tags and Interactions > InteractionsCollide Only With
Tags and Interactions > Collide Only WithShip, Tagged Asteroid
Sprite
Scene Depth Draw Order15
SpriteSaucer Lance Sprite
Transform > SizeX 2.375, Y 1.1875
Tags
Object TagsSaucer Shot
Logic
Saucer Shot Flight
Wrap Around World
Leave When Cleared
Shared Variables
shipShip
aimedYes
ObjectSaucer LargeAddDelete
Transform
Bounding Box > SizeX 3, Y 3
Collider
CollisionSensor
Shape and Transform > SizeX 2.5, Y 1.125
Tags and Interactions > InteractionsCollide Only With
Tags and Interactions > Collide Only WithShip, Shot
Sprite
Scene Depth Draw Order12
SpriteSaucer Large Sprite
Transform > SizeX 3, Y 3
Tags
Object TagsSaucer
Data Structure
From LogicSaucer Flight
Data StructureSaucer Flight Data
Logic
Saucer Flight
Saucer Gun
Saucer Explodes
Leave When Cleared
Shared Variables
shotSaucer Orb
ObjectSaucer SmallAddDelete
Transform
Bounding Box > SizeX 1.875, Y 1.875
Collider
CollisionSensor
Shape and Transform > SizeX 1.5, Y 0.75
Tags and Interactions > InteractionsCollide Only With
Tags and Interactions > Collide Only WithShip, Shot
Sprite
Scene Depth Draw Order12
SpriteSaucer Small Sprite
Transform > SizeX 1.875, Y 1.875
Tags
Object TagsSaucer
Data Structure
From LogicSaucer Flight
Data StructureSaucer Flight Data
Logic
Saucer Flight
Saucer Gun
Saucer Explodes
Leave When Cleared
Shared Variables
speed5.156
shotSaucer Lance
fireEvery0.95
points1000

A saucer cleared this way still stops its siren. Saucer Flight’s When Destroyed runs however a saucer goes: shot down, flown off the far side, and now cleared away.

Nothing sends clearField yet. The title will.

9.5 The Front Door

Now the title, its rocks, and the gold line that blinks under it.

9.5.1 Title Asteroid

Chapter 6 made a promise: the rocks drifting behind the title would set their wave to 1. Here they are.

A Title Asteroid looks like an Asteroid Large and drifts like one. Two things set it apart. Its wave is always 1, never $wave. So it always looks and moves like a rock of the first wave, whatever wave the last game reached. And it has no Break Apart. Nothing can hit it on the title, so there’s nothing to break.

ObjectTitle Asteroid
Transform
Bounding Box > SizeX 3.875, Y 3.875
Physics > Allow RotationOn
Collider
CollisionSensor
Shape and Transform > ShapeCircle
Shape and Transform > Radius1.5
Sprite
Scene Depth Draw Order10
SpriteAsteroid Standard
Transform > SizeX 3.875, Y 3.875
Tags
Object TagsAsteroid
Logic
Asteroid Material
Asteroid Drift
Wrap Around World
Leave When Cleared

It starts as a copy. In the Resources, right-click Asteroid Large and choose Duplicate. The copy, Asteroid Large2, keeps the Tag Asteroid and every Logic Component with its values. Leave When Cleared comes along too. Rename the copy Title Asteroid, with F2 or the Rename line in that same menu.

Open it in Logic mode. Each row of its Attached Logic has a trash button. Press the one on Break Apart’s row. Break Apart goes at once, and its Variables go with it.

Then switch back to Components. Under Variables, the copy’s wave row still reads Expression in its Kind list, with $wave. Pick Constant there. The Value under it is 1, the Starting Value of the Logic itself. That’s why the card has no line for wave at all.

Nothing makes a Title Asteroid yet. Title Screen will.

9.5.3 Title, Title Tagline, Title Prompt, Title High Score and Title Controls

These are Screen UI Objects. You made three like them for the score in Chapter 7, so your hands know them now.

Four of them share a Group, title. It’s a box in their UI Interaction, and you type the name into it. Logic can then show or hide the whole group at once, by that name.

Title Prompt is the one left out of the group. Blink shows and hides it instead. In this game, a word that blinks stays out of every group, and the last part of this chapter shows what goes wrong when one doesn’t. Title High Score reads {$highScore}, so it always shows the best score so far.

ObjectTitle
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Element TypeText
Grouptitle
Text / UI
TextSHATTERFIELD
FontArcade HUD Font
Font Size64
Color#F2FBFF
Letter Spacing6
AlignmentCenter
ObjectTitle Tagline
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Element TypeText
Grouptitle
Text / UI
TextCLEAR THE FIELD. SURVIVE THE SAUCERS.
FontArcade HUD Font
Font Size12
Color#62DCFF
Letter Spacing2
AlignmentCenter
ObjectTitle Prompt
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Element TypeText
Text / UI
TextPRESS ENTER TO START
FontArcade HUD Font
Font Size18
Color#FFD166
Letter Spacing2
AlignmentCenter
Data Structure
From LogicBlink
Data StructureBlink Data
Logic
Blink
ObjectTitle High Score
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Element TypeText
Grouptitle
Text / UI
TextHIGH SCORE {$highScore}
FontArcade HUD Font
Font Size12
Color#9FB4D8
AlignmentCenter
ObjectTitle Controls
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorBottom Center
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Element TypeText
Grouptitle
Text / UI
TextARROWS/WASD TURN+THRUST SPACE FIRE SHIFT HYPERSPACE ESC PAUSE
FontArcade HUD Font
Font Size10
Color#7B8AA8
Letter Spacing1
AlignmentCenter

Mind the spaces in two of these Texts. HIGH SCORE has two before its brace. Title Controls has three between each of its four groups, and it’s all one line. Where the card wraps it, keep typing on the same line.

Element Type is Text on all five, and each Bounding Box > Size is already X 32 and Y 32, as the Wave Banner’s was. Title Prompt also carries Blink, so attach it in Logic mode. Blink Data comes along with it, as the card’s Data Structure lines show. Now place them from the Set up card’s PLACE THESE lines, near the top of this page, the way you placed the Wave Banner. Title Controls is anchored at Bottom Center, so click near the bottom middle of the preview for it. The other four go near the middle. Type each Screen Offset (px), and turn off Visible at Game Start for Title Prompt. Blink shows it when it’s wanted.

9.5.4 Title Screen

Title Screen goes on Game Rules. It has three Events, and the first is the game opening.

Here’s a small puzzle. The game opens already on Title, its Initial Game State. Nothing changed, so Game State Changed doesn’t run. That’s why Title Screen also has Game Start, and all it does is send showTitle to itself.

The middle Event runs when the Game State changes. This kind of Event can’t be told which Game State to wait for. So it asks. Check Game State keeps the answer as isOnTitle.

Back on Title? It sends showTitle again. Anything else, and the title goes away: the title group hides, the prompt stops blinking, the music stops, and the hud group shows.

The last Event, showTitle, does the real work. First it sends clearField to everything, so space is empty of rocks, saucers and shots. Then it calls Create Asteroids Along Edges with titleAsteroid and asteroidsPerBand, 3. That makes six rocks in all. Three come in along the top and bottom edges, and three along the sides. Before its rocks, Waves sets $wave. Title Screen never touches it, and doesn’t need to, since a Title Asteroid’s wave is always 1.

Then the words. Set UI Group Visibility hides the hud group and shows the title group. The hud group is the numbers along the top, and they join it later in this chapter. The prompt gets startBlinking, and Space Theme starts to loop.

Logic ComponentTitle ScreenAttach to: Game Rules

The title screen: its words, its music, and six drifting Title Asteroids, whenever the game is on the title.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
promptObjectConstantNone
titleAsteroidObjectConstantNone
asteroidsPerBandNumberConstant3
edgeBandNumberConstant3.438
sideBandNumberConstant4.688
When the Game Starts
WhenGame Start
1Trigger Custom Event on Object
Custom Event
showTitle
On Game State Changed
WhenGame State Changed
1Check Game State
Action Name
isOnTitle
Game State
Title
2IfisOnTitle.value == true
Then
3Trigger Custom Event on Object
Custom Event
showTitle
4Otherwise
5Set UI Group Visibility
UI Group
title
Visible
No
6Trigger Custom Event on Object
Applies To
@self.prompt
Custom Event
stopBlinking
7Control Sound
Operation
Stop
Sound
"Space Theme"
8Set UI Group Visibility
UI Group
hud
On Show Title
WhenshowTitleCustom Event
1Trigger Custom Event
Custom Event
clearField
2Create Asteroids Along EdgesFunction
creator
self
asteroid
@self.titleAsteroid
perBand
@self.asteroidsPerBand
edgeBand
@self.edgeBand
sideBand
@self.sideBand
3Set UI Group Visibility
UI Group
hud
Visible
No
4Set UI Group Visibility
UI Group
title
5Trigger Custom Event on Object
Applies To
@self.prompt
Custom Event
startBlinking
6Control Sound
Operation
Loop
Sound
"Space Theme"

Its five SHARED VARIABLES come first, all Constant. prompt and titleAsteroid are Objects, each with its None button, and three Numbers follow. Two of those, edgeBand and sideBand, share their names with two of Waves’ values, so on Game Rules each pair will share one row under Variables.

Game Start has one Action, a Trigger Custom Event on Object. Its Applies To starts on Self. So the message comes back to Game Rules, the Object that sent it, and Title Screen hears it there. Type showTitle into its box.

For the middle Event, type Game State into the Add Event window’s filter, and pick Game State Changed. It takes no second window. Check Game State’s Action Name reads gameStateResult, so type isOnTitle over it. Its Game State list already shows Title · Initial, and Title is the one you want here.

The If’s condition is isOnTitle.value == true, in its one box. The Trigger Custom Event on Object goes on its True line with Add inside Then. Then right-click the If and choose Add Else. The Else’s four steps come from Add inside Else, one at a time. The first is a Set UI Group Visibility. Type title into its UI Group, bare, and pick No in its Visible list.

The Trigger Custom Event on Object needs @self.prompt in Applies To. Control Sound goes to Stop. Its Sound list gives Space Theme. The last Set UI Group Visibility takes hud, and its Visible stays Yes, as it starts.

Game Start sends showTitle now, so type its name into the Add Event filter, and it’s there. Its Trigger Custom Event, the one for everyone, takes clearField.

The call is in the Functions group of the Action List. Its creator list starts on self, which is what the card wants, so leave it. Pick @self.titleAsteroid in its asteroid list, and type the card’s three values into the number boxes, @self.asteroidsPerBand and the rest. The others follow the card, with Control Sound on Loop this time.

Attach Title Screen to Game Rules. Under Variables, the Values of prompt and titleAsteroid are buttons that read None. Press the first and pick Title Prompt. The second gets Title Asteroid. The three numbers keep the Starting Values you gave them in the Logic.

Run the game. The title is there, with its six rocks and its music, and the prompt blinks. But your old game runs underneath it: the Ship, the score, WAVE 1 and its rocks. Press Enter, and nothing happens yet. The next parts sort that out, one Logic Component at a time.

9.6 A Breath

Before a game can start properly, it needs a way to stop for a moment.

9.6.1 Paused and Paused Help

PAUSED is more than words. It’s a menu, a piece of the screen that takes over the keys while it’s up.

Paused leaves its Element Type as it starts, on Button. Its Group is pause. Four more fields make it a menu. Its Confirm Command is Start, so Enter or Space confirms it. Its Cancel Command is Pause, so Esc or P closes it. Either way it sends gameResumed, which is in both its Event and its Cancel Event. However the menu closes, the game hears the same news.

Paused Help is the small line under it, PRESS ESC TO RESUME, plain Text in the same group.

ObjectPaused
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Grouppause
EventgameResumed
Confirm CommandStart
Cancel CommandPause
Cancel EventgameResumed
Text / UI
TextPAUSED
FontArcade HUD Font
Font Size44
Color#DFF6FF
Letter Spacing6
AlignmentCenter
ObjectPaused Help
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Element TypeText
Grouppause
Text / UI
TextPRESS ESC TO RESUME
FontArcade HUD Font
Font Size12
Color#9FB4D8
Letter Spacing2
AlignmentCenter

Group, Event and Cancel Event are boxes you type into. Confirm Command and Cancel Command are lists of your Commands. Place both words from the Set up card’s PLACE THESE lines, near the middle, and turn off Visible at Game Start on each. The menu shows them when it opens.

9.6.3 Pause

Pause listens for the Pause Command, Esc or P.

You might expect it to open the menu every time. While PAUSED is up, though, the game is held, and Esc belongs to the menu: it closes it. Pause asks first anyway, as a guard. If PAUSED were ever already open when Pause heard its Command, Pause would do nothing, rather than open the menu twice. Check Menu Open looks for Paused, and keeps the answer as isPauseMenuOpen. Only when it’s false does Pause go on.

Next come two messages, each to the whole game at once, the way Waves sends nextWave. The first, gamePaused, is for anyone who needs to know. The second, showPausedMenu, reaches Menu Pause Lifecycle on Game Rules, which shows PAUSED and holds the game.

When the menu closes, it sends gameResumed, and Pause answers with hideMenu. Menu Pause Lifecycle hides PAUSED, and the game goes on.

Pause’s last Event is On Disable. It runs once when Pause is switched off, as a game ends, and it sends hideMenu too. Press Esc in the very moment your last Ship goes, and PAUSED could open over the end of the game. This Event closes it, so GAME OVER is never left under a menu.

Logic ComponentPauseAttach to: Game Rules

Pause (Esc or P) during play holds the game under the PAUSED menu and lets it go on when the menu reports gameResumed; a menu opened as the game ends is closed.

Attach toAny Object
When Pause Is Pressed
WhenCommand PressedCommand: Pause
1Check Menu Open
Action Name
isPauseMenuOpen
Menu Element
"Paused"
2IfisPauseMenuOpen.value == false
Then
3Trigger Custom Event
Custom Event
gamePaused
4Trigger Custom Event
Custom Event
showPausedMenu
On Game Resumed
WhengameResumedCustom Event
1Trigger Custom Event
Custom Event
hideMenu
When Disabled
WhenOn Disable
1Trigger Custom Event
Custom Event
hideMenu

Pause has no SHARED VARIABLES, so start with its Event, Command Pressed, and pick Pause in the window that asks for the Command. Check Menu Open’s Action Name reads menuOpenResult. Type isPauseMenuOpen over it. Its Menu Element is a list of the words on your screens, starting on (None). Pick Paused.

The If’s condition is isPauseMenuOpen.value == false. Both Trigger Custom Events go on its True line with Add inside Then, and each message’s name goes in as it is, with no quotes.

Type gameResumed into the Add Event filter, and if nothing comes up, add it with Add Custom Event…. The last Event is On Disable. Type Disable into the filter, and pick On Disable.

Attach Menu Pause Lifecycle and Pause to Game Rules, in that order. Under Variables, the Value of menuElement is a button, the menu this Logic shows and hides. Press it, and pick Paused, the word your menu shows.

9.6.4 Thrust Feedback

Who needs gamePaused? The hum, from Chapter 1. Holding the game doesn’t stop a looping sound. So hold Up, press Esc, and the engine would go on humming over PAUSED. Thrust Feedback’s new gamePaused Event stops Thrust.

gameResumed matters too. You might let go of Up while the game is held, or press it. So when the game goes on, Thrust Feedback starts over from the plain Ship: frame 0, and the two-sided shop sign from Chapter 1 turned back to its Coasting side. If Up is still held, Coasting lights the flame and starts the hum on the very next step.

Logic ComponentThrust FeedbackAttach to: ShipAddDelete

While Up is held the Ship shows its thrust flame and the thrust sound loops.

Attach toAny Object
While Command Rotate and Thrust Controls Up Is Held
When2D Direction HeldCommand: Rotate-and-thrust ControlsDirection: Up
ModeCoasting (Starting Mode)
1Set Animation Clip
Clip
"Ship Sprite/Thrust"
2Control Sound
Operation
Loop
Sound
"Thrust"
3Switch Mode
Event
While Command Rotate and Thrust Controls Up Is Held
Mode
Thrusting
While Command Rotate and Thrust Controls Up Is Held
When2D Direction HeldCommand: Rotate-and-thrust ControlsDirection: Up
ModeThrusting
(no Actions)
When Command Rotate and Thrust Controls Up Is Released
When2D Direction ReleasedCommand: Rotate-and-thrust ControlsDirection: Up
1Set Frame
Frame
0
2Control Sound
Operation
Stop
Sound
"Thrust"
3Switch Mode
Event
While Command Rotate and Thrust Controls Up Is Held
Mode
Coasting
When Destroyed
WhenDestroy
1Control Sound
Operation
Stop
Sound
"Thrust"
On Game Paused
WhengamePausedCustom Event
1Control Sound
Operation
Stop
Sound
"Thrust"
On Game Resumed
WhengameResumedCustom Event
1Set Frame
Frame
0
2Switch Mode
Event
While Command Rotate and Thrust Controls Up Is Held
Mode
Coasting

Both messages are in the project now, so type each name into the Add Event filter. Set Frame’s Frame starts at 0, the card’s. Switch Mode’s two lists are the ones from Chapter 1: the Event with Up Is Held in its name, then Coasting.

9.6.5 Saucer Flight

A saucer’s siren is a looping sound too. Saucer Flight gets three new Events. gamePaused stops the siren, and gameResumed starts it looping again, since the saucer is still flying. The third, playStopped, stops it for good when a game ends while a saucer is out. Nothing sends playStopped yet. Play Switch will.

Its card is the whole Saucer Flight from Chapter 8, so it’s long. The three new Events wait at the bottom, in green.

Logic ComponentSaucer FlightAttach to: Saucer Large, Saucer SmallAddDelete

A saucer enters beyond a random side at a random height, crosses at its speed while weaving up and down, and leaves at the far side.

Attach toAny Object
DATA STRUCTURES
Saucer Flight Dataself.saucerFlightData
SHARED VARIABLES
NameTypeKindStarting Value
speedNumberConstant3.75
marginNumberConstant1.25
minDepthNumberConstant2.813
maxDepthNumberConstant21.25
firstWeaveSecondsNumberConstant1
weaveSpeedNumberConstant2.656
weaveMinSecondsNumberConstant0.8
weaveMaxSecondsNumberConstant1.6
When Created
WhenCreate
1Generate Random Integer
Action Name
sideRoll
Maximum
1
2IfsideRoll.value == 0
Then
3Change Component Value
Component Value
self.saucerFlightData.direction
Value
1
4Change Component Value
Component Value
self.saucerFlightData.startX
Value
-@self.margin
5Otherwise
6Change Component Value
Component Value
self.saucerFlightData.direction
Value
-1
7Change Component Value
Component Value
self.saucerFlightData.startX
Value
$areaWidth + @self.margin
8Generate Random Number
Action Name
depthBelowTop
Minimum
@self.minDepth
Maximum
@self.maxDepth
9Set Position
X
self.saucerFlightData.startX
Y
$areaHeight - depthBelowTop.value
10Set Velocity
X Velocity
self.saucerFlightData.direction * @self.speed
Y Velocity
0
11Control Sound
Operation
Loop
Sound
"Saucer Siren"
12Start Recurring Timer
Timer Name
nextWeave
Repeat Every (s)
@self.firstWeaveSeconds
Ring Once
Yes
13Start Recurring Timer
Timer Name
crossing
Repeat Every (s)
($areaWidth + 2 * @self.margin) / @self.speed
Ring Once
Yes
On the Next Weave Timer
WhenRecurring TimerTimer name: nextWeave
1Generate Random Integer
Action Name
weaveRoll
Minimum
-1
Maximum
1
2Set Velocity
Y Velocity
weaveRoll.value * @self.weaveSpeed
3Generate Random Number
Action Name
weaveSeconds
Minimum
@self.weaveMinSeconds
Maximum
@self.weaveMaxSeconds
4Start Recurring Timer
Timer Name
nextWeave
Repeat Every (s)
weaveSeconds.value
Ring Once
Yes
On the Crossing Timer
WhenRecurring TimerTimer name: crossing
1Destroy Instance
When Leaving the View
WhenLeave View
1Ifself.transform.position.y > $areaHeight
Then
2Set Position
X
self.transform.position.x
Y
self.transform.position.y - $areaHeight
3Ifself.transform.position.y < 0
Then
4Set Position
X
self.transform.position.x
Y
self.transform.position.y + $areaHeight
When Destroyed
WhenDestroy
1Control Sound
Operation
Stop
Sound
"Saucer Siren"
On Game Paused
WhengamePausedCustom Event
1Control Sound
Operation
Stop
Sound
"Saucer Siren"
On Game Resumed
WhengameResumedCustom Event
1Control Sound
Operation
Loop
Sound
"Saucer Siren"
On Play Stopped
WhenplayStoppedCustom Event
1Control Sound
Operation
Stop
Sound
"Saucer Siren"

gamePaused and gameResumed are in the Add Event filter. playStopped is new, so add it with Add Custom Event…. Each Control Sound takes its Operation and Saucer Siren from its lists.

Run the game, and press Esc. PAUSED comes up. The rocks stop where they are, and so does everything else. Press Esc again.

They all go on.

9.7 Press Enter

Now the title and the game take turns.

9.7.1 Start Game

Start Game listens for the Start Command, which is Enter or Space.

It only works in two places: on the title, and when Play Again is offered. So it checks both, isOnTitle and isOfferingPlayAgain, and an If with Or asks whether either is true.

When one is, Start plays, and clearField empties space. Last, Set Game State makes it Playing.

The order matters here. When Waves sees a field with no rocks, it starts the next wave. If the game were Playing first, the title’s rocks would vanish under a game in progress, and Waves would count that as a cleared field. Emptied first, they go before anyone is counting.

Logic ComponentStart GameAttach to: Game Rules

Start (Enter or Space) on the title or after a game over clears space and starts a game.

Attach toAny Object
When Start Is Pressed
WhenCommand PressedCommand: Start
1Check Game State
Action Name
isOnTitle
Game State
Title
2Check Game State
Action Name
isOfferingPlayAgain
Game State
Play Again
3IfisOnTitle.value == true || isOfferingPlayAgain.value == true
Then
4Control Sound
Sound
"Start"
5Trigger Custom Event
Custom Event
clearField
6Set Game State
Game State
Playing

Start Game has no SHARED VARIABLES, so begin with Command Pressed, and pick Start in its second window. Each Check Game State arrives on Title · Initial. The first, isOnTitle, keeps it, and the second, isOfferingPlayAgain, needs Play Again picked.

The If’s one box takes both tests, joined by ||, which means or: isOnTitle.value == true || isOfferingPlayAgain.value == true. On the True line, Control Sound plays Start, from its Sound list. Trigger Custom Event takes clearField. Set Game State needs Playing picked in its list.

Attach Start Game to Game Rules.

9.7.2 Lives and Respawn

Four pieces of Logic on Game Rules used to start at Game Start: Lives and Respawn, Waves, Extra Ships and Saucer Spawner. Now they start whenever a game does. Their new Event is On Enable. It runs once, each time the Logic is switched on.

You don’t build the Event again. Right-click the Game Start block and choose Change Event…. Type Enable into the window’s filter, pick On Enable, and press OK. Myth Engine asks to be sure: it will change “When the game starts” to “When this Logic is enabled”, and 1 Mode and its Actions will be kept. Press Change Event. On the card, that’s the struck Game Start line with On Enable in green above it.

Lives and Respawn changes most. Its new Event, spawnShip, makes a Ship in the middle. On Enable sends it, so every game begins with a Ship, and the respawnDelay timer sends it for each Ship after a crash.

The last change is the ending. When lives run out, the If’s new Else sets the Game State to Game Over.

Logic ComponentLives and RespawnAttach to: Game RulesAddDelete

The game starts with startLives; each lost Ship costs one, and a new Ship comes after respawnSeconds while lives are left.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
shipObjectConstantNone
startLivesNumberConstant3
respawnSecondsNumberConstant2.4
When Enabled
WhenOn Enable
When the Game Starts
WhenGame Start
1Change Variable
Variable
$lives
Value
@self.startLives
2Trigger Custom Event on Object
Custom Event
spawnShip
On Ship Destroyed
WhenshipDestroyedCustom Event
1Change Variable
Variable
$lives
Operator
-=
Value
1
2If$lives > 0
Then
3Start Recurring Timer
Timer Name
respawnDelay
Repeat Every (s)
@self.respawnSeconds
Ring Once
Yes
4Otherwise
5Set Game State
Game State
Game Over
On the Respawn Delay Timer
WhenRecurring TimerTimer name: respawnDelay
1Trigger Custom Event on Object
Custom Event
spawnShip
On Spawn Ship
WhenspawnShipCustom Event
1Create Instance
Object to Create
@self.ship
X
$areaWidth / 2
Y
$areaHeight / 2
Created As
newShip
2Control Sound
Sound
"Ship Respawn"

First, On Enable’s Trigger Custom Event on Object. Add it from Mode 1’s right-click, type spawnShip into its box, and Connect to sequence joins it after Change Variable. Now that something sends spawnShip, add its Event: type spawnShip into the Add Event filter, and there it is.

Then the move. The Create Instance and Control Sound in the respawnDelay Event go to spawnShip, and you don’t build them again. On the card, they sit plain under On Spawn Ship, because they aren’t new. Nothing is struck where they were. Click Create Instance, then Shift+click Control Sound to select both. Right-click either one and choose Cut 2 blocks. Then right-click the empty spot close beside On Spawn Ship’s Mode 1, on its right, and choose Paste, as you did for breakUp in Chapter 8. The two arrive loose. Connect to sequence on Create Instance joins them both.

Back in the respawnDelay Event, a Trigger Custom Event on Object takes their place. Add it from that Event’s Mode 1, and type spawnShip.

Last, right-click the If in the shipDestroyed Event and choose Add Else. Right-click the Else, choose Add inside Else, and pick Set Game State. It arrives with Title · Initial in its list. Pick Game Over. Connect to sequence joins it to the False line.

9.7.3 Waves, Extra Ships and Saucer Spawner

The other three change the same way.

Waves and Saucer Spawner also get On Disable, as Pause did. On Disable is for tidying up. A switched-off Logic hears nothing, so it can’t tidy up later. But its timers keep counting, on into the next game, and a banner it showed stays up. So On Disable runs once, as the Logic is switched off, and stops what play started. Waves stops its bannerTime and sectorJump timers and hides the banner. Saucer Spawner stops its saucerCheck timer.

On these three cards, look at the When bar at the top of each. On Disable, where there is one, is at the bottom. The steps between are ones you built before.

Logic ComponentWavesAttach to: Game RulesAddDelete

Each wave announces itself with the banner, then brings its Large Asteroids; clearing every Asteroid starts the sector jump and then the next wave.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
asteroidObjectConstantNone
bannerObjectConstantNone
bannerSecondsNumberConstant1.6
jumpSecondsNumberConstant1.4
maxAsteroidsPerBandNumberConstant6
edgeBandNumberConstant3.438
sideBandNumberConstant4.688
When Enabled
WhenOn Enable
When the Game Starts
WhenGame Start
1Change Variable
Variable
$wave
Value
0
2Trigger Custom Event
Custom Event
nextWave
On Next Wave
WhennextWaveCustom Event
1Change Variable
Variable
$wave
Operator
+=
Value
1
2Set Visible
Applies To
@self.banner
Visible
Yes
3Start Recurring Timer
Timer Name
bannerTime
Repeat Every (s)
@self.bannerSeconds
Ring Once
Yes
On the Banner Time Timer
WhenRecurring TimerTimer name: bannerTime
1Declare Variable
Name
perBandThisWave
Value
1
2Set Visible
Applies To
@self.banner
Visible
No
3Change Variable
Variable
perBandThisWave
Value
$wave + 1
4IfperBandThisWave > @self.maxAsteroidsPerBand
Then
5Change Variable
Variable
perBandThisWave
Value
@self.maxAsteroidsPerBand
6Create Asteroids Along EdgesFunction
creator
self
asteroid
@self.asteroid
perBand
perBandThisWave
edgeBand
@self.edgeBand
sideBand
@self.sideBand
On No Instances Left · Anything Tagged Asteroid
WhenNo Instances LeftObject: tag:Asteroid
1Control Sound
Sound
"Sector Clear"
2Control Sound
Sound
"Hyper"
3Start Recurring Timer
Timer Name
sectorJump
Repeat Every (s)
@self.jumpSeconds
Ring Once
Yes
On the Sector Jump Timer
WhenRecurring TimerTimer name: sectorJump
1Trigger Custom Event
Custom Event
nextWave
When Disabled
WhenOn Disable
1Stop Recurring Timer
Timer Name
bannerTime
2Stop Recurring Timer
Timer Name
sectorJump
3Set Visible
Applies To
@self.banner
Visible
No
Logic ComponentExtra ShipsAttach to: Game RulesAddDelete

Each time the score passes another extraShipEvery points, the player gains a life, with a sound and an "EXTRA SHIP" popup.

Attach toAny Object
DATA STRUCTURES
Extra Ships Dataself.extraShipsData
SHARED VARIABLES
NameTypeKindStarting Value
extraShipEveryNumberConstant10000
popupAboveCenterNumberConstant3.75
popupColorColorConstant#7dffb2
popupSizeNumberConstant0.75
popupRiseNumberConstant1.25
popupSecondsNumberConstant1.2
When Enabled
WhenOn Enable
When the Game Starts
WhenGame Start
1Change Component Value
Component Value
self.extraShipsData.nextExtraShipAt
Value
@self.extraShipEvery
On Scored
WhenscoredCustom Event
1If$score >= self.extraShipsData.nextExtraShipAt
Then
2Change Variable
Variable
$lives
Operator
+=
Value
1
3Change Component Value
Component Value
self.extraShipsData.nextExtraShipAt
Operator
+=
Value
@self.extraShipEvery
4Control Sound
Sound
"ExtraLife"
5Popup Text
Text
EXTRA SHIP
Color
@self.popupColor
Size
@self.popupSize
Rise
@self.popupRise
Seconds
@self.popupSeconds
Position Relative To
World
X
$areaWidth / 2
Y
$areaHeight / 2 + @self.popupAboveCenter
Logic ComponentSaucer SpawnerAttach to: Game RulesAddDelete

The first saucer comes firstSeconds into the game. After that, a saucer check comes a random number of seconds later (fewer in later waves) and sends a saucer when none is flying; the Small one comes more often in later waves and always at high scores.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
largeSaucerObjectConstantNone
smallSaucerObjectConstantNone
firstSecondsNumberConstant16
smallChanceNumberConstant0.12
smallChancePerWaveNumberConstant0.06
smallAlwaysScoreNumberConstant40000
gapMinFloorNumberConstant7
gapMinStartNumberConstant17
gapMaxFloorNumberConstant11
gapMaxStartNumberConstant24
When Enabled
WhenOn Enable
When the Game Starts
WhenGame Start
1Start Recurring Timer
Timer Name
saucerCheck
Repeat Every (s)
@self.firstSeconds
Ring Once
Yes
On the Saucer Check Timer
WhenRecurring TimerTimer name: saucerCheck
1Declare Variable
Name
gapMax
Value
0
2Declare Variable
Name
gapMin
Value
0
3Check Instance Count
Action Name
isSaucerFlying
Object
tag:Saucer
Operator
>
Value
0
4IfisSaucerFlying.value == false
Then
5Generate Random Number
Action Name
saucerRoll
6If$score >= @self.smallAlwaysScore || saucerRoll.value < (@self.smallChance + @self.smallChancePerWave * $wave)
Then
7Create Instance
Object to Create
@self.smallSaucer
Created As
newSmallSaucer
8Otherwise
9Create Instance
Object to Create
@self.largeSaucer
Created As
newLargeSaucer
10Change Variable
Variable
gapMin
Value
@self.gapMinStart - $wave
11IfgapMin < @self.gapMinFloor
Then
12Change Variable
Variable
gapMin
Value
@self.gapMinFloor
13Change Variable
Variable
gapMax
Value
@self.gapMaxStart - $wave
14IfgapMax < @self.gapMaxFloor
Then
15Change Variable
Variable
gapMax
Value
@self.gapMaxFloor
16Generate Random Number
Action Name
checkSeconds
Minimum
gapMin
Maximum
gapMax
17Start Recurring Timer
Timer Name
saucerCheck
Repeat Every (s)
checkSeconds.value
Ring Once
Yes
When Disabled
WhenOn Disable
1Stop Recurring Timer
Timer Name
saucerCheck

Each On Disable comes from the Add Event filter, as Pause’s did. Each Stop Recurring Timer takes its timer’s name bare, bannerTime and the rest. Waves’ Set Visible picks @self.banner in its Applies To, and No in its Visible list.

9.7.4 Saucer Gun

A saucer in flight isn’t on Game Rules, so nothing switches it. It hears the game end another way. Play Switch sends a message to everything, playStopped, when a game is over. Saucer Flight already listens for it. Now Saucer Gun does too, and stops its saucerFire timer.

The saucer drifts on across, silent.

Logic ComponentSaucer GunAttach to: Saucer Large, Saucer SmallAddDelete

A saucer fires its own shot every fireEvery seconds, with the pulse sound.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
shotObjectConstantNone
fireEveryNumberConstant1.35
When Created
WhenCreate
1Start Recurring Timer
Timer Name
saucerFire
Repeat Every (s)
@self.fireEvery
On the Saucer Fire Timer
WhenRecurring TimerTimer name: saucerFire
1Create Instance
Object to Create
@self.shot
Position Relative To
Self
Created As
newShot
2Control Sound
Sound
"Saucer Pulse"
On Play Stopped
WhenplayStoppedCustom Event
1Stop Recurring Timer
Timer Name
saucerFire

playStopped is in the Add Event filter now, because Saucer Flight listens for it.

9.7.5 Play Switch

Play Switch is the piece the others wait for.

It listens for Game State Changed and asks one question: is it Playing now? If it is, Set Logic State switches on five Logic Components, one Action each: Lives and Respawn, Waves, Extra Ships, Saucer Spawner and Pause. Each one’s On Enable runs, and a game begins.

Anything else, and the Else switches the same five off, with State Disable, and sends playStopped. Remember the message Saucer Flight was waiting for? This is who sends it.

Set Logic State has no Applies To line, so it switches them on its own Object, Game Rules.

Logic ComponentPlay SwitchAttach to: Game Rules

Switches the Logic that only makes sense during play on when a game starts, and off when it ends.

Attach toAny Object
On Game State Changed
WhenGame State Changed
1Check Game State
Action Name
isPlaying
Game State
Playing
2IfisPlaying.value == true
Then
3Set Logic State
Logic Component
"Lives and Respawn"
4Set Logic State
Logic Component
"Waves"
5Set Logic State
Logic Component
"Extra Ships"
6Set Logic State
Logic Component
"Saucer Spawner"
7Set Logic State
Logic Component
"Pause"
8Otherwise
9Set Logic State
Logic Component
"Lives and Respawn"
State
Disable
10Set Logic State
Logic Component
"Waves"
State
Disable
11Set Logic State
Logic Component
"Extra Ships"
State
Disable
12Set Logic State
Logic Component
"Saucer Spawner"
State
Disable
13Set Logic State
Logic Component
"Pause"
State
Disable
14Trigger Custom Event
Custom Event
playStopped

Play Switch has no SHARED VARIABLES. Check Game State’s list needs Playing picked. Each Set Logic State’s Logic Component is a list of your Logic Components, so pick the card’s, such as Lives and Respawn. The five on the True line keep State on Enable.

Add Else gives the Else, and Add inside Else gives each of its six steps. Their State list goes to Disable, and the Trigger Custom Event, playStopped, comes last.

Attach Play Switch to Game Rules, last. Now turn off the switch beside five names in the Attached Logic: Lives and Respawn, Waves, Extra Ships, Saucer Spawner and Pause. On the Game Rules card at the end of this chapter, each one says (turned off). They start the game switched off, because the game starts on the title.

Why not let each one check the Game State for itself? Without Play Switch, sixteen Events in this game would each start by asking whether a game is on. Switched-off Logic doesn’t need to ask.

Last, do the Set up card’s REMOVE THESE PLACEMENTS block. Click the Ship in Space’s Scene Explorer and press Delete. spawnShip makes every Ship now, the first one included.

Run the game. The title waits, with nothing else going on. Press Enter. The rocks vanish, Start sounds, a Ship appears in the middle, and WAVE 1 comes up. Esc pauses. On the title, it does nothing.

Lose all your Ships. Everything stops. No new Ship, no waves, no saucers. The rocks drift on, and Enter does nothing. It’s the Game Over Game State, but nothing on the screen says so yet.

9.8 Only During Play

The numbers at the top still show over the title. They belong to play.

9.8.1 Score Display, High Score Display and Wave Display

Give each one the Group hud. Then do the Set up card’s CHANGE THESE PLACEMENTS block: turn off Visible at Game Start on each of their placements. Title Screen already hides and shows the hud group, so they come and go with the game.

ObjectScore DisplayAddDelete
Transform
Presentation > SpaceWindow / UI
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Element TypeText
Grouphud
Text / UI
Text{$score}
FontArcade HUD Font
Font Size24
Color#F2FBFF
Text BoundsWrap to Width
Transform > Size X260
ObjectHigh Score DisplayAddDelete
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorTop Center
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Element TypeText
Grouphud
Text / UI
TextHI {$highScore}
FontArcade HUD Font
Font Size12
Color#9FB4D8
AlignmentCenter
ObjectWave DisplayAddDelete
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorTop Right
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Element TypeText
Grouphud
Text / UI
TextWAVE {$wave}
FontArcade HUD Font
Font Size12
Color#9FB4D8
AlignmentRight
Text BoundsWrap to Width
Transform > Size X180

The tiny Ships in the corner need nothing new. Each Life Icon shows only while $lives reaches its slot. Over the title, $lives is still 0, where Chapter 5’s setup card starts it. When a game begins, Lives and Respawn sets it to three, and the icons appear.

Run it. The title is clean now. Start a game, and the score, the high score, the wave and three tiny Ships appear.

9.9 The End of a Game

Last, the game learns to say it’s over, and to keep your best.

9.9.1 Game Over, Final Score and Play Again Prompt

GAME OVER is big and pink-red, and FINAL SCORE reads {$score}, with two spaces before the brace, as HIGH SCORE has. They share the Group gameOver.

Play Again Prompt blinks, like Title Prompt, and like it, it’s in no group. Here’s why. A group looks like a box that keeps its words hidden. It isn’t. Set UI Group Visibility flips each word’s own switch, the same one Blink’s Set Visible flips, and the last flip wins. In the gameOver group, PRESS ENTER TO PLAY AGAIN would show the moment GAME OVER does, two seconds before Enter works. Out of any group, only Blink shows it, and Game Over Screen tells Blink when.

ObjectGame Over
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Element TypeText
GroupgameOver
Text / UI
TextGAME OVER
FontArcade HUD Font
Font Size48
Color#FF6B8B
Letter Spacing6
AlignmentCenter
ObjectFinal Score
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Element TypeText
GroupgameOver
Text / UI
TextFINAL SCORE {$score}
FontArcade HUD Font
Font Size16
Color#DFF6FF
AlignmentCenter
ObjectPlay Again Prompt
Transform
Presentation > SpaceWindow / UI
Presentation > Screen AnchorCenter
Presentation > Render LayerUI
Bounding Box > SizeX 32, Y 32
UI Interaction
Element TypeText
Text / UI
TextPRESS ENTER TO PLAY AGAIN
FontArcade HUD Font
Font Size16
Color#FFD166
Letter Spacing2
AlignmentCenter
Data Structure
From LogicBlink
Data StructureBlink Data
Logic
Blink

Play Again Prompt carries Blink, as Title Prompt does, and Blink Data comes with it. Place all three near the middle, from the Set up card’s PLACE THESE lines, and turn off Visible at Game Start on each.

9.9.2 Game Over Screen

Game Over Screen goes on Game Rules. Most of its card is one idea. Every time the Game State changes, it clears the stage first, then sets it.

So the Game State Changed Event opens with a clean sweep. Its two timers stop, playAgainDelay and returnToTitle, and the gameOver group goes dark, and so does the blinking prompt. Then it asks which Game State this is. Each of the two it knows gets its words and its timer.

Count the beats. The last Ship goes, and GAME OVER comes up. Two seconds. Enter does nothing yet. When playAgainDelay rings, its Event sets the Game State to Play Again. PRESS ENTER TO PLAY AGAIN blinks. Twelve seconds. Then returnToTitle rings, and its Event sets the Game State back to Title.

Every change stops both timers first. So a timer can never ring in the wrong Game State. Press Enter during Play Again, and returnToTitle is stopped before it can send you anywhere.

Logic ComponentGame Over ScreenAttach to: Game Rules

After the last Ship: GAME OVER and the final score; playAgainSeconds later, the offer to play again; returnSeconds after that, the title.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
playAgainPromptObjectConstantNone
playAgainSecondsNumberConstant2
returnSecondsNumberConstant12
On Game State Changed
WhenGame State Changed
1Stop Recurring Timer
Timer Name
playAgainDelay
2Stop Recurring Timer
Timer Name
returnToTitle
3Set UI Group Visibility
UI Group
gameOver
Visible
No
4Trigger Custom Event on Object
Applies To
@self.playAgainPrompt
Custom Event
stopBlinking
5Check Game State
Action Name
isGameOver
Game State
Game Over
6IfisGameOver.value == true
Then
7Set UI Group Visibility
UI Group
gameOver
8Start Recurring Timer
Timer Name
playAgainDelay
Repeat Every (s)
@self.playAgainSeconds
Ring Once
Yes
9Check Game State
Action Name
isOfferingPlayAgain
Game State
Play Again
10IfisOfferingPlayAgain.value == true
Then
11Set UI Group Visibility
UI Group
gameOver
12Trigger Custom Event on Object
Applies To
@self.playAgainPrompt
Custom Event
startBlinking
13Start Recurring Timer
Timer Name
returnToTitle
Repeat Every (s)
@self.returnSeconds
Ring Once
Yes
On the Play Again Delay Timer
WhenRecurring TimerTimer name: playAgainDelay
1Set Game State
Game State
Play Again
On the Return to Title Timer
WhenRecurring TimerTimer name: returnToTitle
1Set Game State
Game State
Title

Its three SHARED VARIABLES come first, all Constant: playAgainPrompt, an Object with its None button, then two Numbers. The Stop Recurring Timers take their names bare. The Trigger Custom Event on Object picks @self.playAgainPrompt in Applies To. Check Game State arrives on Title · Initial. Pick Game Over for isGameOver. The first If’s two steps go on its True line with Add inside Then.

The second Check Game State goes on the main line, below the first If, where Connect to sequence puts it. It takes Play Again, and its If gets the last three steps. Each timer’s own Event is a Recurring Timer, named as the card names it.

Attach Game Over Screen to Game Rules. Under Variables, press the None button of playAgainPrompt and pick Play Again Prompt.

9.9.3 Score

Remember Score’s Game Start, from Chapter 7? It set $score to 0, for the day a new game could begin without the whole program starting over. That day is here, so the 0 moves. A new Game State Changed Event sets it when the game becomes Playing.

The same Event saves your best. When the Game State is Game Over, Save Persistent Value stores $highScore under the key highScore. A persistent value stays on this computer after the game is closed.

Game Start does the other half. Load Persistent Value reads the key back, as savedHighScore, with 0 if nothing was saved yet. If it’s higher than $highScore, it becomes the high score.

Logic ComponentScoreAttach to: Game RulesAddDelete

The score starts at 0 each game; the high score follows it whenever the score passes it.

Attach toAny Object
When the Game Starts
WhenGame Start
1Change Variable
Variable
$score
Value
0
1Load Persistent Value
Action Name
savedHighScore
Key
"highScore"
Default
0
2IfsavedHighScore.value > $highScore
Then
3Change Variable
Variable
$highScore
Value
savedHighScore.value
On Game State Changed
WhenGame State Changed
1Check Game State
Action Name
isPlaying
Game State
Playing
2IfisPlaying.value == true
Then
3Change Variable
Variable
$score
Value
0
4Check Game State
Action Name
isGameOver
Game State
Game Over
5IfisGameOver.value == true
Then
6Save Persistent Value
Action Name
persistentWriteResult
Key
"highScore"
Value
$highScore
On Scored
WhenscoredCustom Event
1If$score > $highScore
Then
2Change Variable
Variable
$highScore
Value
$score

In Game Start, right-click the old Change Variable and choose Delete. The three new steps join the usual way. The Change Variable goes in with Add inside Then. Load Persistent Value’s Action Name reads persistentValueResult, so type savedHighScore over it. Its Key takes "highScore", quotes and all. Its Default is 0. Save Persistent Value’s Action Name already reads persistentWriteResult. Nothing in the game reads that answer, so leave the name as it is.

The new Event is a Game State Changed, built like Game Over Screen’s: two Check Game States, each followed by its If. The second Check Game State joins the main line below the first If, as Connect to sequence puts it.

9.9.4 Break Apart and Saucer Explodes

A Shot fired a moment before the last crash can still be flying when the game ends. It still breaks what it hits, but it shouldn’t score.

So both pieces ask Check Game State whether it’s Playing, and only then count the points. The three scoring steps from Chapters 7 and 8 now sit on an If’s True line.

Logic ComponentBreak ApartAttach to: Asteroid Large, Asteroid Medium, Asteroid SmallAddDelete

An Asteroid hit by the player scores and shows its points; any Asteroid that breaks up bursts into sparks, plays its break sound, leaves its fragments and is destroyed.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
pointsNumberConstant20
sparkCountNumberConstant34
shakeNumberConstant0.012
shakeSecondsNumberConstant0.18
popupColorColorConstant#dff6ff
popupSizeNumberConstant0.469
popupRiseNumberConstant0.813
popupSecondsNumberConstant0.55
breakSoundSoundConstantExplosionLarge
fragmentObjectConstantNone
fragmentsNumberConstant2
On Hit
WhenhitCustom Event
1Change Variable
Variable
$score
Operator
+=
Value
@self.points
2Trigger Custom Event
Custom Event
scored
3Popup Text
Text
text(@self.points)
Color
@self.popupColor
Size
@self.popupSize
Rise
@self.popupRise
Seconds
@self.popupSeconds
1Check Game State
Action Name
isPlaying
Game State
Playing
2IfisPlaying.value == true
Then
3Change Variable
Variable
$score
Operator
+=
Value
@self.points
4Trigger Custom Event
Custom Event
scored
5Popup Text
Text
text(@self.points)
Color
@self.popupColor
Size
@self.popupSize
Rise
@self.popupRise
Seconds
@self.popupSeconds
6Trigger Custom Event on Object
Custom Event
breakUp
On Break Up
WhenbreakUpCustom Event
1Burst Particles
Particles
"Impact Sparks"
Count
@self.sparkCount
2Control Sound
Sound
@self.breakSound
3If@self.shake > 0
Then
4Camera Shake
Intensity
@self.shake
Seconds
@self.shakeSeconds
5Repeat@self.fragmentstimes
Each time
6Create Instance
Object to Create
@self.fragment
Position Relative To
Self
Created As
newFragment
7Destroy Instance
Logic ComponentSaucer ExplodesAttach to: Saucer Large, Saucer SmallAddDelete

A saucer that is hit gives the player its points, shows them, explodes and is destroyed.

Attach toAny Object
SHARED VARIABLES
NameTypeKindStarting Value
pointsNumberConstant200
explosionCountNumberConstant60
shakeNumberConstant0.012
shakeSecondsNumberConstant0.25
popupColorColorConstant#ffd166
popupSizeNumberConstant0.563
popupRiseNumberConstant1
popupSecondsNumberConstant0.8
On Hit
WhenhitCustom Event
1Change Variable
Variable
$score
Operator
+=
Value
@self.points
2Trigger Custom Event
Custom Event
scored
3Popup Text
Text
text(@self.points)
Color
@self.popupColor
Size
@self.popupSize
Rise
@self.popupRise
Seconds
@self.popupSeconds
1Check Game State
Action Name
isPlaying
Game State
Playing
2IfisPlaying.value == true
Then
3Change Variable
Variable
$score
Operator
+=
Value
@self.points
4Trigger Custom Event
Custom Event
scored
5Popup Text
Text
text(@self.points)
Color
@self.popupColor
Size
@self.popupSize
Rise
@self.popupRise
Seconds
@self.popupSeconds
6Burst Particles
Particles
"Ship Explosion"
Count
@self.explosionCount
7Control Sound
Sound
"ExplosionLarge"
8Camera Shake
Intensity
@self.shake
Seconds
@self.shakeSeconds
9Destroy Instance

In Break Apart’s hit Event, two new blocks go first. Add Check Game State and the If from Mode 1’s right-click, and join them with the round handles, as in Chapter 7. Click the handle at the bottom of Mode 1, then the one at the top of Check Game State. Then click the bottom of Check Game State, and the top of the If. Check Game State takes isPlaying and Playing, and the If’s condition is isPlaying.value == true.

Now the three scoring steps move. They go onto the If’s True line, with Cut and Paste. An empty True line gives Paste nowhere to land, and Paste on the If itself would put them beside it, not inside. So give the True line a block for a moment. Right-click the If, choose Add inside Then, and pick Destroy Instance. Then click Change Variable, Shift+click Popup Text, right-click, and choose Cut 3 blocks. Right-click the new Destroy Instance and choose Paste. The three arrive loose, inside the If. Delete that Destroy Instance, and Connect to sequence on Change Variable joins all three to the True line.

The card shows the three struck at the top, where they stood, and new on the True line. The move does both. The Trigger Custom Event on Object that sends breakUp now follows the If.

Saucer Explodes changes the same way, and its three sit above Burst Particles. Its line ends with a Destroy Instance of its own, so delete only the loose one you added.

9.9.5 Game Rules

Here’s Game Rules with everything this chapter attached. Four of its rows show only (turned off) in green: Lives and Respawn, Waves, Extra Ships and Saucer Spawner. Each is a Logic Component you attached long ago, and only its switch changes. Keep it, with its boxes, and make sure its switch is off. Pause is new, and switched off too.

Its order isn’t quite the order you made them in, and the game plays the same either way. If you’d like yours to match the card, drag the rows by their grips, or click a grip and use Alt with the arrows.

ObjectGame RulesAddDelete
Data Structure
From LogicExtra Ships
Data StructureExtra Ships Data
Logic
Lives and Respawn(turned off)
Waves(turned off)
Score
Extra Ships(turned off)
Saucer Spawner(turned off)
Title Screen
Start Game
Game Over Screen
Menu Pause Lifecycle
Pause(turned off)
Play Switch
Extra Ships
Saucer Spawner
Shared Variables
shipShip
asteroidAsteroid Large
bannerWave Banner
largeSaucerSaucer Large
smallSaucerSaucer Small
promptTitle Prompt
titleAsteroidTitle Asteroid
playAgainPromptPlay Again Prompt
menuElementPaused

Run the game, and play it through. Lose your last Ship, and GAME OVER comes up with your score. Wait. PRESS ENTER TO PLAY AGAIN starts to blink. Press it, and a new game starts at 0, with your high score at the top. Or wait twelve seconds, and the title comes back, with HIGH SCORE showing your best.

Play it!

Watch for each of these.

  • The game opens on the title: SHATTERFIELD, the tagline, the controls line, HIGH SCORE, and six Large rocks drifting. The music plays.
  • PRESS ENTER TO START blinks, about half a second on and half a second off.
  • No score, no wave and no tiny Ships on the title.
  • Press Enter. The rocks vanish without a spark, Start plays, and a Ship appears in the middle with WAVE 1.
  • Press Enter again during play. Nothing happens.
  • Esc or P shows PAUSED and PRESS ESC TO RESUME, and everything stops. Esc, P, Enter or Space goes on.
  • Hold Up and press Esc, and the engine hum stops. Keep Up held as the game goes on, and the flame and the hum come back.
  • A saucer’s siren stops under PAUSED and starts again when the game goes on.
  • Lose your last Ship. GAME OVER and FINAL SCORE come up, and the saucer siren stops.
  • For two seconds Enter does nothing. Then PRESS ENTER TO PLAY AGAIN blinks, and Enter starts a new game at 0.
  • Wait instead, and the title comes back about 14 seconds after GAME OVER, with your best as HIGH SCORE. Its rocks are Standard and slow again, however far you got.
  • Stop the game and run it again. HIGH SCORE still shows your best.
How it works

The title shows, a game starts, a game ends, and the title comes back. Each of those is a change of Game State. Title Screen, Game Over Screen, Score and Play Switch all hear every change, and each asks the same question: what is it now?

Underneath them is one idea. Don’t make every piece of Logic check whether a game is on. Switch it off when it isn’t needed. Play Switch turns the play-only Logic on with the game and off after it, and On Enable and On Disable let each one start and tidy up for itself.

9.10 If It Didn’t Work

Something may be a little off the first time, and that’s normal. Run the game, play it through to GAME OVER, and watch.

The game starts playing behind the title? Look at Game Rules’ Attached Logic. Five switches need to be off: Lives and Respawn, Waves, Extra Ships, Saucer Spawner and Pause.

Enter does nothing on the title? Perhaps Menus still reads Inactive at Start in the Input Manager, so click it. Or look at the Start Command itself, in Menus. Its two rows should read Enter and Space.

P pauses, but Esc doesn’t? The Pause Command’s first row may still read No Input Assigned. Click it and press Escape twice, quickly.

No Ship after Enter? Lives and Respawn’s On Enable needs the Trigger Custom Event on Object, sending spawnShip. And check that the Value of ship, under Game Rules’ Variables, still says Ship.

WAVE 2 comes straight after WAVE 1? Perhaps Start Game sets Playing before clearField. Set Game State has to be last, so move it below Trigger Custom Event with the handles.

PRESS ENTER TO PLAY AGAIN shows the moment GAME OVER does? Play Again Prompt may have a Group, typed in by habit. Empty its Group box.

PAUSED never closes? Look at Paused’s UI Interaction: Confirm Command Start, Cancel Command Pause, and gameResumed in both Event and Cancel Event. And Pause’s gameResumed Event should send hideMenu.

The engine hums on under PAUSED? Thrust Feedback’s gamePaused Event needs its Control Sound on Stop, with Thrust.

Esc pauses on the title? Pause needs its switch off on Game Rules, and its two lines in Play Switch.

GAME OVER never comes? Lives and Respawn’s If needs its Else, with Set Game State on Game Over. Its list starts on Title, so check it.

Every rock scores twice? The scoring steps may have been copied, not cut, so the old three still sit below the If in Break Apart. Delete those three.

No points rise off a broken rock at all? Perhaps the three scoring steps landed beside the If, with no arrow into them. Cut them again, and paste them on a block inside the If, as above.

The title’s rocks wear a later wave’s material? Title Asteroid’s wave row may still read Expression in its Kind list. Pick Constant, and it reads 1.

The high score is gone the next time? Score’s Save Persistent Value and Load Persistent Value need the same Key, "highScore".

Each of these is a 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, finished, if you’d like to compare.

Challenge

What would your title say? Change the tagline to your own words, or give SHATTERFIELD a new color. Try playAgainSeconds at 5, under Game Rules’ Variables. Or set asteroidsPerBand to 6, and fill the whole title with drifting rocks. Chapter 10 is written for the card’s numbers. Set them back before you go on, and write yours down if you’d like to keep them.

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

Your game has a front door now, and a way home. In Chapter 10, the field gets a heartbeat.