Projet de référence pour les plantes

*Ce contenu est traduit en utilisant l'IA (Beta) et peut contenir des erreurs. Pour consulter cette page en anglais, clique ici.

La plante est une expérience de référence où les joueurs plantent et arrosent des graines, afin qu'ils puissent récolter et vendre les plantes résultantes plus tard.

Plant project banner

Le projet se concentre sur des cas d'utilisation communs que vous pourriez rencontrer lors du développement d'une expérience sur Roblox.Lorsque cela est applicable, vous trouverez des notes sur les compromis, les concessions et la raison des différents choix d'implémentation, afin que vous puissiez prendre la meilleure décision pour vos propres expériences.

Obtenir le fichier

  1. Accédez à la page d'expérience Plante.
  2. Cliquez sur le bouton et Éditer dans Studio .

Cas d'utilisation

La plante couvre les cas d'utilisation suivants :

  • Données de session et persistance des données du joueur
  • Gestion des vues d'interface utilisateur
  • Réseau client-serveur
  • Expérience utilisateur pour la première fois (FTUE)
  • Achats de devises dures et souples

En outre, ce projet résout des ensembles de problèmes plus étroits qui sont applicables à de nombreuses expériences, notamment :

  • Personnalisation d'une zone dans l'endroit associé à un joueur
  • Gérer la vitesse de déplacement du personnage joueur
  • Créer un objet qui suit les caractères autour
  • Détecter dans quelle partie du monde se trouve un personnage

Notez qu'il y a plusieurs cas d'utilisation dans cette expérience qui sont trop petits, trop nichés ou ne démontrent pas de solution à un défi de conception intéressant ; ceux-ci ne sont pas couverts.

Structure du projet

La première décision lors de la création d'une expérience est de décider comment structurer le projet, qui comprend principalement où placer des instances spécifiques dans le modèle de données et comment organiser et structurer les points d'entrée pour le client et le serveur.

Modèle de données

La table suivante décrit les services de conteneur dans les instances de modèle de données dans lesquelles ils sont placés.

ServiceLes types d'instance
Workspace

Contient des modèles statiques représentant le monde 3D, plus précisément des parties du monde qui ne appartiennent à aucun joueur.Vous n'avez pas besoin de créer, de modifier ou de supprimer dynamiquement ces instances au moment de l'exécution, donc il est acceptable de les laisser ici.:

Il y a aussi un modèle vide Folder , auquel les modèles de ferme des joueurs seront ajoutés au moment de l'exécution.

Lighting

Effets atmosphériques et de lumière.

ReplicatedFirst

Contient le plus petit sous-ensemble possible d'instances nécessaires pour afficher l'écran de chargement et initialiser le jeu.Plus il y a d'instances placées dans ReplicatedFirst, plus longtemps il faut attendre qu'elles se reproduisent avant que le code dans ReplicatedFirst puisse s'exécuter.:

  • Dans le dossier Instances existe l'interface de chargement GUI.:
  • Dans le dossier Source existe le code de la page de chargement et le code nécessaire pour attendre que le reste du jeu se charge.Le start``Class.LocalScript est le point d'entrée pour tout le code côté client dans le projet.
ReplicatedStorage

Sert de conteneur de stockage pour toutes les instances pour lesquelles l'accès est requis à la fois sur le client et sur le serveur.:

  • Dans le dossier dépendances il existe quelques bibliothèques tierces utilisées par le projet.:
  • Dans le dossier Instances il existe une large gamme d'instances préfabriquées utilisées par différentes classes dans le jeu.:
  • Dans le dossier Source il existe tout le code non requis pour le processus de chargement qui doit être accessible à la fois du client et du serveur.
ServerScriptService

Contient une Script servant de point d'entrée pour tout le code côté serveur dans le projet.

ServerStorage

Sert de conteneur de stockage pour toutes les instances qui ne doivent pas être répliquées au client.:

  • Dans le dossier Instances il existe un modèle de modèle ferme .Une copie de ceci est placée dans Workspace lorsque le joueur rejoint le jeu, où elle sera répliquée à tous les joueurs.:
  • Dans le dossier Source il existe tout le code qui est exclusif au serveur.
SoundService

Contient les objets Sound utilisés pour les effets sonores dans le jeu.En dessous de SoundService, ces objets Sound n'ont pas de position et ne sont pas simulés dans l'espace 3D.

Points d'entrée

La plupart des projets organisent le code à l'intérieur d'un réutilisable ModuleScripts qui peut être importé dans l'ensemble de la base de code.ModuleScripts sont réutilisables mais ne s'exécutent pas par eux-mêmes ; ils doivent être importés par un Script ou LocalScript .De nombreux projets Roblox auront un grand nombre d'objets Script et LocalScript, chacun appartenant à un comportement ou à un système spécifique dans le jeu, créant plusieurs points d'entrée.

Pour le microjeu Plante, une approche différente est mise en œuvre via une seule LocalScript qui est le point d'entrée pour tout le code client, et une seule Script qui est le point d'entrée pour tout le code serveur.La bonne approche pour votre projet dépend de vos exigences, mais un seul point d'entrée fournit un meilleur contrôle sur l'ordre dans lequel les systèmes sont exécutés.

Les listes suivantes décrivent les compromis de chacune des approches :

  • A single Script and a single LocalScript cover server and client code respectively.
  • Greater control over the order in which different systems are started because all code is initialized from a single script.
  • Can pass objects by reference between systems.

Architecture de système de haut niveau

Les systèmes de premier niveau dans le projet sont détaillés ci-dessous.Certains de ces systèmes sont beaucoup plus complexes que d'autres, et dans de nombreux cas, leur fonctionnalité est abstraite à travers une hiérarchie d'autres classes.

Plant project systems architecture diagram

Chacun de ces systèmes est un "singleton", en ce sens qu'il s'agit d'une classe non instantanée initialisée par le script client ou serveur pertinent start.Vous pouvez en savoir plus sur le modèle singleton plus tard dans ce guide.

Serveur

Les systems suivants sont associés au serveur.

SystèmeAvertissement
Réseau
  • Crée toutes les instances RemoteEvent et RemoteFunction .:
  • Expose des méthodes pour l'envoi et l'écoute de messages du client.:
  • Valider le type pour les arguments reçus du client en temps d'exécution
Serveur de données du joueur
  • Sauvegarde et charge les données persistantes du joueur en utilisant DataStoreService .:
  • Stocke les données du joueur dans la mémoire et réplique les mutations au client.:
  • Expose des signaux et des méthodes pour s'abonner, interroger et mettre à jour les données du joueur.
Marché
  • Gère les transactions de devises douces du client.
  • Expose une méthode pour vendre des plantes récoltées.
Gestionnaire de groupe de collision

Attribue les modèles de personnage de joueur aux groupes de collision .:

  • Configure des groupes de collision afin que les personnages des joueurs ne puissent pas se heurter aux wagons de plantes.
Serveur de gestionnaire de ferme
  • Recrée le modèle de ferme d'un joueur à partir de ses données de joueur lorsqu'il rejoint le jeu.:
  • Élimine le modèle de ferme lorsqu'un joueur part.:
  • Mise à jour des données du joueur lorsque la ferme d'un joueur est modifiée:
  • Expose une méthode pour accéder à la classe Ferme associée à un joueur donné.
Conteneur d'objets de joueur
  • Crée différents objets associés à la durée de vie d'un joueur et fournit une méthode pour les récupérer.
Joueurs de tag
Serveur FtueManager
  • Pendant l'FTUE, exécute chaque étape et attends qu'elle soit terminée.
Générateur de caractères
  • Réapparition des personnages lorsqu'ils meurent.Remarquez que Players.CharacterAutoLoads a été désactivé afin que la génération soit suspendue jusqu'à ce que les données du joueur soient chargées.

Client

Les systèmes suivants sont associés au client.

SystèmeAvertissement
Réseau
  • Attend que le serveur crée toutes les instances RemoteEvent et RemoteFunction.:
  • Expose des méthodes pour l'envoi et l'écoute de messages vers et depuis le serveur.:
  • Applique la validation du type de paramètre d'exécution:
  • Exécute pcall() sur les fonctions à distance.
Client de données joueur
  • Stocke les données du joueur local dans la mémoire.:
  • Expose des méthodes et des signaux pour rechercher et s'abonner aux modifications des données du joueur.
Client du marché
  • Expose une méthode pour demander au serveur d'acheter un article pour une devise douce.
Gestionnaire de saut de marche locale
  • Expose des méthodes pour modifier le WalkSpeed ou JumpHeight d'un personnage via des multiplicateurs pour éviter les conflits lors de la modification de ces valeurs à partir de plusieurs endroits.
Clienteur de ferme
  • Écoute les balises spécifiques CollectionService qui sont appliquées aux instances et crée des « composants » qui ajoutent un comportement à ces instances.Un « composant » fait référence à une classe créée lorsqu'une balise CollectionService est ajoutée à une instance et détruite lorsqu'elle est supprimée ; ces derniers sont utilisés pour les invites CTA dans la ferme et diverses classes télégraphiant l'état de la ferme au joueur.
Installation de l'interface utilisateur
  • Initialise toutes les couches d'interface utilisateur.:
  • Configurez certaines couches pour qu'elles soient visibles uniquement dans des sections physiques du monde du jeu.:
  • Relier un effet de caméra spécial pour quand les menus sont activés.
Clienteur FtueManager
  • Configure les étapes FTUE sur le client.
Course de caractères
  • Utilise LocalWalkJumpManager pour augmenter WalkSpeed lorsqu'un personnage de joueur est en dehors de sa ferme. >

Communication entre client et serveur

La plupart des expériences Roblox impliquent une certaine forme de communication entre le client et le serveur.Cela peut inclure la demande du client au serveur d'effectuer une certaine action et la réplication des mises à jour du serveur au client.

Dans ce projet, la communication client-serveur est maintenue aussi générique que possible en limitant l'utilisation des objets RemoteEvent et RemoteFunction afin de réduire le nombre de règles spéciales à suivreCe projet utilise les méthodes suivantes, par ordre de préférence :

  • Réplication via le système de données du joueur.
  • Réplication via attributs.
  • Réplication via des étiquettes .
  • Messagerie directement via le module Réseau .

Réplication via le système de données du joueur

Le système de données joueur permet d'associer des données au joueur qui persiste entre les sessions de sauvegarde .Ce système fournit une réplication du client au serveur et un ensemble d'APIs qui peuvent être utilisées pour interroger des données et s'abonner aux modifications, ce qui le rend idéal pour répliquer les modifications de l'état du joueur du serveur au client.

Par exemple, plutôt que de tirer un bespoke UpdateCoins``Class.RemoteEvent pour dire au client combien de pièces il a, vous pouvez appeler le suivant et laisser le client s'abonner à celui-ci via l'événement PlayerDataClient.updated.


PlayerDataServer:setValue(player, "coins", 5)

Bien sûr, cela n'est utile que pour la réplication serveur-client et pour les valeurs que vous souhaitez persister entre les sessions, mais cela s'applique à un nombre surprenant de cas dans le projet, y compris:

  • L'étape FTUE actuelle
  • L'inventory du joueur
  • Le nombre de pièces que le joueur a
  • L'état de la ferme du joueur

Réplication via des attributs

Dans des situations où le serveur doit répliquer une valeur personnalisée au client qui est spécifique à un donné Instance , vous pouvez utiliser les attributs.Roblox réplique automatiquement les valeurs d'attribut, vous n'avez donc pas besoin de maintenir des chemins de code pour répliquer l'état associé à un objet.Un autre avantage est que cette réplication se produit en même temps que l'instance elle-même.

Cela est particulièrement utile pour les instances créées au moment de l'exécution, car les attributs définis sur une nouvelle instance avant qu'elle ne soit parentée au modèle de données se reproduiront atomiquement avec l'instance elle-même.Cela évite le besoin d'écrire du code pour "attendre" que des données supplémentaires soient répliquées via un RemoteEvent ou StringValue .

Vous pouvez également lire directement les attributs du modèle de données, du client ou du serveur, avec la méthode GetAttribute() et vous abonner aux modifications avec la méthode GetAttributeChangedSignal().Dans le projet Plante, cette approche est utilisée, entre autres, pour répliquer l'état actuel des plantes aux clients.

Réplication via des balises

CollectionService vous permet d'appliquer une balise de chaîne à un Instance. Ceci est utile pour catégoriser les instances et de répliquer cette catégorisation au client.

Par exemple, la balise CanPlant est appliquée sur le serveur pour indiquer au client qu'un pot donné est capable de recevoir une plante.

Message directement via le module réseau

Pour les situations où aucune des options précédentes ne s'applique, vous pouvez utiliser des appels réseau personnalisés via le module réseau .C'est la seule option du projet qui permet la communication client-serveur et est donc la plus utile pour transmettre les demandes du client et recevoir une réponse du serveur.

Plante utilise des appels réseau directs pour une variété de demandes client, y compris :

  • Arroser une plante
  • Semer une graine
  • Acheter un article

L'inconvénient de cette approche est que chaque message individuel nécessite une configuration personnalisée qui peut augmenter la complexité du projet, bien que cela ait été évité partout où cela a été possible, notamment pour la communication serveur-client.

Classements et singletons

Les classes dans le projet Plante peuvent être créées et détruites, comme des instances sur Roblox.Sa syntaxe de classe est inspirée de l'approche idiomatique de Lua à la programmation orientée objet avec un certain nombre de modifications pour activer le support de vérification de type strict.

Instantiation

De nombreuses classes du projet sont associées à une ou plusieurs Instances.Les objets d'une classe donnée sont créés en utilisant une méthode new() , conforme à la façon dont les instances sont créées dans Roblox en utilisant Instance.new() .

Ce modèle est généralement utilisé pour les objets où la classe a une représentation physique dans le modèle de données, et la classe étend sa fonctionnalité.Un bon exemple est BeamBetween qui crée un objet Beam entre deux objets donnés Attachment et garde ces annexes orientées afin que le rayon soit toujours dirigé vers le haut.Ces instances pourraient être clonées à partir d'une version préfabriquée dans ReplicatedStorage ou transférées dans new() en tant qu'argument et stockées à l'intérieur de l'objet sous self.

Instances correspondantes

Comme noté ci-dessus, de nombreuses classes dans ce projet ont une représentation de modèle de données, une instance qui correspond à la classe et qui est manipulée par elle.

Plutôt que de créer ces instances lorsqu'un objet de classe est instancé, le code choisit généralement de Clone() une version préfabriquée du Instance stockée sous ReplicatedStorage ou ServerStorage .Bien qu'il soit possible de sérialiser les propriétés de ces instances et de les créer à partir de zéro dans les fonctions de classe new(), le faire rendrait l'édition des objets très laborieuse et les rendrait plus difficiles à analyser pour un lecteur.De plus, le clonage d'une instance est généralement une opération plus rapide que la création d'une nouvelle instance et la personnalisation de ses propriétés en temps d'exécution.

composition

Bien que l'héritage soit possible dans Luau en utilisant métatables, le projet choisit plutôt d'autoriser les classes à s'étendre les unes aux autres par le biais de composition .Lors de la combinaison de classes par composition, l'objet « enfant » est instancié dans la méthode new() de la classe et est inclus en tant que membre sous self .

Pour un exemple de cela en action, voir la classe CloseButton qui enveloppe la classe Button.

Supprimer

De la même manière qu'un Instance peut être détruit avec la méthode Destroy(), les classes qui peuvent être instanciées peuvent également être détruites.La méthode destructeur pour les classes de projet est avec une minuscule pour la cohérence entre les méthodes de l'ensemble du code source, ainsi que pour distinguer les classes du projet et les instances Roblox.

Le rôle de la méthode destroy() est de détruire toutes les instances créées par l'objet, de couper toutes les connexions, et d'appeler destroy() sur tous les objets enfants.C'est particulièrement important pour les connexions car les instances avec des connexions actives ne sont pas nettoyées par le collecteur de déchets Luau, même si aucune référence à l'instance ou aucune connexion à l'instance ne reste.

Singletons

Les singletons, comme le nom l'indique, sont des classes pour lesquelles un seul objet peut exister à jamais.Ils sont l'équivalent des services de Roblox pour le projet Services.Plutôt que de stocker une référence à l'objet singleton et de le transmettre dans le code Luau, Plante profite du fait que la nécessité d'un ModuleScript cache sa valeur retournée.Cela signifie que la nécessité du même singleton ModuleScript à partir de différents endroits fournit de manière cohérente le même objet retourné.La seule exception à cette règle serait si différents environnements (client ou serveur) accédaient au ModuleScript .

Les singletons sont distingués des classes instantanées par le fait qu'ils n'ont pas de méthode new().Plutôt, l'objet avec ses méthodes et son état est retourné directement via le ModuleScript .Comme les singletons ne sont pas instantanés, la syntaxe self n'est pas utilisée et les méthodes sont plutôt appelées avec un point ( . ) plutôt qu'une virgule ( : ).

Inference de type strict

Luau prend en charge le saisissement progressif ce qui signifie que vous êtes libre d'ajouter des définitions de type optionnelles à certaines ou à toutes vos modifications de code.Dans ce projet, strict le contrôle de type est utilisé pour chaque script.C'est l'option la moins restrictive pour l'outil d'analyse des scripts de Roblox et donc la plus susceptible de détecter les erreurs de type avant l'exécution.

Syntaxe de classe typée

La démarche établie pour créer des classes en Lua est bien documentée, cependant, elle n'est pas bien adaptée au fort typage Luau.Dans Luau, l'approche la plus simple pour obtenir le type d'une classe est la méthode typeof() :


type ClassType = typeof(Class.new())

Cela fonctionne, mais ce n'est pas très utile lorsque votre classe est initialisée avec des valeurs qui n'existent qu'au moment de l'exécution, par exemple des objets Player .En outre, l'hypothèse faite dans la syntaxe de classe Lua idiomatique est que la déclaration d'une méthode sur une classe self sera toujours une instance de cette classe ; ce n'est pas une hypothèse que le moteur d'inférence de type peut faire.

Afin de prendre en charge l'inférence de type strict, le projet Plante utilise une solution qui diffère de la syntaxe de classe Lua idiomatique d'un certain nombre de manières, dont certaines peuvent sembler non intuitives :

  • La définition de self est dupliquée, à la fois dans la déclaration de type et dans le constructeur.Cela introduit une charge de maintenance, mais des avertissements seront affichés si les deux définitions tombent en désaccord les unes avec les autres.
  • Les méthodes de classe sont déclarées avec un point, donc self peut être explicitement déclaré de type ClassType.Les méthodes peuvent toujours être appelées avec une virgule comme prévu.

--!严格ement
local MyClass = {}
MyClass.__index = MyClass
export type ClassType = typeof(setmetatable(
{} :: {
property: number,
},
MyClass
))
function MyClass.new(property: number): ClassType
local self = {
property = property,
}
setmetatable(self, MyClass)
return self
end
function MyClass.addOne(self: ClassType)
self.property += 1
end
return MyClass

Lancez des types après des gardes logiques

Au moment de l'écriture, le type d'une valeur n'est pas restreint après une déclaration conditionnelle de garde.Par exemple, en suivant la garde ci-dessous, le type de optionalParameter n'est pas restreint à number .


--!严格ement
local function foo(optionalParameter: number?)
if not optionalParameter then
return
end
print(optionalParameter + 1)
end

Pour atténuer cela, de nouvelles variables sont créées après ces gardes avec leur type explicitement exprimé.


--!严格ement
local function foo(optionalParameter: number?)
if not optionalParameter then
return
end
local parameter = optionalParameter :: number
print(parameter + 1)
end

Traverser les hiérarchies du modèle de données

Dans certains cas, la base de code doit parcourir la hiérarchie du modèle de données d'un arbre d'objets créés au moment de l'exécution.Cela présente un défi intéressant pour le contrôle de type.Au moment de l'écriture, il n'est pas possible de définir une hiérarchie de modèle de données générique comme un type.Par conséquent, il existe des cas où les seules informations de type disponibles pour une structure de modèle de données sont le type de l'instance de niveau supérieur.

Une approche de ce défi consiste à lancer à any et à affiner ensuite. Par exemple :


local function enableVendor(vendor: Model)
local zonePart: BasePart = (vendor :: any).ZonePart
end

Le problème avec cette approche est qu'elle a un impact sur la lisibilité.Au lieu de cela, le projet utilise un module générique appelé getInstance pour parcourir les hiérarchies de modèle de données qui se traduisent en interne en any.


local function enableVendor(vendor: Model)
local zonePart: BasePart = getInstance(vendor, "ZonePart")
end

À mesure que l'évolution de la compréhension du modèle de données par le moteur de type évolue, il est possible que des modèles comme celui-ci ne soient plus nécessaires

Interface utilisateur

Plante comprend une variété d'interfaces utilisateur 2D complexes et simples.Ceux-ci incluent des éléments de notification non interactifs (HUD) comme le compteur de pièces et des menus interactifs complexes comme la boutique.

Approche UI

Vous pouvez comparer de manière imprécise l'interface utilisateur Roblox à la DOM HTML, car c'est une hiérarchie d'objets qui décrivent ce que l'utilisateur devrait voir.Les approches pour créer et mettre à jour une interface utilisateur Roblox sont largement divisées en pratiques impératives et déclaratives .

ApprocheAvantages et inconvénients
Impératif

Dans l'approche impérative, l'interface utilisateur est traitée comme toute autre hiérarchie d'instance sur Roblox.La structure de l'interface utilisateur est créée avant l'exécution dans Studio et ajoutée au modèle de données, généralement directement dans StarterGui .Ensuite, au moment de l'exécution, le code manipule des parties spécifiques de l'interface utilisateur pour refléter l'état que le créateur requiert.:

Cette approche comporte certains avantages.Vous pouvez créer l'interface utilisateur à partir de zéro dans Studio et la stocker dans le modèle de données.C'est une expérience d'édition simple et visuelle qui peut accélérer la création d'interface utilisateur.Parce que le code d'interface utilisateur impératif ne se soucie que de ce qui doit être modifié, il facilite également l'implémentation de modifications d'interface utilisateur simples.:

Un inconvénient notable est que, puisque les approches d'interface utilisateur impératives nécessitent que l'état soit implémenté manuellement sous forme de transformations, les représentations complexes de l'état peuvent devenir très difficiles à trouver et à déboguer.Il est courant que des erreurs émergent lors du développement de code d'interface utilisateur impératif, notamment lorsque l'état et l'interface utilisateur deviennent désynchronisés en raison de plusieurs mises à jour interagissant dans un ordre inattendu.:

Un autre défi avec des approches imposées est que c'est plus difficile de décomposer l'interface utilisateur en composants significatifs qui peuvent être déclarés une fois et réutilisés.Puisque l'ensemble de l'arbre d'interface utilisateur est déclaré au moment de l'édition, des modèles communs peuvent se répéter dans plusieurs parties du modèle de données.

Déclaratif

Dans l'approche déclarative, l'état souhaité des instances d'interface est déclaré explicitement, et la mise en œuvre efficace de cet état est abstraite par des bibliothèques telles que Roact ou Fusion.:

L'avantage de cette approche est que la mise en œuvre de l'état devient trivial et que vous n'avez besoin de décrire que ce que vous voulez que votre interface utilisateur ressemble.Cela rend l'identification et la résolution des bugs beaucoup plus faciles.:

Le principal inconvénient est de devoir déclarer l'ensemble de l'arbre de l'interface utilisateur en code.Les bibliothèques comme Roact et Fusion ont une syntaxe pour rendre cela plus facile, mais c'est toujours un processus fastidieux et une expérience d'édition moins intuitive lors de la composition de l'interface utilisateur.

L'usine utilise une approche impérative sous la notion que montrer les transformations directement donne une vision plus efficace de la façon dont l'interface utilisateur est créée et manipulée sur RobloxCela ne serait pas possible avec une approche déclarative.Certaines structures et logiques d'interface répétées sont également abstraites en composants réutilisables pour éviter un piège commun dans le design d'interface impératif.

Architecture de haut niveau

Plant project UI architecture diagram

Couches et composants

Dans Plante, toutes les structures d'interface utilisateur sont soit une Layer ou une Component.

  • Layer est défini comme un groupe de niveau supérieur qui enveloppe les structures d'interface utilisateur préfabriquées dans ReplicatedStorage .Une couche peut contenir un certain nombre de composants, ou elle peut encapsuler toute sa propre logique.Des exemples de couches sont le menu d'inventaire ou l'indicateur du nombre de pièces dans l'affichage en aperçu
  • Component est un élément d'interface utilisateur réutilisable.Lorsqu'un nouvel objet de composant est instancé, il clone un modèle préfabriqué à partir de ReplicatedStorage .Les composants peuvent eux-mêmes contenir d'autres composants.Les exemples de composants sont une classe de bouton générique ou la notion d'une liste d'éléments.

Afficher le traitement

Un problème commun de gestion de l'interface utilisateur est la manipulation des vues.Ce projet comporte une gamme de menus et d'éléments HUD, dont certains écoutent l'entrée de l'utilisateur et dont une gestion soigneuse de la visibilité ou de l'activation est requise.

L'entreprise aborde ce problème avec son système UIHandler qui gère quand une couche d'interface utilisateur doit ou ne doit pas être visible.Toutes les couches d'interface utilisateur dans le jeu sont catégorisées comme HUD ou Menu et leur visibilité est gérée par les règles suivantes :

  • L'état activé des couches Menu et HUD peut être basculé.
  • Les couches activées HUD ne sont affichées que si aucune couche Menu n'est activée.
  • Les couches activées Menu sont stockées dans une pile, et une seule couche Menu est visible à la foisLorsqu'une couche Menu est activée, elle est insérée en avant de la pile et est affichée.Lorsqu'une couche Menu est désactivée, elle est supprimée de la pile et la couche suivante activée Menu de la file d'attente est affichée.

Cette approche est intuitive car elle permet de naviguer dans les menus avec l'histoire.Si un menu est ouvert à partir d'un autre menu, la fermeture du nouveau menu affichera à nouveau le menu ancien.

Les singletons de couche d'interface utilisateur s'enregistrent eux-mêmes auprès du gestionnaire d'interface utilisateur et sont fournis avec un signal qui se déclenche lorsque sa visibilité devrait changer

En savoir plus

À partir de cette vue d'ensemble complète du projet Plante, vous pouvez vouloir explorer les guides suivants qui vont plus en profondeur sur les concepts et les sujets liés.