Nous avons utilisé les systèmes suivants pour soutenir à la fois les systèmes de jeu fondamentaux et les objectifs des principales exigences de conception .
Utiliser Manager
UseManager a fourni une API simple pour appliquer un objet saisi sur quelque chose, comme un morceau de vêtements superposés sur un mannequin.La fonction principale de cette API est UseManager.AddUse (balises, objets cibles, distance, réussite, rien équipé, équipé faux, données supplémentaires), qui lie un ensemble de balises à objets cibles .Lorsqu'un joueur a un objet avec l'une des balises et clique sur un objectif, la fonction d'appel de retour onSuccess est appelée.D'autres fonctions d'appel nous ont permis d'afficher des informations visuelles supplémentaires aux joueurs si un clic est effectué sans élément saisi ou avec le mauvais type d'item.
Nous pourrions supprimer l'"utilisation" avec UseManager.RemoveUse, qui était généralement utile lorsqu'une mission était terminée ou qu'un élément spécifique était "utilisé".En outre, nous pourrions ajouter ou supprimer des cibles avec AddUseTargets et RemoveUseTargets .
Mises en évidence
Lorsqu'un joueur était près d'un élément d'intérêt, comme un phoque, nous voulions que cet élément se démarque de son environnement.Pour implémenter cela, nous avons créé un LocalScript appelé HighlightItems qui utilise une sphère centrée autour du joueur pour détecter les touches avec d'autres mailles, se connectant à Touched et TouchEnded événements.La fonction getHighlight vérifie plusieurs balises sur un maillage touché ou ses parents en utilisant une fonction d'aide GetTaggedObjectUpHierarchy .Si aucune mise en évidence n'est pas nécessaire, nous pourrions la supprimer de force en utilisant une balise Pas de mise en évidence .Cependant, si c'est nécessaire mais ne convient pas tout à fait à diverses autres balises, nous pourrions le forcer en utilisant la balise importante .
Cette LocalScript utilise une nouvelle fonctionnalité d'aperçu d'objet Highlight qui dessine un contour d'un objet et/ou remplit l'intérieur de l'objet avec une couleur définie ; pour plus d'informations sur la façon d'utiliser cette fonctionalité, voir Mise en évidence des objets.Highlights et le curseur de la souris OnItemIndicator travaillent ensemble, donc Highlights non seulement déterminent si un maillage a besoin d'un surbrillance, mais ils fournissent également un type de maillage pour OnItemIndicator .
HighlightItemsFunc est utilisé pour communiquer avec d'autres systèmes clients.Par exemple, EventManager l'utilise avec une commande Enable pour activer ou désactiver un Highlight dans certaines scènes coupées, et OnItemIndicator utilise GetType pour demander le type d'objet qu'il est.Pour détecter quand un élément n'est plus présent, comme lorsque une salle corrompue est détruite, nous nous connectons à CollectionService.GetInstanceRemovedSignal .
Lore et ThoughtBubbles
La connaissance et les bulles de pensée sont 2 systèmes similaires.Lore utilise un ScreenGui comme conteneur d'interface utilisateur sur écran avec un enfant Frame pour contrôler la redimensionnement et le redimensionnement de ses enfants TextLabels et ImageLabels , et Lore attend que le joueur clique n'importe où sur l'écran pour le supprimer.De même, les bulles de pensée utilisent un BillboardGui avec un enfant TextLabel pour les objets non-lore, et affichent un dialogue dans l'espace 3D près de l'objet pour une durée et une période de recharge spécifiées sans que le texte ne prenne toute la surface de l'écran.Pour plus d'informations sur le design derrière ces systèmes, voir Lore et bulles de pensée.
Lore est implémenté dans le LoreManger LocalScript .Lorsqu'il est cliqué ou touché, il lance un raycast en utilisant une fonction d'aide utils.RaycastAlongPointingDir , et il utilise un groupe de collisions de joueurs .Si un maillage sous le clic ou l'un des parents a une balise Lore ou ThoughtBubble , nous affichons l'interface utilisateur.Le texte, la légende et l'image sont définis par les attributs LoreText, LoreCaption et LoreImage sur l'objet.
Notez que nous utilisons Camera.ViewportPointToRay ou Camera.ScreenPointToRay pour construire le rayon, en fonction de si il a été appelé à partir d'un non-touch ou touch.Les coordonnées sont dans des systèmes de coordonnées un peu différents.Pour la souris, nous les obtenons de Class.UserInputService.InputEnded``:Connect pour le bouton de souris1, et pour les appareils tactiles, nous les obtenons de Class.UserInputService.TouchTapInWorld``:Connect .
Les bulles de pensée sont globalement similaires, utilisant un raycast pour vérifier si un maillage ou ses parents ont une balise bulles de pensée .Il utilise également l'attribut TextThought pour le texte et une balise ThoughtBubble pour indiquer un objet de remplacement utilisé pour positionner l'interface utilisateur dans le monde.Les bulles de pensée qui utilisent le même objet positionnel mais ont un texte différent ont des temps de recharge différents.
Cas spéciaux
Lore a quelques cas spéciaux, l'un desquels est les phoques corrompus.Lorsqu'un joueur clique sur un sceau corrompu, il affiche l'interface utilisateur de l'histoire et attend un clic pour démarrer une mission, ce qui affecte le flux du jeu.Cela est géré par le GameStateClient qui utilise un bindable LoreManagerFunc pour demander l'interface utilisateur de l'histoire.Un rappel est fourni au système Lore par GameStateClient pour savoir quand le lore est "fermé" par le joueur.Un autre cas spécial est lorsque les balises bulles de pensée et savoir sont sur le même objet.Dans ce cas, pour éviter un chevauchement du texte de la bulle de pensée et du savoir, nous exécutons la bulle de pensée après que le savoir soit fermé. LoreManager gère également un cas spécial en affichant une petite scène lorsqu'on clique sur des portes désactivées qui sont verrouillées jusqu'à ce que le joueur prenne le sceau de la salle.
Indicateur d'objet OnItemIndicator
Nous voulons montrer différentes icônes au centre de l'écran lorsque le joueur regarde certains éléments d'intérêt.Le script client OnItemindicator lance un rayon le long de la caméra Class.CFrame.LookVector et analyse les résultats.Sur la base des résultats, il définit une image dans le OnItemIndicator2 ScreenGui .
Lorsqu'aucun élément d'intérêt n'est touché, l'icône par défaut est un petit point.Nous pouvons définir n'importe quelle icône en ajoutant une balise OnItemIndicator à un maillage spécifique, en utilisant les noms de onItemIndicatorImages , tels que Main, Œil ou DoorCurrentlyLocked.L'attribut n'est nécessaire que dans des cas rares, et la plupart du temps, d'autres balises ou systèmes existants fournissent le type d'icône.Pour plus de détails, voir la fonction Update .
Les vérifications de type effectuent certaines dans un ordre de priorité.Après l'remplacerde OnItemIndicator, nous vérifions s'il est saisissable ou un tiroir pour l'icône "main" via either utils.CanGrabModel(model) ou utils.GetTaggedObjectUpHierarchy("Drawer2", model) .Après cela, nous appelons HighlightManager qui détermine le statut d'évidence, les types d'éléments et l'icône à utiliser.Par exemple :
highlightItemsFunc:Invoke({"GetType", curInst})
Les balises Lore et ThoughtBubble sont vérifiées plus tard en vérifiant les balises.Pour les portes, nous avons 2 icônes différentes : porte actuellement fermée et porte toujours verrouillée .DoorManager définit une valeur vraie ou fausse DoorEnabled pour les portes qui peuvent être ouvertes ou fermées, et nous utilisons la présence et la valeur de l'attribut.Les objets qui ressemblent à des portes mais qui ne s'ouvrent pas ont la balise DoorLocked .
Gestionnaire de porte
Le DoorManager utilise une balise porte et ferme pour gérer l'ouverture et la fermeture des portes.La porte a des déclencheurs avant et arrière que nous connectons avec des événements de toucher et touchEnded .Nous avons créé des adolescents pour ouvrir et fermer une porte des deux côtés et de l'avant.Nous maintenons une carte joueursNear (de joueurs touchant les déclencheurs, séparément pour le côté avant et arrière.
Chaque porte a un système d'état simple, DoorState (Fermé, Ouverture, Ouvert, Fermeture), avec des adolescents utilisés pour les transitions.Nous pourrions activer ou désactiver la capacité d'une porte à s'ouvrir ou à se fermer à partir de systèmes externes en appelant DoorManager.EnableDoor, qui définit un attribut DoorEnabled.
Maître animateur
Le MasterAnimator joue des images animées (atlas de texture), que nous utilisions pour animer les écrans de télévision.Pour parcourir les images, nous devions connaître un ensemble de paramètres : le nombre de lignes et de colonnes, le nombre total de cadres, les périodes, les dimensions de l'image et un ensemble d'ID d'image.Le système nous a permis d'animer à travers plusieurs images, chacune pouvant être divisée en colonnes et en lignes de sous-images.Nous pourrions fournir ces données via des attributs ou des valeurs, mais dans cette expérience, nous avons utilisé des scripts d'aide.UpdateImageAnimations(dT) calcule quelle image ou sous-image nous avions besoin de montrer en utilisant le temps et les paramètres.Si nous devions changer pour une nouvelle image, nous définissons Image.Si nous devons modifier une sous-image, nous définissons ImageRectOffset .
Un objet avec un animé SurfaceGui aurait un animateur ModuleScript , avec le principal but de fournir une fonction Animator.GetParams qui retourne tous les paramètres.Cela aide le MasterAnimator LocalScript qui utilise l'élément Animation d'image et CollectionService pour collecter de tels objets, et trouver l'Animateur ModuleScript sous eux.Il utilise ensuite pcall pour exiger l'Animateur ModuleScript et appeler GetParams dessus.
Animations d'espace local
Les animations d'espace local utilisent une balise LocalSpaceRotation pour faire pivoter principalement des objets "cosmétiques" avec une vitesse de rotation donnée et un délai autour de l'axe X, Y ou Z.Nous l'avons utilisé pour des objets distants avec lesquels les joueurs ne pourraient pas interagir, ou pour des objets plus petits qui n'affectent pas beaucoup la simulation.Paramètres définis via les valeurs Speed, Delay et Axis.Pour les détails de mise en œuvre, voir Meshes du cloud rotatifs.
Gestionnaire de lampe de tête
Le gestionnaire de lampe de tête gère lorsque les utilisateurs sélectionnent l'éclairage à l'écran pour offou désactiver le projecteur au-dessus de leur tête, envoie des commentaires au serveur en utilisant l'événement Headlamp et active les sons de basculement des plaques allumées et éteintes.Lorsqu'un personnage est ajouté, ou que son Head est modifié, la fonction giveCharacterHeadlamp clone la lampe templateHeadlamp et positionne la lampe en utilisant quelques décalages et rotations du FaceFrontAttachment .
Gestionnaire de siège
Nous ne voulons pas que les joueurs s'installent automatiquement lorsqu'ils sont près d'un objet sur lequel ils peuvent s'asseoir.Au lieu de cela, nous voulons exiger que les utilisateurs cliquent près d'un siège pour s'asseoir.Le script Gestionnaire de siège ajoute ClickDetectors en fonction d'une balise siège , et appelle seat:Sit(humanoid) lorsqu'il est cliqué.Lors du téléportation des joueurs entre l'état normal et corrompu d'une salle, nous ne pouvons pas avoir des joueurs assis car CFrame la coordination de changement ne serait pas capable de fonctionner, donc le gestionnaire de sièges a une fonctionnalité pour désactiver ou activer le siège quelques secondes avant et après le téléport.
Gestionnaire de tiroir
Le script DrawerManager utilise une balise Drawer2 et CollectionService pour gérer le clic sur les tiroirs pour les ouvrir ou les fermer, et jouer tout audio correspondant.L'action d'ouverture et de fermeture est effectuée en définissant la position cible pour un PrismaticConstraint .
Tuer les volumes
Dans quelques zones de la zone principale du jeu, telles que les étincelles électriques et l'eau près du début de la route menant à la maison, un joueur peut avoir son Humanoid.Health défini sur 0 lorsqu'il entre dans un volume avec la balise KillVolume .Le script KillVolumes utilise Touched:Connect pour déterminer quand un joueur entre dans un volume, puis réduit sa santé à 0 .
Respawn de la mission du joueur
Le script PlayerMissionRespawn utilise une balise RespawnVolume et CollectionService pour gérer les volumes qui font réapparaître les joueurs lorsqu'ils sont touchés.Nous avons placé ces volumes sous des salles corrompues, car de nombreuses missions ont des lacunes ou des plateformes mobiles dans lesquelles le joueur pourrait tomber.Lorsqu'il est touché, le script joue une petite scène de saut de téléportation et invoque avec la commande .
Lors du traitement de GameEvents.PlayerRespawn, le script peut utiliser RespawnPositions, si la configuration de la mission le fournit.Sinon, il utilise TeleportPositions pour la mission spécifique.Nous n'avons pas de système de "point de contrôle", donc CalcClosestTeleportPos sélectionne simplement les points de réapparition ou de téléportation les plus proches à partir desquels le joueur a frappé le RespawnVolume, en utilisant la seule distance horizontale, "2D".
Petits systèmes d'aide
Gestionnaire de piano
Le script PianoManager utilise une balise Piano et CollectionService pour ajouter ClickDetectors et jouer l'un des sons de piano lorsqu'on clique sur le clavier.
Support rituel
Le foyer où les joueurs placent des scellés a une machinerie complexe qui subit des modifications à chaque fois qu'un scellé est placé à son emplacement défini.Par exemple, en fonction du nombre de phoques placés, des événements spécifiques jouent pour activer/désactiver les lumières et les rayons, changer la transparence de certains objets, etc.Le soutien rituel est un petit emballage sur appels pour ces événements, fournissant des paramètres à l'événement, tels que le "objet racine" sur lequel jouer, en fonction de quel cachet spécifique a été placé.
Gestionnaire restaurable
Certains objets saisissables sont importants pour le partie, tels que les phoques, et nous ne voulions pas qu'ils se perdent si un joueur les laissait quelque part.Si un objet a une balise Restaurable , le script RestaurableManager se souvient de sa transformation lorsqu'il est ajouté au système de restauration.Lorsqu'un joueur lâche un tel objet, le système d'attrape appelle restorableManager.StartTracking .Si l'objet n'est pas récupéré dans les cinq secondes, le script RestorableManger le positionne à la transformation originale et réinitialise le temps de suivi.
Portails
Dans quelques missions, nous téléportons les joueurs à une courte distance dans une mission, comme réapparaître des joueurs qui tombent d'une plateformetournante.Pour simplifier la configuration de ce type de téléportation, que nous appelons « portails » dans le script, une fonction d'aide ProcessPortal dans DemoUtils est utilisée.Par exemple, si P1 est la partie qui définit le déclencheur initial, et que P2 est la partie qui définit la transformation du joueur de destination, le fragment de code suivant pourrait définir une telle fonctionnalité de portail :
P1.Touched:Connect(function(otherPart) utils.ProcessPortal(otherPart, P2) end)
ProcessPortal gère la vérification que l'autre partie est un humain, téléportant le joueur à travers un changement de coordonnées CFrame et en invoquant une petite scène coupée pour cacher la transition en utilisant un événement Teleport_Jump dans EventManager.
Scripts de configuration
Nous avons plusieurs scripts de configuration, de définition de données et de fonctionnalité commune : Config démo . Définitions de missions. Enumérations pour les états de jeu, événements pour les communications client-serveur. DémoGlobalSettings .Nous développons dans un emplacement, mais libérons (et test de jeu) dans d'autres.Le script vérifie placeID et active/désactive diverses fonctionnalités de piratage et de débogage. Outils de démonstration .Fonctions utilitaires diverses.Traiter avec des transformations.Définir la visibilité, ancrée ou d'autres propriétés.Vérification d'un point dans une boîte de modélisation.Trouver des objets dans la hiérarchie par le nom « dotted ».Gérer TempStorage (qui peut être utilisé pour déplacer temporairement des modèles « quelque part loin » et les ramener plus tard).Cliquez sur les assistants détecteurs.Prendre en charge le assistance.Support de vérification des balises (notamment le long de la hiérarchie).Relier les déclencheurs à EventManager. AudioUtils . Quelques fonctions pour jouer des sons aléatoires pondérés d'un configurer. GrabUtil . Fonctions d'aide pour la saisie.