This page guides you through creating a new Scene Graph component named puzzle_component that manages a puzzle built with Scene Graph entities. Once built, place a puzzle_component on a Scene Graph entity to determine whether a puzzle consisting of descendant Scene Graph entities with triggerable components that are specified as puzzle pieces is solved.
For example, the following image is a simple puzzle you will construct in the last section of this tutorial.
The Outliner corresponding to this puzzle is shown in the next image.
Every descendant entity of Prefab_PuzzleManager is part of the puzzle managed by the Prefab_PuzzleManager's corresponding puzzle_component. The puzzle_component:
Receives events when a puzzle piece has been switched to the solved configuration.
Determines when the puzzle is solved.
Sends events down the Scene Graph hierarchy when the puzzle is solved to trigger actions corresponding to the solution.
When the player steps on the platforms and turns on both of the lights, the mesh animates and transforms.
For more information about the Verse language features used on this page, see:
Define the Puzzle Solved Event
To begin, navigate to the Verse Explorer, right-click the project name, and choose Add new Verse file to project.
Choose the template Scene Graph Component and change the Component Name to puzzle_component.
Define the
puzzle_solved_event. This is the event that is transmitted through the Scene Graph hierarchy when the puzzle is solved to trigger an action, such as opening a gate or extending a bridge so the player can move beyond the area gated by the puzzle. Define thepuzzle_solved_eventas a child class ofscene_event. This event does not require any parameters passed down the hierarchy.Versepuzzle_solved_event<public> := class(scene_event){}
Define the Puzzle Component
Next, define the puzzle_component with fields and functions to manage the puzzle and whether or not it is solved.
Add fields to track whether or not the puzzle is solved, an array of which puzzle pieces are in the solved configuration, and whether or not puzzle pieces continue to trigger after the puzzle is solved:
Versepuzzle_component := class<final_super>(component): # Is this puzzle component solved var<private> Solved<public>:logic = false # Map of puzzle pieces and whether they have been "solved" var<private> TriggerableEntities<private>:[]entity = array{} # Disable puzzle pieces triggering once puzzle is solved @editableAdd a function named
InitializeTriggerableDescendantEntitiesto initialize the list of all puzzle pieces that are part of this puzzle. This function traverses down the Scene Graph hierarchy to find all triggerable entities marked as being a puzzle piece and adds them to theTriggerableEntitiesarray.Verse# Initialize array of triggerable entities InitializeTriggereableDescendantEntities<private>()<transacts>:void= for: DescendantEntity : Entity.FindDescendantEntities(entity) DescendantEntityComponent : DescendantEntity.GetComponents() CastToTriggerable := triggerable[DescendantEntityComponent] CastToTriggerable.PuzzlePiece? do: set TriggerableEntities += array{DescendantEntity}Add a function named
DisableTriggerableComponentsto disable any triggerable components on descendant entities.Verse# Disable puzzle pieces DisableTriggerableComponents<private>():void= for: DescendantEntity : Entity.FindDescendantEntities(entity) DescendantEntityComponent : DescendantEntity.GetComponents() CastToTriggerable := triggerable[DescendantEntityComponent] CastToTriggerable.PuzzlePiece? CastToEnableable := enableable[DescendantEntityComponent] do: CastToEnableable.Disable()Add a function named
IsPuzzleSolvedthat decides whether the puzzle is in a solved state. This is done by iterating through all previously found descendant entities with a component that implements thetriggerableinterface, checking whether the associated entity is marked as a puzzle piece, and whether the entity's component that implementstriggerableis in a solved state.Verse# Decides whether puzzle is solved IsPuzzleSolved<private>()<decides><transacts>:void= for: TriggerableEntity : TriggerableEntities TriggerableEntityComponent : TriggerableEntity.GetComponents() CastToTriggerable := triggerable[TriggerableEntityComponent] CastToTriggerable.PuzzlePiece? do: CastToTriggerable.InSolvedState[]Add a function named
HandlePuzzleSolvedto perform all necessary actions once it is determined that the puzzle is solved. This includes setting theSolvedfield on this class, disabling puzzle triggerables based on the class fieldDisablePuzzleTriggerablesWhenSolved, and sending thepuzzle_solved_eventdown the Scene Graph hierarchy.Verse# Handle all necessary actions once puzzle is known to be solved HandlePuzzleSolved<private>():void= set Solved = true if (DisablePuzzleTriggerablesWhenSolved?): DisableTriggerableComponents() Entity.SendDown(puzzle_solved_event{})Next, add a function named
CheckPuzzleSolution. This is an asynchronous wrapper function for determining if the puzzle is solved withIsPuzzleSolvedand, if it is, also callsHandlePuzzleSolvedto perform the necessary actions when the puzzle is solved.Verse# Async wrapper for determining whether puzzle is solved CheckPuzzleSolved()<suspends>:void= Sleep(0.25) if (not Solved?, IsPuzzleSolved[]): HandlePuzzleSolved()Add an override for the Scene Graph component class
OnReceivefunction.Verse# Handle triggered events sent through the Scene Graph hierarchy OnReceive<override>(SceneEvent:scene_event):logic= if (TriggeredEvent := triggered_event[SceneEvent], TriggeredEntity := TriggeredEvent.TriggeredEntity?): spawn{CheckPuzzleSolved()} true falseAdd a call to
InitializeTriggerableDescendantEntitiesto the componentOnBeginSimulationfunction.Verse# Runs when the component should start simulating in a running game. OnBeginSimulation<override>():void = # Run OnBeginSimulation from the parent class before # running this component's OnBeginSimulation logic (super:)OnBeginSimulation() InitializeTriggereableDescendantEntities()
Next Steps
Next, create the Trigger Component and the Triggerable components that implement the Triggerable interface.
Final Code for Puzzle.verse
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Verse.org/SceneGraph }
using { Logging }
puzzle_solved_event<public> := class(scene_event){}
# Scene Graph component handling puzzle component triggered events and when the puzzle is solved.
puzzle_component := class<final_super>(component):