Techniki i konwersja

*Ta zawartość została przetłumaczona przy użyciu narzędzi AI (w wersji beta) i może zawierać błędy. Aby wyświetlić tę stronę w języku angielskim, kliknij tutaj.

Ten przewodnik przedstawia kilka technik efektywnego i skutecznego korzystania z strumieniowania instancji w grze. Chociaż nie ma jednego uniwersalnego rozwiązania do projektowania gry strumieniowej, podążanie za tymi ogólnymi krokami pomoże Ci w dużej mierze osiągnąć cel.

Właściwości strumieniowania

Gdy StreamingEnabled jest włączone dla obiektu Workspace w Studio, ustaw jego powiązane właściwości na następujące zalecane wartości:

WłaściwośćZalecenie
EnableSLIMAvatarsUżyj Enabled, aby renderować standardowe awatary rigów jako lekkie, animowane zamienniki, gdy to możliwe. Zobacz awatare SLIM po więcej informacji.
ModelStreamingBehaviorUżyj Improved, aby włączyć najefektywniejsze strumieniowanie dla Models z potomkami BasePart.
StreamingIntegrityModeUżyj PauseOutsideLoadedArea, aby zrównoważyć integralność rozgrywki bez niepotrzebnego lub zbyt częstego wstrzymywania.
StreamingMinRadiusUżyj domyślnej wartości 64, aby zmaksymalizować, jak bardzo silnik może zmniejszyć rozmiar gry dla urządzeń o niskiej wydajności.
StreamingTargetRadiusUżyj domyślnej wartości 1024, aby osiągnąć dobrą równowagę między widocznością dla graczy na urządzeniach o wysokiej wydajności a rozsądnym zużyciem pamięci.
StreamOutBehaviorUżyj Opportunistic, aby umożliwić klientowi agresywne zbieranie nieużywanych zasobów, znacznie zmniejszając zużycie pamięci i pomagając zapobiegać awariom z powodu braku pamięci.

Poziom szczegółowości modelu

Model.LevelOfDetail pomaga wypełnić nie-strumieniowane treści Model lekkimi kompozytowymi lub imposterowymi siatkami, sprawiając, że świat wygląda wizualnie kompletnie. SLIM (Skalowalne Lekkie Interaktywne Modele) są szczególnie skuteczne, ponieważ gracze często nie mogą odróżnić siatki SLIM od w pełni strumieniowanego oryginału.

Aby uzyskać najlepsze wyniki:

  • Grupuj części, które są przestrzennie i logicznie powiązane, na przykład wszystkie części samochodu.
  • Ustaw LevelOfDetail na SLIM w modelach, które zawierają statyczne siatki i części. Modele, które są modyfikowane w czasie rzeczywistym lub odtwarzają animacje, nie są obsługiwane.
  • Utrzymuj przestrzenny zasięg każdego modelu poniżej ~64 sześciennych studów, aby zwiększyć prawdopodobieństwo, że cały rzeczywisty model strumieniowany będzie razem. Jeśli model ma bardzo duże wymiary, podziel go na mniejsze modułowe modele i zastosuj odpowiedni LevelOfDetail do każdego z nich.

Struktura modelu

Poza ustawieniem poziomu szczegółowości modelu, struktura i ustawienia Twoich Models mają znaczący wpływ na to, jak dobrze działa strumieniowanie. Podczas budowania lub konwersji istniejącej gry:

  • Używaj modeli atomowych do logicznego grupowania — Gdy skrypt potrzebuje dostępu do wszystkich części w modelu, ustaw jego ModelStreamingMode na Atomic. Umożliwia to skryptom po stronie klienta bezpieczny dostęp do instancji wewnątrz modelu bez nadmiernego użycia WaitForChild() (chociaż takie skrypty muszą nadal używać WaitForChild() dla całego atomowego modelu).

  • Minimalizuj modele trwałeTrwałe modele ładują się po dołączeniu i nigdy nie strumieniują się, na stałe zajmując pamięć. Ustaw tryb strumieniowania modelu ModelStreamingMode na Persistent tylko wtedy, gdy musi pozostać dostępny i dostępny dla skryptów przez cały czas.

  • Rozkładaj modele kontenerowe — Powszechnym wzorcem bez strumieniowania jest jeden ogromny Model, który zawiera wiele NPC, rekwizytów lub podobnych grup. W przypadku strumieniowania modele kontenerowe zmniejszają efektywność strumieniowania i nie są optymalne dla poziomu szczegółowości modelu, który działa najlepiej z blisko grupowanymi instancjami. Rozłóż modele kontenerowe na mniejsze modele z fizycznie bliskimi lub logicznie powiązanymi częściami.

  • Spłaszczaj głęboko zagnieżdżone hierarchie modeli — Zagnieżdżenie trwałego modelu wewnątrz atomowego modelu skutecznie zmusza atomowy model do zachowania się jak trwały. Płaskie hierarchie są łatwiejsze do zrozumienia w kontekście strumieniowania.

Awatary SLIM

Awatary platformowe znajdujące się poza aktualnie strumieniowanym obszarem nie są domyślnie widoczne, ale włączenie Workspace.EnableSLIMAvatars renderuje standardowe rig awatary jako lekkie, animowane zamienniki, gdy to możliwe. Efektywnie, silnik:

  • Renderuje wersję SLIM, gdy rzeczywisty model awatara jest strumieniowany.
  • Przełącza się między reprezentacjami SLIM a pełną rozdzielczością w zależności od dostępnych zasobów, nawet wewnątrz promienia strumieniowania.
  • Ogranicza animacje SLIM w zależności od ważności sceny i dostępnej przepustowości.

Awatary SLIM obsługują postacie graczy z rigami standardowymi R15 z ciałem, głową, warstwową odzieżą i akcesoriami. Awatary R6, NPC i awatary o niestandardowych proporcjach są wykluczone. Aby uzyskać pełną listę obsługiwanych i wykluczonych konfiguracji awatarów, danych wydajności i wskazówek dotyczących rozwiązywania problemów, zobacz awatare SLIM.

Wzorce skryptów

Poniższe wzorce skryptów są najczęściej dotknięte przez strumieniowanie. Odpowiednia strategia zależy od intencji kodu, więc każdy wzorzec wymienia wiele opcji, gdzie to stosowne.

Bezpośredni indeks do potomków

Indeksowanie potomków Workspace za pomocą operatora . zgłasza błąd, jeśli jakakolwiek instancja w ścieżce nie jest aktualnie strumieniowana. To samo dotyczy FindFirstChild(), FindFirstChildWhichIsA() i FindFirstChildOfClass(), które zwracają nil, jeśli dziecko nie zostało strumieniowane.

Wyszukiwanie potomków
local house1 = workspace:FindFirstChild("House1") -- nil, jeśli "House1" nie zostało strumieniowane
local door = workspace.House1.Door -- Uszkodzone, jeśli "House1" lub "Door" nie zostały strumieniowane

Podobny wzorzec dotyczy dostępu do Humanoid lub innych potomków postaci bezpośrednio wewnątrz połączenia Player.CharacterAdded. W przypadku strumieniowania model postaci jest rodzicem Workspace przed replikacją wszystkich jego potomków, więc bezpośrednie indeksowanie zawodzi.

Potomkowie postaci
local Players = game:GetService("Players")
local player = Players.LocalPlayer
player.CharacterAdded:Connect(function(character)
local humanoid = character.Humanoid
end)

Jeśli skrypt nie może postępować bez instancji, poczekaj na nią za pomocą WaitForChild():

Wyszukiwanie potomków
local house1 = workspace:WaitForChild("House1")
local door = house1:WaitForChild("Door")

Instancje wysyłane zdalnie

Sygnal RemoteEvent/RemoteFunction i instancja, do której się odnosi, podróżują niezależnie, więc sygnał może dotrzeć do klienta przed obecnością instancji — lub instancja może nigdy nie być obecna. Dwa prawdopodobne powody to:

  • W przypadku strumieniowania może wystąpić niewielkie opóźnienie między momentem, gdy część/model jest tworzony na serwerze, a momentem, gdy zostaje zreplikowany do klientów. Efektywnie, część, do której odnosi się RemoteEvent/RemoteFunction, może po prostu jeszcze nie istnieć, nawet w strumieniowanym obszarze.

  • Wysłanie odniesienia do części/modelu z serwera do klienta za pomocą RemoteEvent lub RemoteFunction wymaga, aby instancja została zreplikowana do odbierającego klienta. Wysłanie ścieżki instancji jako ciągu ma ten sam problem, ponieważ ścieżka może prowadzić do nieistniejącej lokalizacji na kliencie:

    Skrypt klienta
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
    remoteEvent.OnClientEvent:Connect(function(data)
    local checkpoint = data.checkpoint -- Błąd, jeśli "checkpoint" nie jest strumieniowany
    local level = workspace.Levels[data.levelPath] -- Błąd, jeśli ścieżka nie jest strumieniowana
    end)

Jeśli skrypt odbierającego klienta potrzebuje instancji do kontynuowania, dołącz WaitForChild() przed jej użyciem. Zauważ, że może to trwać w nieskończoność, jeśli instancja nigdy nie zostanie strumieniowana, więc rozważ dodanie limitu czasu jako drugiego parametru do WaitForChild().

Desynchronizacja klienta

Desynchronizacja po stronie klienta powinna być traktowana jako wyjątek, a nie standardowy wzorzec projektowy. Wprowadzenie kopii tylko dla klienta lub lokalne zmienianie rodziców instancji może stworzyć poważne problemy. Przejrzyj swój kod pod kątem miejsc, które polegają na tych typach zmian, które utrzymują się na kliencie.

Na przykład, lokalne zmienianie rodzica instancji z ReplicatedStorage do Workspace może sprawić, że ta instancja będzie kwalifikować się do strumieniowania. Podobnie, klonowanie instancji lokalnie (Instance:Clone()) z ReplicatedStorage do Workspace tworzy kopię tylko dla klienta, która nie jest już częścią serwerowego procesu replikacji i nie otrzyma aktualizacji właściwości z oryginalnej instancji należącej do serwera.

Ta sama koncepcja dotyczy wywoływania Instance:Destroy() na kliencie dla obiektu należącego do serwera. To usuwa instancję lokalnie, ale serwer nadal ją ma, więc ponownie strumieniowana będzie z jej oryginalnym stanem, gdy będzie to możliwe.

Proaktywne strumieniowanie

Gdy następne miejsce docelowe gracza można przewidzieć, wykonaj wywołania po stronie serwera do Player:RequestStreamAroundAsync(), aby strumieniować przejściowe obszary do tymczasowego załadowania, lub użyj Player:AddReplicationFocus() w ograniczony sposób dla obszarów, które powinny pozostać załadowane, aż zostaną wyraźnie zwolnione.

Na przykład, gdy postać gracza ma teleportować się przez zmianę CFrame do domu innego gracza w odległej lokalizacji, możesz wstępnie załadować obszar docelowy, aby zminimalizować pojawianie się obiektów i zapewnić płynniejsze przejście. Poniższy skrypt pokazuje, jak można wywołać zdarzenie zdalne z klienta do serwera, aby przenieść postać gracza za pomocą metody wstępnego załadunku. Jeśli żądanie wstępnego załadunku jest udane, gdy funkcja zwraca, minimalny promień wokół lokalizacji docelowej powinien być obecny na kliencie.

Skrypt serwera - Teleportacja postaci gracza
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local teleportEvent = ReplicatedStorage:WaitForChild("TeleportEvent")
local function teleportPlayer(player, teleportTarget)
-- Żądanie strumieniowania wokół lokalizacji docelowej
player:RequestStreamAroundAsync(teleportTarget)
-- Teleportacja postaci
local character = player.Character
if character and character.Parent then
local currentPivot = character:GetPivot()
character:PivotTo(currentPivot * CFrame.new(teleportTarget))
end
end
-- Wywołaj funkcję teleportacji, gdy klient wyśle zdarzenie zdalne
teleportEvent.OnServerEvent:Connect(teleportPlayer)

Odczyty właściwości instancji

Gdy instancja zostaje strumieniowana, jej aktualizacje właściwości nie są już replikowane do tego klienta. Odczytywanie właściwości, takich jak BasePart.Position, nadal się udaje, ale zwraca ostatnią zreplikowaną wartość, która może być dowolnie przestarzała.

local Players = game:GetService("Players")
local player = Players.LocalPlayer
-- Pozycja może być przestarzała, jeśli "target" zostało strumieniowane
local dist = (target.Position - player.Character.HumanoidRootPart.Position).Magnitude

Przenieś logikę na serwer, ponieważ skrypty po stronie serwera widzą wszystkie instancje przez cały czas. To zazwyczaj najpewniejsza opcja dla sprawdzania odległości i innej logiki wrażliwej na pozycję.

Czekanie na krytycznej ścieżce

Niektóre gry bez strumieniowania ładują swoją mapę, klonując ją z ReplicatedStorage do Workspace, a następnie czekają na nią na kliencie, zanim odrzucą ekran ładowania i sygnalizują gotowość. W przypadku strumieniowania to wisi w nieskończoność — postać klienta jeszcze się nie pojawiła, więc nie ma fokusu replikacji, a instancja mapy przestrzennej nigdy się nie strumieniuje.

Przenieś logikę ekranu ładowania, aby nie zależała od obecności konkretnej instancji przestrzennej, na przykład sygnalizując gotowość, gdy postać się pojawi i najbliższy otaczający obszar zostanie strumieniowany.

Obsługa zmiany sygnału

Sygnały takie jak Instance.ChildAdded/Instance.ChildRemoved oraz sygnały CollectionService, takie jak GetInstanceAddedSignal() lub GetInstanceRemovedSignal() również wyzwalają się przy strumieniowaniu, nieodróżnialne od rzeczywistych pojawień/ usunięć. Odbierające skrypty nie mogą rozróżnić różnicy tylko na podstawie sygnału, więc logika, która zakłada, że sygnał odpowiada "rzeczywistemu" zdarzeniu, musi zostać zaktualizowana.

Przejrzyj skrypty pod kątem wszelkich słuchaczy sygnałów, które mogą się zepsuć lub znacznie zmienić, gdy są wyzwalane przez strumieniowanie. Na przykład, jeśli odtwarzasz dźwięk lub efekty wizualne, gdy wrogi NPC początkowo pojawia się w świecie, przypisz każdemu wrogowi atrybut taki jak Spawned przy pierwszym pojawieniu się, i pomiń odtwarzanie tych samych dźwięków/efektów w przyszłych strumieniach wroga.

Śledzenie atrybutów
local CollectionService = game:GetService("CollectionService")
local TAG_NAME = "Enemy"
CollectionService:GetInstanceAddedSignal(TAG_NAME):Connect(function(enemy)
if not enemy:GetAttribute("Spawned") then
-- Ustaw atrybut "Spawned" na wrogu przy początkowym pojawieniu się
enemy:SetAttribute("Spawned", true)
-- Odtwórz dźwięk/efekty wizualne dla tego początkowego pojawienia się
playSpawnEffects(enemy)
end
end)

Iteracja po kolekcjach

Iteracje po kolekcjach po stronie klienta, takie jak Instance:GetChildren() i Instance:GetDescendants(), zwracają tylko strumieniowany podzbiór potomków. Dotyczy to nawet wtedy, gdy sam rodzic jest zawsze replikowany, na przykład Folder bezpośrednio pod Workspace, którego przestrzenne potomstwo strumieniuje się w i z.

local Players = game:GetService("Players")
local player = Players.LocalPlayer
-- Folder "Homes" jest zawsze replikowany, ale jego dzieci strumieniują się w i z
-- Ta pętla może pominąć domy, które nie są aktualnie strumieniowane
for _, home in workspace.Homes:GetChildren() do
if home.Settings.Owner.Value == player.Name then
return home
end
end

Jeśli wymagana jest pełna enumeracja, przeprowadź skanowanie na serwerze i przekaż wynik do gracza za pomocą RemoteEvent, jeśli to konieczne.

Zapytania przestrzenne

Zapytania przestrzenne po stronie klienta, takie jak WorldRoot:Raycast(), WorldRoot:GetPartBoundsInBox(), i Model:GetBoundingBox(), odzwierciedlają tylko strumieniowane treści. To, czy to jest problem, zależy od tego, do czego zapytanie jest używane.

Użyj serwera do zapytań, których wynik musi odzwierciedlać pełny świat, na przykład raycast, który sprawdza, czy gracz ma linię wzroku do odległego celu.

Inne wzorce

Poniższe wzorce mogą również mieć zastosowanie i powinny być starannie rozważone:

  • Sound lub AudioPlayer umieszczone w obiekcie 3D zatrzymuje się, gdy ten obiekt strumieniuje się na zewnątrz. Dla dźwięku otoczenia, który powinien utrzymywać się niezależnie od strumieniowania, umieść emiter w trwałym modelu lub w kontenerze, który nie strumieniuje.

  • Obiekty UI w grze, takie jak BillboardGui lub SurfaceGui, a także efekty wizualne takie jak Beams lub Highlights, których adornee lub przymocowanie strumieniuje się na zewnątrz, po prostu przestają renderować. Może to być zamierzona zachowanie, ale powinieneś to zweryfikować.

  • Zdarzenia BasePart.Touched, ProximityPrompts, DragDetectors i ClickDetectors nie działają dla graczy, których klient nie ma powiązanej części/modelu strumieniowanego. Jeśli interakcja musi być możliwa z dowolnego zasięgu, model musi być trwały lub interakcja musi mieć inny mechanizm.

  • W przypadku PathfindingService i ścieżkowania po stronie klienta, ścieżkarz widzi tylko strumieniowaną geometrię po stronie klienta i może prowadzić przez przeszkody, które istnieją po stronie serwera. Zobacz tutaj dla strategii.

Realistyczne warunki testowe

Gdy skrypty są zaktualizowane, dokładnie przetestuj grę. Błędy strumieniowania często manifestują się tylko na krawędziach strumieniowanego obszaru lub podczas przejść, więc testowanie tylko w pobliżu spawnu lub w promieniu docelowym nie jest wystarczające.

  • Testuj z ustawionym Workspace.StreamingTargetRadius na minimalną wartość (64). Niektóre błędy strumieniowania pojawiają się tylko wtedy, gdy strumieniowany obszar jest mały.

  • Przeprowadź pełne wzorce przejścia w grze, teleportuj się między odległymi obszarami i odwiedzaj obszary po ich opuszczeniu. To są sytuacje, które najwięcej ćwiczą strumieniowanie w i z.

  • Użyj nakładki debugowania strumieniowania, aby monitorować aktywne ustawienia strumieniowania, aktualnie załadowane obszary i stan strumieniowania w czasie rzeczywistym.

  • Obserwuj okno Output i Konsolę dewelopera w poszukiwaniu błędów, ponieważ wiele z wzorców skryptów generuje błędy zamiast cichego niewłaściwego działania. Zwróć szczególną uwagę na błędy w formie attempt to index nil with ..., które często wskazują na brak wywołania WaitForChild().

  • Wyposaż i aktywuj Tools, strzelaj z broni i wyzwalaj różne interakcje w grze.

Umiejętność konwersji strumieniowania AI

Aby pomóc w konwersji strumieniowania i optymalizacji, Roblox oferuje umiejętność strumieniowania AI, dostępną z serwera MCP Studio. Umiejętność automatycznie ocenia Twoją grę, stosuje zalecane konfiguracje i porządkuje problemy z kompatybilnością, w tym:


Aby użyć umiejętności AI w swojej grze:

  1. WAŻNE
    Zrób kopię zapasową swojej gry. Proces konwersji może być skomplikowany, więc zawsze powinieneś zapisać kopię zapasową (Plik ⟩ Opublikuj na Roblox jako) przed uruchomieniem umiejętności.

  2. Możesz uruchomić tę umiejętność za pomocą dowolnego LLM, który preferujesz, przez Model Context Protocol (MCP) w Studio. Zaleca się modele AI wyższej klasy z dużymi oknami kontekstowymi; w Claude Opus typowa konwersja zajmuje 20-30 minut i wykorzystuje około 200 000 tokenów kontekstu.

    1. Otwórz swoją grę w Studio.
    2. Pobierz umiejętność i w swoim kliencie AI otwórz rozpakowany folder (roblox-streaming-conversion) jako bieżący projekt.
    3. Uruchom umiejętność za pomocą /rbx-convert-to-streaming.
    4. Jak w przypadku każdego wyjścia AI, zweryfikuj wyniki i dokładnie przetestuj swoją grę w realistycznych warunkach testowych.
©2026 Roblox Corporation. Nazwa Roblox, logo Roblox oraz hasło „Powering Imagination” należą do naszych zarejestrowanych i niezarejestrowanych znaków towarowych na terenie Stanów Zjednoczonych oraz w innych krajach.