Techniques et conversion

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

Ce guide décrit plusieurs techniques pour utiliser le streaming d'instances dans le jeu de manière efficace et efficiente. Bien qu'il n'existe pas de solution "taille unique" pour concevoir un jeu en streaming, suivre ces étapes de haut niveau vous rapprochera de l'objectif.

Propriétés de streaming

Une fois que StreamingEnabled est activé pour l'objet Workspace dans Studio, définissez ses propriétés associées sur les valeurs recommandées suivantes :

PropriétéRecommandation
EnableSLIMAvatarsUtilisez Enabled pour rendre les avatars de rig standard comme des remplaçants légers et animés lorsque cela est approprié. Voir Avatars SLIM pour plus d'infos.
ModelStreamingBehaviorUtilisez Improved pour activer le streaming le plus efficace pour les Models avec des descendants BasePart.
StreamingIntegrityModeUtilisez PauseOutsideLoadedArea pour équilibrer l'intégrité du gameplay sans mettre en pause inutilement ou trop souvent.
StreamingMinRadiusUtilisez la valeur par défaut de 64 pour maximiser la capacité du moteur à réduire la taille du jeu pour les appareils bas de gamme.
StreamingTargetRadiusUtilisez la valeur par défaut de 1024 pour trouver un bon équilibre entre la visibilité pour les joueurs sur des appareils haut de gamme et une empreinte mémoire raisonnable.
StreamOutBehaviorUtilisez Opportunistic pour permettre au client de collecter agressivement les contenus inutilisés, réduisant ainsi considérablement l'utilisation de la mémoire et aidant à prévenir les plantages dus à un manque de mémoire.

Niveau de détail du modèle

Model.LevelOfDetail aide à remplir le contenu Model non-streamé avec des maillages composites ou imposteurs légers, rendant le monde visuellement complet. Les SLIM (Modèles Légers Interactifs Scalables) sont particulièrement efficaces, car les joueurs ne peuvent souvent pas distinguer un maillage SLIM de l'original entièrement streamé.

Pour de meilleurs résultats :

  • Regroupez les parties qui sont spatialement et logiquement liées, par exemple toutes les parties d'une voiture.
  • Définissez LevelOfDetail sur SLIM pour les modèles contenant des maillages et parties statique. Les modèles qui sont modifiés à l'exécution ou qui jouent des animations ne sont pas pris en charge.
  • Gardez l'étendue spatiale de chaque modèle sous ~64 studs cubes pour augmenter la probabilité que l'ensemble du modèle réel soit streamé ensemble. Si un modèle a des dimensions très grandes, décomposez-le en modèles modulaires plus petits et appliquez un LevelOfDetail approprié à chacun.

Structure du modèle

Au-delà de la définition du niveau de détail du modèle, la structure et les paramètres de vos Models ont un impact significatif sur la performance du streaming. Au fur et à mesure que vous construisez ou convertissez un jeu existant :

  • Utilisez des modèles atomiques pour le regroupement logique — Lorsqu'un script a besoin d'accéder à toutes les parties d'un modèle, définissez son ModelStreamingMode sur Atomic. Cela permet aux scripts côté client d'accéder en toute sécurité aux instances à l'intérieur du modèle sans utiliser excessivement WaitForChild() (bien que ces scripts doivent toujours utiliser WaitForChild() pour le modèle atomique global).

  • Minimisez les modèles persistants — Les modèles persistants se chargent après la connexion et ne streament jamais, occupant ainsi de manière permanente la mémoire. Définissez le ModelStreamingMode d'un modèle sur Persistent uniquement s'il doit rester disponible et accessible aux scripts à tout moment.

  • Décomposez les modèles conteneurs — Un modèle non-streaming courant est un énorme Model contenant de nombreux PNJ, accessoires ou regroupements similaires. Sous streaming, les modèles conteneurs diminuent l'efficacité du streaming et ne sont pas optimaux pour le niveau de détail du modèle qui fonctionne mieux avec des instances étroitement regroupées. Décomposez les modèles conteneurs en modèles plus petits avec des parties physiquement proches ou logiquement liées.

  • Aplatissez les hiérarchies de modèles profondément imbriquées — Imbriquer un modèle persistant à l'intérieur d'un modèle atomique force effectivement le modèle atomique à se comporter comme persistant. Les hiérarchies plates sont plus faciles à comprendre sous streaming.

Avatars SLIM

Les avatars de plateforme en dehors de la zone actuellement streamée ne sont pas visibles par défaut, mais activer Workspace.EnableSLIMAvatars rend les avatars de rig standard comme des remplaçants légers et animés lorsque cela est approprié. Effectivement, le moteur :

  • Rend une version SLIM lorsqu'un modèle d'avatar réel est streamé.
  • Échange entre les représentations SLIM et haute résolution en fonction des ressources disponibles, même à l'intérieur du rayon de streaming.
  • Limite les animations SLIM en fonction de l'importance de la scène et de la bande passante disponible.

Les avatars SLIM prennent en charge les personnages joueurs de rig standard R15 avec corps, tête, vêtements superposés et accessoires. Les avatars R6, les PNJ et les avatars avec des proportions personnalisées sont exclus. Pour la liste complète des configurations d'avatar prises en charge et exclues, des données de performance et des conseils de dépannage, voir Avatars SLIM.

Modèles de script

Les modèles de script suivants sont les plus souvent affectés par le streaming. La bonne stratégie dépend de l'intention du code, donc chaque modèle liste plusieurs options lorsque cela est approprié.

Index direct vers les descendants

Indexer les descendants de Workspace avec l'opérateur . génère une erreur si une instance dans le chemin n'est pas actuellement streamée. Il en va de même pour FindFirstChild(), FindFirstChildWhichIsA() et FindFirstChildOfClass() qui retournent nil si l'enfant n'a pas été streamé.

Recherche de descendant
local house1 = workspace:FindFirstChild("House1") -- nil si "House1" n'a pas été streamé
local door = workspace.House1.Door -- Cassé si "House1" ou "Door" n'a pas été streamé

Un modèle similaire consiste à accéder directement aux descendants Humanoid ou autres personnages à l'intérieur d'une connexion Player.CharacterAdded. Sous streaming, le modèle de personnage est parenté à Workspace avant que tous ses descendants aient été répliqués, donc l'indexation directe échoue.

Descendants de personnage
local Players = game:GetService("Players")
local player = Players.LocalPlayer
player.CharacterAdded:Connect(function(character)
local humanoid = character.Humanoid
end)

Si le script ne peut pas progresser sans une instance, attendez-la avec WaitForChild() :

Recherche de descendant
local house1 = workspace:WaitForChild("House1")
local door = house1:WaitForChild("Door")

Instances envoyées à distance

Un signal RemoteEvent/RemoteFunction et l'instance à laquelle il fait référence voyagent indépendamment, donc le signal peut arriver sur le client avant que l'instance soit présente — ou l'instance peut ne jamais être présente du tout. Deux causes probables incluent :

  • Sous streaming, il peut y avoir un léger délai entre la création d'une partie/modèle sur le serveur et sa réplication aux clients. Effectivement, une partie référencée par un RemoteEvent/RemoteFunction peut simplement ne pas exister encore, même à l'intérieur d'une zone streamée.

  • Envoyer une référence de partie/modèle du serveur au client via un RemoteEvent ou RemoteFunction nécessite que l'instance soit répliquée au client récepteur. Envoyer un chemin d'instance sous forme de chaîne a le même problème, car le chemin peut se résoudre à un emplacement inexistant sur le client :

    Script Client
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
    remoteEvent.OnClientEvent:Connect(function(data)
    local checkpoint = data.checkpoint -- Erreurs si "checkpoint" n'est pas streamé
    local level = workspace.Levels[data.levelPath] -- Erreurs si le chemin n'est pas streamé
    end)

Si le script client a besoin de l'instance pour progresser, incluez WaitForChild() avant de l'utiliser. Notez que cela peut bloquer indéfiniment si l'instance ne stream jamais, donc envisagez d'ajouter un délai d'attente comme deuxième paramètre de WaitForChild().

Désynchronisation côté client

La désynchronisation côté client doit être considérée comme une exception, pas comme un modèle de conception standard. Introduire des copies uniquement côté client ou reparenting d'instances localement peut créer des problèmes graves. Auditez votre code pour les endroits qui dépendent de ces types de changements persistants sur le client.

Par exemple, reparenter une instance localement de ReplicatedStorage à Workspace peut rendre cette instance éligible pour être streamée. De même, cloner une instance localement (Instance:Clone()) de ReplicatedStorage dans Workspace crée une copie uniquement côté client qui ne fait plus partie du pipeline de réplication du serveur et ne recevra pas de mises à jour de propriété de l'instance d'origine appartenant au serveur.

Le même concept s'applique lorsque vous appelez Instance:Destroy() sur le client pour un objet appartenant au serveur. Cela supprime l'instance localement mais le serveur l'a toujours, donc elle sera à nouveau streamée avec son état d'origine lorsqu'elle sera éligible.

Streaming proactif

Lorsque la prochaine destination d'un joueur peut être anticipée, effectuez des appels côté serveur à Player:RequestStreamAroundAsync() pour streamer des zones transitoires pour un chargement temporaire, ou utilisez Player:AddReplicationFocus() sur une base limitée pour des zones qui doivent rester chargées jusqu'à ce qu'elles soient explicitement libérées.

Par exemple, lorsqu'un personnage joueur est sur le point de se téléporter par un changement de CFrame vers la maison d'un autre joueur dans un emplacement éloigné, vous pouvez pré-récupérer la zone de destination pour minimiser le pop-in et fournir une transition plus fluide. Le script suivant montre comment un événement distant client-serveur peut être déclenché pour déplacer un personnage joueur en utilisant une méthode de pré-récupération. Si la demande de pré-récupération est réussie lorsque la fonction retourne, le rayon minimum autour de l'emplacement cible devrait être présent sur le client.

Script Serveur - Téléporter le personnage joueur
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local teleportEvent = ReplicatedStorage:WaitForChild("TeleportEvent")
local function teleportPlayer(player, teleportTarget)
-- Demander le streaming autour de l'emplacement cible
player:RequestStreamAroundAsync(teleportTarget)
-- Téléporter le personnage
local character = player.Character
if character and character.Parent then
local currentPivot = character:GetPivot()
character:PivotTo(currentPivot * CFrame.new(teleportTarget))
end
end
-- Appeler la fonction de téléportation lorsque le client déclenche l'événement distant
teleportEvent.OnServerEvent:Connect(teleportPlayer)

Lectures de propriétés d'instance

Une fois qu'une instance est streamée, ses mises à jour de propriété ne sont plus répliquées à ce client. La lecture de propriétés telles que BasePart.Position continue de réussir mais retourne la dernière valeur répliquée qui peut être arbitrairement obsolète.

local Players = game:GetService("Players")
local player = Players.LocalPlayer
-- La position peut être obsolète si "target" a été streamé
local dist = (target.Position - player.Character.HumanoidRootPart.Position).Magnitude

Déplacez la logique vers le serveur, car les scripts côté serveur voient toutes les instances à tout moment. C'est généralement l'option la plus fiable pour les vérifications de distance et d'autres logiques sensibles à la position.

Attente sur le chemin critique

Certains jeux non-streaming chargent leur carte en la clonant depuis ReplicatedStorage dans Workspace, puis attendent qu'elle soit présente sur le client avant de supprimer un écran de chargement et de signaler la disponibilité. Sous streaming, cela reste bloqué indéfiniment — le personnage du client n'a pas encore été généré, donc il n'y a pas de focalisation de réplication, et l'instance de carte spatiale ne stream jamais.

Déplacez la logique de l'écran de chargement afin qu'elle ne dépende pas d'une instance spatiale spécifique étant présente, par exemple en signalant la disponibilité une fois que le personnage a été généré et que la zone immédiate a été streamée.

Gestion des changements de signal

Des signaux tels que Instance.ChildAdded/Instance.ChildRemoved et des signaux de CollectionService comme GetInstanceAddedSignal() ou GetInstanceRemovedSignal() se déclenchent également lors du streaming in/out, indiscernables des véritables apparitions/retirages. Les scripts récepteurs ne peuvent pas faire la différence uniquement à partir du signal, donc la logique qui suppose qu'un signal correspond à un événement "réel" doit être mise à jour.

Auditez les scripts pour tout écouteur de signal qui pourrait se briser ou changer de manière significative lorsqu'il est déclenché par le streaming in et/ou le streaming out. Par exemple, si vous jouez des effets audio ou visuels lorsque un PNJ ennemi apparaît initialement dans le monde, attribuez à chaque ennemi un attribut tel que Spawned lors de la première apparition, et évitez de rejouer le même audio/effets lors des futurs streaming in de l'ennemi.

Suivi d'attribut
local CollectionService = game:GetService("CollectionService")
local TAG_NAME = "Enemy"
CollectionService:GetInstanceAddedSignal(TAG_NAME):Connect(function(enemy)
if not enemy:GetAttribute("Spawned") then
-- Définir l'attribut "Spawned" sur l'ennemi pour l'apparition initiale
enemy:SetAttribute("Spawned", true)
-- Jouer des effets audio/visuels pour cette apparition initiale
playSpawnEffects(enemy)
end
end)

Itération sur des collections

Les itérations de collection côté client comme Instance:GetChildren() et Instance:GetDescendants() ne retournent que le sous-ensemble streamé des descendants. Cela s'applique même lorsque le parent lui-même est toujours répliqué, comme un Folder directement sous Workspace dont les descendants spatiaux streament in et out.

local Players = game:GetService("Players")
local player = Players.LocalPlayer
-- Le dossier "Homes" est toujours répliqué mais ses enfants stream in et out
-- Cette boucle peut manquer des maisons qui ne sont pas actuellement streamées
for _, home in workspace.Homes:GetChildren() do
if home.Settings.Owner.Value == player.Name then
return home
end
end

Si une énumération complète est requise, effectuez le scan sur le serveur et passez le résultat au joueur via un RemoteEvent si nécessaire.

Requêtes spatiales

Les requêtes spatiales côté client comme WorldRoot:Raycast(), WorldRoot:GetPartBoundsInBox(), et Model:GetBoundingBox() ne reflètent que le contenu streamé. Que cela soit un problème dépend de l'utilisation de la requête.

Utilisez le serveur pour les requêtes dont le résultat doit refléter le monde entier, par exemple un raycast qui vérifie si le joueur a une ligne de vue sur une cible éloignée.

Autres modèles

Les modèles suivants peuvent également s'appliquer et doivent être soigneusement considérés :

  • Un Sound ou AudioPlayer parenté à un objet 3D s'arrête lorsque cet objet est streamé. Pour l'audio ambiant qui doit persister indépendamment du streaming, parent l'émetteur à un modèle persistant ou à un conteneur non-streaming.

  • Les objets UI dans le jeu comme BillboardGui ou SurfaceGui ainsi que les effets visuels comme Beams ou Highlights dont l'adornee ou l'attachement est streamé s'arrêtent simplement de rendre. Cela peut être le comportement prévu, mais vous devez le vérifier.

  • Les événements BasePart.Touched, ProximityPrompts, DragDetectors, et ClickDetectors ne fonctionnent pas pour les joueurs dont le client n'a pas l'objet/modèle associé streamé. Si l'interaction doit être possible de n'importe quelle distance, le modèle doit être persistant ou l'interaction doit avoir un mécanisme différent.

  • Pour PathfindingService et le pathfinding côté client, le chemin ne voit que la géométrie streamée sur le client et peut passer à travers des obstacles qui existent sur le serveur. Voir ici pour des stratégies.

Conditions de test réalistes

Une fois que les scripts sont mis à jour, testez le jeu de manière approfondie. Les bugs de streaming se manifestent souvent uniquement aux bords de la zone streamée ou lors des transitions, donc tester uniquement près du spawn ou à un rayon cible n'est pas suffisant.

  • Testez avec Workspace.StreamingTargetRadius défini sur sa valeur minimale (64). Certains bugs de streaming n'apparaissent que lorsque la zone streamée est petite.

  • Jouez à travers les motifs de traversée complets du jeu, téléportez-vous entre des zones éloignées et revisitez des zones après les avoir quittées. Ce sont les situations qui exercent le plus le streaming in et out.

  • Utilisez la superposition de débogage de streaming pour surveiller les paramètres de streaming actifs, les régions actuellement chargées et l'état de streaming à l'exécution.

  • Surveillez la fenêtre Output et la Console de Développeur pour les erreurs, car de nombreux modèles de script produisent des erreurs plutôt que des comportements silencieux. Faites particulièrement attention aux erreurs de la forme attempt to index nil with ... qui indiquent souvent un appel manquant à WaitForChild().

  • Équipez et activez des Tools, tirez des armes et déclenchez différentes interactions de jeu.

Compétence de conversion de streaming AI

Pour aider à la conversion et à l'optimisation du streaming, Roblox propose une compétence de streaming AI, accessible depuis le serveur MCP de Studio. La compétence évalue automatiquement votre jeu, applique des configurations recommandées et nettoie les problèmes de compatibilité, y compris :


Pour utiliser la compétence AI dans votre jeu :

  1. IMPORTANT
    Sauvegardez votre jeu. Le processus de conversion peut être complexe, donc vous devriez toujours sauvegarder une copie de sauvegarde (Fichier ⟩ Publier sur Roblox en tant que) avant d'exécuter la compétence.

  2. Vous pouvez exécuter cette compétence en utilisant n'importe quel LLM que vous préférez via le Protocole de Contexte de Modèle (MCP) dans Studio. Des modèles AI haut de gamme avec de grandes fenêtres de contexte sont recommandés ; dans Claude Opus, la conversion typique prend 20 à 30 minutes et utilise environ 200 000 tokens de contexte.

    1. Ouvrez votre jeu dans Studio.
    2. Téléchargez la compétence et, dans votre client AI, ouvrez le dossier décompressé (roblox-streaming-conversion) comme projet actuel.
    3. Exécutez la compétence avec /rbx-convert-to-streaming.
    4. Comme pour toute sortie AI, vérifiez les résultats et testez votre jeu de manière extensive dans des conditions de test réalistes.
©2026 Société Roblox. Roblox, le logo Roblox et Powering Imagination font partie de nos marques déposées aux États-Unis et dans d'autres pays.