Halaman ini menjelaskan masalah kinerja umum dan praktik terbaik untuk menguranginya.
Perhitungan skrip
Operasi mahal dalam kode Luau membutuhkan waktu lebih lama untuk diproses dan dapat mempengaruhi tingkat bingkai. Kecuali jika dijalankan secara paralel, kode Luau berjalan secara sinkron dan memblokir thread utama sampai menemukan fungsi yang menangguhkan thread tersebut.
Masalah umum
Operasi intensif pada struktur tabel - Operasi kompleks seperti serialisasi, deserialisasi, dan kloning dalam dapat memicu biaya kinerja yang tinggi, terutama pada struktur tabel yang besar. Ini terutama benar jika operasi ini rekursif atau melibatkan iterasi di atas struktur data yang sangat besar.
Peristiwa frekuensi tinggi - Mengaitkan operasi mahal dengan peristiwa berbasis bingkai dari RunService tanpa membatasi frekuensinya berarti operasi ini diulang setiap bingkai, yang sering kali mengakibatkan peningkatan waktu komputasi yang tidak perlu. Peristiwa ini termasuk:
Mitigasi
- Jalankan kode pada peristiwa RunService dengan hati-hati, membatasi penggunaan pada kasus di mana pemanggilan frekuensi tinggi penting (misalnya, memperbarui kamera). Anda dapat menjalankan sebagian besar kode lainnya pada peristiwa lain atau dengan frekuensi yang lebih rendah dalam sebuah loop.
- Pecah tugas besar atau mahal menggunakan task.wait() untuk menyebarkan pekerjaan di berbagai bingkai.
- Identifikasi dan optimalkan operasi yang tidak perlu mahal dan gunakan multithreading untuk tugas komputasi mahal yang tidak perlu mengakses model data.
- Skrip sisi server tertentu dapat memanfaatkan generasi kode asli, sebuah bendera sederhana yang mengompilasi skrip menjadi kode mesin daripada bytecode.
Skop MicroProfiler
| Skop | Perhitungan terkait |
| RunService.PreRender | Kode yang dieksekusi pada peristiwa PreRender |
| RunService.PreSimulation | Kode yang dieksekusi pada peristiwa Stepped |
| RunService.PostSimulation | Kode yang dieksekusi pada peristiwa Heartbeat |
| RunService.Heartbeat | Kode yang dieksekusi pada peristiwa Heartbeat |
Untuk informasi lebih lanjut tentang debugging skrip menggunakan MicroProfiler, lihat perpustakaan debug, yang mencakup fungsi untuk menandai kode tertentu dan meningkatkan spesifikasi lebih lanjut, seperti debug.profilebegin dan debug.profileend. Banyak metode API Roblox yang dipanggil oleh skrip juga memiliki tag MicroProfiler terkait mereka sendiri yang dapat memberikan sinyal yang berguna.
Penggunaan memori skrip
Kebocoran memori dapat terjadi ketika Anda menulis skrip yang mengonsumsi memori yang tidak dapat dilepaskan dengan benar oleh pengumpul sampah ketika tidak lagi digunakan. Kebocoran ini khususnya menjamur di server, karena mereka dapat terus online selama berhari-hari, sedangkan sesi klien jauh lebih pendek.
Nilai memori berikut dalam Konsol Pengembang dapat menunjukkan masalah yang perlu penyelidikan lebih lanjut:
- LuaHeap - Konsumsi tinggi atau tumbuh menunjukkan adanya kebocoran memori.
- InstanceCount - Jumlah instansi yang terus tumbuh menunjukkan referensi ke beberapa instansi dalam kode Anda tidak dihapus oleh pengumpul sampah.
- PlaceScriptMemory - Memberikan rincian penggunaan memori per skrip.
Masalah umum
Meninggalkan koneksi terhubung - Mesin tidak pernah menghapus acara yang terhubung ke sebuah instansi dan nilai-nilai yang dirujuk di dalam callback yang terhubung. Oleh karena itu, koneksi aktif dari acara dan kode di dalam instansi yang terhubung, fungsi yang terhubung, dan nilai yang dirujuk, berada di luar jangkauan untuk pengumpul sampah, bahkan setelah acara dipanggil.
Meskipun acara dicabut ketika instansi yang menjadi miliknya dihancurkan, kesalahan umum adalah menganggap ini berlaku pada objek Player. Setelah seorang pengguna meninggalkan permainan, mesin tidak secara otomatis menghancurkan objek perwakilan Player mereka dan model karakter, sehingga koneksi ke objek Player dan instansi di bawah model karakter, seperti CharacterAdded, masih mengkonsumsi memori jika Anda tidak mencabut koneksi ini dalam skrip Anda. Ini dapat mengakibatkan kebocoran memori yang sangat signifikan dari waktu ke waktu pada server ketika ratusan pengguna bergabung dan meninggalkan permainan.
Tabel - Menyisipkan objek ke dalam tabel tetapi tidak menghapusnya ketika tidak lagi diperlukan menyebabkan konsumsi memori yang tidak perlu, terutama untuk tabel yang mencatat data pengguna saat mereka bergabung. Misalnya, contoh kode berikut membuat tabel yang menambahkan informasi pengguna setiap kali pengguna bergabung:
Contohlocal playerInfo = {}Players.PlayerAdded:Connect(function(player)playerInfo[player] = {} -- beberapa informasiend)Jika Anda tidak menghapus entri ini ketika tidak lagi dibutuhkan, tabel akan terus tumbuh dalam ukuran dan mengkonsumsi lebih banyak memori seiring bertambahnya jumlah pengguna yang bergabung dalam sesi. Kode apa pun yang mengiterasi tabel ini juga menjadi lebih mahal secara komputasi seiring bertambahnya ukuran tabel.
Mitigasi
Untuk membersihkan semua nilai yang digunakan agar mencegah kebocoran memori:
Cabut semua koneksi - Tinjau basis kode Anda dan pastikan setiap koneksi dibersihkan melalui salah satu jalur berikut:
- Mencabut secara manual menggunakan fungsi Disconnect().
- Menghancurkan instansi yang menjadi milik acara dengan fungsi Destroy().
- Menghancurkan objek skrip yang menjadi jejak koneksi.
Hapus objek pemain dan karakter setelah meninggalkan - Aktifkan Workspace.PlayerCharacterDestroyBehavior untuk secara otomatis menghancurkan objek pemain dan model karakter setelah seorang pengguna meninggalkan. Jika Anda mau, Anda bisa membersihkannya secara manual:
Contoh pembersihan pemain dan karakterlocal 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)
Perhitungan fisika
Simulasi fisika yang berlebihan dapat menjadi penyebab utama peningkatan waktu komputasi per bingkai baik di server maupun klien.
Masalah umum
Frekuensi langkah waktu fisika yang berlebihan - Secara default, perilaku langkah berada dalam mode adaptif, di mana fisika melangkah pada 60 Hz, 120 Hz, atau 240 Hz, tergantung pada kompleksitas mekanisme fisika.
Mode tetap dengan akurasi fisika yang ditingkatkan juga tersedia, yang memaksa semua perakitan fisika untuk melangkah pada 240 Hz (empat kali per bingkai). Ini mengakibatkan lebih banyak komputasi setiap bingkai.
Jumlah objek yang disimulasikan berlebihan atau memiliki kompleksitas berlebihan - Semakin banyak perakitan 3D yang disimulasikan, semakin lama waktu komputasi fisika setiap bingkai. Sering kali, permainan akan memiliki objek yang disimulasikan yang tidak perlu atau akan memiliki mekanisme yang memiliki lebih banyak batasan dan sambungan daripada yang dibutuhkan.
Deteksi tabrakan yang terlalu tepat - Bagian mesh memiliki properti CollisionFidelity untuk mendeteksi tabrakan yang menawarkan berbagai mode dengan tingkat dampak kinerja yang berbeda. Mode deteksi tabrakan yang tepat untuk bagian mesh memiliki biaya kinerja yang paling mahal dan membutuhkan waktu lebih lama untuk dihitung oleh mesin.
Mitigasi
Jaga agar bagian yang tidak memerlukan simulasi tetap tetap - Jaga semua bagian yang tidak perlu didorong oleh fisika, seperti NPC statis.
Gunakan langkah fisika adaptif - Langkah adaptif secara dinamis mengatur laju perhitungan fisika untuk mekanisme fisika, memungkinkan pembaruan fisika dilakukan kurang sering dalam beberapa kasus.
Kurangi kompleksitas mekanisme
- Di mana memungkinkan, minimalkan jumlah batasan fisika atau sambungan dalam suatu perakitan.
- Kurangi jumlah tabrakan diri dalam suatu mekanisme, seperti dengan menerapkan batasan atau batasan tidak terjadi tabrakan pada anggota ragdoll untuk mencegah mereka saling bertabrakan.
Kurangi penggunaan kecocokan tabrakan yang tepat untuk mesh
Untuk objek kecil atau tidak dapat berinteraksi di mana pengguna jarang memperhatikan perbedaannya, gunakan kecocokan kotak.
Untuk objek ukuran kecil-menengah, gunakan kecocokan kotak atau kerangka, tergantung pada bentuknya.
Untuk objek besar dan sangat kompleks, bangun kolisi kustom menggunakan bagian tak terlihat jika memungkinkan.
Untuk objek yang tidak memerlukan kolisi, nonaktifkan kolisi dan gunakan kecocokan kotak atau kerangka, karena geometri kolisi masih disimpan dalam memori.
Anda dapat merender geometri kolisi untuk tujuan debug di Studio dengan mengaktifkan Collision fidelity dari widget Visualization Options di sudut kanan atas jendela tampilan 3D.
Sebagai alternatif, Anda dapat menerapkan filter CollisionFidelity=PreciseConvexDecomposition ke Explorer yang menunjukkan jumlah semua bagian mesh dengan kecocokan yang tepat dan memungkinkan Anda untuk memilihnya dengan mudah.
Untuk penjelasan mendalam tentang cara memilih opsi kecocokan tabrakan yang seimbang antara ketepatan dan persyaratan kinerja Anda, lihat Set physics and rendering parameters.
Skop MicroProfiler
| Skop | Perhitungan terkait |
| physicsStepped | Perhitungan fisika keseluruhan |
| worldStep | Langkah fisika diskrit diambil setiap bingkai |
Penggunaan memori fisika
Gerakan fisika dan deteksi tabrakan mengkonsumsi memori. Bagian mesh memiliki properti CollisionFidelity yang menentukan pendekatan yang digunakan untuk mengevaluasi batas tabrakan dari mesh.
Masalah umum
Mode deteksi tabrakan default dan tepat mengkonsumsi memori secara signifikan lebih banyak daripada dua mode lainnya dengan bentuk kecocokan tabrakan yang lebih rendah.
Jika Anda melihat tingkat konsumsi memori tinggi di bawah PhysicsParts, Anda mungkin perlu mengeksplorasi pengurangan collision fidelity objek dalam permainan Anda.
Cara mitigasi
Untuk mengurangi memori yang digunakan untuk collision fidelity:
- Untuk bagian yang tidak memerlukan kolisi, nonaktifkan kolisi mereka dengan mengatur BasePart.CanCollide, BasePart.CanTouch, dan BasePart.CanQuery menjadi false.
- Kurangi fidelity deteksi tabrakan menggunakan pengaturan CollisionFidelity. Box memiliki overhead memori terendah, dan Default dan Precise umumnya lebih mahal.
- Umumnya aman untuk mengatur kecocokan tabrakan bagian tetap kecil mana pun ke Box.
- Untuk mesh besar yang sangat kompleks, Anda mungkin ingin membangun mesh kolisi Anda sendiri dari objek yang lebih kecil dengan kecocokan kolisi kotak.
Humanoids
Humanoid adalah kelas yang menyediakan berbagai fungsi untuk karakter pemain dan non-pemain (NPC). Meskipun kuat, Humanoid memiliki biaya komputasi yang signifikan.
Masalah umum
- Meninggalkan semua HumanoidStateTypes diaktifkan pada NPC - Ada biaya kinerja untuk membiarkan beberapa HumanoidStateTypes diaktifkan. Nonaktifkan yang tidak diperlukan untuk NPC Anda. Misalnya, kecuali NPC Anda akan mendaki tangga, aman untuk menonaktifkan keadaan Climbing.
- Membuat, memodifikasi, dan merespawn model dengan Humanoids atau MeshParts yang terkait secara sering
- Ini bisa sangat intensif bagi mesin untuk memproses, terutama jika model-model ini menggunakan pakaian berlapis. Ini juga bisa menjadi sangat problematik dalam permainan di mana avatar sering kali merespawn.
- Dalam MicroProfiler, tag updateInvalidatedFastClusters yang panjang (lebih dari 4 ms) sering menjadi sinyal bahwa instansiasi/modifikasi avatar memicu invalidasi yang berlebihan.
- Menggunakan Humanoids dalam kasus di mana mereka tidak dibutuhkan - NPC statis yang tidak bergerak umumnya tidak memerlukan kelas Humanoid.
- Memutar animasi pada sejumlah besar NPC dari server - Animasi NPC yang berjalan di server perlu disimulasikan di server dan direplikasi ke klien. Ini bisa menjadi beban yang tidak perlu.
- Melakukan perubahan ukuran dan skala yang tidak perlu - Perubahan ukuran/skala menyebabkan FastCluster dibangun kembali. Cobalah untuk mengurangi ini selama permainan jika Anda melihat masalah kinerja terkait FastCluster. Demikian juga, perubahan properti lainnya juga mungkin menyebabkan FastCluster dibangun kembali, jadi secara umum kurangi perubahan ini sebanyak mungkin.
Mitigasi
- Putar animasi NPC di klien - Dalam permainan dengan sejumlah besar NPC, pertimbangkan untuk membuat Animator di klien dan menjalankan animasi secara lokal. Ini mengurangi beban pada server dan kebutuhan untuk replikasi yang tidak perlu. Ini juga memungkinkan optimasi tambahan (seperti hanya memutar animasi untuk NPC yang dekat dengan karakter).
- Gunakan alternatif ramah-kinerja untuk Humanoids - Model NPC tidak perlu mencakup objek humanoid.
- Untuk NPC statis, gunakan AnimationController sederhana, karena mereka tidak perlu bergerak tetapi hanya perlu memutar animasi.
- Untuk NPC yang bergerak, pertimbangkan untuk menerapkan pengontrol gerakan sendiri dan menggunakan AnimationController untuk animasi, tergantung pada kompleksitas NPC Anda.
- Nonaktifkan status humanoid yang tidak digunakan - Gunakan Humanoid:SetStateEnabled() untuk hanya mengaktifkan status yang diperlukan untuk setiap humanoid.
- Menyediakan model NPC dengan respawn yang sering - Alih-alih menghancurkan NPC sepenuhnya, kirim NPC ke kumpulan NPC tidak aktif. Dengan cara ini, ketika NPC baru diperlukan untuk respawn, Anda bisa cukup mengaktifkan kembali salah satu NPC dari kumpulan tersebut. Proses ini disebut pooling, yang meminimalkan jumlah kali karakter perlu diinstansiasi.
- Hanya muncul NPC saat pengguna berada di dekatnya - Jangan muncul NPC saat pengguna tidak dalam jangkauan, dan hilangkan mereka saat pengguna meninggalkan jangkauan mereka.
- Hindari membuat perubahan pada hierarki avatar setelah diinstansiasi - Beberapa modifikasi pada hierarki avatar memiliki implikasi kinerja yang signifikan. Beberapa optimisasi tersedia:
- Untuk animasi prosedural khusus, jangan memperbarui properti JointInstance.C0 dan JointInstance.C1. Sebaliknya, perbarui properti Motor6D.Transform.
- Jika Anda perlu melampirkan objek BasePart ke avatar, lakukan di luar hierarki model avatar.
Skop MicroProfiler
| Skop | Perhitungan terkait |
| stepHumanoid | Kontrol humanoid dan fisika |
| stepAnimation | Animasi humanoid dan animator |
| updateInvalidatedFastClusters | Terkait dengan instansiasi atau memodifikasi avatar |
Rendering
Sebagian besar waktu yang dihabiskan klien setiap bingkai adalah untuk merender adegan dalam bingkai saat ini. Server tidak melakukan rendering, jadi bagian ini eksklusif untuk klien.
Panggilan gambar
Sebuah panggilan gambar adalah serangkaian instruksi dari mesin ke GPU untuk merender sesuatu. Panggilan gambar memiliki overhead yang signifikan. Umumnya, semakin sedikit panggilan gambar per bingkai, semakin sedikit waktu komputasi yang dihabiskan untuk merender satu bingkai.
Anda dapat melihat berapa banyak panggilan gambar yang saat ini terjadi dengan item Render Stats ⟩ Timing di Studio. Anda dapat melihat Render Stats di klien dengan menekan ShiftF2.
Semakin banyak objek yang perlu digambar di adegan Anda dalam satu bingkai, semakin banyak panggilan gambar yang dibuat ke GPU. Namun, Mesin Roblox memanfaatkan proses yang disebut instancing untuk menggabungkan mesh identik dengan karakteristik tekstur yang sama menjadi satu panggilan gambar. Secara spesifik, beberapa mesh dengan MeshContent yang sama ditangani dalam satu panggilan gambar ketika:
- SurfaceAppearances identik jika ada, jika tidak ketika TextureContents identik.
- Material identik ketika baik SurfaceAppearance dan MeshPart.TextureID tidak ada.
Masalah umum lainnya
Kepadatan objek yang berlebihan - Jika sejumlah besar objek terkonsentrasi dengan kepadatan tinggi, maka merender area ini di adegan memerlukan lebih banyak panggilan gambar. Jika Anda menemukan bahwa tingkat bingkai Anda menurun saat melihat bagian tertentu dari peta, ini bisa menjadi sinyal bahwa kepadatan objek di area ini terlalu tinggi.
Objek seperti decal, tekstur, dan partikel tidak melakukan pengelompokan dengan baik dan memperkenalkan panggilan gambar tambahan. Berikan perhatian ekstra pada jenis objek ini dalam suatu adegan. Secara khusus, perubahan properti pada ParticleEmitters dapat memiliki dampak dramatis pada kinerja.
Kesempatan instancing yang terlewat - Sering kali, suatu adegan akan menyertakan mesh yang sama yang dilipatgandakan beberapa kali, tetapi setiap salinan mesh memiliki ID aset mesh atau tekstur yang berbeda. Ini mencegah instancing dan dapat menyebabkan panggilan gambar yang tidak perlu.
Penyebab umum dari masalah ini adalah ketika seluruh adegan diimpor sekaligus, bukan aset individual yang diimpor ke Roblox dan kemudian digandakan setelah diimpor untuk merakit adegan.
Bahkan skrip sederhana seperti ini dapat membantu Anda mengidentifikasi bagian mesh dengan nama yang sama yang menggunakan ID mesh yang berbeda:
for _,descendant in workspace:GetDescendants() doif descendant:IsA("MeshPart") thenprint(descendant.Name .. ", " .. descendant.MeshId)endendKeluaran (dengan Stack Lines diaktifkan) mungkin terlihat seperti ini. Baris yang berulang menunjukkan penggunaan kembali mesh yang sama, yang baik. Baris yang unik tidak selalu buruk, tetapi tergantung pada skema penamaan Anda, bisa menunjukkan adanya mesh duplikat di permainan Anda:
LargeRock, rbxassetid://106420009602747 (x144) -- baikLargeRock, rbxassetid://120109824668127LargeRock, rbxassetid://134460273008628LargeRock, rbxassetid://139288987285823LargeRock, rbxassetid://71302144984955LargeRock, rbxassetid://90621205713698LargeRock, rbxassetid://113160939160788LargeRock, rbxassetid://135944592365226 -- semua kemungkinan duplikatKompleksitas objek yang berlebihan - Meskipun tidak sepenting jumlah panggilan gambar, jumlah segitiga dalam suatu adegan memengaruhi berapa lama waktu yang dibutuhkan untuk merender satu bingkai. Adegan dengan jumlah sangat besar dari mesh yang sangat kompleks adalah masalah umum, serta adegan dengan properti MeshPart.RenderFidelity diatur ke Precise pada terlalu banyak mesh.
Pembuatan bayangan berlebihan - Menangani bayangan adalah proses yang mahal, dan peta yang mengandung banyak objek cahaya dan part yang memancarkan bayangan (atau banyak bagian kecil yang dipengaruhi oleh bayangan) dapat mengalami masalah kinerja.
Overdraw transparansi tinggi yang tidak perlu - Menempatkan objek dengan transparansi parsial berdekatan memaksa mesin untuk merender piksel yang tumpang tindih beberapa kali, yang dapat merusak kinerja. Untuk informasi lebih lanjut tentang mengidentifikasi dan memperbaiki masalah ini, lihat Hapus transparansi berlapis.
Gerakan MeshPart berskinned yang tidak perlu - MeshParts berskinned yang merupakan bagian dari Model tanpa Humanoid dikelompokkan menggunakan FastClusters yang terorganisir secara spasial. Ketika MeshParts ini bergerak, mereka harus secara terus-menerus ditambahkan dan dihapus dari kluster spasial ini, memaksa kluster untuk dibangun kembali dan memengaruhi kinerja.
- Solusi yang sangat efektif adalah dengan menyematkan Humanoid di dalam Model. Kehadiran Humanoid akan menggantikan perilaku pengelompokan spasial default, memaksa penggunaan satu FastCluster yang disatukan untuk seluruh Model. Akibatnya, pembaruan posisi tidak lagi memerlukan pembangunan kembali kluster, sehingga mengurangi kendala kinerja. Teknik ini sebaiknya hanya diterapkan untuk MeshParts dengan gerakan yang diharapkan, karena mungkin memperkenalkan overhead memori dan mengabaikan manfaat optimalisasi spasial. Kami merekomendasikan untuk selalu memprofil permainan Anda setelah membuat perubahan jenis ini. Lihat tips kinerja humanoid untuk informasi tambahan.
Terlalu banyak bagian dalam Model - Terlalu banyak bagian dalam Model dapat menyebabkan pembangunan kembali lebih sering karena potensi bahwa properti bagian berubah yang memerlukan pembangunan ulang penuh. Temukan keseimbangan yang tepat dari bagian dalam sebuah Model ketika menggunakan FastCluster.
Mitigasi
Instancing mesh identik dan mengurangi jumlah mesh unik - Jika Anda memastikan semua mesh identik memiliki ID aset yang sama, mesin dapat mengenali dan merendernya dalam satu panggilan gambar. Pastikan untuk hanya mengupload setiap mesh di peta sekali dan kemudian menduplikasinya di Studio untuk digunakan kembali, daripada mengimpor peta besar sekaligus, yang mungkin menyebabkan mesh identik memiliki ID konten terpisah dan dianggap sebagai aset unik oleh mesin. Paket adalah mekanisme yang berguna untuk penggunaan ulang objek.
Penghapusan - Penghapusan menggambarkan proses menghilangkan panggilan gambar untuk objek yang tidak terlibat dalam bingkai yang dirender. Secara default, mesin melewati panggilan gambar untuk objek di luar bidang pandang kamera (frustum culling) dan bagian, mesh, serta medan yang terhalang dari pandangan oleh objek lain (occlusion culling). Dalam skenario tertentu, seperti lingkungan dalam ruangan, Anda mungkin dapat menerapkan sistem ruangan atau portal dan secara manual menghapus objek untuk lebih mengurangi panggilan gambar atau beban komputasi keseluruhan.
Mengurangi level detail untuk model - Aktifkan streaming instansi dan atur properti LevelOfDetail model dunia Anda ke SLIM untuk merender mesh SLIM yang ringan yang dioptimalkan untuk model seiring meningkatnya jarak dari kamera.
Mengurangi level detail untuk avatar - Aktifkan streaming instansi dan atur properti Workspace.EnableSLIMAvatars untuk merender model avatar platform dengan jumlah aksesori atau layer pakaian yang tak terbatas sebagai representasi avatar ringan yang dioptimalkan dengan dukungan penuh untuk animasi seiring meningkatnya jarak dari kamera.
Mengurangi fidelity rendering - Atur MeshPart.RenderFidelity ke Automatic atau Performance. Ini memungkinkan mesh untuk jatuh kembali ke alternatif yang kurang kompleks, yang dapat mengurangi jumlah poligon yang perlu digambar.
Nonaktifkan pembuatan bayangan pada bagian dan objek cahaya yang sesuai - Mesin Roblox secara otomatis menurunkan kualitas bayangan seiring tingkat kualitas grafis klien menurun, akhirnya menonaktifkan bayangan sama sekali pada tingkat kualitas di bawah 4. Namun, Anda dapat selectively menonaktifkan properti pembuatan bayangan pada objek cahaya dan bagian untuk meningkatkan kinerja saat bayangan diaktifkan dan meningkatkan kemungkinan bayangan tetap aktif. Beberapa contoh optimisasi yang dapat Anda lakukan baik pada waktu edit atau secara dinamis pada saat runtime:
Gunakan properti BasePart.CastShadow untuk menonaktifkan pembuatan bayangan pada bagian kecil di mana bayangan tidak mungkin terlihat. Strategi ini sangat efektif ketika diterapkan pada bagian yang jauh dari kamera pengguna.
Nonaktifkan bayangan pada objek bergerak bila memungkinkan.
Nonaktifkan Light.Shadows pada instansi cahaya di mana objek tidak perlu memancarkan bayangan.
Batasi jangkauan dan sudut instansi cahaya.
Gunakan lebih sedikit instansi cahaya.
Pertimbangkan untuk menonaktifkan lampu yang berada di luar jangkauan tertentu atau berdasarkan ruangan untuk lingkungan dalam.
Skop MicroProfiler
| Skop | Perhitungan terkait |
| Prepare and Perform | Rendering keseluruhan |
| Perform/Scene/computeLightingPerform | Pembaruan grid cahaya dan bayangan |
| LightGridCPU | Pembaruan grid cahaya voxel |
| ShadowMapSystem | Pemetaan bayangan |
| Perform/Scene/UpdateView | Persiapan untuk rendering dan pembaruan partikel |
| Perform/Scene/RenderView | Rendering dan pemrosesan pasca |
Jaringan dan replikasi
Jaringan dan replikasi menggambarkan proses di mana data dikirim antara server dan klien yang terhubung. Informasi dikirim antara klien dan server setiap bingkai, tetapi jumlah data yang lebih besar memerlukan waktu komputasi yang lebih banyak.
Masalah umum
Lalu lintas jarak jauh yang berlebihan - Mengirim sejumlah besar data melalui objek RemoteEvent atau RemoteFunction atau memanggilnya sangat sering dapat menyebabkan waktu CPU yang besar dihabiskan untuk memproses paket masuk setiap bingkai. Kesalahan umum meliputi:
- Mereplikasi data setiap bingkai yang tidak perlu direplikasi.
- Mereplikasi data pada input pengguna tanpa mekanisme untuk membatasi frekuensi.
- Mengirimkan lebih banyak data dari yang diperlukan. Sebagai contoh, mengirimkan seluruh inventaris pemain ketika mereka membeli sebuah item daripada hanya rincian item yang dibeli.
Pembuatan atau penghapusan pohon instansi yang kompleks - Ketika perubahan dilakukan pada model data di server, itu direplikasi ke klien yang terhubung. Ini berarti membuat dan menghancurkan hierarki instansi besar seperti peta pada waktu runtime dapat sangat berat di jaringan.
Penyebab umum di sini adalah data animasi kompleks yang disimpan oleh plugin Animation Editor dalam rig. Jika ini tidak dihapus sebelum permainan dipublikasikan dan model animasi dikeclone secara reguler, sejumlah besar data akan direplikasi tanpa perlu.
TweenService sisi server - Jika TweenService digunakan untuk tween objek di sisi server, properti yang di tween direplikasi ke setiap klien setiap bingkai. Ini tidak hanya mengakibatkan tween menjadi goyang saat latensi klien berfluktuasi, tetapi juga menyebabkan lalu lintas jaringan yang tidak perlu.
Mitigasi
Anda dapat menerapkan taktik berikut untuk mengurangi replikasi yang tidak perlu:
- Hindari mengirim sejumlah besar data sekaligus melalui acara jarak jauh. Sebaliknya, hanya kirim data yang diperlukan dengan frekuensi yang lebih rendah. Sebagai contoh, untuk status karakter, replikasi kapan saja berubah daripada setiap bingkai.
- Bagi pohon instansi yang kompleks seperti peta dan muat mereka dalam potongan untuk mendistribusikan pekerjaan mereplikasi ini di berbagai bingkai.
- Bersihkan metadata animasi, khususnya direktori animasi dari rig, setelah mengimpor.
- Batasi replikasi instansi yang tidak perlu, terutama dalam kasus di mana server tidak perlu mengetahui instansi yang sedang dibuat. Ini termasuk:
- Efek visual seperti ledakan atau ledakan mantra sihir. Server hanya perlu mengetahui lokasi untuk menentukan hasilnya, sementara klien dapat membuat visual secara lokal.
- Model tampilan item pandangan orang pertama.
- Tween objek di klien daripada di server.
Skop MicroProfiler
| Skop | Perhitungan terkait |
| ProcessPackets | Memproses paket jaringan yang masuk, seperti pemanggilan acara dan perubahan properti |
| Allocate Bandwidth and Run Senders | Acara keluar yang relevan pada server |
Penggunaan memori aset
Mekanisme berdampak tinggi yang tersedia untuk pembuat untuk meningkatkan penggunaan memori klien adalah dengan mengaktifkan streaming instansi.
Streaming instansi
Streaming instansi secara selektif memuat bagian model data yang tidak diperlukan, yang dapat menyebabkan waktu muat yang sangat berkurang dan meningkatkan kemampuan klien untuk mencegah kegagalan saat mengalami tekanan memori.
Jika Anda mengalami masalah memori dan streaming instansi dinonaktifkan, pertimbangkan untuk memperbarui permainan Anda untuk mendukungnya, terutama jika dunia 3D Anda besar. Streaming instansi didasarkan pada jarak dalam ruang 3D, jadi dunia yang lebih besar secara alami mendapatkan manfaat lebih dari itu.
Jika streaming instansi diaktifkan, Anda dapat meningkatkan agresivitasnya. Misalnya, pertimbangkan:
- Mengurangi penggunaan Enum.ModelStreamingMode.Persistent di mana memungkinkan. Anda mungkin perlu memperbarui skrip Anda jika Anda menggunakannya sebagai langkah kompatibilitas.
- Mengurangi Workspace.StreamingMinRadius dan Workspace.StreamingTargetRadius.
Untuk informasi lebih lanjut tentang opsi streaming dan manfaatnya, lihat streaming properties.
Masalah umum lainnya
Duplikasi aset - Kesalahan umum adalah mengupload aset yang sama beberapa kali yang mengakibatkan ID aset yang berbeda. Ini dapat menyebabkan konten yang sama dimuat ke memori beberapa kali.
Volume aset yang berlebihan - Bahkan jika aset tidak identik, ada kasus ketika peluang untuk menggunakan aset yang sama dan menghemat memori terlewat.
File audio - File audio bisa menjadi kontributor mengejutkan terhadap penggunaan memori, terutama jika Anda memuat semuanya di klien sekaligus daripada hanya memuat apa yang Anda butuhkan untuk sebagian permainan. Untuk strategi, lihat Waktu muat.
Tekstur resolusi tinggi - Konsumsi memori grafis untuk tekstur tidak terkait dengan ukuran tekstur di disk; jumlah piksel dalam tekstur menentukan penggunaan memori. Misalnya, tekstur 1024x1024 piksel menggunakan empat kali lipat memori grafis dari tekstur 512x512.
Gambar yang diupload ke Roblox ditranskode ke format tetap, jadi tidak ada keuntungan memori untuk mengupload gambar dalam model warna yang terkait dengan lebih sedikit byte per piksel. Demikian juga, mengompresi gambar sebelum diupload atau menghapus saluran alfa dari gambar yang tidak membutuhkannya dapat mengurangi ukuran gambar di disk, tetapi tidak meningkatkan penggunaan memori.
Saat sebuah permainan dimuat, mesin secara otomatis memulai dengan tekstur berkualitas rendah dan kemudian meningkatkan kualitas berdasarkan memori perangkat yang tersedia, jarak dari kamera, jumlah ruang layar yang diambil oleh tekstur, dan faktor lainnya. Meskipun demikian, secara strategis menentukan ukuran tekstur Anda dapat meningkatkan penggunaan memori dalam permainan Anda.
Mitigasi
Hanya upload aset sekali - Gunakan ID aset yang sama di seluruh objek dan pastikan aset yang sama, terutama mesh dan gambar, tidak diupload secara terpisah beberapa kali.
Temukan dan perbaiki aset duplikat - Cari bagian mesh dan tekstur yang identik yang diupload beberapa kali dengan ID yang berbeda.
- Meskipun tidak ada API untuk mendeteksi kesamaan aset secara otomatis, Anda dapat mengumpulkan semua ID aset gambar di tempat Anda (baik secara manual atau dengan skrip), mendownloadnya, dan membandingkannya menggunakan alat perbandingan eksternal.
- Untuk bagian mesh, strategi terbaik adalah mengambil ID mesh unik dan mengorganisirnya berdasarkan ukuran untuk mengidentifikasi duplikat secara manual.
- Alih-alih menggunakan tekstur terpisah untuk warna yang berbeda, unggah satu tekstur dan gunakan properti SurfaceAppearance.Color untuk menerapkan berbagai tint ke tekstur tersebut.
Impor aset dalam peta secara terpisah - Alih-alih mengimpor seluruh peta sekaligus, impor dan rekonstruksi aset dalam peta secara individu dan rekonstruksikan mereka. Pengimpor tidak melakukan de-duplikasi mesh, jadi jika Anda mengimpor peta besar dengan banyak ubin lantai yang terpisah, masing-masing dari ubin tersebut akan diimpor sebagai aset terpisah (meskipun mereka adalah duplikat). Ini dapat menyebabkan masalah kinerja dan memori di kemudian hari, karena setiap mesh dianggap terpisah dan mengambil memori serta panggilan gambar.
Batasi piksel gambar menjadi tidak lebih dari jumlah yang diperlukan. Kecuali gambar menempati banyak ruang fisik di layar, biasanya memerlukan paling banyak 512x512 piksel. Kebanyakan gambar minor harus lebih kecil dari 256x256 piksel.
Gunakan trim sheets untuk memastikan penggunaan tekstur maksimum yang dapat diulang dalam peta 3D. Untuk langkah-langkah dan contoh tentang cara membuat trim sheets, lihat Buat trim sheets.
Anda mungkin juga mempertimbangkan untuk menggunakan sprite sheets untuk memuat banyak gambar UI kecil sebagai satu gambar. Anda kemudian dapat menggunakan ImageLabel.ImageRectOffset dan ImageLabel.ImageRectSize untuk menampilkan bagian dari lembaran.
Waktu muat
Banyak permainan menerapkan layar pemuatan kustom dan menggunakan metode ContentProvider:PreloadAsync() untuk meminta aset agar gambar, suara, dan mesh diunduh di latar belakang.
Keuntungan dari pendekatan ini adalah bahwa ini memungkinkan Anda memastikan bagian penting dari permainan Anda sepenuhnya dimuat tanpa pop-in. Namun, kesalahan umum adalah memanfaatkan metode ini secara berlebihan untuk memuat lebih banyak aset daripada yang sebenarnya diperlukan.
Contoh praktik buruk adalah memuat seluruh Workspace. Meskipun ini mungkin mencegah pop-in tekstur, ini secara signifikan meningkatkan waktu muat.
Praktik serupa lainnya adalah memanfaatkan ContentProvider.RequestQueueSize untuk memastikan bahwa semua aset yang diminta telah selesai dimuat. Namun, ini menghadirkan masalah yang sama dari peningkatan waktu muat yang signifikan, sambil juga menjadi metode yang tidak dapat diandalkan karena sifatnya yang berfluktuasi.
Sebagai gantinya, hanya gunakan ContentProvider:PreloadAsync() dalam situasi yang diperlukan, yang mencakup:
- Gambar di layar pemuatan.
- Gambar penting di menu permainan Anda, seperti latar belakang tombol dan ikon.
- Aset penting di area awal atau pemunculan.
Jika Anda harus memuat sejumlah besar aset, kami merekomendasikan memberikan tombol Lewati Muat.