คู่มือนี้สรุปเทคนิคหลายประการในการใช้การ สตรีมอินสแตนซ์ ในเกมอย่างมีประสิทธิภาพและมีประสิทธิผล ในขณะที่ไม่มี "วิธีที่เหมาะกับทุกคน" สำหรับการออกแบบเกมสตรีมหรือการแปลงเกมที่ไม่ใช่สตรีมไปเป็นสตรีม การทำตามขั้นตอนระดับสูงเหล่านี้จะช่วยให้คุณไปถึงจุดหมายได้เกือบทั้งหมด
คุณสมบัติการสตรีม
เมื่อ StreamingEnabled ถูกเปิดใช้งานสำหรับวัตถุ Workspace ใน Studio แล้ว ให้ตั้งค่าคุณสมบัติที่เกี่ยวข้องต่อไปนี้เป็นค่าที่แนะนำ:
| คุณสมบัติ | คำแนะนำ |
|---|---|
| EnableSLIMAvatars | ใช้ Enabled เพื่อเรนเดอร์อวาตาร์แบบน้ำหนักเบาที่มีการเคลื่อนไหวเมื่อเหมาะสม ดูเพิ่มเติมเกี่ยวกับ SLIM avatars |
| ModelStreamingBehavior | ใช้ Improved เพื่อเปิดใช้งานการสตรีมที่มีประสิทธิภาพที่สุดสำหรับ Models ที่มีผู้สืบทอด BasePart |
| StreamingIntegrityMode | ใช้ PauseOutsideLoadedArea เพื่อรักษาความสมบูรณ์ของการเล่นโดยไม่หยุดชะงักมากเกินไปหรือบ่อยเกินไป |
| StreamingMinRadius | ใช้ค่าเริ่มต้นที่ 64 เพื่อเพิ่มประสิทธิภาพให้อินจินสามารถทำงานได้อย่างเหมาะสมสำหรับอุปกรณ์ที่มีประสิทธิภาพต่ำ |
| StreamingTargetRadius | ใช้ค่าเริ่มต้นที่ 1024 เพื่อให้เกิดความสมดุลระหว่างการมองเห็นสำหรับผู้เล่นบนอุปกรณ์ที่มีประสิทธิภาพสูงและการใช้หน่วยความจำที่เหมาะสม |
| StreamOutBehavior | ใช้ Opportunistic เพื่อให้ไคลเอ็นต์เก็บข้อมูลที่ไม่ใช้งานได้อย่างรวดเร็ว ลดการใช้หน่วยความจำอย่างมากและช่วยป้องกันการเกิดข้อผิดพลาดจากหน่วยความจำเต็ม |
ระดับรายละเอียดของโมเดล
Model.LevelOfDetail ช่วยเติมเต็มเนื้อหาของ Model ที่ไม่ได้สตรีมด้วยส่วนผสมที่ง่ายหรืออิมโพสเตอร์เมช ซึ่งทำให้โลกดูสมบูรณ์ทางสายตา SLIM (Scalable Lightweight Interactive Model) มีประสิทธิภาพโดยเฉพาะ เพราะผู้เล่นมักไม่สามารถแยกแยะระหว่างเมช SLIM กับโมเดลต้นฉบับที่สตรีมเข้ามาได้
เพื่อให้ได้ผลลัพธ์ที่ดีที่สุด:
- จัดกลุ่มส่วนประกอบที่มีความสัมพันธ์กันทั้งทางกายภาพและทางตรรกศาสตร์ เช่น ส่วนประกอบทั้งหมดของรถยนต์
- ตั้ง LevelOfDetail เป็น SLIM สำหรับโมเดลที่มีพื้นผิวและชิ้นส่วน คงที่ โมเดลที่มีพื้นผิวแบบผิวหนัง ถูกปรับเปลี่ยนระหว่างการทำงาน หรือมีการเล่นอนิเมชันจะไม่ได้รับการสนับสนุน
- รักษาขนาดที่เกิดขึ้นจริงของแต่ละโมเดลไม่ให้เกินประมาณ 64 ลูกบาศก์ studs เพื่อเพิ่มความน่าจะเป็นว่าโมเดลทั้งหมดจะถูกสตรีมเข้ามาพร้อมกัน หากโมเดลมีขนาดใหญ่เกินไป ให้แบ่งเป็นโมเดลขนาดเล็กที่มีความหลากหลายมากขึ้นและใช้ LevelOfDetail ที่เหมาะสมสำหรับแต่ละโมเดล
โครงสร้างโมเดล
นอกเหนือจากการตั้ง ระดับรายละเอียดของโมเดล แล้ว โครงสร้างและการตั้งค่าของ Models มีผลกระทบอย่างมีนัยสำคัญต่อประสิทธิภาพของการสตรีม ขณะที่คุณสร้างหรือแปลงเกมที่มีอยู่:
ใช้โมเดลที่เป็นอะตอมสำหรับการจัดกลุ่มทางตรรกศาสตร์ — เมื่อสคริปต์ต้องเข้าถึงส่วนประกอบทั้งหมดในโมเดล ให้ตั้งค่า ModelStreamingMode เป็น Atomic ซึ่งช่วยให้สคริปต์ด้านไคลเอ็นต์สามารถเข้าถึงอินสแตนซ์ภายในโมเดลได้โดยปลอดภัยโดยไม่ต้องใช้ WaitForChild() มากเกินไป (แม้ว่าสคริปต์เหล่านี้จะต้องยังคงใช้ WaitForChild() สำหรับโมเดลอะตอมทั้งหมด)
ลดจำนวนโมเดลที่ติดอยู่ — โมเดลที่ ติดอยู่ จะโหลดหลังจากเข้าร่วมและไม่เคยสตรีมออกจะทำให้ใช้หน่วยความจำตลอดไป ตั้งค่า ModelStreamingMode ของโมเดลเป็น Persistent เฉพาะเมื่อมีความจำเป็นที่จะต้องรักษาให้สามารถใช้งานได้และเข้าถึงได้จากสคริปต์ตลอดเวลา
แยกโมเดลคอนเทนเนอร์ — รูปแบบการไม่สตรีมที่พบได้ทั่วไปคือไลน์ของ Model ขนาดใหญ่ที่มี NPCs, props หรือการจัดกลุ่มที่คล้ายกันอยู่ภายใน โมเดลคอนเทนเนอร์ลดประสิทธิภาพในการสตรีมภายใต้การสตรีมและไม่เหมาะสำหรับ ระดับรายละเอียดของโมเดล ซึ่งทำงานได้ดีที่สุดเมื่อมีอินสแตนซ์ที่ถูกจัดกลุ่มอย่างใกล้ชิด แยกโมเดลคอนเทนเนอร์ออกเป็นโมเดลขนาดเล็กที่มีส่วนประกอบใกล้กันหรือมีความสัมพันธ์ทางตรรกศาสตร์
ลดการซ้อนระบบโมเดล — การซ้อน โมเดลที่ติดตั้ง ภายใน โมเดลอะตอม จะบังคับให้โมเดลอะตอมทำงานเป็นโมเดลติดตั้ง ที่มีระบบลำดับที่แบนราบสามารถเข้าใจง่ายกว่าในระหว่างการสตรีม
SLIM avatars
อวาตาร์ภายนอกที่อยู่นอกเขตที่ถูกสตรีมโดยเริ่มจากจะไม่สามารถมองเห็นได้ตามค่าเริ่มต้น แต่การเปิดใช้งาน Workspace.EnableSLIMAvatars จะเรนเดอร์ Standard rig อวาตาร์ให้เป็นอวตาร์ที่มีน้ำหนักเบาและมีการเคลื่อนไหวเมื่อเหมาะสม โดยทั่วไปแล้ว เอนจิ้นจะ:
- เรนเดอร์เวอร์ชัน SLIM เมื่อโมเดลอวาตาร์จริงสตรีมออก
- สลับ SLIM/จริงโดยใช้ทรัพยากรที่สามารถใช้ได้ภายในรัศมีการสตรีม เนื่องจากโมเดล SLIM อาจมีต้นทุนในการเรนเดอร์ที่ต่ำกว่ามากเมื่อเทียบกับโมเดลความละเอียดเต็ม
- ลดการเคลื่อนไหวของ SLIM โดยความสำคัญของฉากและแบนด์วิธ
ระบบระดับรายละเอียดของอวาตาร์มีการปรับแต่งเฉพาะสำหรับอวาตาร์ ต่อไปนี้อธิบายว่าจะมีการประมวลผลอะไรและไม่ประมวลผลโดย SLIM:
รูปแบบสคริปต์
รูปแบบสคริปต์ต่อไปนี้มักได้รับผลกระทบจากการสตรีม กลยุทธ์ที่ถูกต้องขึ้นอยู่กับเจตนาของโค้ด ดังนั้นรูปแบบแต่ละรูปแบบจึงมีตัวเลือกหลายตัวเลือกไว้เมื่อเหมาะสม
ดัชนีโดยตรงไปยังผู้ส่งทอด
การเข้าถึงผู้ส่งทอดของ Workspace ด้วยตัวดำเนินการ . จะทำให้เกิดข้อผิดพลาดหากอินสแตนซ์ใด ๆ ในเส้นทางนั้นไม่ได้ถูกสตรีมเข้ามาในขณะนั้น สิ่งเดียวกันนี้ใช้ได้กับ FindFirstChild(), FindFirstChildWhichIsA(), และ FindFirstChildOfClass() ซึ่งจะคืนค่า nil หากลูกค้าไม่ได้อยู่
การค้นหา Descendantlocal house1 = workspace:FindFirstChild("House1") -- nil หาก "House1" ยังไม่ได้ถูกสตรีมเข้ามาlocal door = workspace.House1.Door -- ขัดข้องหาก "House1" หรือ "Door" ยังไม่ได้ถูกสตรีมเข้ามา
รูปแบบที่คล้ายคลึงกันคือการเข้าถึง Humanoid หรือผู้ส่งทอดตัวละครอื่น ๆ โดยตรงภายในการเชื่อมต่อ Player.CharacterAdded การสตรีมจะทำให้โมเดลตัวละครถูกสร้างเป็นลูกของ Workspace ก่อนที่ผู้ส่งทอดทั้งหมดจะถูกทำซ้ำ ดังนั้นการเข้าถึงโดยตรงจึงล้มเหลว
Descendant ของตัวละคร
local Players = game:GetService("Players")
local player = Players.LocalPlayer
player.CharacterAdded:Connect(function(character)
local humanoid = character.Humanoid
end)
หากสคริปต์ไม่สามารถดำเนินการต่อได้โดยไม่มีอินสแตนซ์ ให้รอด้วย WaitForChild():
การค้นหา Descendantlocal house1 = workspace:WaitForChild("House1")local door = house1:WaitForChild("Door")
อินสแตนซ์ที่ถูกส่งไปทางไกล
สัญญาณ RemoteEvent/RemoteFunction และอินสแตนซ์ที่มันอ้างอิงเดินทางอย่างอิสระ ดังนั้นสัญญาณจึงสามารถมาถึงที่ไคลเอ็นต์ก่อนที่อินสแตนซ์จะปรากฏ — หรืออินสแตนซ์อาจจะไม่ปรากฏเลย สาเหตุที่น่าจะเป็นสองประการ ได้แก่:
ภายใต้การสตรีม อาจมีความล่าช้าระหว่างเมื่อส่วน/โมเดลถูกสร้างบนเซิร์ฟเวอร์และเมื่อมันถูกทำซ้ำไปยังไคลเอ็นต์ ซึ่งทางการสตรีมอาจทำให้ส่วนที่มีการอ้างอิงโดย RemoteEvent/RemoteFunction ไม่มีอยู่เลย แม้กระทั่งในพื้นที่ที่ถูกสตรีม
การส่งอ้างอิงของส่วน/โมเดลจากเซิร์ฟเวอร์ไปยังไคลเอ็นต์ผ่านทาง RemoteEvent หรือ RemoteFunction เป็นการกำหนดให้ต้องมีการทำซ้ำอินสแตนซ์ไปยังไคลเอ็นต์ที่รับข้อมูล การส่งเส้นทางของอินสแตนซ์เป็นสตริงมีปัญหาเดียวกัน เนื่องจากเส้นทางนั้นอาจจะชี้ไปที่ตำแหน่งที่ไม่เกิดขึ้นในไคลเอ็นต์:
สคริปต์ของไคลเอ็นต์local ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")remoteEvent.OnClientEvent:Connect(function(data)local checkpoint = data.checkpoint -- ข้อผิดพลาดหาก "checkpoint" ยังไม่ได้ถูกสตรีมเข้ามาlocal level = workspace.Levels[data.levelPath] -- ข้อผิดพลาดหากเส้นทางยังไม่ได้ถูกสตรีมเข้ามาend)
หากสคริปต์ของไคลเอ็นต์ต้องการอินสแตนซ์เพื่อดำเนินการต่อให้รวม WaitForChild() ก่อนการใช้งาน ควรทราบว่านี่อาจจะต้องหยุดรอแบบไม่สิ้นสุดหากอินสแตนซ์ไม่เคยถูกสตรีมเข้ามา ดังนั้นให้พิจารณาเพิ่มการหมดเวลาที่จำเป็นเป็นพารามิเตอร์ที่สองของ WaitForChild()
การไม่ซิงค์ของไคลเอ็นต์
การไม่ซิงค์ด้านไคลเอ็นต์ควรได้รับการพิจารณาเป็นข้อยกเว้น ไม่ใช่รูปแบบการออกแบบมาตรฐาน การแนะนำสำเนาเฉพาะที่เป็นของไคลเอ็นต์หรือการเปลี่ยนแปลงอินสแตนซ์ท้องถิ่นอาจสร้างปัญหาร้ายแรง ตรวจสอบโค้ดของคุณว่า มีที่ที่พึ่งพาการเปลี่ยนแปลงเหล่านี้ที่ได้รับการอนุญาตอยู่หรือไม่
ตัวอย่างเช่น การเปลี่ยนแปลงอินสแตนซ์ในท้องถิ่นจาก ReplicatedStorage ไปยัง Workspace จะทำให้สามารถสตรีมออกได้ การสร้างองค์ประกอบใหม่ในลักษณะเดียวกัน (Instance:Clone()) จาก ReplicatedStorage ไปยัง Workspace จะสร้างสำเนาเฉพาะที่เป็นของไคลเอ็นต์ ซึ่งจะไม่อยู่ภายใต้กระบวนการทำซ้ำของเซิร์ฟเวอร์และจะไม่ได้รับการอัปเดตคุณสมบัติจากอินสแตนซ์ที่เป็นของเซิร์ฟเวอร์ดั้งเดิม
แนวคิดเดียวกันนี้ใช้ได้เมื่อต้องเรียก Instance:Destroy() จากโมเดลที่เป็นของเซิร์ฟเวอร์ การละทิ้งอินสแตนซ์ในท้องถิ่น แต่ว่าเซิร์ฟเวอร์ยังคงมีอยู่ ดังนั้นมันจะถูกสตรีมเข้าใหม่อีกครั้งด้วยสถานะเดิมเมื่อมีสิทธิ์
การสตรีมเชิงรุก
เมื่อสถานที่ถัดไปของผู้เล่นสามารถคาดการณ์ได้ ให้เรียกใช้การโทรจากเซิร์ฟเวอร์ไปยัง Player:RequestStreamAroundAsync() เพื่อสตรีมพื้นที่ชั่วคราวสำหรับการโหลดชั่วคราว หรือใช้ Player:AddReplicationFocus() บนพื้นฐาน จำกัด สำหรับพื้นที่ที่ควรจะมีโหลดจนกว่าจะมีการปล่อยอย่างชัดเจน
ตัวอย่างเช่น เมื่อตัวละครผู้เล่นกำลังจะทำการเทเลพอร์ตโดยการเปลี่ยนค่า CFrame ไปยังบ้านของผู้เล่นคนอื่นในตำแหน่งที่ห่างไกล คุณสามารถจัดการโหลดพื้นที่ปลายทางล่วงหน้าเพื่อช่วยลดการเกิดอาการกระตุกและมอบการเปลี่ยนแปลงที่ราบรื่น สคริปต์ต่อไปนี้แสดงให้เห็นถึงวิธีที่เหตุการณ์ remote event จากไคลเอ็นต์สามารถถูกเรียกใช้เพื่อเคลื่อนย้ายตัวละครของผู้เล่นโดยใช้วิธีการโหลดล่วงหน้า หากการร้องขอโหลดล่วงหน้าเป็นไปได้ หากฟังก์ชันนี้คืนค่ากลับมา รัศมีขั้นต่ำรอบตำแหน่งเป้าหมายควรจะมีอยู่ในไคลเอ็นต์
สคริปต์จากเซิร์ฟเวอร์ - เทเลพอร์ตตัวละครของผู้เล่น
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)
การอ่านคุณสมบัติของอินสแตนซ์
เมื่ออินสแตนซ์ถูกสตรีมออก การอัปเดตคุณสมบัติของมันจะไม่ถูกทำซ้ำไปยังไคลเอ็นต์นั้นอีกต่อไป การอ่านคุณสมบัติเช่น BasePart.Position ยังคงประสบความสำเร็จ แต่จะคืนค่าเป็นค่าที่ถูกทำซ้ำล่าสุดซึ่งอาจเก่ามาก
local Players = game:GetService("Players")local player = Players.LocalPlayer-- ตำแหน่งอาจเก่าได้หาก "target" ได้ถูกสตรีมออกไปlocal dist = (target.Position - player.Character.HumanoidRootPart.Position).Magnitude
ย้ายตรรกะไปยังเซิร์ฟเวอร์ เนื่องจากสคริปต์ด้านเซิร์ฟเวอร์มองเห็นอินสแตนซ์ทั้งหมดได้ตลอดเวลา นี่โดยทั่วไปเป็นทางเลือกที่เชื่อถือได้ที่สุดสำหรับการตรวจสอบระยะทางและตรรกะที่ไวต่อระยะทางอื่น ๆ
รอในเส้นทางสำคัญ
บางเกมที่ไม่ใช่สตรีมโหลดแผนที่ของพวกมันโดยการคัดลอกไปยัง ReplicatedStorage ไปยัง Workspace และจากนั้นรอในไคลเอ็นต์ก่อนที่จะยกเลิกหน้าจอการโหลดและสัญญาณความพร้อม ในระหว่างการสตรีมนี้จะทำให้ค้างไปอย่างไม่สิ้นสุด — ตัวละครของไคลเอ็นต์ยังไม่ถูกสร้าง เลยไม่มี replication focus และหน้าตารางอินสแตนซ์จะไม่ถูกสตรีมเข้ามา
ย้ายตรรกะหน้าจอโหลดเพื่อให้ไม่ขึ้นอยู่กับอินสแตนซ์เชิงพื้นที่เฉพาะที่มีอยู่ เช่น โดยการสัญญาณความพร้อมเมื่อมีตัวละครเกินมาและยังมีพื้นที่รอบข้างที่ถูกสตรีมเข้ามา
การจัดการการเปลี่ยนแปลงสัญญาณ
สัญญาณเช่น Instance.ChildAdded/Instance.ChildRemoved และสัญญาณ CollectionService เช่น GetInstanceAddedSignal() หรือ GetInstanceRemovedSignal() จะถูกเรียกใช้เมื่อมีการสตรีมเข้า/ออก ซึ่งไม่สามารถแยกความแตกต่างจากการเกิดหรือการลบจริงได้ สคริปต์ที่รับข้อมูลไม่สามารถแยกความต่างจากสัญญาณเพียงอย่างเดียวได้ ดังนั้นตรรกะที่สมมุติว่ามีสัญญาณที่เกี่ยวข้องกับเหตุการณ์ "จริง" จะต้องได้รับการอัปเดต
ตรวจสอบสคริปต์สำหรับผู้ฟังสัญญาณใด ๆ ที่อาจขัดข้องหรือเปลี่ยนแปลงอย่างมีนัยสำคัญเมื่อถูกเรียกใช้จากการสตรีมเข้าและ/หรือออก ตัวอย่างเช่น หากคุณเล่นเสียงหรือเอฟเฟกต์ภาพเมื่อ NPC ศัตรูเกิดขึ้นในโลก ให้กำหนดแท็ก Spawned สำหรับแต่ละศัตรูในการปรากฏตัวครั้งแรก และข้ามการเล่นเสียง/เอฟเฟกต์เดียวกันในอนาคตที่จะเกิดขึ้นอีกต่อไป
การติดตามแอตทริบิวต์
local CollectionService = game:GetService("CollectionService")
local TAG_NAME = "ศัตรู"
CollectionService:GetInstanceAddedSignal(TAG_NAME):Connect(function(enemy)
if not enemy:GetAttribute("Spawned") then
-- ตั้งค่าแอตทริบิวต์ "Spawned" สำหรับศัตรูในการปรากฏตัวครั้งแรก
enemy:SetAttribute("Spawned", true)
-- เล่นเสียง/เอฟเฟกต์ภาพสำหรับการเกิดครั้งแรกนี้
playSpawnEffects(enemy)
end
end)
การทำซ้ำในคอลเลกชัน
การทำซ้ำคอลเลกชันฝั่งไคลเอ็นต์เช่น Instance:GetChildren() และ Instance:GetDescendants() จะส่งค่าผลลัพธ์เฉพาะในกลุ่มผู้ส่งทอดที่สตรีมมาแล้วเท่านั้น แม้ว่าผู้ปกครองเองจะถูกทำซ้ำเสมอ เช่น Folder ที่อยู่โดยตรงภายใต้ Workspace ซึ่งมีคอลเลกชันของผู้ส่งทอดที่ไหลเข้าหรือออก
local Players = game:GetService("Players")local player = Players.LocalPlayer-- โฟลเดอร์ "Homes" ถูกทำซ้ำเสมอแต่เด็กของมันจะถูกสตรีมเข้าหรือออก-- ลูปนี้อาจพลาดบ้านที่ไม่ได้สตรีมอยู่ในขณะนี้for _, home in workspace.Homes:GetChildren() doif home.Settings.Owner.Value == player.Name thenreturn homeendend
หากการระบุทั้งหมดเป็นสิ่งจำเป็น ให้ดำเนินการสแกนบนเซิร์ฟเวอร์และส่งผลลัพธ์ไปยังผู้เล่นผ่านทาง RemoteEvent หากจำเป็น
คิวรีเชิงพื้นที่
การค้นหาทางกายภาพภายในโปรเจคเช่น WorldRoot:Raycast(), WorldRoot:GetPartBoundsInBox(), และ Model:GetBoundingBox() จะสะท้อนเฉพาะเนื้อหาที่มีการไหลเข้ามาเท่านั้น รายละเอียดที่อยู่ที่ใช้จะไม่ทำให้การแก้ไขอักขระสำหรับข้อมูลที่ต้องทำ
ใช้เซิร์ฟเวอร์สำหรับคิวรีที่ผลลัพธ์จะต้องอยู่ที่ทั่วโลก เช่น การยิงว่า ผู้เล่นมีห้องมองระยะใกล้ไปยังเป้าหมายหรือไม่
รูปแบบอื่น ๆ
รูปแบบต่อไปนี้อาจนำมาใช้ได้เช่นกันและควรได้รับการพิจารณาอย่างรอบคอบ:
Sound หรือ AudioPlayer ที่อยู่ภายใต้วัตถุ 3D จะหยุดเมื่อวัตถุดังกล่าวสตรีมออก สำหรับเสียงบรรยากาศที่ควรรักษาเสมออย่างไรก็ตาม ให้วางตัวส่งสัญญาณไว้ภายใต้โมเดล ที่ติดตั้ง หรือในคอนเทนเนอร์ที่ไม่ใช่การสตรีม
วัตถุ UI ในเกม เช่น BillboardGui หรือ SurfaceGui รวมไปถึง เอฟเฟกต์ภาพ อย่างเช่น Beams หรือ Highlights ซึ่งมีอแดปเตอร์หรือติดตั้งสตรีมออกจะหยุดการเรนเดอร์ โดยทั่วไปก็เป็นพฤติกรรมที่ตั้งใจไว้ แต่คุณควรตรวจสอบ
เหตุการณ์ BasePart.Touched, ProximityPrompts, DragDetectors, และ ClickDetectors จะไม่ทำงานให้กับผู้เล่นที่ไคลเอ็นต์ของเขายังไม่ได้มีส่วนที่เกี่ยวข้องถูกสตรีมเข้า หากการมีส่วนร่วมต้องจะทำได้จากทุกระยะ โมเดลจำเป็นต้องเป็น ที่ติดตั้ง หรือกลไกการมีส่วนร่วมต้องมีการออกแบบใหม่
สำหรับ PathfindingService และการหาทางฝั่งไคลเอ็นต์ พาธฟายเดอร์มองเห็นเฉพาะรูปทรงที่ถูกสตรีมเข้าในไคลเอ็นต์และอาจกำหนดเส้นทางผ่านอุปสรรคที่มีอยู่ในเซิร์ฟเวอร์ ดูข้อมูลเพิ่มเติม ที่นี่ เพื่อดูแนวทางการทำงาน
เงื่อนไขการทดสอบที่สมจริง
เมื่อ สคริปต์ได้รับการอัปเดต ทดสอบเกมอย่างละเอียด ปัญหาการสตรีมมักจะปรากฏเฉพาะที่ขอบของพื้นที่สตรีมหรือระหว่างการเปลี่ยนแปลง ดังนั้นการทดสอบทั้งหมดตั้งอยู่ใกล้จุดเกิดหรือที่รัศมีเป้าหมายเพียงครึ่งอาจไม่เพียงพอ
ทดสอบโดยใช้ Workspace.StreamingTargetRadius ที่ตั้งอยู่ที่ค่าต่ำสุด (64) ปัญหาการสตรีมบางประการจะเกิดขึ้นเมื่อพื้นที่ที่สตรีมนั้นมีขนาดเล็ก
เล่นทัวร์อย่างเต็มตัวภายในเกม เทเลพอร์ตระหว่างพื้นที่ที่ห่างกัน และกลับมายังพื้นที่หลังจากออกไป เหล่านี้เป็นสถานการณ์ที่ใช้งานการสตรีมเข้าและออกมากที่สุด
ใช้ การตรวจสอบการดีบักการสตรีม เพื่อติดตามการตั้งค่าการสตรีมที่ใช้อยู่, เขตที่มีการโหลดในปัจจุบัน, และสถานะการสตรีมในขณะนั้น
ตรวจสอบหน้าต่าง Output และ Developer Console สำหรับข้อผิดพลาด เนื่องจากหลาย ๆ รูปแบบ script patterns จะผลิตข้อผิดพลาดแทนที่จะเงียบเสียง การให้ความสนใจโดยเฉพาะต่อข้อผิดพลาดในรูปแบบ attempt to index nil with ... ที่มักจะบ่งบอกถึงการขาดการเรียก WaitForChild()
เก็บและเปิดใช้งาน Tools, ยิงอาวุธ และกระตุ้นการมีส่วนร่วมในเกมที่แตกต่างกัน

