Questa guida delinea diverse tecniche per utilizzare lo streaming delle istanze in gioco in modo efficiente ed efficace. Anche se non esiste una soluzione "taglia unica" per progettare un gioco in streaming, seguire questi passaggi di alto livello ti porterà la maggior parte della strada.
Proprietà di streaming
Una volta che StreamingEnabled è attivato per l'oggetto Workspace in Studio, imposta le sue proprietà correlate ai seguenti valori raccomandati:
| Proprietà | Raccomandazione |
|---|---|
| EnableSLIMAvatars | Usa Enabled per rendere gli avatar rig standard come sostituti leggeri e animati quando appropriato. Vedi avatar SLIM per ulteriori informazioni. |
| ModelStreamingBehavior | Usa Improved per abilitare lo streaming più efficiente per Models con discendenti di BasePart. |
| StreamingIntegrityMode | Usa PauseOutsideLoadedArea per bilanciare l'integrità del gameplay senza mettere in pausa inutilmente o troppo spesso. |
| StreamingMinRadius | Usa il valore predefinito di 64 per massimizzare quanto il motore può ridurre il gioco per dispositivi a bassa potenza. |
| StreamingTargetRadius | Usa il valore predefinito di 1024 per trovare un buon equilibrio tra visibilità per i giocatori su dispositivi ad alte prestazioni e un'impronta di memoria ragionevole. |
| StreamOutBehavior | Usa Opportunistic per consentire al client di raccogliere aggressivamente contenuti non utilizzati, riducendo significativamente l'uso della memoria e aiutando a prevenire crash per esaurimento della memoria. |
Livello di dettaglio del modello
Model.LevelOfDetail aiuta a riempire i contenuti Model non streaming con mesh composite o impostore leggere, rendendo il mondo visivamente completo. SLIM (Modelli Leggeri Interattivi Scalabili) sono particolarmente efficaci, poiché i giocatori spesso non possono distinguere una mesh SLIM dall'originale completamente streaming.
Per i migliori risultati:
- Raggruppa le parti che sono spazialmente e logicamente correlate, ad esempio tutte le parti di un'auto.
- Imposta LevelOfDetail su SLIM sui modelli che contengono mesh e parti statiche. I modelli che vengono modificati durante il runtime o che riproducono animazioni non sono supportati.
- Mantieni l'estensione spaziale di ciascun modello sotto ~64 stud cubici per aumentare la probabilità che l'intero modello effettivo venga streaming insieme. Se un modello ha estensioni molto grandi, suddividilo in modelli modulari più piccoli e applica un appropriato LevelOfDetail a ciascuno di essi.
Struttura del modello
Oltre a impostare il livello di dettaglio del modello, la struttura e le impostazioni dei tuoi Models hanno un impatto significativo su quanto bene lo streaming funzioni. Mentre costruisci o converti un gioco esistente:
Usa modelli atomici per raggruppamenti logici — Quando uno script ha bisogno di accesso a tutte le parti all'interno di un modello, imposta il suo ModelStreamingMode su Atomic. Questo consente agli script lato client di accedere in modo sicuro alle istanze all'interno del modello senza un uso eccessivo di WaitForChild() (anche se tali script devono comunque utilizzare WaitForChild() per l'intero modello atomico).
Minimizza i modelli persistenti — I modelli persistenti vengono caricati dopo l'accesso e non vengono mai streaming, occupando permanentemente memoria. Imposta il ModelStreamingMode di un modello su Persistent solo se deve rimanere disponibile e accessibile agli script in ogni momento.
Decomponi i modelli contenitore — Un modello non streaming comune è un singolo enorme Model che contiene molti NPC, oggetti o raggruppamenti simili. Sotto streaming, i modelli contenitore diminuiscono l'efficienza dello streaming e non sono ottimali per il livello di dettaglio del modello che funziona meglio con istanze strettamente raggruppate. Decomponi i modelli contenitore in modelli più piccoli con parti fisicamente vicine o logicamente correlate.
Appiattisci le gerarchie di modelli profondamente annidate — Annidare un modello persistente all'interno di un modello atomico costringe effettivamente il modello atomico a comportarsi come persistente. Gerarchie piatte sono più facili da comprendere sotto streaming.
Avatar SLIM
Gli avatar della piattaforma al di fuori dell'area attualmente streaming non sono visibili per impostazione predefinita, ma abilitando Workspace.EnableSLIMAvatars si rendono gli avatar rig standard come sostituti leggeri e animati quando appropriato. Effettivamente, il motore:
- Rende una versione SLIM quando un modello avatar effettivo viene streaming.
- Scambia tra rappresentazioni SLIM e a risoluzione completa in base alle risorse disponibili, anche all'interno del raggio di streaming.
- Limita le animazioni SLIM in base all'importanza della scena e alla larghezza di banda disponibile.
Gli avatar SLIM supportano i personaggi giocatori con rig standard R15 con corpo, testa, abbigliamento a strati e accessori. Gli avatar R6, gli NPC e gli avatar con proporzioni personalizzate sono esclusi. Per l'elenco completo delle configurazioni di avatar supportate ed escluse, dati sulle prestazioni e suggerimenti per la risoluzione dei problemi, vedere avatar SLIM.
Modelli di script
I seguenti modelli di script sono i più comunemente influenzati dallo streaming. La strategia corretta dipende dall'intento del codice, quindi ogni modello elenca più opzioni dove appropriato.
Indice diretto ai discendenti
Indicizzare i discendenti di Workspace con l'operatore . genera un errore se qualsiasi istanza nel percorso non è attualmente streaming. Lo stesso vale per FindFirstChild(), FindFirstChildWhichIsA() e FindFirstChildOfClass() che restituiscono nil se il figlio non è stato streaming.
local house1 = workspace:FindFirstChild("House1") -- nil se "House1" non è stato streaming
local door = workspace.House1.Door -- Rotto se "House1" o "Door" non è stato streamingUn modello simile è accedere direttamente ai discendenti di Humanoid o ad altri discendenti del personaggio all'interno di una connessione Player.CharacterAdded. Sotto streaming, il modello del personaggio è parentato a Workspace prima che tutti i suoi discendenti siano stati replicati, quindi l'indicizzazione diretta fallisce.
local Players = game:GetService("Players")
local player = Players.LocalPlayer
player.CharacterAdded:Connect(function(character)
local humanoid = character.Humanoid
end)Se lo script non può progredire senza un'istanza, attendila con WaitForChild():
local house1 = workspace:WaitForChild("House1")
local door = house1:WaitForChild("Door")Istanze inviate da remoto
Un segnale RemoteEvent/RemoteFunction e l'istanza a cui si riferisce viaggiano in modo indipendente, quindi il segnale può arrivare al client prima che l'istanza sia presente — o l'istanza potrebbe non essere mai presente. Due cause probabili includono:
Sotto streaming, potrebbe esserci un leggero ritardo tra quando una parte/modello viene creato sul server e quando viene replicato ai client. Effettivamente, una parte referenziata da un RemoteEvent/RemoteFunction potrebbe semplicemente non esistere ancora, anche all'interno di un'area streaming.
Inviare un riferimento a parte/modello dal server al client tramite un RemoteEvent o RemoteFunction richiede che l'istanza sia replicata al client ricevente. Inviare un percorso di istanza come stringa ha lo stesso problema, poiché il percorso potrebbe risolversi in una posizione non esistente sul client:
Script Clientlocal ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")remoteEvent.OnClientEvent:Connect(function(data)local checkpoint = data.checkpoint -- Errori se "checkpoint" non è stato streaminglocal level = workspace.Levels[data.levelPath] -- Errori se il percorso non è stato streamingend)
Se lo script del client ricevente ha bisogno dell'istanza per procedere, includi WaitForChild() prima di usarla. Nota che questo può bloccarsi indefinitamente se l'istanza non viene mai streaming, quindi considera di aggiungere un timeout come secondo parametro di WaitForChild().
Desincronizzazione del client
La desincronizzazione lato client dovrebbe essere trattata come un'eccezione, non come un modello di design standard. Introdurre copie solo client o riparentare istanze localmente può creare seri problemi. Controlla il tuo codice per i luoghi che si basano su questi tipi di modifiche che persistono sul client.
Ad esempio, riparentare un'istanza localmente da ReplicatedStorage a Workspace può rendere quell'istanza idonea per essere streaming. Allo stesso modo, clonare un'istanza localmente (Instance:Clone()) da ReplicatedStorage in Workspace crea una copia solo client che non fa più parte del pipeline di replicazione del server e non riceverà aggiornamenti delle proprietà dall'istanza originale di proprietà del server.
Lo stesso concetto si applica quando si chiama Instance:Destroy() sul client per un oggetto di proprietà del server. Questo rimuove l'istanza localmente ma il server la possiede ancora, quindi verrà streaming di nuovo con il suo stato originale quando sarà idonea.
Streaming proattivo
Quando la prossima destinazione di un giocatore può essere anticipata, fai chiamate lato server a Player:RequestStreamAroundAsync() per streaming aree transitorie per il caricamento temporaneo, oppure usa Player:AddReplicationFocus() su base limitata per aree che dovrebbero rimanere caricate fino a quando non vengono esplicitamente rilasciate.
Ad esempio, quando un personaggio giocatore sta per teletrasportarsi cambiando CFrame in casa di un altro giocatore in una posizione distante, puoi pre-fetch l'area di destinazione per ridurre al minimo il pop-in e fornire una transizione più fluida. Il seguente script mostra come un evento remoto da client a server può essere attivato per spostare un personaggio giocatore utilizzando un metodo di pre-fetch. Se la richiesta di pre-fetch ha successo quando la funzione restituisce, il raggio minimo attorno alla posizione target dovrebbe essere presente sul client.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local teleportEvent = ReplicatedStorage:WaitForChild("TeleportEvent")
local function teleportPlayer(player, teleportTarget)
-- Richiedi streaming attorno alla posizione target
player:RequestStreamAroundAsync(teleportTarget)
-- Teletrasporta il personaggio
local character = player.Character
if character and character.Parent then
local currentPivot = character:GetPivot()
character:PivotTo(currentPivot * CFrame.new(teleportTarget))
end
end
-- Chiama la funzione di teletrasporto quando il client attiva l'evento remoto
teleportEvent.OnServerEvent:Connect(teleportPlayer)Letture delle proprietà delle istanze
Una volta che un'istanza viene streaming, gli aggiornamenti delle sue proprietà non vengono più replicati a quel client. La lettura di proprietà come BasePart.Position continua a riuscire ma restituisce l'ultimo valore replicato che può essere arbitrariamente obsoleto.
local Players = game:GetService("Players")
local player = Players.LocalPlayer
-- La posizione potrebbe essere obsoleta se "target" è stato streaming
local dist = (target.Position - player.Character.HumanoidRootPart.Position).MagnitudeSposta la logica sul server, poiché gli script lato server vedono tutte le istanze in ogni momento. Questa è generalmente l'opzione più affidabile per controlli di distanza e altre logiche sensibili alla posizione.
Attesa sul percorso critico
Alcuni giochi non streaming caricano la loro mappa clonandola da ReplicatedStorage in Workspace, quindi attendono che sia presente sul client prima di rimuovere uno schermo di caricamento e segnalare la prontezza. Sotto streaming questo si blocca indefinitamente — il personaggio del client non è ancora stato generato, quindi non c'è focalizzazione della replicazione, e l'istanza della mappa spaziale non viene mai streaming.
Sposta la logica dello schermo di caricamento in modo che non dipenda dalla presenza di un'istanza spaziale specifica, ad esempio segnalando la prontezza una volta che il personaggio è stato generato e l'area immediata è stata streaming.
Gestione del cambiamento del segnale
Segnali come Instance.ChildAdded/Instance.ChildRemoved e segnali di CollectionService come GetInstanceAddedSignal() o GetInstanceRemovedSignal() si attivano anche durante lo streaming in/out, indistinguibili da veri spawn/rimozioni. Gli script riceventi non possono distinguere la differenza dal segnale da solo, quindi la logica che presume che un segnale corrisponda a un evento "reale" deve essere aggiornata.
Controlla gli script per eventuali listener di segnali che potrebbero rompersi o cambiare significativamente quando attivati dallo streaming in e/o streaming out. Ad esempio, se riproduci audio o effetti visivi quando un NPC nemico appare inizialmente nel mondo, assegna a ciascun nemico un attributo come Spawned al primo spawn, e salta la riproduzione dello stesso audio/effetti nei futuri streaming in del nemico.
local CollectionService = game:GetService("CollectionService")
local TAG_NAME = "Nemico"
CollectionService:GetInstanceAddedSignal(TAG_NAME):Connect(function(enemy)
if not enemy:GetAttribute("Spawned") then
-- Imposta l'attributo "Spawned" sul nemico per lo spawn iniziale
enemy:SetAttribute("Spawned", true)
-- Riproduci audio/effetti visivi per questo spawn iniziale
playSpawnEffects(enemy)
end
end)Iterazione su collezioni
Le iterazioni di collezione lato client come Instance:GetChildren() e Instance:GetDescendants() restituiscono solo il sottoinsieme di discendenti streaming. Questo si applica anche quando il genitore stesso è sempre replicato, come una Folder direttamente sotto Workspace i cui discendenti spaziali vengono streaming in e out.
local Players = game:GetService("Players")
local player = Players.LocalPlayer
-- La cartella "Homes" è sempre replicata ma i suoi figli vengono streaming in e out
-- Questo ciclo potrebbe perdere case che non sono attualmente streaming
for _, home in workspace.Homes:GetChildren() do
if home.Settings.Owner.Value == player.Name then
return home
end
endSe è necessaria un'enumerazione completa, esegui la scansione sul server e passa il risultato al giocatore tramite un RemoteEvent se necessario.
Query spaziali
Le query spaziali lato client come WorldRoot:Raycast(), WorldRoot:GetPartBoundsInBox() e Model:GetBoundingBox() riflettono solo contenuti streaming. Se questo sia un problema dipende da come viene utilizzata la query.
Usa il server per query il cui risultato deve riflettere il mondo intero, ad esempio un raycast che controlla se il giocatore ha linea di vista su un obiettivo distante.
Altri modelli
I seguenti modelli possono anche applicarsi e dovrebbero essere considerati con attenzione:
Un Sound o AudioPlayer parentato a un oggetto 3D si ferma quando quell'oggetto viene streaming. Per audio ambientale che dovrebbe persistere indipendentemente dallo streaming, parenta l'emettitore a un modello persistente o a un contenitore non streaming.
Oggetti UI in gioco come BillboardGui o SurfaceGui così come effetti visivi come Beams o Highlights il cui adornee o attacco viene streaming semplicemente smettono di rendere. Questo potrebbe essere il comportamento previsto, ma dovresti verificarlo.
Gli eventi BasePart.Touched, ProximityPrompts, DragDetectors, e ClickDetectors non operano per i giocatori il cui client non ha l'oggetto/il modello associato streaming. Se l'interazione deve essere possibile da qualsiasi distanza, il modello deve essere persistente o l'interazione deve avere un meccanismo diverso.
Per PathfindingService e il pathfinding lato client, il cercatore di percorso vede solo la geometria streaming sul client e potrebbe instradarsi attraverso ostacoli che esistono sul server. Vedi qui per strategie.
Condizioni di test realistiche
Una volta che gli script sono stati aggiornati, testa il gioco a fondo. I bug di streaming spesso si manifestano solo ai bordi dell'area streaming o durante le transizioni, quindi testare solo vicino allo spawn o al raggio target non è sufficiente.
Testa con Workspace.StreamingTargetRadius impostato al suo valore minimo (64). Alcuni bug di streaming appaiono solo quando l'area streaming è piccola.
Gioca attraverso i modelli di traversata completi del gioco, teletrasportati tra aree distanti e visita aree dopo averle lasciate. Queste sono le situazioni che esercitano di più lo streaming in e out.
Usa il sovrapposizione di debug dello streaming per monitorare le impostazioni di streaming attive, le regioni attualmente caricate e lo stato di streaming in tempo reale.
Controlla la finestra Output e la Console Sviluppatore per errori, poiché molti dei modelli di script producono errori piuttosto che comportamenti silenziosi errati. Presta particolare attenzione agli errori della forma attempt to index nil with ... che spesso indicano una chiamata mancante a WaitForChild().
Equipaggia e attiva Tools, spara armi e attiva diverse interazioni di gioco.
Abilità di conversione streaming AI
Per assistere con la conversione e l'ottimizzazione dello streaming, Roblox offre un'abilità di streaming AI, accessibile dal server MCP di Studio. L'abilità valuta automaticamente il tuo gioco, applica configurazioni raccomandate e risolve problemi di compatibilità, inclusi:
- Configura le impostazioni di streaming ai valori di base raccomandati.
- Imposta il livello di dettaglio per i modelli su SLIM dove applicabile.
- Rifattorizza le strutture dei modelli per ottenere dimensioni ottimali e qualità visiva.
Per utilizzare l'abilità AI nel tuo gioco:
- IMPORTANTEFai un backup del tuo gioco. Il processo di conversione può essere complesso, quindi dovresti sempre salvare un backup (File ⟩ Pubblica su Roblox Come) prima di eseguire l'abilità.
Puoi eseguire questa abilità utilizzando qualsiasi LLM tu preferisca tramite il Protocollo di Contesto del Modello (MCP) in Studio. Si raccomandano modelli AI di fascia alta con ampie finestre di contesto; in Claude Opus, la conversione tipica richiede 20-30 minuti e utilizza circa 200.000 token di contesto.
- Apri il tuo gioco in Studio.
- Scarica l'abilità e, nel tuo client AI, apri la cartella decompressa (roblox-streaming-conversion) come progetto corrente.
- Esegui l'abilità con /rbx-convert-to-streaming.
- Come con qualsiasi output AI, verifica i risultati e metti alla prova il tuo gioco ampiamente in condizioni di test realistiche.

