Payloads
Before this: Enums
Next steps: Option and Result
Parts that use this: Round Manager, Whack-a-Light, Team Match
A variant can carry data of its own. A countdown carries how many seconds are left, and a finished game carries how long it took. This lesson builds a small game round as a state machine: one enum value, moved from variant to variant by buttons and a clock.
Contents
button1 Held -> chip start
button2 Held -> chip finish
chip sign -> decal Text
Code
enum Phase { Lobby, Countdown(int), Playing { started: int }, Over { seconds: int } }
@left in start: exec
@left in finish: exec
var phase: Phase = Phase.Lobby
@right out sign = match phase {
Lobby => "Press start",
Countdown(n) => "Starting in ${n}",
Playing { .. } => "Go!",
Over { seconds } => "Finished in ${seconds} seconds",
}
on start {
if phase is Phase.Lobby || phase is Phase.Over {
phase = Phase.Countdown(3)
}
}
on finish {
let Playing { started } = phase else { return }
phase = Phase.Over { seconds: GetUnixTime() - started }
}
on Clock(interval = 1.0) {
match phase {
Countdown(n) => {
if n <= 1 {
phase = Phase.Playing { started: GetUnixTime() }
} else {
phase = Phase.Countdown(n - 1)
}
}
_ => {}
}
}
Countdown(int)carries one value by position, built asPhase.Countdown(3).Playing { started: int }carries a named field, built asPhase.Playing { started: ... }.- In a
matcharm,Countdown(n)names the carried valuen, andOver { seconds }names the field.Playing { .. }matches without naming anything. phase is Phase.Lobbyistruewhilephaseis that variant.let Playing { started } = phase else { return }takes the data out ifphaseisPlaying, and otherwise runs theelse, which must leave the handler, here withreturn. After it,startedis ready to use.GetUnixTime()is the current time as a whole number of seconds._ => {}covers every variant not named above it.
Press start. What does the sign show over the next few seconds? What
happens if you press finish before the countdown ends?
Run
- Compile the chip and paste it in-game. Place two Buttons and a brick with a Text Decal.
- Wire the Buttons’ Held outputs to
startandfinish, andsignto the Text Decal’s Text. - Press
start. The sign counts “Starting in 3”, 2, 1, then “Go!”. Wait a while and pressfinish. The sign shows “Finished in 7 seconds”, or however long it was. finishdoes nothing until the round is playing, andstartdoes nothing while one is running.
Under the Hood
Open the chip. phase is four Var gates: phase.__disc for the variant’s
number, and one for each piece of data, phase.__Countdown_0,
phase.__Playing_started and phase.__Over_seconds. Every variant has its
own slots, side by side. The sign’s match reads the number to choose an arm,
and each arm reads only its own variant’s slot.
Each phase = Phase.Countdown(3) writes the number and the new data with Set
Variables, and clears the slots of the other variants. The extra Var gates
named Phase.__... hold the zeros it clears them with.
is is a single Equal on the number, as is the test in let ... else. That
number is also readable as phase.Discriminant: 0 for Lobby up to 3 for
Over.
An enum has no ==, because comparing two values would mean comparing every
slot. Test the variant with is:
enum Phase { Lobby, Countdown(int) }
@left in start: exec
var phase: Phase = Phase.Lobby
on start {
if phase == Phase.Lobby {
phase = Phase.Countdown(3)
}
}
Error: [WS004] no overload for '==' on Phase, Phase
Modify
- Show the step number on a second sign:
@right out step = phase.Discriminant. It reads 0 in the lobby and 3 when the round is over. - Ignore a
finishin the first five seconds of play. After thelet ... else, addif GetUnixTime() - started < 5 { return }. - Add a
Paused { left: int }variant and a pause button that stops a countdown and keeps the seconds left. The sign’smatchstops compiling until it has aPausedarm. Pressingstartwhile paused carries on from where it stopped.
Make
Make a microwave. It is Idle, Cooking(int) with the seconds left, or
Done. A button adds ten seconds while it is idle or cooking, a Clock counts
down, and a light shows Done until a door button sends it back to Idle.
button1 Held -> chip add
button2 Held -> chip door
chip done -> light Enabled
Good to Know
GetUnixTime()counts whole seconds, so a round’s time is rounded to a second.- The Clock and the buttons start separate handlers with no order between
them. A
finishpressed in the same tick as the last countdown step may see either the countdown or the round.
See Enums, is and
if let / let else.
Next: Option and Result.