インスタンスストリーミング技術

*このコンテンツは、ベータ版のAI(人工知能)を使用して翻訳されており、エラーが含まれている可能性があります。このページを英語で表示するには、 こちら をクリックしてください。

このガイドでは、経験内でのインスタンスストリーミングを効率的かつ効果的に使用するためのさまざまなテクニックを説明します。

ストリーミングのために意図的にデザインする

ストリーミングは無料ではありません。裏では、ネットワーク、状態追跡、動的コンテンツ管理のための複雑なエンジン全体のシステムが関与しています。ストリーミングの利点を最大限に活かすためには、ゲームプレイの流れやプレイヤーのインタラクションパターンを明確に理解した上で体験をデザインすることが重要です。効率的なストリーミングには、データモデルでの意図的なコンテンツ構造と、インスタンスの可用性が必要なタイミングや場所を慎重に考慮する必要があります。

ストリーミングの範囲を理解する

ストリーミングのロジックと機能は、Workspaceの子孫であるインスタンスにのみ適用され、ReplicatedStorageReplicatedFirstなどの他のコンテナに格納されているインスタンスはストリーミングの対象外です。たとえば、アトミックモデルをReplicatedStorageの下に置いても、アトミックなレプリケーションは保証されません。

モデルを適切に整理する

多くの子孫を持つModelsは、エンジンにとって更新や維持にコストがかかるため、そのようなモデルは小さくモジュラーなモデルに分解することをお勧めします。これにより、エンジンはストリーミング操作をより効率的に処理でき、体験の構造の明確さと整理整頓が向上します。

たとえば、すべてのNPCを単一のアトミックモデルに配置し、その中にインスタンスを動的に追加または削除することは推奨されません。代わりに、各NPCとその関連スクリプトやアセットを自己完結型のモデルにカプセル化して、個別のキャラクターをストリーミングする際の整理整頓とモジュラリティを向上させることを検討してください。

論理的グルーピングのためにアトミックモデルを使用する

インスタンスのグループが常に一緒に表示される必要がある場合(たとえば、インタラクティブな小道具や建物など)、それらをアトミックモデルにカプセル化します。アトミックモデルは、初期子孫がすべてストリーミングされた後にのみクライアントのWorkspaceに親子関係が設定されるため、アトミックモデル内のインスタンスが存在することで、すべての初期子孫が利用可能になります。これにより、クライアント側のスクリプトは、過度にWaitForChild()を使用することなく、アトミックモデル内のインスタンスに安全にアクセスできます。

ただし、そのようなクライアント側のスクリプトも、全体のアトミックモデルに対してはWaitForChild()を使用する必要があることに注意してください。ただし、モデルが利用可能になれば、初期子孫に対してWaitForChild()を呼び出す必要はありません。

永続モデルの使用を最小限に抑える

永続モデルは、参加時にストリーミングされ、決してストリーミングアウトされることはありません。永続モデルの過度の使用は、パフォーマンスの劣化やメモリ圧力につながる可能性があります。モデルとその子孫がクライアントに常に利用可能であることが不可欠な場合にのみ、永続モデルを使用してください。

たとえば、ゲームプレイの間に「場合によっては」参照される可能性のあるすべてのメッシュや部品を含む大きな永続モデルを定義することは効果的なデザイン戦略ではありません。代わりに、論理的に関連する部品やインスタンスを小さなアトミックモデル(またはそれが望ましい場合は永続モデル)にグループ化して、エンジンがそれらを独立したユニットとしてストリーミングイン/アウトできるようにしてください。

ネストモデルに注意する

深くネストされたモデルは、意図したストリーミング動作に干渉する可能性があります。たとえば、永続モデルをアトミックモデル内に含めることは、実質的にアトミックモデル全体を永続にすることを強制します。可能な限り、モデルの階層をフラット化して結合を減らし、デバッグを簡素化し、意図しない動作を避けるようにしてください。

クライアントの非同期状態に注意する

クライアント側の非同期状態は例外として扱うべきであり、標準的なデザインパターンではありません。クライアント専用のコピーを導入したり、インスタンスをローカルで親子関係を変更することは、深刻な問題を引き起こす可能性があります。

たとえば、ReplicatedStorageからWorkspaceにインスタンスをローカルで親子関係を変更すると、そのインスタンスはストリーミングアウトされる資格が得られる可能性があります。同様に、ReplicatedStorageからWorkspaceにインスタンスをローカルでクローン(Instance:Clone())すると、クライアント専用のコピーが作成され、元のサーバー所有のインスタンスからのプロパティ更新を受け取らなくなります。

タイミング遅延を理解する

サーバー上で部品が作成されてからクライアントにレプリケートされるまでに、約10ミリ秒のわずかな遅延が生じることがあります。以下の各シナリオでは、部分ストリーミングと同時にイベントやプロパティ更新が常に発生するとは仮定せずに、WaitForChild()や他の技術を使用する必要があるかもしれません。

シナリオストリーミング動作
クライアント側のスクリプトがサーバーにRemoteFunctionを呼び出してBasePartを作成します。RemoteFunctionがクライアントに戻るとき、BasePartはまだ存在しない可能性があります。ストリーミングされた領域内にあってもです。
サーバー側のスクリプトがRemoteEventを使用して、クライアント上のプレイヤーキャラクターに非常に近くでBasePartを作成します。RemoteEvent信号がクライアントに受信されたとき、BasePartはまだ存在しない可能性があります。ストリーミングされた領域内にあってもです。

インスタンスストリーミングを検出する

ストリーミングは主に3D空間の近接性に基づいているため、Workspace以下のすべてのインスタンスがクライアントで常に利用可能であるとは仮定できません。インスタンスにアクセスする前にその存在を常に検証し、オブジェクトのストリーミングインまたはアウトを検出して対処する必要があります。ストリーミングの検出には、以下のような便利なパターンがあります。

  1. インスタンスのプロパティのタグセクションを使用して、影響を受けるすべてのオブジェクトに論理的なCollectionServiceタグを割り当てます。

  2. シングルクライアント側スクリプトから、タグ付けされたオブジェクトがGetInstanceAddedSignal()およびGetInstanceRemovedSignal()を介してストリーミングインまたはアウトするときに検出し、オブジェクトを適切に処理します。たとえば、以下のコードは、タグ付けされたLightオブジェクトをストリーミングインするときに「点滅」ループに追加し、ストリーミングアウトするときに削除します。

    クライアントスクリプト - CollectionServiceストリーミング検出

    local CollectionService = game:GetService("CollectionService")
    local tagName = "FlickerLightSource"
    local random = Random.new()
    local flickerSources = {}
    -- 現在および新たにタグが付けられた部品がストリーミングインまたはアウトするのを検出する
    for _, light in CollectionService:GetTagged(tagName) do
    flickerSources[light] = true
    end
    CollectionService:GetInstanceAddedSignal(tagName):Connect(function(light)
    flickerSources[light] = true
    end)
    CollectionService:GetInstanceRemovedSignal(tagName):Connect(function(light)
    flickerSources[light] = nil
    end)
    -- 点滅ループ
    while true do
    for light in flickerSources do
    light.Brightness = 8 + random:NextNumber(-0.4, 0.4)
    end
    task.wait(0.05)
    end

機会的ストリームアウトを使用する

OpportunisticモードのWorkspace.StreamOutBehaviorは、クライアントがWorkspace.StreamingTargetRadiusの外部のコンテンツを積極的にガベージコレクトできるようにします。これにより、特にローエンドデバイスでのメモリ使用量が大幅に削減され、クラッシュやメモリ不足の条件を防ぐのに役立ちます。Opportunisticモードは、大規模またはコンテンツが豊富な体験が多様なハードウェア全体でパフォーマンスを維持する必要がある場合に最適です。

モデルの詳細レベルを設定する

現在ストリーミングされている領域外のModelsはデフォルトでは表示されません。ただし、存在しないクライアント向けに、軽量な「SLIM」メッシュまたは低解像度の「インポスター」メッシュをモデルとしてレンダリングするようにエンジンに指示できます。この動作は、各モデルのLevelOfDetailプロパティを通じて制御します。

非デフォルトのLevelOfDetailプロパティを持つモデルについては、Robloxは、モデルが不完全である場合、ストリーミング半径内であってもSLIMまたはインポスターメッシュを表示します; モデルから欠落しているインスタンスによりLODが表示されます。これらのモデルのゲーム内スペースを64立方スタッド以下に保つことで、全体のモデルが一緒にストリーミングされる可能性が高まり、またEnum.ModelStreamingMode.Atomic設定を使用して、一緒にストリーミングされるようにします。さらに、クライアントでこれらのモデルを変更しないようにしてください。どんな変更もモデルを不完全と見なす原因となります。

ModelインスタンスのLevelOfDetailプロパティが示されている
地球儀モデルがその実際の詳細レベルで表示されています。
オリジナルモデル
同じ地球儀モデルがSLIMメッシュで、元の地球儀として認識できます。
軽量「SLIM」メッシュ(ベータ版)
同じ地球儀モデルが低解像度のインポスターメッシュで、粗いエッジが地球儀の詳細を隠しています。
低解像度の「インポスター」メッシュ
モデル設定ストリーミング半径外の動作
SLIM

オリジナルモデルがクライアントに存在しない場合、モデル内のすべての子部品の複合メッシュが表示されます。Robloxは、モデルに対して多くのSLIM(スケーラブル軽量インタラクティブモデル)メッシュを自動的に生成し、カメラからの距離が増すにつれて徐々に複雑さが低下します。

  • ビジュアル品質はインポスターメッシュよりも優れており、パフォーマンスは同等です。
  • SLIMメッシュが表示されるかどうかはキャラクターの位置に依存します。SLIMメッシュの品質レベルはカメラの位置に依存します。
  • SLIMは、静的メッシュとアニメーションを持つプラットフォームアバターのみをサポートします。スキンメッシュを含むモデルや、ランタイムで修正されるモデル、アニメーションを再生するモデルはサポートされません。
  • SLIMに設定されたモデルが最初にロードされるとき、Robloxはその最適化されたアセットをクラウドで生成します。この一度きりのプロセスは、非常に複雑なモデルに対して数分かかることがあります。大きなプレースを持ち、一時的にモデルが表示されない場合は、数分待ってから再度試してください。
  • SLIMは、モデルがジオメトリをグループ化する方法を理解することに依存しています。最良の結果を得るには、Modelsを使用して空間的かつ論理的に関連する部品をグループ化します(たとえば、車のすべての部品など)。プロジェクトの任意の整理にはフォルダを使用し、SLIMは無視します。
StreamingMesh

クライアントにモデルが存在しないときに、インポスターメッシュが表示されます。

  • モデルとその子孫のすべてがStreamingMeshに設定されている場合、トップレベルのモデルのみがインポスターメッシュとしてレンダリングされ、すべてのジオメトリとその子孫モデルをラッピングします。パフォーマンスを向上させるには、子孫モデルをDisabledに設定してください。
  • インポスターメッシュは、カメラから1024スタッド離れた位置で最も良い見た目になります。StreamingTargetRadiusを小さい値に削減すると、インポスターメッシュがモデルの適切なビジュアル置き換えとならない場合があります。SLIMがこのユースケースにより適しているか検討してください。
  • インポスターメッシュはテクスチャをサポートしておらず、スムーズなメッシュとしてレンダリングされます。
  • モデルが完全にストリーミングインされていない場合、インポスターメッシュがレンダリングされ、モデルの個々の部品ではなくなります。すべての個々の部品がストリーミングインされると、それらがレンダリングされ、インポスターメッシュは無視されます。
  • インポスターメッシュには物理的な意味はなく、レイキャスティング衝突検出、および物理シミュレーションの観点からは存在しません。
  • スタジオでモデルを編集する(子部品の追加、削除、再配置、色のリセットなど)は、代表メッシュを自動的に更新します。
Disabled / Automaticモデルはストリーミング半径にプレイヤーが入るまで存在せず、プレイヤーが半径を離れた後はいつでもストリーミングアウトできます。

アバターの詳細レベルを設定する

現在ストリーミングされている領域外のプラットフォームアバターはデフォルトでは表示されません。ただし、エンジンにプラットフォームアバターモデルを標準リグでレンダリングし、最適化された軽量「SLIM」アバター表現として補助的な衣服やレイヤーを含む任意の数のアクセサリを持たせるように指示できます。

Workspace.EnableSLIMAvatarsプロパティをインスタンスストリーミングとともに有効にすると、各複合SLIMモデルがクラウド内で複数のLODを生成します。これにより、エンジンは自動的に次のことを行います。

  • ストリーミング半径の外部でプラットフォームアバターがストリーミングアウトされるときにSLIMバージョンをレンダリングします。
  • ストリーミング半径内のプラットフォームアバターが利用可能なリソースに応じて、SLIMバージョンまたはフルモデルのレンダリングを切り替えます。
  • シーンの重要性と利用可能なネットワーク帯域幅に基づいて、SLIMアバターのアニメーション更新を制御します。

これらのパフォーマンス最適化により、視覚的に満たされたソーシャルスペースや混雑したイベントを実現し、さまざまなデバイス機能にわたってスケーリングできます。最良の視覚体験を保証するために、ワールドモデルのLevelOfDetailプロパティをSLIMに設定することも忘れないでください。

アバターの詳細レベルシステムには、アバターに特定の最適化があります。以下は、SLIMによって処理されるものとそうでないものを示します:

含まれる:

  • ストリーミングが有効な状態でプレイヤーがあなたの経験に参加するときにRobloxによって追加される標準リグを持つ任意のアバター。これには、キャラクターの体、頭、レイヤード衣服、アクセサリが含まれます。
  • Player.CharacterAdded()信号の発火時とPlayer.CharacterAppearanceLoaded()信号の発火前に、プレイヤーのアバターに加えられた変更。

除外される:

  • R6アバター。
  • NPC(ノンプレイヤーキャラクター)、たとえそれに標準リグが含まれていても。
  • 比率や衣服、体のパーツを変更するカスタムアバター設定。その代わりに、アバターモデルがクライアントにストリーミングされるときに元の「プレイヤーの選択」アバターがレンダリングされます。
  • Player.CharacterAppearanceLoaded()信号が発火した後のアバターモデルの変更は、SLIMモデルには反映されません。これには、次のような変更が含まれます:
    • アバターモデルやその外観を修正するスクリプト。
    • アバターがツールを装備する。
    • アバターがアクセサリや衣服を追加または削除する。
    • アバターに追加されたハイライト。

ストリーミング半径を戦略的に使用する

Workspace.StreamingMinRadiusプロパティは、正しいゲームプレイを開始または継続するために読み込まれなければならないエリアを定義します。この最小半径は、参加時間や体験中のパフォーマンスに大きな影響を与え、特に半径が大きく過剰なコンテンツが含まれている場合には顕著です。

Workspace.StreamingTargetRadiusプロパティは、エンジンがランタイムセッションを通じてストリーミングインしようとする広範囲のエリアを定義します。最小半径に比べて、ターゲット半径内のコンテンツは優先度が低く、ゲームプレイをブロックすることなく段階的に読み込むことができます。

この動作は戦略的に活用できます。Workspace.StreamingTargetRadiusを大きめに設定し、顕著なゲームプレイの問題や視覚的不整合を回避しますが、サーバーが不要なコンテンツをストリーミングするほど大きくすることは避けてください。

ストリーミングの整合性を活用する

Workspace.StreamingIntegrityModeプロパティは、十分なコンテンツがストリーミングされているかどうかに応じて、クライアントが一時停止するかどうかを制御します。これにより、キャラクターが読み込まれていない地形を通過する、プレイヤーがアクセスしてはいけない領域を見える、またはプレイヤーが部分的に読み込まれた環境と相互作用するなどの状況を防ぎます。

ほとんどのシナリオでは、PauseOutsideLoadedAreaオプションが推奨されます。これにより、初期読み込みや重いストリーミング変遷の際の決定論的な動作が保証され、ストリーミングされた世界が不完全な場合の予測不能なゲームプレイを最小限に抑えることができます。

プロアクティブにストリーミングする

プレイヤーの動きはしばしば予測可能です。次の目的地が予測できる場合は、サーバー側でPlayer:RequestStreamAroundAsync()を呼び出して、一時的にロードできるストリーミングインエリアに入り、Player:AddReplicationFocus()を使用して、明示的に解放されるまでロードされたままにしておく必要があるエリアを定義します。

たとえば、プレイヤーが他のプレイヤーの家に訪問しようとしている場合、目的地エリアをRequestStreamAroundAsync()を使用して事前に取得し、ポップインを最小限に抑え、スムーズな遷移を提供します。

頻繁に訪問されるエリアに対しては、AddReplicationFocus()制限されたベースで使用し、追加のレプリケーションフォーカスを追加します。これにより、それらのエリアがメモリに保持され、ストリーミングアウトされるのを防ぎ、次回訪問時の再読み込み時間が短縮されます。

以下のスクリプトは、プリフェッチメソッドを使用してCFrameにプレイヤーキャラクターを移動するために、クライアントからサーバーへのリモートイベントを発火させる方法を示しています。関数が戻るときにプリフェッチリクエストが成功していれば、ターゲット位置の周りの最小半径がクライアントに存在するはずです。

サーバースクリプト - プレイヤーキャラクターのテレポート

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local teleportEvent = ReplicatedStorage:WaitForChild("TeleportEvent")
local function teleportPlayer(player, teleportTarget)
-- ターゲット位置の周りのストリーミングをリクエスト
player:RequestStreamAroundAsync(teleportTarget)
-- キャラクターをテレポート
local character = player.Character
if character and character.Parent then
local currentPivot = character:GetPivot()
character:PivotTo(currentPivot * CFrame.new(teleportTarget))
end
end
-- クライアントがリモートイベントを発火させたときにテレポート関数を呼び出す
teleportEvent.OnServerEvent:Connect(teleportPlayer)
クライアントスクリプト - リモートイベントを発火

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local teleportEvent = ReplicatedStorage:WaitForChild("TeleportEvent")
local teleportTarget = Vector3.new(50, 2, 120)
-- リモートイベントを発火させる
teleportEvent:FireServer(teleportTarget)

ポーズ画面をカスタマイズする

プレイヤーがあなたの体験でストリーミングの一時停止に遭遇したときのために、ポーズ画面をカスタマイズすることを検討してください。Player.GameplayPausedプロパティは、プレイヤーの現在のポーズ状態を示し、GetPropertyChangedSignal()との接続に使用してカスタムGUIを表示または非表示にすることができます。

LocalScript

local Players = game:GetService("Players")
local GuiService = game:GetService("GuiService")
local player = Players.LocalPlayer
-- デフォルトのポーズモーダルを無効にする
GuiService:SetGameplayPausedNotificationEnabled(false)
local function onPauseStateChanged()
if player.GameplayPaused then
-- カスタムGUIを表示
else
-- カスタムGUIを非表示
end
end
player:GetPropertyChangedSignal("GameplayPaused"):Connect(onPauseStateChanged)

画面上のデバッグを使用する

エンジンには、キーボードショートカットを使用してクライアント上で有効にできる複数の画面上のデバッグパネルが含まれています。ストリーミングデバッグ情報にアクセスするには:

  1. ShiftCtrlF3(Windows)またはShiftF3(Mac)でネットワーク概要デバッグオーバーレイを開きます。

  2. デバッグオーバーレイが開いたら、Shift1を繰り返し押して利用可能なパネルを切り替えます。4番目のパネルはストリーミングデバッグビューで、役立つランタイム情報を表示します:

    • アクティブなストリーミング設定
    • 現在ロードされている(ストリーミングインされた)領域
    • ストリーミングの動作と状態

このパネルを使用して、ゲームプレイ中にどのようにコンテンツがストリーミングされているかを検査し、奇妙なゲームプレイの動作やストリーミング領域が欠如している問題を診断するのに役立ててください。

©2026 Roblox Corporation。Roblox(ロブロックス)、RobloxロゴおよびPowering Imaginationは、米国並びにその他の国における登録商標および非登録商標です。