There are two puzzles created using Verse, the first is the Tagged Lights Puzzle. The Tagged Lights puzzle is used in the hidden room behind the stairs in the sub basement.
You can copy and paste the code from the last section of the tutorial, but it’s strongly recommended that you build the puzzle piece-by-piece to get an understanding for how the Verse language works.
The second puzzle uses a hard-coded logic key to check each switch device to ensure the right switch has been triggered in the proper sequence.
When the proper switch is triggered, a success sound accompanies the switch. Likewise, a failure sound and message are triggered when the wrong switch is turned on during the sequence. A final success sound and message are played, and four item spawners are activated when the puzzle is solved.
You can use an array to check valid and invalid states, as well as trigger any device connected to a state. For this example, the answer key was hard-coded to help those new to coding understand what the code is doing.
Set Up the Puzzle Devices
For this puzzle you’ll need the following devices:
4 x Switch Device
1 x Trigger Device
1 x Verse Device
Rename your Item Spawners with the item they spawn.
Switch Device
Place a Switch device on the wall next to the door and set the following options
| Option | Value | Explanation |
|---|---|---|
Device Model | Circuit Breaker | For this puzzle we want players to flip the circuit breaker. |
Sound | False | Audio devices will play different sound cues for valid, invalid, and successful puzzle states. |
Interaction Time | 0.1 | The interaction time should be immediate. |
Interaction Radius | 1.0 | The player must be standing within one tile space in front of the switch to interact with it. |
Check State at Game Start | False | The Verse device is going to run this check instead. |
Copy three more Switch devices on the wall and place them in a row.
Audio Device
In the center of the square place an Audio device. Set the Audio options to the following.
| Option | Value | Explanation |
|---|---|---|
Restart Audio when Activated | True | You want the audio to be able to play more than once and start from the beginning each time. |
Play on Hit | False | The Verse device is going to trigger the Audio device. |
Copy two more Audio devices. Rename the devices and add a sound cue to each:
Valid - For the Valid Audio device play, Match_Round_Change_01_Cue.
Invalid - For the Invalid Audio device play, Player_Checkpoint_Trigger_Cue.
Completed - For the Completed Audio device play, CTF_Return_Team_Cue
Trigger Device
To the right of the switches, place the Trigger device and set the following options.
| Option | Value | Explanation |
|---|---|---|
Visible In Game | False | This device does not need to be visible in the game. |
Enabled on Game Start | False | The Verse device is going to control the Trigger device. |
Triggered By Player | False | The Verse device is going to control the Trigger device. |
Triggered by Vehicles | False | The Verse device is going to control the Trigger device. |
Triggered by Sequencers | False | The Verse device is going to control the Trigger device. |
Triggered by Water | False | The Verse device is going to control the Trigger device. |
Times Can Trigger | True, 10 | You want the trigger to be able to be used more than once in the puzzle |
Trigger VFX | False | There isn’t a need for the visual effects. |
Trigger SFX | False | The Audio devices will control the sound. |
Rename the device Invalid Trigger.
HUD Message Device
Set up the first HUD Message device using the following options.
| Option | Value | Explanation |
|---|---|---|
Message | Invalid HUD Message:
FindItems HUD Message:
| These messages for the puzzle cover the failure and success states. |
Display Time | Invalid HUD Message - 3.0 Completed HUD Message - 5.0 | The amount of time messages display for. |
Afterward, translate the HUD Message device outside of the basement wall so it’s not visible in the room and copy it.
Rename each of the HUD MEssage devices:
Find Items HUD Message
Invalid HUD Message
Verse Device
Now you’re ready to create the Verse program that controls the puzzle. Create a new Verse device named switch_state_puzzle using Verse Explorer, and drag the device into the level. (For steps on how to create a new Verse device, see Create Your Own Device Using Verse.)
Puzzle Design
Turning on switches in the correct sequence allows players to move past this point of the escape room.
When the player turns on a switch in the correct sequence a bell sounds. If the wrong switch is turned on, a buzzer sounds and resets the switches. Invalid states cause a message to pop up, and successfully completing the puzzle plays a success sound, displays a helpful message and spawns items.
You can visualize the logic of the puzzle using the flowchart below.
Click image to enlarge.
The correct solution to the puzzle is shown in the table below.
| Puzzle Solution Matrix | ||||
|---|---|---|---|---|
Switches | 2 | 3 | 1 | 4 |
1 | X | |||
2 | X | X | ||
3 | X | X | X | |
4 | X | X | X | X |
Verse Language Features Used
if,then,else: With theif,then, andelseexpressions you can find valid and invalid states for each switch device and other devices dependent upon states.failure: Failure contexts are used to decide the current state of the puzzle and its solution.for: Theforexpression is used to iterate over each switch in the puzzle and perform operations on them.
APIs Used
Editable Properties: Multiple Verse-authored device properties are exposed to UEFN so you can customize them in the editor. You’ll be able to create new puzzle configurations by changing these properties.
Device Events: The buttons’
InteractedWithEventare used to control the game state.
Switch Interaction
Think about the steps required to execute the puzzle. First you’ll want to check if the Verse device registers an event when a player checks the box. To accomplish this, write pseudocode first to prove the interaction concept.
Underneath the switch_state_puzzle class definition, add the following editable fields.
An editable array of type
switch_devicenamedSwitches. This will refer to all your switches in the puzzle.A variable array of type
cancelablenamedSwitchSubscriptions. This holds a reference to each switch_device subscription that you can use to reset the switches.Verseswitch_state_puzzle := class(creative_device): @editable Switches : []switch_device = array{} #References the switches players can interact with var SwitchSubscriptions : []cancelable = array{}
In the same file, create a new class called
switch_event_handler.In this class you’ll identify the Verse device and the switches.Add a new method
OnSwitchPressed()to theswitch_event_handlerclass. This method checks the Verse device against player interaction by callingCheckSequence()in theitem_switch_puzzleclass. It also prints Clicked everytime a switch is interacted with.Verse## An event handler class to handle switch interactions ## This event handler is attached to events in the loop above switch_event_handler := class(): PuzzleDevice : item_switch_puzzle Switch : switch_device OnSwitchPressed(InPlayer : agent) : void = Print("Clicked") PuzzleDevice.CheckSequence(InPlayer)
Add a Print Logger
One way to check whether your code is successful or not is to print to a log. This allows you to see visually which parts of your code work as planned by printing messages. Add the print logger above the creative device class.
Print<native><public>(Message:[]char, Level:log_level):void
Referencing Switches
Now you need a way to reference your switch devices in the puzzle. Referencing the switch devices provides a way for you to loop through all switches and add event handlers to each switch when the game is running.
In
OnBegin()in theswitch_state_puzzleclass, add aforexpression to iterate through eachSwitchin theSwitchesarray. Retrieve the index of eachSwitchand store it in a variableSwitchIndex.Add a Print function under the for expression that identifies the switch being interacted with during running time by typing Switch {SwitchIndex} added in the Print command.
Because the puzzle solution is based on a certain order of switch states, you need to check if the puzzle is solved whenever any switch changes state. To do this, you’ll use the
switch_event_handlerclass you defined earlier to listen for two different events per switch. For each switch, create two subscriptions, one for the switchesTurnedOnEvent, and one for the switchesTurnedOffEvent. Subscribe both events to theOnSwitchPressed()function of yourswitch_event_handlerclass. Pass a reference to both theswitch_state_puzzleand the currentSwitch.Verse## Runs when the device is started in a running game OnBegin<override>()<suspends>:void= Print("Loading Switch Puzzle") # Looping through each switch and adding event handlers for each switch for (SwitchIndex -> Switch : Switches): Print("Switch {SwitchIndex} added") Switch.TurnedOnEvent.Subscribe(switch_event_handler{PuzzleDevice := Self, Switch := Switch}.OnSwitchPressed) Switch.TurnedOffEvent.Subscribe(switch_event_handler{PuzzleDevice := Self, Switch := Switch}.OnSwitchPressed)Save the script in Visual Studio Code, and in UEFN, click Verse -> Build Verse Code.
When testing your level, everytime you turn a switch on or off, you should see printed both the index of the switch you interacted with and word Clicked.
Puzzle States
Each switch in the puzzle can have two states, valid and invalid.
To solve the puzzle, the player needs to toggle the switches on in a certain order. To implement this order in code, you need to define a sequence of valid states for each switch and check this sequence whenever a player updates the switch state..
Add a new method
ValidState()to theswitch_state_puzzleclass. This method takes a string and plays an audio clip whenever a player flips a switch to a valid state, giving them audio feedback to know they’re on the right track.In
ValidState(), print out theStatestring that was passed and callPlay()on theValidAudioPlayeryou set up ealier.Verse# Actions to perform when the state is valid ValidState(State : string) : void = # Play a validation sound Print("Valid {State}") ValidAudioPlayer.Play()Add a new method
InvalidState()to theswitch_state_puzzleclass. This method resets all the switches after playing a sound when the player triggers an invalid state.
# Actions to perform when the state is invalid
InvalidState(InPlayer : agent) : void =
# Play a buzz sound
# Clear all switches
Print("Invalid")
In
InvalidState(), let the player know they triggered an invalid state by printing Invalid and playing and audio clip by callingPlay()on theInvalidAudioPlayeryou set up earlier. You also need to callTrigger()on yourInvalidTrigger, andShow()yourInvalidHUDMessage.
# Actions to perform when the state is invalid
InvalidState(InPlayer : agent) : void =
# Play a buzz sound
# Clear all switches
Print("Invalid")
InvalidAudioPlayer.Play()
InvalidTrigger.Trigger()
InvalidHUDMessage.Show()
Create a for loop that subscribes to events on the switch devices. The print statement identifies which switches a player flips and the sequence the switches are flipped.
# Looping through each switch and adding event handlers for each switch
for (SwitchIndex -> Switch : Switches):
Print("Switch {SwitchIndex} added")
Switch.TurnedOnEvent.Subscribe(switch_event_handler{PuzzleDevice := Self, Switch := Switch}.OnSwitchPressed)
Switch.TurnedOffEvent.Subscribe(switch_event_handler{PuzzleDevice := Self, Switch := Switch}.OnSwitchPressed)
In a for loop, loop through all switches and turn each one off. Because the Switch’s TurnOff() method requires a player instigator, pass in the player who triggered the invalid state.
## Looping through the switches and turning each one off
for (SwitchIndex -> Switch : Switches):
Switch.TurnOff(InPlayer)
Save your code and go back to UEFN and select Verse > Build Verse Code.
Next you need to create the logic in the item_switch_puzzle class that loops through each switch and validates its state against the puzzle matrix to determine which state (valid or invalid) the switch flip falls under.
Sorting Switch States
Checking the validity of a switch flip is accomplished by creating a CheckSequence method that uses a for expression to check the current state of the switch. To define whether a switch’s state change is valid or not you can use an if statement to define which switch flip is valid in the sequence and which switch flips are not.
Add a new method
CheckSequence(). This method takes the player as instigating the switch state changes and an array of logic values corresponding to switch states. InCheckSequence(), create aforloop to iterate through each switch in theSwitchesarray. Get the index of each switch in the array and save it in a variableSwitchIndex. In the for loop, check each switch state by callingGetCurrentState[]. Then print the state of the switch to the log.Verse# Function to validate the sequence of the switches CheckSequence(InPlayer : agent) : void = for (SwitchIndex -> Switch : Switches): if(Switch.GetCurrentState[]) then Print("{SwitchIndex} On") else Print("{SwitchIndex} Off")
Now you need to create a sequence of states to check against using CheckSequence(). To do this, you’re going to add new functionality to the switch_event_handler’s OnSwitchPressed() method.
Sequence States
Create the sequence for the switch states using arrays. Each array checks the validity of the sequence the switches are flipped. Log the sequence of the player’s actions on the switches using the print logger to log whether the switches have been Clicked and whether the sequence is valid by printing the number of the sequence to the logger (“One”, “Two”, “Three”, and “Four”).
In
OnSwitchPressed(), inside anifstatement, callCheckSequence()passing both the player and a new array of logic values. This new array should correspond to your series of switches, withfalsevalues representing off switches, andtruevalues representing on switches. Set the switch you want players to press first totrue, and all other values to false. If the call toCheckSequence[]succeeds, callValidState()passing in "One" to represent the first switch pressed.VerseOnSwitchPressed(InPlayer : agent) : void = Print("Clicked") PuzzleDevice.CheckSequence(InPlayer)Hardcode the answer key for the switch flips for each of the switches in your puzzle, in the order you want them to be pressed.
Verseif: # check for valid states and hardcodes the validation of the states # [off],[off],[on],[off] State One not Switches[0].GetCurrentState[] not Switches[1].GetCurrentState[] Switches[2].GetCurrentState[] not Switches[3].GetCurrentState[] then: ValidState("One")Finally, add an
elseexpression at the end that callsInvalidState(). This will happen if any of the calls toCheckSequence[]fail.Verseelse: # It isn't a valid state, so it's invalid InvalidState(InPlayer)Your
switch_event_handlercode should now look like the following.Verse# Function to validate the sequence of the switches CheckSequence(InPlayer : agent) : void = for (SwitchIndex -> Switch : Switches): if(Switch.GetCurrentState[]) then Print("{SwitchIndex} On") else Print("{SwitchIndex} Off") if: # check for valid states and hardcodes the validation of the states # [off],[off],[on],[off] State One not Switches[0].GetCurrentState[]Save your code and go back to UEFN and select Verse > Build Verse Code.
Now as you turn on switches in the game, the log will print:
Loading Switch Puzzle - when the game starts
Switch {SwitchIndex} added - when a switch is added to the loop
Clicked - when a player turns on a switch
Valid {State} - if the player turns on the right switch in the sequence order
Invalid - if the player turns on the wrong switch
If the log is reporting correctly to your switch flips, you’re ready to add more editable devices to the item_switch_puzzle class and make each of these states do something.
Adding Devices
Once the puzzle has been successfully completed by the player and the puzzle has looped through the switches’ ValidStates all the way to the CompletedState, the success result should do something, like grant items.
The same is true for the InvalidStates. If a player gets the puzzle wrong, the script should account for that and let players know they need to try again. To accomplish this, you need to add additional devices to the item_switch_puzzle class.
By adding editable devices to your script, the devices show up in the Verse Device’s User Options where you can connect the devices to the Verse Device so they function in the game as it’s written in the Verse script.
Add the following @editable devices under the item_switch_puzzle:
Verse@editable InvalidTrigger : trigger_device = trigger_device{} @editable InvalidHUDMessage : hud_message_device = hud_message_device{} @editable InvalidAudioPlayer : audio_player_device = audio_player_device{}Add a new method
CompletedState()to theitem_switch_puzzleclass. This method handles the actions performed when the puzzle is completed.Verse## Actions to perform when the puzzle is completed CompletedState() : void = # Play a success sound # Set all switches to disabled # Spawn items on the attached item spawners Print("Completed")Add a for expression to the
CompletedState()method that iterates through each item spawner inItemSpawners. Enable each item spawner withEnable(), then callSpawnItem()to grant the player the reward for solving the puzzle.Verse## Looping through the Item Spawners allowing you to call each Item Spawner to enable and spawn its item for (ItemSpawnerIndex -> ItemSpawner : ItemSpawners): ItemSpawner.Enable() ItemSpawner.SpawnItem()
Once the puzzle has been completed successfully, you need to call
Play()onCompletedAudioPlayeryou set up earlier, spawn the metal pieces on the Item Spawners using theItemSpawnerIndexand the callEnable1andSpawnItem. Inform the player they need to search for the newly spawned items by callingShow()on theFindItemsHUDMessage. Additionally, you don’t want the player to continue interacting with your switches. Add a second for expression to loop through each switch inSwitchesand disable them by callingDisable().Verse# Actions to perform when the puzzle is completed CompletedState() : void = # Play a success sound # Set all switches to disabled # Spawn items on the attached item spawners Print("Completed") # Looping through the Item Spawners allowing you to call each Item Spawner to enable and spawn its item for (ItemSpawnerIndex -> ItemSpawner : ItemSpawners):Save your code and go back to UEFN and select Verse > Build Verse Code.
Now these devices have been added to the Item Switch Puzzle device in UEFN.
Select Devices
All the @editable devices are added to the Verse device. Now you need to attach the devices you pulled out to create the puzzle to the Verse device. To do this select item_switch_puzzle in the Outliner and all the device slots are visible in the Details panel. You just have to match the device to the slot.
Add the puzzle Switch devices to the Switches 4 array elements under Item Switch Puzzle.
Add the Invalid Trigger to the InvalidTrigger slot
Add the Invalid HUD Message to the InvalidHUDMessage slot.
Add the Invalid Audio Player to the InvalidAudioPlayer slot.
Add the Valid Audio Player to the ValidAudioPlayer slot.
Add the Find HUD Message device to the FindHUDMessage slot.
Add the Completed Audio Player to the CompletedAudioPlayer slot.
Add the Item Spawners to the ItemSpawners 4 array elements.
Uncheck the Visible in Game option to hide the Verse Device during the game.
Now you’re ready to playtest your level and see how the puzzles enhance the escape room experience.
Next Section
With the Switch State Puzzle working, you're ready to create the automatic teleporting Verse script that takes players from staring in the opening cinematic to the holding room in the cabin's sub-basement once the cinematic finishes playing.