Apa tipikal jebakan saat menulis game dengan Bahasa yang dikelola seperti C #? [Tutup]


66

Perangkap apa yang Anda temui ketika menulis game untuk PC dengan Bahasa yang dikelola seperti C # dan bagaimana Anda mengatasinya?


Pertanyaan ini lebih baik ditanyakan pada Stack Overflow, karena ada sedikit tentang hal itu yang khusus untuk game.
Chris Garrett

31
@ Chris: Sangat tidak setuju: Pertanyaannya secara spesifik menyebutkan game! Masalah yang Anda hadapi ketika Anda harus mendorong pembaruan setiap 16ms sangat berbeda dengan apa yang Anda dapatkan di sebagian besar aplikasi desktop.
Andrew Russell

Pertanyaannya cukup tidak jelas. Java dan C # cukup berbeda karena hanya saran yang sangat umum yang berlaku untuk keduanya. Semua jawaban sejauh ini adalah C #. Juga platform target yang tidak disebutkan - saran yang baik mungkin berbeda tergantung pada perangkat (mis pemrograman untuk ponsel, zune, xbox, berbeda dari pemrograman untuk pc). Bahkan telah menjadi pertanyaan yang cukup luas bahwa seseorang telah menjawab bahwa bahasa yang dikelola sendiri adalah "perangkap".
paulecoyote

@paulecoyote: Saya berubah ke pertanyaan hanya bertanya tentang C #. Juga, karena tidak ada platform spesifik yang disebutkan, ini tentang PC.
Michael Klement

@Michael mengasumsikan platform adalah asumsi berbahaya karena mereka sangat berbeda dalam implementasi, akan lebih baik untuk menyebutkan Windows secara khusus dan drop "like" dan "Java" sama sekali.
paulecoyote

Jawaban:


69

Saya tidak tahu banyak tentang Java, jadi ini dari sudut pandang pengembang .net.

Yang terbesar sejauh ini adalah sampah. Pengumpul sampah .NET di Windows melakukan pekerjaan yang fantastis, dan Anda dapat pergi tanpa bayi yang paling sering melakukannya. Di Xbox / Windows Phone 7 itu masalah yang berbeda. Jika Anda mendapatkan kios setiap beberapa bingkai, pengumpulan sampah mungkin menyebabkan masalah bagi Anda. Saat ini ia memicu setelah setiap alokasi 1MB.

Berikut ini beberapa kiat untuk menangani sampah. Anda seharusnya tidak perlu khawatir tentang sebagian besar dari ini dalam kenyataan, tetapi mereka mungkin berguna suatu hari.

  • Gambarkan konten GC.GetTotalMemory()ke layar. Ini memberi Anda perkiraan jumlah byte yang dialokasikan yang digunakan game Anda. Jika sulit bergerak, Anda baik-baik saja. Jika naik cepat, Anda memiliki masalah.
  • Cobalah untuk mengalokasikan semua objek tumpukan Anda di muka. Jika Anda tidak mengalokasikan semuanya sebelum game dimulai, setiap kali Anda menekan satu jatah alokasi, Anda akan mandek. Tidak ada alokasi, tidak ada koleksi. Sesimpel itu.
  • Setelah memuat, hubungi GC.Collect(). Jika Anda tahu sebagian besar alokasi besar Anda tidak ada, itu bagus untuk membiarkan sistem mengetahuinya.
  • JANGAN PANGGIL GC.Collect()setiap frame. Ini mungkin tampak seperti ide yang bagus, menjaga di atas sampah Anda dan semua itu, tapi ingat satu-satunya yang lebih buruk daripada pengumpulan sampah adalah pengumpulan sampah.
  • Cari dari mana sampah Anda berasal. Ada beberapa penyebab umum seperti merangkai string daripada menggunakan StringBuilder(waspadalah, StringBuilderbukan peluru ajaib, dan masih dapat menyebabkan alokasi! Ini berarti operasi sederhana seperti menambahkan nomor ke ujung string dapat membuat jumlah sampah yang mengejutkan) atau menggunakan foreachloop atas koleksi yang menggunakan IEnumerableantarmuka juga dapat membuat sampah tanpa Anda sadari (misalnya, foreach (EffectPass pass in effect.CurrentTechnique.Passes)adalah yang umum)
  • Gunakan alat seperti profiler memori CLR untuk mencari tahu di mana memori dialokasikan. Ada banyak tutorial di luar sana tentang cara menggunakan alat ini.
  • Ketika Anda tahu di mana alokasi Anda selama bermain game, lihat apakah Anda dapat menggunakan trik seperti mengumpulkan objek untuk menurunkan jumlah alokasi itu.
  • Jika semuanya gagal, buat koleksi Anda berjalan lebih cepat! GC pada kerangka kompak mengikuti setiap referensi dalam kode Anda untuk mengetahui objek apa yang tidak digunakan lagi. Perbaiki kode Anda menggunakan lebih sedikit referensi!
  • Ingatlah untuk menggunakan IDisposablekelas yang berisi sumber daya yang tidak dikelola. Anda dapat menggunakan ini untuk membersihkan memori GC tidak dapat membebaskan dirinya sendiri.

Hal lain yang perlu dipikirkan adalah kinerja floating point. Meskipun .NET JITer melakukan cukup banyak optimasi khusus prosesor, ia tidak dapat menggunakan SSE atau set instruksi SIMD lainnya untuk mempercepat matematika floating point Anda. Ini dapat menyebabkan perbedaan kecepatan yang cukup besar antara C ++ dan C # untuk game. Jika Anda menggunakan mono, mereka memiliki beberapa perpustakaan matematika SIMD khusus yang dapat Anda manfaatkan.


Setuju sepenuhnya. Implementasi pengumpul sampah di platform "lebih rendah" tampaknya menjadi sampah lengkap.
Krisc

Posting yang bagus, namun sehubungan dengan pernyataan Anda tentang "mengalokasikan objek tumpukan di depan" Saya sarankan membaca The Truth About Value Types
Justin

Poin bagus di sana, ketika Anda mengoptimalkan kode, sangat layak untuk memahami platform yang ingin Anda optimalkan. Bukankah itu benar-benar komentar tentang tipe nilai / tipe referensi, objek yang berumur panjang tidak mungkin berada di tumpukan. Ini benar-benar memastikan Anda mendapatkan sebanyak mungkin alokasi Anda dilakukan pada waktu buka mungkin Anda tidak mencapai penghalang 1MB ajaib selama bermain game. Semua implementasi .net yang target xna juga memiliki jaminan rapi, objek yang dialokasikan berdekatan dalam waktu akan dekat dalam ruang, yang bisa bagus untuk perf.
Cubed2D

Juga sepertinya saya lupa menyebutkan bahwa kerangka kerja kompak saat ini di xbox alergi terhadap panggilan metode inlineing. Tetap satu itu untuk skenario perf case terburuk Anda, menggunakan versi ref dari metode matematika terlihat cukup jelek seperti itu!
Cubed2D

10

Jebakan kinerja tipical tidak mempertimbangkan pengumpul sampah dalam desain / pengembangan game. Memproduksi terlalu banyak sampah dapat menyebabkan "cegukan" dalam permainan, yang terjadi ketika GC berjalan untuk waktu yang cukup lama.

Untuk C #, menggunakan objek nilai dan pernyataan "menggunakan" dapat mengurangi tekanan dari GC.


3
Selain itu, Anda dapat memberi tahu Pengumpul Sampah untuk menjalankannya secara eksplisit jika Anda baru saja menyelesaikan pengalokasian / loop berat gratis atau jika Anda merasa memiliki siklus cadangan.
BarrettJ

16
The usingpernyataan tidak ada hubungannya dengan pengumpulan sampah! Ini untuk IDisposableobjek - yang untuk melepaskan sumber daya yang tidak dikelola (yaitu: yang tidak ditangani oleh pemulung ).
Andrew Russell

9

Saya akan mengatakan masalah terbesar yang saya temui dalam menulis game di C # adalah kurangnya perpustakaan yang layak. Sebagian besar yang saya temukan adalah port langsung, tetapi tidak lengkap, atau dibungkus dengan pustaka C ++ yang menghasilkan penalti performa yang berat untuk marshaling. (Saya berbicara secara khusus tentang MOgre dan Axiom untuk perpustakaan OGRE, dan BulletSharp untuk perpustakaan fisika Bullet)

Bahasa yang dikelola (berbeda dari yang Diartikan - baik Java maupun C # tidak benar-benar ditafsirkan lagi) dapat secepat bahasa asli jika Anda memiliki pemahaman yang baik tentang apa yang sebenarnya membuatnya lambat (mengelompokkan, mengumpulkan sampah). Masalah sebenarnya, saya pikir, adalah pengembang perpustakaan belum menyadarinya.


Itu poin bagus tentang C # dan Java dikelola alih-alih ditafsirkan ... diedit pertanyaan saya untuk membuatnya lebih akurat :)
Michael Klement

2
Marshalling secara umum adalah hambatan kinerja, tetapi juga membantu untuk menyadari jenis yang mudah terbakar - jenis yang dapat dipetakan langsung ke memori yang tidak dikelola tanpa dampak kinerja yang signifikan. msdn.microsoft.com/en-us/library/75dwhxf7.aspx
Sean Edwards

8

Seperti yang dikatakan orang lain, jeda pengumpulan GC adalah masalah terbesar. Menggunakan kolam objek adalah salah satu solusi khas.


4

C # dan Java tidak diartikan. Mereka dikompilasi ke bytecode menengah yang, setelah JIT , menjadi secepat kode asli (atau cukup dekat untuk menjadi tidak signifikan)

Jebakan terbesar yang saya temukan adalah membebaskan sumber daya yang secara langsung memengaruhi pengalaman pengguna. Bahasa-bahasa ini tidak secara otomatis mendukung finalisasi deterministik seperti yang dilakukan C ++, yang jika Anda tidak mengharapkannya dapat menyebabkan hal-hal seperti jerat melayang di tempat kejadian setelah Anda berpikir mereka dihancurkan. (C # menyelesaikan finalisasi deterministik melalui IDisposable , saya tidak yakin apa yang dilakukan Java.)

Selain itu, bahasa yang dikelola benar-benar jauh lebih mampu menangani jenis kinerja yang dibutuhkan game daripada yang mereka dapatkan. Kode yang dikelola dengan baik jauh lebih cepat daripada kode asli yang ditulis dengan buruk.


Ya, terima kasih atas catatannya, sudah mengoreksi hal yang ditafsirkan / dikelola;) Juga, poin yang bagus dengan jerat melayang di tempat kejadian. Tidak memikirkan hal itu ketika memikirkan masalah GC ...
Michael Klement

1
IDisposablememungkinkan pembersihan deterministik dari sumber daya waktu-kritis dan tidak dikelola, tetapi tidak secara langsung mempengaruhi finalisasi atau pengumpul sampah.
Sam Harwell

4

Baik Java maupun C # tidak ditafsirkan. Keduanya dikompilasi ke dalam kode mesin asli.

Masalah terbesar dengan mereka berdua dan permainan adalah harus kode sedemikian rupa sehingga mereka tidak pernah mengumpulkan sampah selama bermain game. Jumlah lingkaran yang harus Anda lewati untuk mencapai yang hampir melebihi manfaat dari menggunakannya di tempat pertama. Sebagian besar fitur yang membuat bahasa tersebut menyenangkan untuk digunakan untuk aplikasi atau pemrograman server harus dihindari untuk pemrograman game, jika tidak Anda akan mendapat jeda lama selama bermain game saat mereka pergi dan mengumpulkan sampah.


Pengumpulan sampah dapat ditangani, setidaknya dalam C #, cukup baik, jadi saya tidak akan mengatakan bahwa itu adalah pemecah kesepakatan. Dengan threading yang benar dan kesadaran akan status program, Anda dapat menghindari masalah kinerja. Ini masih hal lain yang harus Anda pikirkan, dan itu membuat bahasa yang dikelola sedikit kurang terkelola.
Karantza

4
Perlu dicatat bahwa dalam. NET 4, pengumpul sampah mendukung pengumpulan latar belakang untuk ketiga generasi objek. Ini harus secara efektif meminimalkan dampak kinerja pengumpulan sampah di game. Tautan yang Relevan: geekswithblogs.net/sdorman/archive/2008/11/07/…
Mike Strobel

Pengumpul sampah sedang berevolusi, dan seperti dicatat oleh Mike Strobel, beberapa sudah dalam produksi yang hampir menghilangkan jebakan ini.
Sam Harwell

2
Baik C # maupun Java tidak dikompilasi ke kode mesin asli. C # mengkompilasi ke MSIL dan Java untuk bytecode. Pengumpulan sampah tidak akan memberikan jeda "lama", tetapi mungkin memberikan "cegukan".
Cloudanger

2

Satu perangkap besar yang saya lihat dari membuat game dengan bahasa seperti ini (atau menggunakan alat seperti XNA, mesin TorqueX, dll.) Adalah bahwa Anda akan kesulitan menemukan tim orang-orang baik dengan keahlian yang dibutuhkan untuk membuat game yang setara dengan apa akan cukup mudah untuk menemukan orang-orang di C ++ dan OpenGL / DirectX.

Industri game dev masih sangat mendalami C ++ karena sebagian besar alat dan jalur pipa yang digunakan untuk mendorong game kecil besar atau terpoles dengan baik ditulis dalam C ++, dan sejauh yang saya tahu SEMUA kit dev resmi yang Anda bisa dapatkan untuk XBox, PS3, dan Wii dirilis hanya dengan kompatibilitas untuk C ++ (XBox toolset mungkin lebih dikelola saat ini, ada yang tahu lebih banyak?)

Jika Anda ingin mengembangkan gim untuk konsol saat ini, Anda cukup banyak mendapatkan XNA dan C # di XBox dan kemudian hanya di bagian samping perpustakaan gim yang disebut XBox Live Indie Games. Beberapa yang memenangkan kontes dll. Dipilih untuk memport game mereka ke XBox Live Arcade asli. Selain itu berencana membuat game untuk PC.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.