Créer un mouvement dans n'importe quel environnement dans une expérience l'aide à se sentir instantanément plus immersif et réaliste dans notre monde, que ce soit du fait du mouvement des arbres ambiants, de portes réactives de l'interaction du joueur ou même de boîtes qui se déplacent lorsqu'elles se heurtent à elles.Studio a de nombreuses méthodes uniques pour créer des mouvements afin d'aider les mondes à se sentir plus vivants, y compris un système de physique, TweenService , et des animations, et l'analyse des besoins spécifiques de votre expérience peut vous aider à déterminer celui à utiliser.Dans cette section, nous allons démontrer comment nous avons déterminé le type de mouvement que nous voulions créer dans Studio, et les outils que nous avons utilisés pour atteindre ces objectifs distincts.

Créer la tempête
La tempête a traversé de nombreuses itérations avant que nous nous fixions sur ce qui est en direct dans The Mystery of Duvall Drive.Tôt, nous avons pensé à la tempête comme à un pilier d'obsidienne géant, et dans les itérations ultérieures, nous l'avons jugé être un portail géant vers l'espace corrompu.Après avoir expérimenté avec de nombreuses tempêtes avec des looks et des sensations uniques pour elles, nous nous sommes installés sur une tempête avec un «œil» central plus petit parce que :
- La tempête devrait donner aux joueurs une idée de l'impact de cet événement sur le monde », y compris les arbres qui se balancent et les débris qui volent.
- Le tourbillon tournant du cloud lui-même devrait donner aux joueurs un aperçu du portail central sans tout révéler .Cela encouragerait les joueurs à enquêter plus près pour voir ce qui se passe.
- Le point de lumière plus serré nous permettrait de nous concentrer sur la composition de la maison, qui est à la fois le personnage principal et où se trouve la plupart du gameplay.




Pour que la tempête se sente dynamique, agressive et changeante à l'intérieur de son environnement, nous avons utilisé les systèmes et les fonctionnalités suivants :
- TweenService - Pour le mouvement du cloud.
- Changements d'éclairage - Pour créer la foudre du nuage au nuage.
- Poutres - Pour la "lumière volumique" et les éclairs.
- Émetteurs de particules - Pour les débris volant jusqu'au portail et volant autour en raison du souffle du vent.
- Animations - Pour les arbres qui soufflaient dans le vent.
Ajouter des nuages avec des textures
Bien que les nuages dynamiques soient excellents pour les nuages réalistes de haute altitude normaux, nous avions besoin de quelque chose qui soit dramatique et que nous puissions diriger et personnaliser plus lourdement.Pour ce faire, nous avons appliqué l'apparence de la surface objets avec une semi-transparence à une série de mailles nuageuses superposées et empilées afin de simuler une couverture nuageuse.Pourquoi les avons-nous empilés et superposés si lourdement ? Parce que lorsque chaque maillage de nuage se déplace à des vitesses différentes, ils se croisent et créent des formes de nuage qui vont à l'intérieur et à l'extérieur les uns des autres.Ce processus a fait en sorte que les nuages se sentent un peu plus dynamiques et naturels, malgré le fait qu'ils soient simplement des disques tournants.Il était également important que les nuages soient semi-transparents, car nous voulions que les joueurs puissent les regarder pour voir quelque chose de brillant au centre avant d'arriver à la maison !


Puisque chaque maillage de nuage devait être massif pour entourer complètement la maison et transmettre à quel point la tempête était énorme, nous savions que nous devions carreler la texture que nous voulions utiliser sur les mailles de nuage individuelles afin qu'elle soit fortement répétée sur toute la surface du maillage.Nous avons testé les matériaux que nous avons fabriqués pour le cloud sur ces pièces simples, puis les avons appliqués au vortex !

Contrairement aux émetteurs de particules ou aux faisceaux, les mailles nous ont permis d'être en mesure de rebondir la lumière sur chaque maillage, ce qui était important lorsque nous voulions implémenter la foudre du nuage au nuage.Nous avons également modélisé dans la torsion afin que la lumière rebondissante dessus ressemble à une profondeur ! Cela était important, notamment dans des situations où les exigences de performance de l'expérience a fait baisser les niveaux de qualité de l'apparence de notre surface.

Faire pivoter les mailles du cloud
Une fois que nous avions été satisfaits de l'apparence visuelle globale des nuages, nous avions besoin de les faire bouger ! Nous avions les formes générales de chaque couche de nuage en emplacement, mais il a fallu faire des essais et des erreurs pour s'assurer que l'effet de rotation avait l'air bien en pratique.Nous avons initialement essayé d'utiliser contraintes pour introduire une vitesse qui conduirait physiquement les nuages à se déplacer.C'était plus difficile que ce que nous voulions qu'il soit pour itérer plus tard, et le joueur ne l'interagirait jamais, donc nous n'avions pas besoin qu'il soit aussi précis dans son mouvement.
Nous voulions une méthode facile à utiliser pour faire pivoter des instances qui étaient trop éloignées pour être interactives, telles que les nuages, ou trop petites ou décoratives pour être importantes pour le jeu/la physique, comme les meubles intérieurs comme de petites lampes.Nous avons décidé d'utiliser un LocalScript pour réduire la bande passante client-serveur, permettre un mouvement plus doux et faire en sorte que chaque maillage de nuage soit capable d'avoir un différent taux de rotation et de retard.Pour le rendre plus générique, nous avons également rendu possible de spécifier l'axe de rotation.Il est possible d'utiliser 3 attributs, mais pour notre cas, nous avons utilisé 3 valeurs : Axis , Delay et Speed .

Comme dans de nombreux cas dans la démonstration, nous avons utilisé une balise LocalSpaceRotation pour que nous puissions gérer les instances affectées dans Studio en utilisant un plugin de marquage d'instance.Nous n'avons utilisé qu'une seule balise LocalScript qui a géré toutes les instances marquées en utilisant la balise CollectionService afin que nous n'ayons pas eu une tonne de scripts à maintenir tout au long du processus de développement.
Dans notre démonstration, des parties du monde sont clonées à partir du ServerStorage dans l'espace de travail comme nécessaire, donc nous avons dû gérer des cas où des objets étiquetés ont été créés et détruits.Avec LocalScripts, nous devons également être conscients du streaming, où les mailles et leurs valeurs enfants peuvent être diffusées et reçues.Nous avons initialement traité les objets placés dans la fonction Init() et les avons connectés à CollectionService.GetInstanceAddedSignal et CollectionService.GetInstanceRemovedSignal pour les objets étiquetés afin de gérer les objets nouvellement créés/détruits.La même fonction SetupObj a été utilisée pour initialiser de nouveaux objets dans Init() et dans CollectionService.GetInstanceAddedSignal .
local function Init()
for _, obj in CollectionService:GetTagged("LocalSpaceRotation") do
if obj:IsDescendantOf(workspace) then
SetupObj(obj)
end
end
end
CollectionService:GetInstanceAddedSignal("LocalSpaceRotation"):Connect(function(obj)
objInfoQueue[obj] = true
end)
CollectionService:GetInstanceRemovedSignal("LocalSpaceRotation"):Connect(function(obj)
if objInfo[obj] then
objInfo[obj] = nil
if objInfoQueue[obj] then
objInfoQueue[obj] = nil
end
end
end)
Init()
objInfo est une carte qui contient des informations pour tous les objets pertinents, comme leur vitesse de rotation et leur axe.Notez que nous n'appelons pas SetupObj immédiatement à partir de CollectionService.GetInstanceAddedSignal , mais nous avons ajouté un objet à objInfoQueue .Avec les objets de streaming et de clonage sur le serveur, lorsque CollectionService.GetInstanceAddedSignal est appelé, nous n'avons peut-être pas encore eu nos valeurs Axis , Delay et Speed, donc nous ajoutons l'objet dans une file d'attente, et appelé SetupObj sur les cadres suivants de la fonction Update jusqu'à ce que les valeurs soient là et que nous puissions les lire dans la structure "info" par objet.
Nous avons fait pivoter les instances dans la fonction Update connectée au battement de cœur.Nous avons obtenu la transformation parentale (parentTransform), cumulé un nouvel angle de rotation ( curObjInfo.curAngle ) en fonction de la vitesse de rotation de cet objet, calculé la transformation locale ( rotatedLocalCFrame) ) et l'a finalement définie sur le CFrame .Notez que le parent et l'objet peuvent tous deux être un Model ou MeshPart , nous avons donc dû vérifier IsA("Modèle") et utiliser soit un PrimaryPart.CFrame ou CFrame .
local parentTransformif parentObj:IsA("Model") thenif not parentObj.PrimaryPart then-- la partie principale peut ne pas encore être diffuséecontinue -- attendez que la partie principale se répliqueendparentTransform = parentObj.PrimaryPart.CFrameelseparentTransform = parentObj.CFrameendcurObjInfo.curAngle += dT * curObjInfo.timeToAnglelocal rotatedLocalCFrame = curObjInfo.origLocalCFrame * CFrame.Angles( curObjInfo.axisMask.X * curObjInfo.curAngle, curObjInfo.axisMask.Y * curObjInfo.curAngle, curObjInfo.axisMask.Z * curObjInfo.curAngle )if obj:IsA("Model") thenobj.PrimaryPart.CFrame = parentTransform * rotatedLocalCFrameelseobj.CFrame = parentTransform * rotatedLocalCFrameend
Nous avons vérifié qu'un Model.PrimaryPart valide devait être défini pour gérer le streaming.Si une mise à jour a été appelée sur notre objet alors qu'un Model.PrimaryPart (qui peut pointer vers un maillage enfant) n'a pas encore été diffusé, nous sautons simplement la mise à jour.Le système actuel est une deuxième itération de la rotation d'objets, et le système précédent fonctionnait différemment : les valeurs étaient 12 fois différentes ! Pour conserver les mêmes données, nous l'avons converti dans notre script, comme "12 * obj.Speed.Value".
Concevoir des éclairs de foudre
Parce que Studio ne propose pas de générateur de foudre en boîte, et que le système de particules avait quelques limitations qui ne fonctionneraient pas pour les coups de foudre des héros, nous avons dû être créatifs avec une solution pour les coups de foudre des héros.Nous avons décidé de deux systèmes principaux pour constituer la foudre : des rayons texturés pour les frappes de foudre du héros venant de l'œil de la tempête sont des rayons texturés scriptés qui révèlent et se synchronisent avec les effets audio et post-traitement, et un simple effet de particules pour la foudre lointaine du nuage au nuage.
Rayons de texture
Nous utiliserions généralement un séquenceur ou un outil de calendrier pour piloter le timing d'un effet de frappe de boulon d'éclairage comme celui-ci, mais puisque Studio ne propose pas encore cette fonctionnalité, nous avons décidé d'écrire des scripts qui contrôleraient le temps du boulon d'éclairage.Le scripting de cet effet est plutôt simple, mais il atteint les objectifs suivants importants :
- Les éléments des coups de foudre, tels que leurs textures, leur luminosité et leurs délais, sont randomisés à chaque coup.
- Les modifications audio et post FX sont en phase avec les modifications FX de grève.
- Les joueurs qui sont à l'intérieur ou dans la zone corrompue ne pourraient pas les voir ou les entendre.
Nous avons un côté serveur Script qui calcule divers paramètres et délais, les envoie à tous les clients et attend une quantité aléatoire de temps :
local function LightningUpdate()
while true do
task.wait(rand:NextNumber(3.0, 10.0))
local info = CreateFXData()
lightningEvent:FireAllClients(info)
end
end
À l'intérieur de CreateFXData, nous remplissons la structure d'information afin que tous les clients obtiennent les mêmes paramètres.
Du côté du client ( LightningVFXClient ), nous vérifions si ce client doit exécuter le FX :
local function LightningFunc(info)
…
-- pas de FX en intérieur
if inVolumesCheckerFunc:Invoke() then
return
end
-- pas de FX lorsqu'on n'est pas dans le monde "normal"
if not gameStateInfoFunc:Invoke("IsInNormal") then
return
end
…
En outre, nous exécutons la séquence pour définir les textures, les positions et la luminosité, exécuter les préadolescents et utiliser task.wait(number).Les paramètres aléatoires proviennent de la structure d'information que nous avons reçue du serveur, et certains chiffres sont fixés.
beam.Texture = textures[info.textIdx]beamPart.Position = Vector3.new(info.center.X + og_center.X, og_center.Y, info.center.Y + og_center.Z)-- Effacerbeam.Brightness = 10ppCC.Brightness = maxPPBrightnessppBloom.Intensity = 1.1bottom.Position = top.PositiontweenBrightness:Play()tweenPPBrightness:Play()tweenPPBrightness:Play()tweenBottomPos:Play()tweenBrightness.Completed:Wait()-- audioif audioFolder and audioPart thenif audioFolder.Value and audioPart.Value thenaudioUtils.PlayOneShot(audioObj, audioFolder.Value, audioPart.Value)endendtask.wait(info.waitTillFlashes)-- and so on
Pour vérifier si un joueur est à l'intérieur, nous utilisons une fonction d'aide inVolumesCheckerFunc, qui parcourt les volumes pré placés qui approchent les zones intérieures, et vérifie si la position du joueur se trouve dans l'une d'entre elles (PointInABox).Nous aurions pu utiliser la détection basée sur le toucher, mais nous avons découvert que lorsqu'un joueur prend une place à l'intérieur du volume, il ne « touche » plus le volume.Tester un point dans quelques boîtes est plus simple, et nous le faisons seulement lorsque le joueur se déplace assez loin de la position précédemment testée.
Pour vérifier si un joueur se trouve dans des zones corrompues, nous invoquons une fonction d'aide gameStateInfoFunc qui vérifie l'état du jeu actuel.Pour jouer un son aléatoire d'un dossier, nous avons également utilisé une fonction d'aide PlayOneShot .Pour les éclairs eux-mêmes, c'était super facile à créer dans Photoshop ; nous avons dessiné une ligne sinueuse, puis ajouté un effet de couche "lueur extérieure".


Utiliser des systèmes d'émetteurs de particules
Les coups de foudre héroïques sont soutenus par un système de particules qui suggère un éclair distant en créant l'impression d'une couche de nuages dans l'arrière-plan qui capture la lumière des coups de foudre distants ou de la lumière du nuage au nuage.Nous avons obtenu cet effet grâce à un système de particules très simple qui éclaire une banderole de nuage sur la périphérie du nuage de tempête principal.Le système émet une particule de nuage périodiquement avec une courbe de transparence aléatoire :


Faire souffler les arbres dans le vent
Une fois que nous avions les nuages et la foudre qui fonctionnaient comme nous le voulions, nous avons ensuite eu besoin d'ajouter deux autres composants majeurs d'une tempête : le vent et la pluie ! Ces éléments ont présenté quelques défis, dont le besoin de travailler dans les limites actuelles du système de physique et d'effets spéciaux de Studio.Par exemple, faire bouger les arbres avec le vent réel n'est pas possible dans le moteur d'aujourd'hui, donc nous avons utilisé les effets de diffuseur de particules et animations de personnages personnalisées pour les arbres.
Nous savions vraiment vendre l'effet du vent et de la pluie, nous avions besoin que les arbres se déplacent eux-mêmes.Il y a quelques façons de le faire dans le moteur, y compris en déplaçant des parties en utilisant plugins qui sont publiquement disponibles, en utilisant TweenService ou en animant directement des modèles.Pour nos fins, les animations nous ont donné la capacité de contrôler le mouvement que nous voulions de nos arbres, et cela nous a permis d'utiliser une seule animation que nous pouvions partager parmi tous les arbres dans l'expérience.
Nous avons commencé par écorcer plusieurs arbres du pack d'approbation du modèle - ressources forestières.Puisque ces arbres existaient déjà, et que notre expérience a eu lieu dans le nord-ouest du Pacifique, cela nous a fait gagner du temps au début de la création de chaque modèlisation'arbre.

Après avoir choisi nos arbres, nous savions que nous devions les peler. Dékiniser un maillage est l'acte d'ajouter des articulations (ou des os) à un maillage dans une autre application de modélisation 3D, telle que Blender ou Maya, puis d'appliquer une influence à ces articulations/os pour déplacer le maillage.Cela est le plus souvent utilisé dans les personnages humanoïdes , mais avec des personnages personnalisés , vous pouvez peaufiner pratiquement tout.
Nous savions que nous voulions gagner du temps et réutiliser la même animations, alors nous avons construit notre première structure de tronc et nous nous sommes assurés que les noms joints étaient génériques car nous voulions utiliser ces mêmes noms dans les structures de tronc pour les autres arbres.Nous savions également que nous devions inclure des jointures/os secondaires et tertiaires primaires pour que les troncs se plient avec le vent, que les branches se balancent et que les feuilles semblent comme s'elles tremblaient en réponse.Pour ce processus, nous avons dû créer une mouvement secondaire , qui est un concept d'animation où toute action provoque la réaction d'autres parties de l'objet à cette action et semble rattraper le mouvement initial.

Une fois que nous avions créé nos articulations/os, il était temps de créer une animation de test pour se déplacer autour de toutes les articulations et os dans Studio pour voir si elle se déplaçait comme nous le voulions.Pour ce faire, nous avons dû importer l'arbre dans Studio par le biais du paramètre Rig personnalisé dans le importateur 3D , puis déplacer/animer le maillage en utilisant l'éditeur d'animation .Nous configurons les matériaux et les textures après ces tests, mais vous pouvez voir le résultat ci-dessous.

Après que nous ayons été satisfaits des résultats sur cet arbre, il était temps de tester la même animation sur un arbre différent ! Nous savions déjà que ce serait la même animation entre les différents régimes pour chaque taperd'arbre, donc nous nous sommes assurés que notre animation ressemblait à celle qui était suffisamment générale pour fonctionner entre un grand séquoia et un solide bois de hêtre !

Pour ce faire, nous avons pris l'arbre de Beechwood de ce pack de forêt et avons construit une plateformesimilaire, en utilisant le même nom exact pour les jointures.C'était pour que l'animation que nous avions précédemment importée puisse être appliquée à cet arbre aussi.Puisque toutes les animations étaient basées sur des articulations rotatives, peu importait la taille, la petite, la grande ou la largeur de l'arbre !

Après avoir rig et skin l'arbre de Beechwood, nous pourrions ensuite l'importer et appliquer exactement la même animation.Cela signifiait que l'itération et l'édition n'avaient besoin d'être effectuées que sur un seul fichier, et qu'elles étaient également sauvegardées sur la performance avec moins d'animations lors de l'exécution de l'expérience.

Une fois que nous avions tous les types d'arbres que nous voulions animer, nous les avons tous faits en packages afin que nous puissions continuer à les modifier et à les mettre à jour pendant que nous jouions plusieurs des animations autour de la zone principale de l'expérience.Comme nous savions qu'ils avaient un coût de performance, nous les avons utilisés de manière parcimonieuse autour de la maison où l'effet était le plus précieux ! À l'avenir, à mesure que cela devient plus performant, vous pourrez en ajouter de plus en plus d'instances de maillage peaufinées !

Faire des débris de tempête
Nous voulions que la pluie apparaisse lourde, et que la brume et les débris soufflent à travers les arbres.Pour ce faire, nous configurons quelques parties invisibles pour agir comme des volumes de particules avec des émetteurs de particules enfants immédiatement en dessous des grands nuages de tempête.En raison de la limite du nombre de particules dans Studio, nous n'avons pas pu utiliser un émetteur de particules pour l'ensemble de l'espace.Au lieu de cela, nous avons ajouté plusieurs qui étaient de la même taille l'une que l'autre dans un motif de grille sur l'espace de la zone jouable, car la présence des arbres signifie que les joueurs ne pourraient pas voir très loin.

Les particules de pluie ont fait appel à une nouvelle propriété d'émetteur de particules ParticleEmitter.Squash qui vous permet de rendre une particule plus longue ou plus squattante.Il est particulièrement utile pour la pluie car cela signifiait que nous n'avions pas besoin d'une grande texture de pluie, étirez simplement celle qui était là.Sachez simplement que si vous augmentez la valeur de ParticleEmitter.Squash , vous devrez peut-être augmenter également la propriété globale ParticleEmitter.Size pour qu'elle ne soit pas trop mince ! En général, c'était juste une question de jouer avec les valeurs jusqu'à ce que nous ayons eu la pluie assez lourde, mais pas tellement que cela ait bloqué la visibilité de l'expérience !


Pour la brume, la brume et les feuilles qui soufflaient à travers, il était beaucoup plus simple d'ajouter un seul volume de partie plus important couvrant moins de zones car nous n'avions pas besoin d'une tonne de particules qui courent à la fois.Nous avons commencé par configurer un volume et obtenu la fréquence des particules où elles étaient recherchées.


Après cela, nous avons fait nos textures de souffle et de vent, et avons configuré les particules pour qu'elles tournent/se déplacent toutes à différentes vitesses et commencent à différentes vitesses.Cela signifiait que les particules de brouillard plus grandes interagiraient de manière plus naturelle et n'auraient pas l'air si beaucoup comme une texture répétitive, surtout en raison de leur taille.



Le résultat a été une grande action entre les arbres qui se déplacent, la fenêtre qui souffle et la foudre pour créer l'effet de la tempête qui entoure l'œil central de la tempête.
Configurer l'œil de la tempête
L'œil en pierre fracturé avec un noyau lumineux est destiné à donner aux joueurs la première indication qu'il y a quelque chose de sinistre et d'arcanique se produisant à la maison qu'ils doivent explorer plus en détail.Puisque notre scène est sombre et que l'œil est loin dans le ciel, il était important de créer une silhouette de pierre fracturée crédible, mais il n'était pas aussi important de créer des détails de surface de pierre crédibles car les joueurs ne pourraient pas les voir.Savoir ce qui est réaliste pour vos joueurs de voir dans l'éclairage de votre scène avant d'investir beaucoup de temps dans des détails inutiles peut vous faire économiser de nombreuses ressources dans le processus de développement.


La distance du joueur signifiait également que nous pouvions compter entièrement sur une carte normale pour les détails de la surface de l'œil afin que le maillage soit simplement une sphère normale ! Nous avons sculpté les détails dans un maillage de haute qualité et cuit sa carte normale sur une sphère de polymère beaucoup plus basse afin que nous puissions obtenir tous ces détails magnifiques sans le coût énorme de la performance.



Afin d'ajouter un sentiment surnaturel à l'œil et de souligner sa présence, nous avons décidé de créer un magma lumineux et fluo qui s'infiltrerait à travers ses fissures.Bien qu'il n'y ait pas de canal émissif pour l'apparence de la surface, nous surmontons cette difficulté en créant l'œil à partir de 2 sphères : une pour la surface rocheuse extérieure et une deuxième, légèrement plus petite, pour le magma rayonnant.Dans Peinture de substance, nous avons créé une texture de couleur de base pour la sphère extérieure avec de la transparence dans les zones où nous voulions que le noyau interne passe.Dans Blender, nous avons "vertex peint" la sphère intérieure d'une manière bon marché et facile pour obtenir une variation de couleur dessus.

Un autre défi auquel nous avons été confrontés lors de la création de l'œil a été imposé par notre utilisation de streaming combinée avec la distance de l'œil du joueur.Étant donné la centralité de cette structure, nous voulions qu'elle soit toujours visible malgré sa distance mais, sans aucun piratage de son maillage, les joueurs n'ont pas pu voir l'œil à moins qu'ils ne soient dans le solarium.Nous avons pu forcer la présence constante de l'œil dans la scène en ajoutant de la géométrie à l'œil et à ses anneaux.Cette géométrie se situe juste en dessous de la surface du terrain, et cela suffit à tromper le moteur pour qu'il pense que la sphère est plus proche du joueur qu'elle ne l'est et qu'elle soit toujours diffusée.Cela devrait être fait de manière plutôt parcimonieuse cependant car forcer trop de grands objets à être diffusés pourrait annuler les avantages du streaming activé et avoir un impact négatif sur les performances du jeu.
Nous avons pu ajouter du mouvement à l'œil et à ses anneaux grâce au même script que nous utilisions pour faire pivoter les mailles du nuage.Pour une touche finale, nous avons décidé d'ajouter une indication de la présence d'un autre monde au-delà des nuages, mais nous avons dû adopter une approche créative pour éviter d'ajouter plus de géométrie à la scène et de devoir également faire face aux obstacles mentionnés précédemment posés par le streaming activé.Nous avons créé une scène qui avait beaucoup de profondeur en raison de la taille et de la distance relative des objets, rendu une image de cette scène, puis utilisé cette image comme décalcomanie décalcomanie sur une partie placée juste derrière l'œil de la tempête.Nous avons utilisé la même méthode pour faire tourner cette partie comme nous l'avons fait pour l'œil et ses anneaux.

Faites l'étagère étendue
Une des choses les plus amusantes à produire étaient les espaces corrompus, où nous pouvions contester les attentes des joueurs envers la réalité en la changeant littéralement autour d'eux.Par exemple, dans le puzzle du père, nous voulions imiter un moment semblable à un cauchemar où, peu importe à quelle vitesse vous lancer, la pièce semble s'allonger sans fin.Nous avons décidé de faire une pantry étendue qui s'échapperait des joueurs alors qu'ils cherchaient des ingrédients pour transformer la salle en son état normal.
Nous avons configuré cela avec un simple mouvement des murs et une disposition intelligente de nos chambres qui apparaîtrait à l'un ou à l'autre côté de la cuisine.Dans l'état normal de la salle, la cuisine était un simple couloir, mais dans l'espace corrompu, c'était en fait beaucoup plus long avec plusieurs ailes et un mur faux !


Le mur faux était un groupe de modèles que nous ferions reculer le moment où les joueurs entreraient dans un volume déclencheur, qui était une partie transparente plus tôt dans la cuisine qu'ils traverseraient.Ce déclencheur a également été utilisé dans un script similaire à ceux utilisés sur toutes nos portes, qui a appelé le TweenService pour se déplacer d'un objectif à un autre.Nous avons utilisé des volumes de parties pour indiquer à l'opération de triangulation où les positions de début et de fin étaient pour le mur.


Parce que TweenService est un système si général, tous nos modèles de données de mur devaient contenir les mêmes composants.Par exemple, un script général « Door_Script » joue un son défini par une « valeur » en dessous du modèlisation« Grow_Wall ».Ce même script, avec quelques modifications dans l'exemple de code suivant, a également déclenché l'audio pour le déplacement de la cuisine.Cela a beaucoup ajouté au mouvement !
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local model = script.Parent
local sound = model.Sound.Value
local trigger = model.Trigger
local left = model.TargetL_Closed
local right = model.TargetR_Closed
local tweenInfo = TweenInfo.new(
model.Speed.Value, --Temps/vitesse du tween de la porte
Enum.EasingStyle.Quart, --Style d'aisance
Enum.EasingDirection.InOut, --Direction d'allègement
0, --Compter à nouveau
false, --Inversez vrai
0 --Retard
)
local DoorState = {
["Closed"] = 1,
["Opening"] = 2,
["Open"] = 3,
["Closing"] = 4,
}
local doorState = DoorState.Closed
local playersNear = {}
local tweenL = TweenService:Create(left, tweenInfo, {CFrame = model.TargetL_Open.CFrame})
local tweenR = TweenService:Create(right, tweenInfo, {CFrame = model.TargetR_Open.CFrame})
local tweenLClose = TweenService:Create(left, tweenInfo, {CFrame = model.TargetL_Closed.CFrame})
local tweenRClose = TweenService:Create(right, tweenInfo, {CFrame = model.TargetR_Closed.CFrame})
local function StartOpening()
doorState = DoorState.Opening
sound:Play()
tweenL:Play()
tweenR:Play()
end
local function StartClosing()
doorState = DoorState.Closing
--modèlisation["Porte"]:Jouer()
tweenLClose:Play()
tweenRClose:Play()
end
local function tweenOpenCompleted(playbackState)
if next(playersNear) == nil then
StartClosing()
else
doorState = DoorState.Open
end
end
local function tweenCloseCompleted(playbackState)
if next(playersNear) ~= nil then
StartOpening()
else
doorState = DoorState.Closed
end
end
tweenL.Completed:Connect(tweenOpenCompleted)
tweenLClose.Completed:Connect(tweenCloseCompleted)
local function touched(otherPart)
if otherPart.Name == "HumanoidRootPart" then
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if player then
--print("touch")
playersNear[player] = 1
if doorState == DoorState.Closed then
StartOpening()
end
end
end
end
Une fois que nous avions le mur faux se déplaçant vers l'arrière de la salle, nous avions besoin du reste du contenu pour se déplacer avec lui.Pour ce faire, nous avions besoin que tous les articles libres dans la cuisine soient soudés au mur pendant qu'il se déplaçait.En utilisant Contraintes de soudure, nous avons pu rapidement souder tous les objets au mur de la cuisine pour nous déplacer comme un seul objet.Cela signifiait que nous avions l'option de désoudre ces éléments afin que les joueurs puissent les heurter et les faire tomber !
Fabrique la cabane dans les arbres corrompue
Studio est un moteur physiquement basé fantastique que vous pouvez utiliser pour créer tout, du portail balançant à la plateformetournante.Avec notre démo, nous voulions utiliser la physique pour créer un sentiment de réalisme dans un ensemble d'environnements autrement irréaliste.En utilisant seulement quelques contraintes , vous pouvez créer des courses d'obstacles amusantes et difficiles dans vos propres expériences !

Contraintes sont un groupe de moteurs physiquement basés qui alignent les objets et restreignent les comportements.Par exemple, vous pouvez utiliser une contrainte de barre pour vous connecter à des objets afin de les maintenir à une distance fixe les uns des autres, ou la contrainte de corde pour avoir une lampe suspendue à la fin de la ligne.Pour le puzzle du fils dans lequel les joueurs sont transportés dans l'état corrompu de l'étude, nous voulions littéralement retourner le monde de son côté.Faire ainsi contournerait les attentes des joueurs envers la réalité et les règles qui s'y appliquent, tout en utilisant toujours le système de physique tel qu'il était destiné !

Une fois que les joueurs ont travaillé jusqu'à la zone principale du puzzle, ils ont été accueillis avec une vue familière sur Roblox : un parcours d'obstacles.Ce parcours d'obstacles spécifique comprenait plusieurs plateformes tournantes et des murs rotatifs, ainsi que des « zones sûres » qui ont progressé l'histoire.Nous nous concentrerons sur les éléments rotatifs/旋轉 elements.

Pourquoi avons-nous utilisé des contraintes ici ? Parce que TweenService ou d'autres méthodes ne déplaceront pas le joueur tant qu'il se tient dessus.Sans que l'objet déplace le joueur, quelqu'un pourrait sauter sur une plate-forme et elle se détacherait sous eux.Au lieu de cela, nous voulions que les joueurs naviguent sur une plate-forme tournante tout en essayant de sauter sur la suivante.En raison de cette approche, les joueurs se sont sentis enracinés là où ils se trouvaient tout en prenant une décision sur la façon de procéder à travers le parcours, et nous n'avions pas besoin de faire quoi que ce soit de spécial pour les assurer de se déplacer avec une surface rotative !

Pour ce faire, nous devions d'abord utiliser des ressources de notre kit actuel et ajouter tout nouveau contenu pour un effet visuel.Nous avons fait quelques murs et plates-formes incomplètes avec des trous dedans pour raconter l'histoire de la grand-mère qui a construit la cabane dans les arbres.Comme nous ne voulions pas créer un tas de plates-formes uniques, nous avons fabriqué 4 pièces de base et des balustrades séparément.Cela nous a permis de mélanger et d'assortir des pièces de base et de balustrade individuelles pour avoir beaucoup de variété.

Nous savions que puisque nous utilisions des contraintes, nous ne pourrions pas ancrer ces mailles car elles ne se déplairaient pas même avec la présence d'une contrainte/moteur les guidant.La contrainte nécessaire pour être un enfant de quelque chose qui a été ancré afin que la plate-forme ne tombe pas simplement du monde.Nous avons résolu cela via une partie que nous avons nommée Motor_Anchor qui avait une contrainte articulaire pour alimenter le mouvement global de la plateforme.Après cela, nous avions besoin des deux mailles pour se déplacer comme une seule, alors nous avons créé une partie que nous avons nommée Motor_Turn , puis nous avons soudé les deux mailles à elle.De cette façon, la contrainte serait capable de travailler sur une seule partie, à l'inverse de plusieurs charnières travaillant avec plusieurs parties.

Il était maintenant temps de configurer le comportement réel de la contrainte de charnière elle-même, et d'ajouter les pièces jointes qui agiraient comme l'orientation de la pièce et la contrainte ensemble.Nous avons placé l'attache tournante sur le Motor_Turn, auquel les pièces de passerelle ont été soudées, et une autre attache pour le comportement d'ancrage sur le Motor_Anchor lui-même, à côté de la contrainte de charnière.Puisque cela devait tourner par lui-même, à l'inverse d'être influencé par le joueur (comme une charnière de porte), nous avons défini le HingeConstraint.ActuatorType sur Moteur , traitant la contrainte comme un moteur se déplaçant lui-même.
Pour maintenir les plateformes en rotation à une vitesse constante, nous configurons ensuite les propriétés , , et pour des valeurs qui permettraient le mouvement et empêcheraient l'interruption si un joueur sautait dessus.

Maintenant, nous devions fabriquer les murs rotatifs.Les murs devaient tourner sur leur centre apparent, et nous savions que nous voulions qu'ils puissent gérer n'importe quelle orientation par rapport au reste du niveau.Comme les plates-formes, nous avons construit ces dernières afin que tous les murs soient non ancrés et soudés au Motor_Turn.

Nous avons utilisé des objets Texture en plus des objets SurfaceAppearance pour ajouter une certaine variation à nos matériaux de base.Les textures, semblables aux décalcomanies, vous permettent de placer une image sur un plan d'un maillage.Cela peut être utile si vous voulez ajouter de la saleté à un mur de briques ou faire paraître le bois vieux en utilisant le même matériau de base en bois.Texture les objets ont un comportement légèrement différent de celui des objets Decal dans lequel vous pouvez carreler et décaler l'image comme vous le souhaitez, ce qui est très utile si vous voulez pouvoir redimensionner votre texture d'Overlay et ne vous souciez pas qu'elle se répète !

Une fois que nous avions testé quelques plates-formes et murs rotatifs, nous avons fait plusieurs variations et joué avec leur placement pour nous assurer que le parcours d'obstacles était difficile, mentalisant et aussi clair où le joueur devait aller ! Il a fallu faire quelques ajustements à la fois à leurs valeurs et positions pour les faire fonctionner correctement.Nous avons eu plusieurs points où les plateformes et les murs se heurtaient les uns aux autres ou aux environs, mais avec quelques mouvements et des tests fréquents, nous avons pu atterrir sur les paramètres que nous avons dans la démo !
Si vous n'êtes pas sûr de ce que vos objets physiques frappent, vous pouvez activer la fidélité à la collision à partir du widget Options de visualisation dans le coin supérieur droit de la fenêtre de jeu3D.



Comme vous pouvez le voir ci-dessous, les trous d'entrée/fenêtre sont visibles, mais les détails plus petits comme le sous-panneau ne le sont pas.C'est parce que la propriété CollisionFidelity pour les murs a été définie sur Boîte .Nous n'avions pas besoin de la précision pour ces panneaux, donc pour économiser sur le coût de performance, c'était suffisamment détaillé pour que les joueurs puissent sauter dessus.Avec les plates-formes et les murs rotatifs terminés, nous n'avions plus qu'à ajouter des ressources de détail comme des boîtes et des lampes, puis c'était prêt à être joué !
