หน้านี้อธิบายเกี่ยวกับปัญหาประสิทธิภาพทั่วไปและแนวทางที่ดีที่สุดในการลดผลกระทบเหล่านั้น
การคำนวณสคริปต์
การดำเนินงานที่ใช้เวลามากในโค้ด Luau ใช้เวลานานขึ้นในการประมวลผลและอาจส่งผลกระทบต่ออัตราเฟรม ขณะที่ถ้าไม่ได้ดำเนินการแบบขนาน โค้ด Luau จะรันแบบซิงโครนัสและบล็อกเธรดหลักจนกว่าจะพบฟังก์ชันที่ทำให้เธรดหยุด
ปัญหาทั่วไป
การดำเนินการอย่างเข้มข้นบนโครงสร้างตาราง - การดำเนินการที่ซับซ้อนเช่น การซีเรียลไลซ์ การถอดซีเรียลไลซ์ และการคลอนลึกมีค่าใช้จ่ายด้านประสิทธิภาพสูง โดยเฉพาะอย่างยิ่งในโครงสร้างตารางขนาดใหญ่ สิ่งนี้เป็นจริงโดยเฉพาะหากการดำเนินการเหล่านี้เป็นการทำซ้ำหรือเกี่ยวข้องกับการเรียกผ่านโครงสร้างข้อมูลที่มีขนาดใหญ่มาก
เหตุการณ์ความถี่สูง - การเชื่อมโยงการดำเนินการที่มีค่าใช้จ่ายสูงกับเหตุการณ์ที่อิงเฟรมของ RunService โดยไม่มีการจำกัดความถี่หมายความว่าการดำเนินการเหล่านี้จะถูกทำซ้ำในทุกเฟรม ซึ่งมักจะส่งผลให้เวลาคำนวณเพิ่มขึ้นอย่างไม่จำเป็น เหตุการณ์เหล่านี้รวมถึง:
การลดผลกระทบ
- เรียกใช้โค้ดในเหตุการณ์ RunService อย่างระมัดระวัง โดยจำกัดการใช้งานในกรณีที่ต้องมีการเรียกใช้งานบ่อยๆ (เช่น การอัปเดตกล้อง) คุณสามารถดำเนินการโค้ดอื่นๆ ได้ในเหตุการณ์อื่น ๆ หรือในลูปที่ไม่บ่อยนัก
- แบ่งงานใหญ่หรือที่มีค่าใช้จ่ายสูงด้วยการใช้ task.wait() เพื่อกระจายงานไปยังหลายเฟรม
- ระบุและปรับปรุงการดำเนินการที่มีค่าใช้จ่ายสูงอย่างไม่จำเป็นและใช้ มัลติเธรดดิ้ง สำหรับงานที่ใช้การคำนวณสูงซึ่งไม่ต้องเข้าถึงแบบจำลองข้อมูล
- สคริปต์บางตัวที่ทำงานบนเซิร์ฟเวอร์อาจได้รับประโยชน์จาก การสร้างโค้ดเฉพาะ ซึ่งเป็นธงง่ายๆ ที่คอมไพล์สคริปต์เป็นโค้ดเครื่องแทนที่จะเป็นไบต์โค้ด
ขอบเขตของ MicroProfiler
| ขอบเขต | การคำนวณที่เกี่ยวข้อง |
| RunService.PreRender | โค้ดที่ดำเนินการในเหตุการณ์ PreRender |
| RunService.PreSimulation | โค้ดที่ดำเนินการในเหตุการณ์ Stepped |
| RunService.PostSimulation | โค้ดที่ดำเนินการในเหตุการณ์ Heartbeat |
| RunService.Heartbeat | โค้ดที่ดำเนินการในเหตุการณ์ Heartbeat |
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการดีบักสคริปต์โดยใช้ MicroProfiler โปรดดูที่ ห้องสมุด debug ซึ่งรวมถึงฟังก์ชันสำหรับแท็กโค้ดเฉพาะและ เพิ่มความเฉพาะเจาะจงเพิ่มเติม เช่น debug.profilebegin และ debug.profileend เมธอด API ของ Roblox จำนวนมากที่ถูกเรียกโดยสคริปต์ก็มี แท็ก MicroProfiler ที่เกี่ยวข้องซึ่งสามารถให้สัญญาณที่มีประโยชน์ได้
การใช้งานหน่วยความจำสคริปต์
การรั่วไหลของหน่วยความจำอาจเกิดขึ้นเมื่อคุณเขียนสคริปต์ที่ใช้หน่วยความจำที่ ตัวเก็บขยะแทบไม่สามารถปล่อยเมื่อมันไม่ถูกใช้งานอีกต่อไป รั่วไหลเกิดขึ้น โดยเฉพาะอย่างยิ่งในเซิร์ฟเวอร์ เนื่องจากมันสามารถออนไลน์ติดต่อกันนานหลายวัน ในขณะที่ เซสชันของไคลเอนต์มีเวลาสั้นมาก
ค่าหน่วยความจำต่อไปนี้ใน Developer Console อาจบ่งบอกถึงปัญหาที่จำเป็นต้อง การตรวจสอบเพิ่มเติม:
- LuaHeap - การใช้สูงหรือการใช้งานที่เพิ่มขึ้นบ่งบอกถึงการรั่วไหลของหน่วยความจำ
- InstanceCount - จำนวนอินสแตนซ์ที่เพิ่มขึ้นอย่างสม่ำเสมอบ่งบอกว่าการอ้างอิงไปยังบาง อินสแตนซ์ในโค้ดของคุณทำให้ไม่สามารถเก็บขยะได้
- PlaceScriptMemory - ให้รายละเอียดการใช้หน่วยความจำแบบย่อยต่อสคริปต์
ปัญหาทั่วไป
คงการเชื่อมต่อที่เชื่อมโยงไว้ - เอนจิ้นไม่ทำการเก็บขยะแม้กระทั่งเหตุการณ์ที่เชื่อมโยงกับอินสแตนซ์และค่าที่ถูกอ้างอิงภายในฟังก์ชันที่เชื่อมโยง ดังนั้น การเชื่อมต่อที่ใช้งานอยู่ของเหตุการณ์และโค้ดภายในอินสแตนซ์ที่เชื่อมต่อ ฟังก์ชันที่เชื่อมโยง และค่าที่ถูกอ้างอิงจะอยู่นอกขอบเขตสำหรับตัวเก็บขยะแม้หลังจากเหตุการณ์นี้ถูกเรียก
แม้ว่าเหตุการณ์จะถูกตัดการเชื่อมกับสิ่งที่พวกเขาเป็นเจ้าของ ได้ถูกทำลายแล้ว ความเข้าใจผิดที่พบบ่อยคือการเข้าใจว่าสิ่งนี้ใช้ได้กับวัตถุ Player หลังจากผู้ใช้ออกจากเกม เอนจิ้นจะไม่ทำการทำลายวัตถุ Player ที่เป็นตัวแทนของพวกเขาและโมเดลตัวละคร อันเป็นเหตุให้การเชื่อมต่อกับวัตถุ Player และอินสแตนซ์ใต้โมเดลตัวละคร เช่น CharacterAdded ยังคงใช้หน่วยความจำหากคุณไม่ตัดการเชื่อมต่อในสคริปต์ของคุณ ซึ่งอาจส่งผลให้เกิดการรั่วไหลของหน่วยความจำเป็นจำนวนมากเมื่อเวลาผ่านไปบนเซิร์ฟเวอร์เนื่องจากผู้ใช้หลายร้อยคนเข้าร่วมและออกจากเกม
ตาราง - การแทรกวัตถุในตารางแต่ไม่ลบออกเมื่อไม่มีความจำเป็นทำให้การใช้หน่วยความจำไม่จำเป็น โดยเฉพาะอย่างยิ่งสำหรับตารางที่ติดตามข้อมูลผู้ใช้เมื่อเข้าร่วม ตัวอย่างเช่น โค้ดตัวอย่างต่อไปนี้สร้างตารางเพื่อเพิ่มข้อมูลผู้ใช้ทุกครั้งที่ผู้ใช้เข้าร่วม:
Examplelocal playerInfo = {}Players.PlayerAdded:Connect(function(player)playerInfo[player] = {} -- ข้อมูลบางอย่างend)หากคุณไม่ลบรายการเหล่านี้เมื่อไม่มีความจำเป็นอีก ตารางจะยังคงเติบโตในขนาดและใช้หน่วยความจำมากขึ้นเมื่อมีผู้ใช้เข้าร่วมเซสชัน โค้ดใดๆ ที่วนรอบตารางนี้ก็จะมีค่าใช้จ่ายในการคำนวณมากขึ้นเมื่อขนาดของตารางเพิ่มขึ้น
การลดผลกระทบ
เพื่อทำความสะอาดค่าทั้งหมดที่ใช้เพื่อป้องกันการรั่วไหลของหน่วยความจำ:
ตัดการเชื่อมต่อการเชื่อมต่อทั้งหมด - ตรวจสอบโค้ดของคุณและทำให้แน่ใจว่าการเชื่อมต่อแต่ละส่วนถูกทำความสะอาดผ่านทางหนึ่งในเส้นทางต่อไปนี้:
- ตัดการเชื่อมต่อด้วยตนเองโดยใช้ฟังก์ชัน Disconnect()
- ทำลายอินสแตนซ์ที่เหตุการณ์ได้เป็นเจ้าของโดยใช้ฟังก์ชัน Destroy()
- ทำลายวัตถุสคริปต์ที่การเชื่อมต่อย้อนกลับไปถึง
ลบวัตถุและตัวละครของผู้เล่นหลังจากออก - เปิดใช้งาน Workspace.PlayerCharacterDestroyBehavior เพื่อทำลายวัตถุของผู้เล่นและโมเดลตัวละครโดยอัตโนมัติเมื่อผู้ใช้ออก หากคุณต้องการ คุณสามารถทำความสะอาดด้วยตนเองได้แทน:
Example player and character cleanuplocal Players = game:GetService("Players")Players.PlayerAdded:Connect(function(player)player.CharacterRemoving:Connect(function(character)task.defer(character.Destroy, character)end)end)Players.PlayerRemoving:Connect(function(player)task.defer(player.Destroy, player)end)
การคำนวณฟิสิกส์
การจำลองฟิสิกส์มากเกินไปสามารถเป็นสาเหตุหลักที่ทำให้เวลาในการคำนวณต่อเฟรมเพิ่มสูงขึ้นทั้งในเซิร์ฟเวอร์และไคลเอนต์
ปัญหาทั่วไป
ความถี่ของเวลาสเต็ปฟิสิกส์ที่มากเกินไป - ตามค่าเริ่มต้น การดำเนินการอยู่ใน โหมดปรับได้ ซึ่งฟิสิกส์จะขั้นตอนที่อัตรา 60 Hz, 120 Hz หรือ 240 Hz ขึ้นอยู่กับความซับซ้อนของกลไกฟิสิกส์
ยังมีโหมดคงที่ที่ช่วยให้ได้ความแม่นยำของฟิสิกส์ที่ดีขึ้น ซึ่งบังคับให้ฟิสิกส์ทำงานที่ 240 Hz (สี่ครั้งต่อเฟรม) ซึ่งส่งผลให้การคำนวณใช้เวลามากขึ้นในแต่ละเฟรม
จำนวนและความซับซ้อนของวัตถุที่ถูกจำลองมากเกินไป - ยิ่งมีการจำลองการประกอบ 3 มิติมากเท่าไหร่ การคำนวณฟิสิกส์ก็จะใช้เวลานานขึ้นในแต่ละเฟรม บ่อยครั้งเกมจะมีวัตถุที่ถูกจำลองซึ่งไม่จำเป็นต้องถูกจำลองหรือจะมีกลไกที่มีข้อจำกัดและข้อต่อมากกว่าที่จำเป็น
การตรวจจับการชนที่แม่นยำเกินไป - Mesh parts มีคุณสมบัติ CollisionFidelity สำหรับการตรวจจับการชนซึ่งเสนอหลากหลายโหมดด้วยระดับการส่งผลกระทบต่อประสิทธิภาพที่แตกต่างกัน โหมดการตรวจจับการชนที่แม่นยำสำหรับ mesh parts มีค่าใช้จ่ายด้านประสิทธิภาพที่มากที่สุดและใช้เวลาในการคำนวณนานขึ้น
การลดผลกระทบ
ทำเครื่องหมายวัตถุที่ไม่ต้องการจำลอง - ทำเครื่องหมายทุกส่วนที่ไม่จำเป็นต้องถูกขับเคลื่อนด้วยฟิสิกส์ เช่น NPC ที่อยู่กับที่
ใช้การก้าวฟิสิกส์แบบปรับได้ - การก้าวแบบปรับได้จะปรับอัตราการคำนวณฟิสิกส์ตามกลไกฟิสิกส์ ซึ่งช่วยให้การอัปเดตฟิสิกส์เกิดขึ้นน้อยลงในบางกรณี
ลดความซับซ้อนของกลไก
- ลดจำนวนข้อจำกัดหรือข้อต่อในประกอบให้เหลือน้อยที่สุดเท่าที่จะทำได้
- ลดการชนกันเองภายในกลไก โดยการใช้ขีดจำกัดหรือข้อจำกัดที่ไม่ชนกันในแขนของ ragdoll เพื่อป้องกันไม่ให้พวกเขาชนกัน
ลดการใช้งานความแม่นยำในการตรวจจับการชนสำหรบ Meshes
สำหรับวัตถุเล็กหรือไม่สามารถโต้ตอบได้ซึ่งผู้ใช้น่าจะไม่สังเกตเห็นความแตกต่าง ให้ใช้ความแม่นยำของกล่อง
สำหรับวัตถุขนาดเล็กถึงกลาง ให้ใช้ความแม่นยำของกล่องหรือเปลือก ขึ้นอยู่กับรูปร่าง
สำหรับวัตถุขนาดใหญ่และซับซ้อนมาก ให้สร้างการชนแบบกำหนดเองโดยใช้ส่วนที่มองไม่เห็นเมื่อทำได้
สำหรับวัตถุที่ไม่ต้องการการชน ปิดการชนและใช้ความแม่นยำของกล่องหรือเปลือก เนื่องจากเรขาคณิตการชนยังคงถูกจัดเก็บในหน่วยความจำ
คุณสามารถเรนเดอร์เรขาคณิตการชนเพื่อวัตถุประสงค์ในการดีบักใน Studio โดยเปิดใช้งาน Collision fidelity จาก Visualization Options ในมุมขวาบนของ viewport 3D
หรือคุณสามารถใช้ฟิลเตอร์ CollisionFidelity=PreciseConvexDecomposition กับ Explorer ซึ่งจะแสดงจำนวน mesh parts ที่มีความแม่นยำและช่วยให้คุณเลือกได้อย่างง่ายดาย
สำหรับแนวทางที่ลึกซึ้งเกี่ยวกับวิธีเลือกตัวเลือกความแม่นยำในการตรวจจับการชนที่สมดุลระหว่างความต้องการความแม่นยำและประสิทธิภาพ ให้ดูที่ กำหนดพารามิเตอร์ฟิสิกส์และการเรนเดอร์
ขอบเขตของ MicroProfiler
| ขอบเขต | การคำนวณที่เกี่ยวข้อง |
| physicsStepped | การคำนวณฟิสิกส์โดยรวม |
| worldStep | ขั้นตอนฟิสิกส์แบบไม่ต่อเนื่องที่ใช้ในแต่ละเฟรม |
การใช้งานหน่วยความจำฟิสิกส์
การเคลื่อนที่ทางฟิสิกส์และการตรวจจับการชนจะใช้หน่วยความจำ Mesh parts มีคุณสมบัติ CollisionFidelity ที่กำหนดวิธีการที่ใช้ในการประเมินขอบเขตการชนของ mesh
ปัญหาทั่วไป
โหมดการตรวจจับการชนที่เริ่มต้นและแม่นยำจะใช้หน่วยความจำมากกว่าถึง 2 โหมดอื่นที่มีรูปร่างการชนที่มีความแม่นยำต่ำกว่า
หากคุณเห็นระดับการใช้หน่วยความจำสูงใน PhysicsParts คุณอาจต้องลด ความแม่นยำในการตรวจจับการชน ของวัตถุในเกมของคุณ
วิธีการลดผลกระทบ
เพื่อลดหน่วยความจำที่ใช้สำหรับความแม่นยำในการตรวจจับการชน:
- สำหรับวัตถุที่ไม่ต้องการการชน ให้ปิดการชนด้วยการตั้งค่าของ BasePart.CanCollide, BasePart.CanTouch และ BasePart.CanQuery เป็น false
- ลดความแม่นยำของการชนโดยใช้การตั้งค่า CollisionFidelity การตั้งค่า Box จะมีค่าใช้จ่ายหน่วยความจำต่ำสุด และ Default และ Precise จะมีค่าใช้จ่ายที่สูงมากขึ้น
- โดยทั่วไปจะปลอดภัยในการตั้งค่าความแม่นยำของการชนของวัตถุที่ยึดให้อยู่กับที่ขนาดเล็กทุกตัวที่เป็น Box
- สำหรับ Meshes ขนาดใหญ่ที่ซับซ้อนมาก คุณอาจต้องสร้าง Mesh ของคุณเองจากวัตถุขนาดเล็กที่มีความแม่นยำของการชนเป็นกล่อง
มนุษย์
Humanoid เป็นคลาสที่ให้ฟังก์ชันการทำงานมากมายแก่ ตัวละครผู้เล่นและตัวละครที่ไม่ใช่ผู้เล่น (NPCs) แม้จะมีพลัง แต่ Humanoid มาพร้อมกับค่าใช้จ่ายในการคำนวณที่สำคัญ
ปัญหาทั่วไป
- ทิ้ง HumanoidStateTypes ทั้งหมดในการใช้งานกับ NPCs - มีค่าใช้จ่ายทางประสิทธิภาพจากการที่ต้องเปิดใช้บาง HumanoidStateTypes ค้างอยู่ ปิดใช้งานค่าที่ไม่จำเป็นสำหรับ NPCs ของคุณ ตัวอย่างเช่น หาก NPC ของคุณไม่ได้จะปีนบันได ก็ปลอดภัยที่จะปิดใช้งานสถานะ Climbing
- การสร้างขึ้น แก้ไข และเกิดใหม่ของโมเดลด้วย Humanoids หรือ MeshParts ที่ถูกผูกไว้บ่อยครั้ง
- สิ่งนี้อาจทำให้เอนจิ้นประมวลผลได้มาก โดยเฉพาะถ้าโมเดลดังกล่าวใช้ เสื้อผ้าทับซ้อน สิ่งนี้อาจเป็นปัญหาโดยเฉพาะในเกมที่อวตารเกิดใหม่บ่อยครั้ง
- ใน MicroProfiler แท็กที่มีอายุ updateInvalidatedFastClusters ที่ใช้เวลารวมกันมาก (มากกว่า 4 ms) มักจะเป็นสัญญาณที่การสร้าง/แก้ไขอวตารกระตุ้นให้มีการทำลายค่าใช้จ่ายมากเกินไป
- การใช้งาน Humanoids ในกรณีที่ไม่จำเป็น - NPCs ที่อยู่กับที่ซึ่งไม่ต้องเคลื่อนที่โดยปกติจะไม่มีความจำเป็นต้องใช้คลาส Humanoid
- การเล่นอนิเมชันบน NPCs จำนวนมากจากเซิร์ฟเวอร์ - อนิเมชัน NPC ที่รันจากเซิร์ฟเวอร์จำเป็นต้องได้รับการจำลองในเซิร์ฟเวอร์และทำซ้ำไปยังไคลเอนต์ สิ่งนี้อาจทำให้เกิดการใช้งานที่ไม่จำเป็น
- การทำการเปลี่ยนแปลงขนาดและอัตราส่วนที่ไม่จำเป็น - การเปลี่ยนแปลงขนาด/อัตราส่วนทำให้ FastCluster ต้องสร้างใหม่ ลองลดสิ่งนี้ในระหว่างการเล่นเกมหากคุณเห็นปัญหาประสิทธิภาพที่เกี่ยวข้องกับ FastCluster นอกจากนี้ การเปลี่ยนแปลงคุณสมบัติอื่นอาจทำให้ FastCluster ถูกสร้างขึ้นใหม่ ดังนั้นโดยทั่วไปควรลดการเปลี่ยนแปลงนี้ให้มากที่สุด
การลดผลกระทบ
- เล่นอนิเมชัน NPC บนไคลเอนต์ - ในเกมที่มี NPC จำนวนมาก ให้พิจารณาสร้าง Animator บนไคลเอนต์และทำการเล่นอนิเมชันในเครื่อง สิ่งนี้ช่วยลดภาระในเซิร์ฟเวอร์และความจำเป็นในการทำสำเนาที่ไม่จำเป็น นอกจากนี้ ยังทำให้มีการปรับปรุงโดยเฉพาะ (เช่น การเล่นอนิเมชันเฉพาะสำหรับ NPC ที่ใกล้กับตัวละคร)
- ใช้ทางเลือกที่เป็นมิตรต่อประสิทธิภาพแทน Humanoids - โมเดล NPC ไม่จำเป็นต้องมีวัตถุ Humanoid
- สำหรับ NPC ที่อยู่กับที่ ให้ใช้ AnimationController ง่ายๆ เพราะไม่ต้องเคลื่อนที่แต่ต้องเล่นอนิเมชัน
- สำหรับ NPC ที่เคลื่อนที่ให้พิจารณาการใช้ตัวควบคุมการเคลื่อนที่ของคุณเองและใช้ AnimationController สำหรับการอนิเมชัน ขึ้นอยู่กับความซับซ้อนของ NPCs ของคุณ
- ปิดการใช้งานสถานะ Humanoid ที่ไม่ใช้ - ใช้ Humanoid:SetStateEnabled() เพื่อตั้งค่าสถานะที่จำเป็นสำหรับ Humanoid แต่ละตัว
- ทำการจัดกลุ่มโมเดล NPC ที่ถอนการติดตั้งบ่อยๆ - แทนที่จะทำลาย NPC เสร็จสิ้น ให้ส่ง NPC ไปยังสระของ NPC ที่ไม่ได้ใช้งาน วิธีนี้ เมื่อมีการเรียกคืน NPC ใหม่ ก็สามารถเปิดใช้งาน NPC ที่มาจากสระได้ทันที ขั้นตอนนี้เรียกว่า pooling ซึ่งลดจำนวนครั้งที่ตัวละครต้องสร้างขึ้น
- สร้าง NPC เมื่อผู้ใช้อยู่ใกล้เท่านั้น - อย่าสร้าง NPC เมื่อผู้ใช้ไม่อยู่ในระยะ และลบ NPC เมื่อผู้ใช้ออกจากระยะ
- หลีกเลี่ยงการทำการเปลี่ยนแปลงต่อระดับการจัดเรียงหลังจากการสร้างไปแล้ว - การปรับเปลี่ยนบางประการกับระดับการจัดเรียงของอวตารอาจมีผลต่อประสิทธิภาพอย่างมีนัยสำคัญ มีวิธีการปรับปรุงบางประการ:
- สำหรับการอนิเมชันที่สร้างด้วยโปรแกรมที่กำหนดเอง อย่าปรับปรุงคุณสมบัติ JointInstance.C0 และ JointInstance.C1 แทนที่จะปรับปรุงคุณสมบัติ Motor6D.Transform
ขอบเขตของ MicroProfiler
| ขอบเขต | การคำนวณที่เกี่ยวข้อง |
| stepHumanoid | การควบคุมมนุษย์และฟิสิกส์ |
| stepAnimation | การอนิเมชันของ Humanoid และ Animator |
| updateInvalidatedFastClusters | ที่เกี่ยวข้องกับการสร้างหรือการเปลี่ยนแปลงอวตาร |
การเรนเดอร์
ช่วงเวลาที่สำคัญแห่งการใช้เวลามากที่สุดคือการเรนเดอร์ ฉากในเฟรมปัจจุบัน เซิร์ฟเวอร์ไม่ทำการเรนเดอร์ใดๆ ดังนั้นส่วนนี้เป็นเฉพาะสำหรับไคลเอนต์
การเรียกวาด
การเรียกวาด (draw call) คือชุดของคำสั่งจากเอนจิ้นถึง GPU เพื่อเรนเดอร์ บางสิ่ง การเรียกวาดมีค่าใช้จ่ายสูง โดยทั่วไปยิ่งมีการเรียกวาดน้อยลงในแต่ละเฟรม จะใช้เวลาน้อยลงในการเรนเดอร์เฟรม
คุณสามารถดูว่ามีกี่ครั้งที่มีการเรียกวาดเกิดขึ้นในขณะที่รายการ Render Stats ⟩ Timing ใน Studio คุณสามารถดู Render Stats ในไคลเอนต์โดยการกด ShiftF2
ยิ่งมีวัตถุที่ต้องวาดในฉากของคุณในเฟรมหนึ่งมากขึ้นเท่าไหร่ก็จะยิ่งมีการเรียกวาดไปที่ GPU มากขึ้นเท่านั้น อย่างไรก็ตาม เอนจิ้น Roblox ใช้กระบวนการที่เรียกว่า instancing เพื่อรวม meshes ที่เหมือนกันซึ่งมีลักษณะการทำ texture เดียวกันไว้ในการเรียกวาดครั้งเดียว โดยเฉพาะอย่างยิ่ง หลาย meshes ที่มี MeshContent เดียวกันจะถูกจัดการในการเรียกครั้งเดียวเมื่อ:
- SurfaceAppearances เหมือนกันถ้ามี หากไม่มีก็จะมี TextureContents เหมือนกัน
- วัสดุเหมือนกันเมื่อทั้ง SurfaceAppearance และ MeshPart.TextureID ไม่มีอยู่
ปัญหาอื่น ๆ
ความหนาแน่นของวัตถุมากเกินไป - หากมีวัตถุจำนวนมากรวมกันในความหนาแน่นสูง การเรนเดอร์พื้นที่นี้ในฉากจะทำให้จำเป็นต้องมีการเรียกวาดจำนวนมาก หากคุณพบว่าระดับเฟรมต่ำลงเมื่อมองไปยังส่วนหนึ่งของแผนที่ อาจเป็นสัญญาณที่ดีว่าความหนาแน่นของวัตถุในพื้นที่นี้สูงเกินไป
วัตถุเช่น decal, texture และ particles ไม่มีการรวมกันที่ดีและแนะนำให้เกิดการเรียกวาดเพิ่มเติม ให้ความสนใจกับวัตถุประเภทเหล่านี้ในฉาก โดยเฉพาะอย่างยิ่งการเปลี่ยนคุณสมบัติของ ParticleEmitters อาจมีผลกระทบต่อประสิทธิภาพอย่างมาก
โอกาสในการใช้ instancing ที่หายไป - มักจะมีฉากที่รวม mesh เดียวกันซ้ำหลายครั้ง แต่แต่ละสำเนาของ mesh มี ID ของ asset mesh หรือ texture ที่แตกต่างกัน สิ่งนี้ป้องกันการใช้ instancing และอาจนำไปสู่การเรียกวาดซ้ำที่ไม่จำเป็น
สาเหตุทั่วไปของปัญหานี้คือเมื่อฉากทั้งฉากถูกนำเข้าสูตรในครั้งเดียว แต่แทนที่จะนำเข้าสินค้าแบบแยกก่อนจากนั้นก็ทำการทำสำเนาเพื่อประกอบฉากด้วยกัน
แม้จะมีสคริปต์ที่ง่าย ๆ แบบนี้ก็สามารถช่วยคุณระบุ mesh parts ที่มีชื่อเดียวกันที่ใช้ mesh IDs ที่แตกต่างกันได้:
for _,descendant in workspace:GetDescendants() doif descendant:IsA("MeshPart") thenprint(descendant.Name .. ", " .. descendant.MeshId)endendข้อมูลที่แสดง (โดยเปิดใช้งาน Stack Lines) อาจมีรูปลักษณ์เช่นนี้ บรรทัดที่ซ้ำกันแสดงถึงการใช้ mesh ที่เหมือนกัน ซึ่งดี บรรทัดที่ไม่ซ้ำกันไม่ได้แย่ necessarily แต่ตามแผนการตั้งชื่อของคุณ อาจบ่งบอกถึง mesh ซ้ำในเกมของคุณ:
LargeRock, rbxassetid://106420009602747 (x144) -- ดีLargeRock, rbxassetid://120109824668127LargeRock, rbxassetid://134460273008628LargeRock, rbxassetid://139288987285823LargeRock, rbxassetid://71302144984955LargeRock, rbxassetid://90621205713698LargeRock, rbxassetid://113160939160788LargeRock, rbxassetid://135944592365226 -- เป็นซ้ำทั้งหมดที่เป็นไปได้ความซับซ้อนของวัตถุที่มากเกินไป - แม้ว่าจะไม่สำคัญเท่ากับจำนวนการเรียกวาด แต่จำนวนสามเหลี่ยมในฉากมีอิทธิพลต่อเวลาในการเรนเดอร์ให้กับเฟรมเป็นอย่างมาก ฉากที่มีสามเหลี่ยมจำนวนมากและซับซ้อนมากเป็นปัญหาทั่วไป เช่นเดียวกับฉากที่มีการตั้งค่าคุณสมบัติ MeshPart.RenderFidelity เป็น Precise มากเกินไป
การสร้างเงาที่มากเกินไป - การจัดการเงาเป็นกระบวนการที่มีค่าใช้จ่ายสูง แผนที่ที่มีวัตถุแสงที่สร้างเงาจำนวนมากและความหนาแน่นสูง (หรือจำนวนและความหนาแน่นสูงของชิ้นส่วนเล็ก ๆ ที่ได้รับผลกระทบจากเงา) อาจมีปัญหาด้านประสิทธิภาพ
ความโปร่งใสของการให้แสงที่สูงเกินไป - การวางวัตถุที่มีความโปร่งใสบางใกล้กันทำให้เอนจิ้นต้องเรนเดอร์พิกเซลที่ซ้อนทับหลายครั้ง ซึ่งอาจทำให้ประสิทธิภาพต่ำลง สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการระบุและแก้ไขปัญหานี้ ให้ดูที่ Delete layered transparencies
การเคลื่อนที่ของ MeshPart ที่มีการผูกพันมากเกินไป - Skinned MeshParts ที่เป็นส่วนหนึ่งของ Model โดยไม่ต้องมี Humanoid จะถูกรวมกลุ่มโดยใช้ FastClusters ที่มีการจัดระเบียบทางพื้นที่ เมื่อ MeshParts เหล่านี้เคลื่อนที่ จะต้องมีการเพิ่มเข้าไปในแต่ละเวลาที่กลุ่มเหล่านี้ถูกสร้างใหม่และกระทบต่อประสิทธิภาพ
- วิธีแก้ปัญหาที่มีประสิทธิภาพมากคือการซ่อน Humanoid ภายใน Model การมี Humanoid จะทำให้การจัดกลุ่มเชิงพื้นที่เป็นแบบใหม่โดยอัตโนมัติ อีกทั้งยังทำให้ไปยังการใช้ FastCluster เดียวกันสำหรับ Model ทั้งหมด ในขณะที่อัปเดตตำแหน่งจะไม่ทำให้เกิดการสร้างใหม่ของกลุ่มและจะลดจุดคอขวดด้านประสิทธิภาพ วิธีนี้ควรใช้เฉพาะสำหรับ MeshParts ที่มีการเคลื่อนที่ เนื่องจากอาจส่งผลให้เกิดการใช้งานหน่วยความจำที่เพิ่มขึ้นและทำให้ประโยชน์ของการปรับให้เหมาะสมทางพื้นที่ลดลง เราขอแนะนำให้อัปเดตประสิทธิภาพในเกมของคุณหลังจากทำการเปลี่ยนแปลงดังกล่าว ดูที่ คำแนะนำในการปรับปรุงประสิทธิภาพของ Humanoid สำหรับข้อมูลเพิ่มเติม
มีชิ้นส่วนมากเกินไปใน Model - ชิ้นส่วนมากเกินไปใน Model อาจทำให้เกิดการสร้างใหม่บ่อยเกินไปเนื่องจากความเป็นไปได้ของการเปลี่ยนคุณสมบัติของชิ้นส่วนที่ไม่ให้ซ้ำซ้อน ทำการหายใจให้ถูกต้องรวมถึงชิ้นส่วนใน Model เมื่อมันใช้ FastCluster
การลดผลกระทบ
สร้าง meshes ที่เหมือนกันและลดจำนวน mesh ที่ไม่เหมือนกัน - หากคุณสามารถรับรองว่า mesh ที่เหมือนกันทั้งหมดมี ID ของสินทรัพย์พื้นฐานเดียวกัน เอนจิ้นจะสามารถระบุและเรนเดอร์พวกเขาในการเรียกวาดครั้งเดียว ตรวจสอบให้แน่ใจว่าสามารถอัปโหลด mesh แต่ละอันในแผนที่ได้เพียงครั้งเดียวแล้วทำการทำสำเนาใน Studio ใช้ซ้ำแทนการนำเข้าทั้งแผนที่ในครั้งเดียว ซึ่งอาจทำให้ mesh ที่เหมือนกันมี ID ของเนื้อหาที่แยกกันและถูกระบุว่าเป็นสินทรัพย์ที่ไม่เหมือนกันตามเอนจิ้น Packages เป็นกลไกที่ช่วยในการใช้ซ้ำวัตถุ.
การถอนการใช้งาน - การถอนการใช้งานหมายถึงกระบวนการกำจัดการเรียกวาดสำหรับวัตถุที่ไม่เกี่ยวข้องกับเฟรมที่สร้างสุดท้าย โดยค่าเริ่มต้น เอนจิ้นจะข้ามการเรียกวาดสำหรับวัตถุที่อยู่นอกมุมมองของกล้อง (frustum culling) และชิ้นส่วน เมมเบอร์ และดินที่ถูกปิดจากการวิจารณ์ของวัตถุอื่น (occlusion culling) ในบางกรณี เช่นสิ่งแวดล้อมในอาคาร คุณอาจสามารถใช้งานระบบห้องหรือพอร์ตและตัดการใช้วัตถุเพื่อช่วยลดการเรียกวาดหรือลดความต้องการในการคำนวณโดยรวม
การลดระดับความละเอียดของโมเดล - เปิดใช้งาน instance streaming และตั้งค่า LevelOfDetail ของโมเดลในโลกของคุณเป็น SLIM เพื่อเรนเดอร์ optimized lightweight SLIM meshes ให้กับโมเดลเมื่อระยะห่างจากกล้องเพิ่มขึ้น
การลดระดับความละเอียดของตัวอวตาร - เปิดใช้งานการสตรีมประจำและตั้งค่า Workspace.EnableSLIMAvatars เพื่อเรนเดอร์โมเดลตัวอวตารของแพลตฟอร์มที่มีจำนวนอุปกรณ์เสริมหรือชั้นของเสื้อผ้าเป็น optimizing lightweight avatar representations พร้อมการสนับสนุนเต็มรูปแบบสำหรับอนิเมชันเมื่อห่างจากกล้องมากขึ้น
การลดความละเอียดในการเรนเดอร์ - ตั้งค่า MeshPart.RenderFidelity เป็น Automatic หรือ Performance วิธีนี้ช่วยให้ meshes สามารถย้อนกลับไปสู่ตัวเลือกที่ซับซ้อนน้อยลง ซึ่งสามารถลดจำนวนโพลิกอนที่ต้องเรนเดอร์ให้ลดลง
การปิดการสร้างเงาที่ชิ้นงานและวัตถุแสงที่เหมาะสม - เอนไจน์ Roblox จะลดคุณภาพของเงาเมื่อระดับคุณภาพกราฟิกของไคลเอนต์ลดลง บ่อยครั้งจะปิดการสร้างเงาโดยสิ้นเชิงที่ระดับคุณภาพที่ต่ำกว่า 4 อย่างไรก็ตาม คุณสามารถเลือกปิดการสร้างเงาออกจากคุณสมบัติของการสร้างเงาที่วัตถุแสงและชิ้นงานเพื่อให้ประสิทธิภาพดีขึ้นในขณะที่เปิดใช้การสร้างเงาและเพิ่มโอกาสที่เงาจะเปิดใช้งานอยู่ บางตัวอย่างของการปรับปรุงที่คุณสามารถทำได้ในระหว่างเวลาปรับแต่งหรือปรับปรุงได้:
ใช้คุณสมบัติ BasePart.CastShadow เพื่อปิดการสร้างเงาที่ชิ้นส่วนขนาดเล็กที่เงาไม่ค่อยชัดเจน วิธีนี้มีประสิทธิภาพโดยเฉพาะเมื่อใช้กับชิ้นส่วนที่อยู่ไกลจากกล้องของผู้ใช้
ปิดเงาบนวัตถุที่มีการเคลื่อนที่เมื่อเป็นไปได้
ปิด Light.Shadows บนinstance ของแสงที่วัตถุไม่จำเป็นต้องสร้างเงา
จำกัดระยะและมุมของ instance ของแสง
ใช้การดำเนินการของแสงน้อยลง
พิจารณาปิดการสร้างแสงที่อยู่นอกช่วงที่กำหนดหรือในระดับห้องต่อห้องสำหรับสิ่งแวดล้อมในอาคาร
ขอบเขตของ MicroProfiler
| ขอบเขต | การคำนวณที่เกี่ยวข้อง |
| Prepare and Perform | การเรนเดอร์โดยรวม |
| Perform/Scene/computeLightingPerform | การปรับและการอัปเดตเงา |
| LightGridCPU | การอัปเดตกริดแสง voxel |
| ShadowMapSystem | การทำแผนที่เงา |
| Perform/Scene/UpdateView | การเตรียมการเรนเดอร์และการอัปเดตอนิเมชั่น |
| Perform/Scene/RenderView | การเรนเดอร์และการประมวลผลหลังการเรนเดอร์ |
เครือข่ายและการทำสำเนา
เครือข่ายและการทำสำเนาบรรยายถึงกระบวนการที่ข้อมูลถูกส่งระหว่าง เซิร์ฟเวอร์และไคลเอนต์ที่เชื่อมต่อ ข้อมูลจะถูกส่งระหว่างไคลเอนต์และเซิร์ฟเวอร์ในทุกเฟรม แต่จำนวนข้อมูลที่มากขึ้นต้องใช้เวลาคำนวณมากขึ้น
ปัญหาทั่วไป
การจราจรทางไกลเกินไป - การส่งข้อมูลจำนวนมากผ่าน RemoteEvent หรือ RemoteFunction หรือการเรียกใช้งานมันบ่อยเกินไปสามารถสร้างค่าใช้จ่ายทาง CPU ในการประมวลผลแพ็กเกจที่เข้ามาในแต่ละเฟรม ข้อผิดพลาดทั่วไป ได้แก่:
- การทำสำเนาข้อมูลในทุกเฟรมโดยไม่จำเป็นต้องทำสำเนา
- การทำสำเนาข้อมูลเมื่อผู้ใช้มีการป้อนข้อมูลโดยไม่มีกลไกในการจำกัดความถี่
- การส่งข้อมูลมากกว่าที่จำเป็น เช่น การส่งทั้งชุดค่าผสมของผู้เล่นเมื่อพวกเขาซื้อสินค้าแทนที่จะส่งเพียงรายละเอียดของสินค้าที่ซื้อ
การสร้างหรือการลบโครงสร้างอินสแตนซ์ที่ซับซ้อน - เมื่อมีการเปลี่ยนแปลงในแบบจำลองข้อมูลในเซิร์ฟเวอร์ จะมีการส่งต่อไปยังไคลเอนต์ ซึ่งหมายความว่าการสร้างและทำลายโครงสร้างอินสแตนซ์ใหญ่ ๆ เช่น maps ในระยะเวลาที่ทำงานสามารถใช้ บริการเครือข่ายได้อย่างมาก
สาเหตุทั่วไปที่นี่คือข้อมูลอนิเมชั่นจำนวนมาก ที่เซฟโดย plugins Animation Editor ใน rigs หากสิ่งเหล่านี้ไม่ได้ถูกลบก่อนที่เกมจะถูกเผยแพร่และโมเดลที่ถูกอนิเมตนั้นถูกทำสำเนาอยู่บ่อยครั้ง จำนวนข้อมูลมากมายที่ไม่จำเป็นจะถูกทำสำเนาอยู่
TweenService ทางเซิร์ฟเวอร์ - หากใช้ TweenService เพื่อทำให้วัตถุดำเนินการทางเซิร์ฟเวอร์ คุณค่าที่ถูกทำทวีจะถูกทำสำเนาไปยังไคลเอนต์ในทุกเฟรม ทำให้การทำงานนี้เกิดสะดุดเพราะความแปรปรวนของความเสถียรในการตอบสนองสำหรับผู้ใช้ ส่งผลให้เกิดการจราจรเครือข่ายที่ไม่จำเป็น
การลดผลกระทบ
คุณสามารถใช้ตรรกะต่อไปนี้เพื่อลดการทำสำเนาที่ไม่จำเป็น:
- หลีกเลี่ยงการส่งข้อมูลจำนวนมากในครั้งเดียวผ่านเหตุการณ์ทางไกล แทนที่จะส่งข้อมูลที่จำเป็นที่ระยะเวลาที่ต่ำกว่า ตัวอย่างเช่น สำหรับสถานะของตัวละคร ให้ทำการส่งเมื่อมีการเปลี่ยนแปลงแทนที่จะเป็นทุกเฟรม
- แบ่งโครงสร้างอินสแตนซ์ที่ซับซ้อน เช่น maps และโหลดเป็นส่วน ๆ เพื่อกระจายงานการทำสำเนานี้ไปยังหลายเฟรม
- ทำความสะอาด metadata อนิเมชัน โดยเฉพาะไดเรกทอรีอนิเมชั่นของ rigs หลังจากนำเข้าเรียบร้อยแล้ว
- จำกัดการทำสำเนาของอินสแตนซ์ที่ไม่จำเป็น โดยเฉพาะในกรณีที่เซิร์ฟเวอร์ไม่ต้องการมีความรู้เกี่ยวกับอินสแตนซ์ที่ถูกสร้างขึ้น ซึ่งรวมถึง:
- เอฟเฟกส์ภาพเช่นการระเบิดหรือเวทย์มนต์ เฟิร์สเซิร์ฟเวอร์เพียงแค่ต้องการรู้ตำแหน่งเพื่อกำหนดผลที่เกิดขึ้นในขณะที่ไคลเอนต์สามารถสร้างภาพในเครื่องได้
- มุมมองของไอเท็มในมุมมองมุมมองบุคคลแรก (first-person)
- ทำให้วัตถุ Tween ทางไคลเอนต์แทนที่จะเป็นเซิร์ฟเวอร์
ขอบเขตของ MicroProfiler
| ขอบเขต | การคำนวณที่เกี่ยวข้อง |
| ProcessPackets | การประมวลผลสำหรับแพ็กเกจเครือข่ายที่เข้ามา เช่น การเรียกใช้เหตุการณ์และการเปลี่ยนแปลงคุณสมบัติ |
| Allocate Bandwidth and Run Senders | เหตุการณ์ที่ส่งไปยังเซิร์ฟเวอร์ |
การใช้งานหน่วยความจำทรัพย์สิน
กลไกที่มีผลกระทบสูงสุดต่อผู้สร้างในการปรับปรุงการใช้หน่วยความจำของไคลเอนต์คือการเปิดใช้งาน การสตรีมอินสแตนซ์.
การสตรีมอินสแตนซ์
การสตรีมอินสแตนซ์จะโหลดเฉพาะส่วนที่ไม่จำเป็นของโมเดลข้อมูลซึ่งอาจทำให้เวลาโหลดลดลงและเพิ่มความสามารถของไคลเอนต์ในการป้องกันการเกิดข้อผิดพลาดเมื่อมีการใช้หน่วยความจำ
หากคุณประสบปัญหาเกี่ยวกับหน่วยความจำและได้ปิดการใช้การสตรีมอินสแตนซ์ ให้พิจารณาอัปเดตเกมของคุณให้สนับสนุนมัน โดยเฉพาะหากโลก 3 มิติของคุณมีขนาดใหญ่ การสตรีมอินสแตนซ์จะอิงจากระยะทางในพื้นที่ 3 มิติ ดังนั้นโลกที่ใหญ่ขึ้นจะมีประโยชน์มากขึ้นจากมัน
หากเปิดใช้งานการสตรีมอินสแตนซ์ คุณสามารถเพิ่มความเข้มข้นของมันได้ ตัวอย่างเช่น โปรดพิจารณา:
- ลดการใช้งาน Enum.ModelStreamingMode.Persistent จนกว่าคุณจะสามารถทำได้ คุณอาจจำเป็นต้องอัปเดตสคริปต์ของคุณหากคุณใช้ก็เพื่อความเข้ากันได้
- ลดค่า Workspace.StreamingMinRadius และ Workspace.StreamingTargetRadius.
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกการสตรีมและประโยชน์ของมัน โปรดดูที่ ค่าพารามิเตอร์การสตรีม.
ปัญหาอื่น ๆ ที่พบบ่อย
การทำสำเนาทรัพย์สิน - ข้อผิดพลาดทั่วไปคือการอัปโหลดทรัพย์สินเดียวกันหลายครั้งซึ่งส่งผลให้ได้ ID ที่แตกต่างกัน ซึ่งอาจทำให้เนื้อหาเดียวกันถูกโหลดลงในหน่วยความจำหลายครั้ง
ปริมาณทรัพย์สินมากเกินไป - แม้ว่าทรัพย์สินไม่ซ้ำกัน บางครั้งก็มีกรณีที่โอกาสในการใช้ทรัพย์สินเดียวกันและประหยัดหน่วยความจำถูกพลาด
ไฟล์เสียง - ไฟล์เสียงอาจเป็นผู้บริจาคที่ทำให้การใช้หน่วยความจำสูงอย่างน่าประหลาดใจ โดยเฉพาะอย่างยิ่งหากคุณโหลดมันทั้งหมดลงในไคลเอนต์ครั้งเดียวแทนที่จะโหลดเฉพาะสิ่งที่คุณต้องการในช่วงเวลาหนึ่งของเกม สำหรับกลยุทธ์ให้ดูที่ เวลาในการโหลด
Textures ความละเอียดสูง - การใช้หน่วยความจำภาพกราฟฟิกสำหรับ texture ไม่มีความสัมพันธ์กับขนาดของ texture บนดิสก์ แต่จำนวนพิกเซลใน texture จะกำหนดการใช้หน่วยความจำ ตัวอย่างเช่น texture ขนาด 1024x1024 จะใช้หน่วยความจำกราฟฟิกสี่เท่าของตัวแปรหน่วยความจำแบบ 512x512
รูปภาพที่อัปโหลดไปยัง Roblox จะถูกแปลงรหัสเป็นรูปแบบที่ชัดเจน ดังนั้นจึงไม่มีประโยชน์ใด ๆ ในการอัปโหลดรูปภาพในโมเดลสีที่เกี่ยวข้องกับจำนวนไบต์ต่อพิกเซลที่น้อยลง นอกจากนี้ การบีบอัดภาพก่อนการอัปโหลดหรือการลบช่องอัลฟาจากภาพที่ไม่ต้องการสามารถลดขนาดของภาพบนดิสก์ได้ แต่ไม่ได้ปรับปรุงการใช้หน่วยความจำ
ขณะที่เกมกำลังเปิดใช้งาน เอนจิ้นโดยอัตโนมัติเริ่มต้นด้วย texture ที่มีคุณภาพต่ำกว่าแล้วค่อยๆ สูงขึ้นตามความสามารถในการใช้หน่วยความจำของอุปกรณ์ ระยะห่างจากกล้อง จำนวนพื้นที่หน้าจอที่ texture ครอบครองลงในพื้นที่ และปัจจัยอื่น ๆ แม้ว่าเช่นนี้ การปรับขนาด texture ของคุณอย่างมีกลยุทธ์อาจปรับปรุงการใช้หน่วยความจำในเกมของคุณ
การลดผลกระทบ
อัปโหลดสินทรัพย์เพียงครั้งเดียว - ใช้ ID ของทรัพย์สินเดียวกันในวัตถุและตรวจสอบให้แน่ใจว่าไม่มีสินทรัพย์เดียวกัน โดยเฉพาะ mesh และภาพที่ถูกอัปโหลดแยกกันหลายครั้ง
ค้นหาและแก้ไขทรัพย์สินซ้ำกัน - มองหาชิ้นส่วน mesh และ textures ที่เหมือนกันที่ถูกอัปโหลดหลายครั้งด้วย ID ที่แตกต่างกัน
- แม้ว่าจะไม่มี API เพื่อตรวจจับความคล้ายคลึงกันของทรัพย์สินโดยอัตโนมัติ แต่คุณสามารถรวบรวม ID ของภาพทั้งหมดในสถานที่ (ไม่ว่าจะเป็นแบบแมนนวลหรือด้วยสคริปต์) ดาวน์โหลดมันและเปรียบเทียบโดยใช้เครื่องมือเปรียบเทียบภายนอก
- สำหรับชิ้นส่วน mesh ยุทธศาสตร์ที่ดีที่สุดคือการนำ ID ของ mesh ที่ไม่ซ้ำกันมาเรียงลำดับตามขนาดเพื่อตรวจจับซ้ำ
- แทนที่จะใช้แยก texture สำหรับสีที่ต่างกัน ให้อัปโหลด texture เดียวและใช้คุณสมบัติ SurfaceAppearance.Color เพื่อใช้สีที่ต่างกัน
นำเข้าสินทรัพย์ในแผนที่แยกกัน - แทนที่จะนำเข้าฉากทั้งฉากในครั้งเดียว ให้ทำการนำเข้าสินทรัพย์และสร้างใหม่ในแผนที่แยกกัน โปรแกรมสร้างไม่ทำการจำแนกซ้ำกันของ mesh ดังนั้นหากคุณนำเข้าแผนที่ขนาดใหญ่ที่มีพื้นแตกต่างกันมากมาย หนึ่งในพื้นแต่ละชิ้นจะถูกนำเข้ามาเป็นทรัพย์สินที่แยกต่างหาก (แม้กระทั่งเมื่อเป็น mesh ซ้ำกัน) สิ่งนี้อาจทำให้เกิดปัญหาเรื่องประสิทธิภาพและหน่วยความจำในภายหลัง เนื่องจากแต่ละ mesh ถูกมองว่าเป็นสิ่งที่ไม่ซ้ำกันและใช้หน่วยความจำและการเรียกวาดแยกกัน
จำกัดจำนวนพิกเซลของภาพ ไม่ให้เกินจำนวนที่จำเป็น โดยเฉพาะอย่างยิ่งหากภาพไม่ครอบครองพื้นที่มาก เมื่อความต้องการพื้นที่ของภาพในหน้าจอสูงที่สุดมักจะต้องการให้มีเพียง 512x512 พิกเซลเท่านั้น โดยจำนวนมากจะต้องมีขนาดเล็กกว่า 256x256 พิกเซล
ใช้แผ่นตัด เพื่อให้แน่ใจว่าการใช้โครงสร้างพื้นฐานสูงสุดในแผนที่ 3 มิติ สำหรับ ขั้นตอนและตัวอย่างการสร้างแผ่นตัด ให้ดูที่ Create trim sheets.
คุณอาจพิจารณาใช้ sprite sheets เพื่อโหลดภาพ UI ขนาดเล็กหลายภาพเป็นภาพเดียว ดังนั้นจึงสามารถใช้ ImageLabel.ImageRectOffset และ ImageLabel.ImageRectSize เพื่อแสดงส่วนหนึ่งของแผ่น
เวลาในการโหลด
เกมหลายเกมมีหน้าจอโหลดแบบกำหนดเองและใช้วิธีการ ContentProvider:PreloadAsync() เพื่อขอทรัพย์สินเพื่อให้ภาพ เสียง และ mesh ได้ถูกดาวน์โหลดในพื้นหลัง
ข้อดีของวิธีนี้คือช่วยให้คุณมั่นใจได้ว่าส่วนสำคัญของเกมของคุณจะมีการโหลดทั้งหมดโดยไม่เกิดปัญหาระหว่างการโหลด อย่างไรก็ตาม ข้อผิดพลาดทั่วไปคือการใช้งานวิธีนี้มากเกินไปเพื่อโหลดมากกว่าที่จำเป็น
ตัวอย่างของแนวทางที่ไม่ดีคือการโหลดทั้ง Workspace แม้ว่าจะสามารถป้องกันการโหลดภาพที่เกิดขึ้นแบบพุ่งได้ แต่ก็เพิ่มเวลาในการโหลดอย่างมีนัยสำคัญ
อีกแนวทางที่คล้ายกันคือการใช้งาน ContentProvider.RequestQueueSize เพื่อทำให้แน่ใจว่าสินทรัพย์ทั้งหมดที่ขอได้เสร็จสิ้นการโหลด อย่างไรก็ตาม ข้อเสียของมันคือมันจะเพิ่มเวลาในการโหลดอย่างมีนัยสำคัญในขณะที่เป็นวิธีการที่เชื่อถือได้เนื่องจากธรรมชาติที่แปรผัน
แทนที่จะทำเช่นนี้ ให้ใช้ ContentProvider:PreloadAsync() ในกรณีที่จำเป็นซึ่งรวมถึง:
- รูปภาพในหน้าจอโหลด
- รูปภาพสำคัญในเมนูเกมของคุณ เช่น พื้นหลังของปุ่มและไอคอน
- ทรัพย์สินที่สำคัญในพื้นที่เริ่มต้นหรือตั้งแต่ต้น