Avant de vous lancer dans l'écriture du code Verse pour le jeu de casse-tête avec lumières balisées, nous vous conseillons de réfléchir sur la méthode à utiliser pour obtenir le résultat escompté. Dans cette rubrique, nous vous expliquons comment aborder la création d'une mécanique de casse-tête. À la fin de cette étape, vous disposerez d'un pseudo-code qui représente l'algorithme permettant de créer ce jeu de casse-tête. Dans l'étape suivante, nous vous expliquerons comment mettre en œuvre cet algorithme dans Verse et l’UEFN.
Identifier les objectifs, les exigences et les contraintes
La première étape consiste à identifier vos objectifs, vos exigences et vos contraintes. Les exigences proviennent souvent de la décomposition d'objectifs plus larges en éléments plus petits.
| Objectifs |
|
| Exigences |
|
| Contraintes |
|
Diviser le problème
Maintenant que vous avez défini vos objectifs et compris les éléments dont vous avez besoin pour créer le jeu, divisez le problème en plus petits problèmes plus faciles à raisonner. Poser des questions peut vous aider à résoudre un problème plus complexe :
- Comment le joueur peut-il interagir avec le jeu de casse-tête ?
- Comment utiliser les balises de jeu pour trouver les lumières ?
- Comment définir les conditions initiales et les solutions qui peuvent être modifiées dans l'éditeur ?
- Comment mettre en correspondance l'état du jeu stocké dans une structure Verse avec les visuels du jeu ?
- Comment une interaction de joueur peut-elle mettre à jour un ensemble spécifique de lumières ?
- Comment désactiver l'interaction du joueur après la résolution du casse-tête ?
Ensuite, identifiez les dépendances potentielles entre ces divers problèmes. Dans cet exemple, les problèmes semblent être indépendants, mais cela vaut la peine d'y réfléchir :
- Les questions 1, 5 et 6 n'ont pas vraiment de connexion.
- Pour les questions 1 et 6, la façon dont le joueur interagit avec le casse-tête ne peut pas déterminer le mode de désactivation de l'interaction une fois le jeu résolu.
- Pour les questions 1 et 5, une seule interaction permet d'activer/de désactiver plusieurs lumières à la fois. Cela permettra de déterminer la structure de données à utiliser pour mettre en correspondance les interactions avec les lumières.
- La question 2 est importante en ce qui concerne la conception. Le fonctionnement de l'API Balises de jeu peut avoir un impact sur le mode de contrôle des lumières dans le code. Cette question renvoie indirectement aux questions 4 et 5, car vous devrez modifier l'état des lumières dans le jeu, et donc trouver une méthode pour y parvenir.
- Les questions 3 et 4 doivent probablement aboutir à une solution unique pour la structure de données sous-jacente pour l'état de départ, l'état actuel et la solution.
Créer des solutions potentielles
Maintenant que vous avez décomposé le problème en plusieurs petits problèmes, vous devez répondre aux questions que posent ces divers problèmes :
1. Comment le joueur peut-il interagir avec le jeu de casse-tête ?
Il existe plusieurs réponses à cette question. En général, vous pouvez faire appel à tout appareil avec lequel le joueur peut interagir et que Verse peut utiliser pour détecter l'interaction. La trousse à outils du mode Créatif comporte de nombreux appareils qui répondent à ces exigences, par exemple les déclencheurs, les boutons, mais aussi les [carrés de recolorisation](https://www.epicgames.com/fortnite/fr/creative/docs/using-color-changing-tiles-devices-in-fortnite-creative et les déclencheurs à perception.
Dans cet exemple, nous utilisons l'appareil Bouton et son événement InteractedWithEvent, lequel est distribué chaque fois que le joueur interagit avec le bouton, à condition que celui-ci soit activé. Pour en savoir plus sur les événements, consultez la rubrique Interactions des appareils de codage.
2. Comment utiliser les balises de jeu pour trouver les lumières ?
Grâce aux étiquettes de jeu, vous pouvez récupérer des groupes d'acteurs auxquels est attribuée une balise personnalisée que vous définissez dans votre code Verse.
Vous pouvez utiliser la fonction GetCreativeObjectsWithTag() pour obtenir une matrice de tous les acteurs disposant de votre balise personnalisée. La fonction renvoie une matrice de tous les objets qui implémentent creative_object_interface. customizable_light_device est la représentation Verse d'un appareil de lumière personnalisable, et une sous-classe qui implémente creative_object_interface.
La liste d'appareils renvoyée par GetCreativeObjectsWithTag() ne suit aucun ordre particulier, et l'appel de fonction peut mettre un certain temps à renvoyer tous les appareils, notamment si le niveau comporte un grand nombre d'appareils ; il est donc judicieux de stocker les lumières pour pouvoir y accéder rapidement plus tard. Cette opération, appelée mise en cache, permet généralement d'améliorer les performances. Étant donné que les lumières sont de même type, vous pouvez utiliser une matrice pour les stocker ensemble.
Vous pouvez ainsi effectuer les tâches suivantes :
- Créez une nouvelle balise appelée
puzzle_light. - Marquez toutes les lumières du casse-tête avec la balise
puzzle_light. - Appelez
GetCreativeObjectsWithTag(puzzle_light)pour obtenir tous les acteurs disposant de la balisepuzzle_light. - Déterminez quels résultats de l'appel de fonction sont un
customizable_light_device. - Enregistrez la liste des objets
customizable_light_devicedans une matrice pour pouvoir y accéder ultérieurement.
3. Comment définir les conditions initiales et les solutions qui peuvent être modifiées dans l'éditeur ?
Une lumière n'a que deux états : allumé ou éteint. Vous pouvez utiliser le type logic dans Verse pour représenter l'état allumé/éteint d'une lumière, car le type logic ne peut avoir que la valeur true ou false. Dans la mesure où le jeu comporte plusieurs lumières, vous pouvez utiliser une matrice ici aussi pour y stocker toutes les valeurs logic, et mettre en correspondance la position (ou l'index) de la matrice d'un état de lumière avec l'index de la lumière à laquelle elle est associée.
Vous pouvez alors utiliser cette matrice de valeurs logic pour définir l'état initial des lumières du casse-tête ; elle contient par ailleurs l'état actuel des lumières pendant le jeu. Vous pouvez exposer cette matrice à l'éditeur avec l'attribut @editable. Les lumières au début du jeu peuvent donc s'allumer ou s'éteindre pour correspondre visuellement à l'état stocké dans la matrice.
La solution du casse-tête doit correspondre au type utilisé pour stocker l'état actuel des lumières. Vous pouvez ainsi vérifier si le casse-tête est résolu en comparant les deux. En d'autres termes, vous disposerez de deux matrices logic modifiables, l'une représentant l'état actuel des lumières et l'autre représentant la solution du casse-tête. Vous pouvez donc modifier l'état initial des lumières du casse-tête et la solution du jeu à partir de l'éditeur, et réutiliser ainsi le casse-tête avec différentes configurations.
4. Comment mettre en correspondance l'état du jeu stocké dans une structure Verse avec les visuels du jeu ?
Vous pouvez allumer ou éteindre un appareil customizable_light_device dans le jeu en utilisant les fonctions TurnOn() et TurnOff(). Ainsi, chaque fois que vous mettez à jour l'état actuel des lumières tel qu'il est représenté par la matrice logique, vous devez également appeler les fonctions TurnOn() et TurnOff() pour mettre en correspondance les visuels du jeu et l'état du jeu.
5. Comment une interaction de joueur peut-elle mettre à jour un ensemble spécifique de lumières ?
Dans la première question, vous avez déjà déterminé que le joueur va interagir avec le casse-tête en utilisant l'appareil Bouton. Vous pouvez abonner un gestionnaire d'événements à l'événement InteractedWithEvent du bouton, qui change l'état des lumières lorsque le joueur interagit avec le bouton. Étant donné que le joueur doit utiliser plusieurs boutons, vous pouvez, ici aussi, faire appel à une matrice pour stocker les boutons ensemble.
Vous devez maintenant déterminer comment associer chaque événement de bouton distinct à l'ensemble des lumières qu'il doit activer/désactiver.
Compte tenu du fait que l'ordre des lumières dans la matrice customizable_light_device est le même que celui de la matrice logique pour représenter l'état des lumières, vous pouvez créer un mappage entre un bouton et les index des lumières sur lesquelles il aura une incidence. Ce mappage peut être représenté dans une matrice, où l'ordre des éléments correspond à l'ordre des boutons et où les éléments sont des matrices d'index.
Vous pouvez rendre la matrice modifiable afin de changer le mappage entre les boutons et les lumières dans l'éditeur, et pouvoir ainsi réutiliser le casse-tête sans modifier le code proprement dit.
6. Comment désactiver l'interaction du joueur après la résolution du casse-tête ?
Vous savez déjà que le joueur interagit avec le jeu en utilisant l'appareil Bouton, détecté par InteractedWithEvent.
Une fois le casse-tête résolu, comment cesser de recevoir les entrées du joueur afin que ce dernier ne puisse plus modifier le casse-tête ?
Il existe trois façons d'y parvenir :
- Désactivez les boutons du jeu une fois le casse-tête résolu.
- Ajoutez un champ
logicautagged_lights_puzzlequi est modifié lorsque le casse-tête est résolu. Chaque fois que l'état du jeu est mis à jour, ce champlogicdoit être vérifié pour s'assurer que le casse-tête n'a pas déjà été résolu. - Désabonnez-vous aux boutons
InteractedWithEventlorsque le casse-tête est résolu, afin que les gestionnaires d'événements ne soient plus appelés.
Nous vous recommandons d'opter pour la troisième proposition, car il s'agit d'une solution simple et efficace. En effet, vous n'avez pas besoin de créer de nouveaux champs pour vérifier l'exécution du code conditionnel. Il est également possible de réutiliser le concept de désabonnement d'un événement d'appareil dans d'autres situations. En général, nous vous recommandons de vous abonner à un événement lorsque vous souhaitez être informé de cet événement, et de vous désabonner lorsque vous n'en avez plus besoin. La procédure de désabonnement est expliquée plus loin dans ce tutoriel.
Combiner les solutions et planifier avec un pseudo-code
Maintenant que vous avez défini les solutions aux différents problèmes, combinez-les pour résoudre le problème initial. Formalisez l'algorithme pour créer la solution en utilisant un pseudo-code.
Que se passe-t-il lorsque le jeu commence ? Les lumières sont configurées. Vous vous abonnez aux boutons InteractedWithEvent, recherchez tous les appareils avec la balise puzzle_light et les mettez en cache. Vous allumez ou éteignez les lumières du jeu en fonction de l'état des lumières de départ.
OnBegin:
Result of GetCreativeObjectsWithTag(puzzle_light) is stored in the variable FoundDevices
for each Device in FoundDevices:
if Device is a Customizable Light Device:
Store the Light
if ShouldLightBeOn?:
Turn on Light
else:
Turn off Light
for each Button:
Subscribe to the Button InteractedWithEvent using the handler OnButtonInteractedWith
Une version du pseudo-code de OnButtonInteractedWith peut être similaire à celle-ci, où InteractedButtonIndex représente l'index à la matrice button_device qui correspond au bouton avec lequel le joueur a interagi. Nous vous expliquerons comment recevoir ces informations dans le gestionnaire d'événements plus tard dans ce tutoriel.
OnButtonInteractedWith:
Get lights associated with the button interacted with using the ButtonsToLights array and store in the variable Lights
# Toggle lights
for each Light in Lights:
if IsLightOn?:
Set the Light game state to off
Turn off Light
else:
Set the Light game state to on
Turn on Light
if IsPuzzleSolved():
Enable Item Spawner
for each Button:
Unsubscribe from the Button InteractedWithEvent
Le pseudo-code de IsPuzzleSolved vérifie si l'état actuel des lumières correspond à la solution. Si l'état actuel ne correspond pas à la solution, la vérification échoue et le bloc if IsPuzzleSolved du pseudo-code ci-dessus n'est pas exécuté. Si l'état actuel ne correspond pas à la solution, alors la vérification fonctionne et le bloc if IsPuzzleSolved est exécuté.
IsPuzzleSolved:
for each Light:
if IsLightOn is not equal to IsLightOnInSolution
fail and return
succeed (réussite)
Vous venez de développer votre propre algorithme.
Étape suivante
Dans l'étape suivante de ce tutoriel, vous allez traduire cet algorithme en langage de programmation Verse et tester votre projet.