Dans cette étape du tutoriel Créer un jeu de casse-tête avec séquences de lumières balisées, vous allez apprendre à détecter le moment où le joueur résout le casse-tête afin de pouvoir faire apparaître un objet et éviter toute autre interaction avec le jeu.
Détecter la résolution d'un casse-tête
Dans cette rubrique, nous vous expliquons comment détecter le moment où le joueur résout le casse-tête en trouvant la bonne combinaison de lumières. Une fois le casse-tête résolu, le générateur d'objets doit être activé pour générer l'objet correspondant.
Procédez comme suit pour détecter le moment où le joueur résout le casse-tête :
- Ajoutez un champ
item_spawner_devicemodifiable nomméItemSpawnerà la classetagged_lights_puzzle, pour représenter le générateur d'objets.@editable ItemSpawner : item_spawner_device = item_spawner_device{} - Ensuite, définissez l'état dans lequel les lumières doivent se trouver pour résoudre l'énigme. La représentation de l'état des lumières étant une matrice
logic, l'état résolu des lumières doit aussi être une matricelogicpour comparer facilement les deux. Créez un champ de matricelogicmodifiable nomméSolvedLightsStatesur la classetagged_lights_puzzle. Dans cet exemple, le joueur doit allumer toutes les lumières pour résoudre l'énigme. Initialisez donc chaque élément avec la valeurtruepour représenter la lumière allumée.@editable SolvedLightsState : []logic = array{true, true, true, true} - Enregistrez le fichier dans Visual Studio Code.
- Dans la barre d'outils de l'UEFN, cliquez sur Générer les scripts Verse pour mettre à jour votre appareil Verse dans le niveau.
- Dans l'Organiseur, sélectionnez l'appareil tagged_lights_puzzle pour ouvrir le panneau Détails correspondant.
- Dans le panneau Détails, définissez la propriété Générateur d'objets sur l'appareil Générateur d'objets qui se trouve dans le niveau.
- Ensuite, développez le code qui vérifie si le
LightsStateactuel correspond auSolvedLightsState. Ajoutez une nouvelle méthode appeléeIsPuzzleSolved()à la classetagged_lights_puzzle. Cette méthode doit réussir si l'énigme est résolue et échouer si elle ne l'est pas, afin d'informer l'appelant du résultat de la vérification. Cela signifie que la méthode doit être marquée comme faillible à l'aide du spécificateurdecides. Dans la mesure où la méthode possède le spécificateurdecides, elle doit aussi posséder le spécificateurtransactsafin que les actions exécutées par cette méthode puissent être annulées (comme si elles n'avaient jamais été effectuées) en cas d'échec de la méthode.IsPuzzleSolved()<decides><transacts> : void = Logger.Print(“Checking if puzzle is solved”)Verse utilise la réussite/échec pour prendre des décisions. Pour en savoir plus sur la façon dont Verse utilise l'échec, consultez la rubrique Échec.
- Quand l'appareil doit-il vérifier si le casse-tête a été résolu ? L'appareil doit vérifier si le casse-tête a été résolu lorsque la matrice
LightsStatevient d'être mise à jour au sein de la méthodeToggleLights(). Une fois que l'expressionfora terminé la mise à jour de la matriceLightsState, appelez la méthodeIsPuzzleSolved[]pour déterminer si le casse-tête est résolu et générer ainsi un élément (en appelantItemSpawner.Enable()). Dans la mesure oùIsPuzzleSolved[]est une expression faillible (raison pour laquelle la méthode utilise[]plutôt que()lorsque vous l'appelez), elle doit être appelée dans un contexte d'échec. Dans cet exemple, le contexte d'échec est une expressionif. Vous pouvez donc exécuter des expressions de manière conditionnelle en fonction de la résolution du casse-tête.ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices IsLightOn := LightsState[LightIndex] Light := Lights[LightIndex] do: Logger.Print("Turning light at index {LightIndex} {if (IsLightOn?) then "Off" else "On"}") NewLightState := if (IsLightOn?): Light.TurnOff() false else: Light.TurnOn() true if (set LightsState[LightIndex] = NewLightState): Logger.Print("Updated the state for light at {LightIndex}") if (IsPuzzleSolved[]): Logger.Print("Puzzle solved!") ItemSpawner.Enable() - Ensuite, configurez la méthode
IsPuzzleSolved()de sorte à détecter la résolution de l'énigme. Dans la mesure oùIsPuzzleSolved()est un contexte d'échec, vous pouvez utiliser des expressions faillibles dans le corps de la méthode sans avoir à utiliser un autre contexte d'échec, comme une expressionif. Dans ce cas, vous devez vérifier si l'état de chaque lumière est le même que celui de l'énigme résolue. Pour tester si deux valeurslogicsont identiques, vous pouvez utiliser l'opérateur d'égalité=, qui est une expression faillible. Dès que le système détecte que deux valeurs en cours de vérification ne sont pas les mêmes, l'expression échoue. La méthode échoue donc elle aussi et revient au contexte de son appelant (en l'occurrence, l'expressionifde la méthodeToggleLights()).IsPuzzleSolved()<decides><transacts> : void = Logger.Print(“Checking if puzzle is solved”) for: LightIndex -> IsLightOn : LightsState IsLightOnInSolution := SolvedLightsState[LightIndex] do: IsLightOn = IsLightOnInSolution - Enregistrez les modifications dans Visual Studio Code.
- Dans la barre d'outils de l'UEFN, cliquez sur Générer les scripts Verse pour compiler votre code.
- Cliquez sur Jouer dans la barre d'outils de l'UEFN pour tester le niveau.
Lorsque vous testez votre niveau avec les paramètres indiqués dans cet exemple, une seule interaction avec tous les boutons doit résoudre le casse-tête et générer l'objet.

Désactiver l'interaction avec le bouton une fois le casse-tête résolu
Une fois que le joueur a terminé le casse-tête, il ne doit plus pouvoir interagir avec les boutons ou allumer ou éteindre les lumières. Dans cette section, nous vous expliquons comment vous désabonner d'un événement afin que votre gestionnaire d'événements ne soit plus appelé lorsqu'un joueur interagit avec le bouton.
Lorsque vous appelez Subscribe() sur un événement d'appareil, l'appel de fonction génère un résultat cancelable. L'appel de Cancel() sur une variable cancelable désabonne la fonction qui gère l'événement, de sorte que la fonction n'est plus appelée lorsque l'événement est distribué.
Procédez comme suit pour supprimer les interactions entre les boutons une fois le casse-tête résolu :
- Ajoutez un champ de variable de matrice
cancelablenomméButtonSubscriptionsà la classetagged_lights_puzzlepour stocker le résultat de l'abonnement à l'événement de chaque bouton, puis initialisez le champ à l'aide d'une matrice vide.var ButtonSubscriptions : []cancelable = array{} - Comme il s'agit de la dernière instruction de l'expression
for, les valeurs de retour de toutes les itérations réussies sont collectées dans une matrice du type de l'expression renvoyée. Comme nous l'avons expliqué précédemment, le type de retour d'un appel d'événementSubscribeestcancelable. Les résultatsforsont appliqués à ToggleLights dans une matrice decancelable([]cancelable). Cela correspond au typeButtonsSubscription, vous pouvez donc affecter le résultat de l'expressionforà la matriceButtonsSubscription. Ajoutez le code suivant dans la fonctionOnBegin, aprèsSetupPuzzleLights:OnBegin<override>()<suspends> : void = SetupPuzzleLights() set ButtonSubscriptions = for: ButtonIndex -> Button : Buttons LightIndices := ButtonsToLights[ButtonIndex] do: Button.InteractedWithEvent.Subscribe(button_event_handler{Indices := LightIndices, PuzzleDevice := Self}.OnButtonPressed) - Enfin, n'oubliez pas que les boutons doivent être désactivés pour que le joueur ne puisse plus modifier le
LightsState. Pour cela, il est nécessaire de désabonner les gestionnairesInteractedWithEventde chaque bouton avec un appel à leur abonnementcancelable. CesButtonSubscriptionsont été enregistrés lors de la création des gestionnaires d'événements dansOnBegin. Il ne vous reste plus qu'à itérer cette matrice et à appeler l'annulation de chaqueButtonSubcription:ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices IsLightOn := LightsState[LightIndex] Light := Lights[LightIndex] do: Logger.Print("Turning light at index {LightIndex} {if (IsLightOn?) then "Off" else "On"}") NewLightState := if (IsLightOn?): Light.TurnOff() false else: Light.TurnOn() true if (set LightsState[LightIndex] = NewLightState): Logger.Print("Updated the state for light at {LightIndex}") if (IsPuzzleSolved[]): Logger.Print("Puzzle solved!") ItemSpawner.Enable() for (ButtonSubscription : ButtonSubscriptions): ButtonSubscription.Cancel() - Enregistrez les modifications dans Visual Studio Code.
- Dans la barre d'outils de l'UEFN, cliquez sur Générer les scripts Verse pour compiler votre code.
- Cliquez sur Jouer dans la barre d'outils de l'UEFN pour tester le niveau.
Avec les propriétés par défaut, une seule interaction avec tous les boutons doit résoudre le casse-tête, générer l'objet et désactiver les autres interactions avec les boutons.
Étape suivante
Dans la dernière étape de ce tutoriel, vous découvrirez le script complet de ce tutoriel et pourrez obtenir des conseils pour modifier davantage l'exemple.