ข้อผิดพลาดทั่วไปเมื่อเขียนเกมด้วยภาษาที่มีการจัดการเช่น C # คืออะไร [ปิด]


66

คุณพบข้อผิดพลาดอะไรบ้างเมื่อเขียนเกมสำหรับพีซีด้วยภาษาที่มีการจัดการเช่น C # และคุณแก้ปัญหาได้อย่างไร


คำถามนี้ถูกถามที่ดีกว่าใน Stack Overflow เนื่องจากมีเพียงเล็กน้อยเกี่ยวกับคำถามเฉพาะสำหรับเกม
Chris Garrett

31
@Chris: ไม่เห็นด้วยอย่างยิ่ง: คำถามที่กล่าวถึงเกมโดยเฉพาะ! ปัญหาที่คุณพบเมื่อต้องผลักดันการอัปเดตทุก ๆ 16ms นั้นแตกต่างจากสิ่งที่คุณได้รับในแอปพลิเคชันเดสก์ท็อปส่วนใหญ่
Andrew Russell

คำถามไม่ชัดเจน Java และ C # ต่างกันมากพอสำหรับคำแนะนำทั่วไปที่ใช้ได้กับทั้งคู่เท่านั้น คำตอบทั้งหมดจนถึงตอนนี้คือ C # นอกจากนี้แพลตฟอร์มเป้าหมายไม่ได้กล่าวถึง - คำแนะนำที่ดีอาจแตกต่างกันไปขึ้นอยู่กับอุปกรณ์ (เช่นการเขียนโปรแกรมสำหรับโทรศัพท์มือถือ, zune, xbox, แตกต่างจากการเขียนโปรแกรมสำหรับพีซี) มันเป็นคำถามที่กว้างพอที่ใครบางคนตอบว่าภาษาที่จัดการเองนั้นเป็น
paulecoyote

@paulecoyote: ฉันเปลี่ยนเป็นคำถามที่ถามเฉพาะเกี่ยวกับ C # นอกจากนี้เนื่องจากไม่มีแพลตฟอร์มเฉพาะที่กล่าวถึงเป็นเรื่องเกี่ยวกับพีซี
Michael Klement

@Michael สมมติว่าแพลตฟอร์มเป็นข้อสันนิษฐานที่อันตรายเนื่องจากมีความแตกต่างกันมากในการนำไปใช้งานจะเป็นการดีที่จะกล่าวถึง Windows โดยเฉพาะและวาง "like" และ "Java" ไว้ด้วยกัน
paulecoyote

คำตอบ:


69

ฉันไม่รู้เกี่ยวกับจาวามากนักดังนั้นนี่มาจากมุมมองของ. dev สุทธิ

ที่ใหญ่ที่สุดคือขยะ ตัวรวบรวมขยะ. net บน windows ทำหน้าที่ได้อย่างยอดเยี่ยมและคุณสามารถออกไปได้โดยไม่ต้องให้ลูกนั่งเป็นส่วนใหญ่ บน xbox / winPhone7 นั่นเป็นเรื่องที่แตกต่าง หากคุณได้รับแผงลอยทุก ๆ สองสามครั้งการรวบรวมขยะอาจทำให้คุณมีปัญหา ในขณะนี้มันจะเริ่มทำงานหลังจากการจัดสรร 1mb ทุกครั้ง

นี่คือเคล็ดลับในการจัดการกับขยะ คุณไม่ต้องกังวลเกี่ยวกับสิ่งเหล่านี้ในความเป็นจริง แต่พวกเขาอาจมีประโยชน์ในหนึ่งวัน

  • วาดเนื้อหาของGC.GetTotalMemory()ไปยังหน้าจอ สิ่งนี้จะช่วยให้คุณประมาณจำนวนไบต์ที่จัดสรรเกมของคุณใช้ ถ้ามันแทบจะไม่เคลื่อนไหวคุณก็โอเค หากเกิดขึ้นเร็วคุณมีปัญหา
  • พยายามจัดสรรวัตถุฮีปทั้งหมดของคุณล่วงหน้า หากคุณไม่จัดสรรทุกอย่างก่อนที่เกมจะเริ่มขึ้นทุกครั้งที่คุณมีการจัดสรรจำนวนมาก ไม่มีการจัดสรรไม่มีการรวบรวม ง่ายเหมือนที่
  • หลังจากโหลดแล้วให้เรียก GC.Collect () หากคุณรู้ว่าการจัดสรรขนาดใหญ่ส่วนใหญ่ของคุณเป็นไปอย่างไม่น่าเชื่อก็เป็นเรื่องดีที่จะให้ระบบทราบ
  • อย่าโทรGC.Collect()ทุกเฟรม มันอาจเป็นความคิดที่ดีโดยเฉพาะอย่างยิ่งการเก็บขยะและสิ่งอื่น ๆ แต่อย่าลืมว่าสิ่งที่แย่กว่าการเก็บขยะก็คือการเก็บขยะ
  • มองหาที่ขยะของคุณมาจากไหน มีสาเหตุบางอย่างที่พบบ่อยเช่นการต่อสตริงแทนที่จะใช้StringBuilder(ระวังStringBuilderไม่ใช่ bullet เวทมนตร์และยังสามารถทำให้เกิดการจัดสรร!ซึ่งหมายถึงการดำเนินการอย่างง่ายเช่นการเพิ่มตัวเลขไปยังจุดสิ้นสุดของสตริงสามารถสร้างขยะที่น่าประหลาดใจ) หรือ การใช้foreachลูปมากกว่าคอลเลกชันที่ใช้IEnumerableอินเทอร์เฟซยังสามารถสร้างขยะโดยที่คุณไม่รู้ตัว (เช่นforeach (EffectPass pass in effect.CurrentTechnique.Passes)เป็นเรื่องธรรมดา)
  • ใช้เครื่องมือเช่นตัวสร้างโปรไฟล์หน่วยความจำ CLRเพื่อหาตำแหน่งที่จะจัดสรรหน่วยความจำ มีบทเรียนมากมายเกี่ยวกับวิธีใช้เครื่องมือนี้
  • เมื่อคุณทราบว่าการจัดสรรของคุณในระหว่างการเล่นเกมดูว่าคุณสามารถใช้เทคนิคเช่นการรวมวัตถุเพื่อลดจำนวนการจัดสรรนั้น
  • หากสิ่งอื่นล้มเหลวทำให้คอลเล็กชันของคุณทำงานได้เร็วขึ้น! GC ในเฟรมเวิร์กขนาดกะทัดรัดติดตามทุกการอ้างอิงในรหัสของคุณเพื่อหาว่าวัตถุใดไม่ได้ใช้งานอีกต่อไป Refactor รหัสของคุณใช้การอ้างอิงน้อยลง!
  • จำไว้ว่าให้ใช้IDisposableกับคลาสที่มีทรัพยากรที่ไม่มีการจัดการ คุณสามารถใช้สิ่งเหล่านี้เพื่อล้างหน่วยความจำที่ GC ไม่สามารถทำให้ตัวเองว่างเปล่าได้

อีกอย่างที่ต้องคิดคือประสิทธิภาพของจุดลอย ในขณะที่. Net JITer ทำจำนวนการปรับแต่งเฉพาะโปรเซสเซอร์ให้เหมาะสม แต่ก็ไม่สามารถใช้ SSE หรือชุดคำสั่ง SIMD อื่น ๆ เพื่อเพิ่มความเร็วในการคำนวณเลขทศนิยมของคุณ นี่อาจทำให้ความเร็วแตกต่างกันค่อนข้างมากระหว่าง C ++ และ C # สำหรับเกม หากคุณใช้โมโนพวกเขามีไลบรารี่คณิตศาสตร์ SIMD พิเศษที่คุณสามารถใช้ประโยชน์ได้


เห็นด้วยอย่างสมบูรณ์ การใช้งานตัวรวบรวมขยะบนแพลตฟอร์ม "น้อยกว่า" ดูเหมือนว่าจะเป็นขยะที่สมบูรณ์
Krisc

โพสต์ที่ดีอย่างไรก็ตามสำหรับคำสั่งของคุณเกี่ยวกับ "การจัดสรรวัตถุฮีปล่วงหน้า" ฉันขอแนะนำให้อ่านความจริงเกี่ยวกับประเภทค่า
Justin

จุดที่ดีเมื่อคุณปรับโค้ดให้เหมาะสมควรเข้าใจแพลตฟอร์มที่คุณพยายามปรับให้เหมาะสม นั่นไม่ใช่ความคิดเห็นเกี่ยวกับประเภทค่า / ประเภทการอ้างอิงวัตถุที่มีอายุการใช้งานยาวนานไม่น่าจะอยู่ในสแต็ก มันเกี่ยวกับการทำให้แน่ใจว่าคุณได้รับการจัดสรรมากที่สุดเท่าที่ทำได้ในขณะโหลดมากที่สุดเท่าที่จะเป็นไปได้ การติดตั้ง. net ทั้งหมดที่ xna กำหนดเป้าหมายนอกจากนี้ยังมีการรับประกันที่เรียบร้อยวัตถุที่จัดสรรไว้ใกล้เคียงกันในเวลาจะถูกปิดลงในพื้นที่ซึ่งอาจเป็นสิ่งที่ดีสำหรับความสมบูรณ์แบบ
Cubed2D

ดูเหมือนว่าฉันลืมที่จะพูดถึงว่ากรอบกะทัดรัดในปัจจุบันบน xbox จะแพ้การเรียกวิธีการแบบอินไลน์ เก็บสิ่งนั้นไว้ในสถานการณ์ที่เลวร้ายที่สุดของคุณ แต่การใช้วิธีการทางคณิตศาสตร์ในรุ่น ref ดูน่าเกลียดพอเหมือนเดิม!
Cubed2D

10

ข้อผิดพลาดของประสิทธิภาพในการทำงานนั้นไม่ได้พิจารณาถึงตัวรวบรวมขยะในการออกแบบ / พัฒนาเกม การผลิตขยะมากเกินไปสามารถนำไปสู่ ​​"hiccups" ในเกมซึ่งเกิดขึ้นเมื่อ GC ทำงานเป็นเวลานาน

สำหรับ C # การใช้วัตถุที่มีค่าและคำสั่ง "การใช้" สามารถบรรเทาความกดดันจาก GC


3
นอกจากนี้คุณสามารถบอกให้ Garbage Collector ทำงานอย่างชัดเจนหากคุณเพิ่งเสร็จสิ้นการจัดสรร / ปล่อยลูปอย่างหนักหรือถ้าคุณพบว่าคุณมีรอบว่าง
BarrettJ

16
usingคำสั่งมีอะไรจะทำอย่างไรกับการเก็บขยะ! สำหรับIDisposableวัตถุ - ซึ่งมีไว้สำหรับปล่อยทรัพยากรที่ไม่มีการจัดการ (เช่น: สิ่งที่ไม่ได้รับการจัดการโดยตัวรวบรวมขยะ )
Andrew Russell

9

ฉันจะบอกว่าปัญหาที่ใหญ่ที่สุดที่ฉันพบการเขียนเกมใน C # คือการขาดห้องสมุดที่เหมาะสม ส่วนใหญ่ฉันพบว่าเป็นพอร์ตโดยตรง แต่ไม่สมบูรณ์หรือล้อมรอบห้องสมุด C ++ ที่ต้องเสียค่าปรับหนักสำหรับ marshaling (ฉันกำลังพูดเฉพาะเกี่ยวกับ MOgre และ Axiom สำหรับห้องสมุด OGRE และ BulletSharp สำหรับห้องสมุดฟิสิกส์ Bullet)

ภาษาที่มีการจัดการ (แตกต่างจากการตีความ - Java และ C # จะไม่ถูกตีความอีกต่อไป) สามารถเร็วเท่ากับภาษาท้องถิ่นหากคุณมีความเข้าใจอย่างถ่องแท้เกี่ยวกับสิ่งที่ทำให้พวกเขาช้า (การจัดเก็บขยะ) ฉันคิดว่าปัญหาที่แท้จริงคือผู้พัฒนาห้องสมุดยังไม่เข้าใจ


นั่นเป็นจุดที่ดีเกี่ยวกับ C # และ Java ถูกจัดการแทนการตีความ ... แก้ไขคำถามของฉันจะทำให้มันถูกต้องมากขึ้น :)
ไมเคิล Klement

2
มาร์แชลโดยทั่วไปเป็นคอขวดของประสิทธิภาพการทำงาน แต่มันก็ช่วยให้ระวังประเภท blittable - ประเภทที่สามารถแมปโดยตรงกับหน่วยความจำที่ไม่มีการจัดการโดยไม่มีผลกระทบต่อประสิทธิภาพที่สำคัญ msdn.microsoft.com/en-us/library/75dwhxf7.aspx
Sean Edwards


4

C # และ Java ไม่ถูกตีความ พวกเขาจะถูกรวบรวมเป็นไบต์กลางซึ่งหลังจากJITกลายเป็นเร็วเป็นรหัสพื้นเมือง (หรือใกล้พอที่จะไม่มีนัยสำคัญ)

ข้อผิดพลาดที่ใหญ่ที่สุดที่ฉันพบคือการปลดปล่อยทรัพยากรที่ส่งผลกระทบโดยตรงต่อประสบการณ์ของผู้ใช้ ภาษาเหล่านี้ไม่รองรับการกำหนดขั้นสุดท้ายแบบอัตโนมัติเช่น C ++ แต่ถ้าคุณไม่คาดหวังว่ามันจะนำไปสู่สิ่งต่าง ๆ เช่นตาข่ายที่ลอยอยู่รอบ ๆ ฉากหลังจากที่คุณคิดว่ามันถูกทำลาย (C # บรรลุการกำหนดค่าขั้นสุดท้ายผ่านIDisposableฉันไม่แน่ใจว่า Java ทำอะไร)

นอกเหนือจากนั้นภาษาที่ได้รับการจัดการนั้นมีความสามารถในการจัดการประสิทธิภาพที่เกมต้องการมากกว่าที่ได้รับเครดิต โค้ดที่มีการจัดการที่เขียนดีนั้นเร็วกว่าโค้ดเนทีฟที่เขียนไม่ดีมาก


ใช่ขอบคุณสำหรับบันทึกย่อได้แก้ไขสิ่งที่ตีความ / จัดการแล้ว) จุดที่ดีกับตาข่ายที่ลอยอยู่รอบ ๆ ฉาก ไม่ได้คิดอย่างนั้นเมื่อคิดถึงปัญหา GC ...
Michael Klement

1
IDisposableอนุญาตการล้างค่าที่กำหนดเวลาล่วงหน้าของทรัพยากรที่สำคัญและไม่มีการจัดการ แต่ไม่ส่งผลกระทบโดยตรงต่อการสรุปหรือตัวรวบรวมขยะ
Sam Harwell

4

ไม่มีการตีความ Java หรือ C # ทั้งคู่ได้รับการคอมไพล์เป็นรหัสเครื่องดั้งเดิม

ปัญหาที่ใหญ่ที่สุดของพวกเขาและเกมคือการเขียนโค้ดในแบบที่พวกเขาไม่เคยเก็บขยะในระหว่างการเล่นเกม จำนวนของห่วงที่คุณต้องข้ามไปให้สำเร็จนั้นเกือบจะเกินดุลประโยชน์ของการใช้พวกมันตั้งแต่แรก ฟีเจอร์ส่วนใหญ่ที่ทำให้ภาษาสนุกสำหรับการใช้งานแอพพลิเคชั่นหรือการเขียนโปรแกรมเซิร์ฟเวอร์ต้องหลีกเลี่ยงการเขียนโปรแกรมเกมมิฉะนั้นคุณจะหยุดเล่นนานในระหว่างการเล่นเกมขณะที่พวกเขาออกไปและเก็บขยะ


การรวบรวมขยะสามารถจัดการได้อย่างน้อยก็ใน C # ดีพอสมควรดังนั้นฉันจะไม่พูดว่ามันเป็นตัวจัดการที่ดี ด้วยเธรดที่เหมาะสมและการรับรู้สถานะโปรแกรมคุณสามารถหลีกเลี่ยงปัญหาประสิทธิภาพการทำงาน ยังคงเป็นอีกสิ่งที่คุณต้องคิดและทำให้ภาษาที่มีการจัดการมีการจัดการน้อยลงเล็กน้อย
Karantza

4
เป็นที่น่าสังเกตว่าใน. NET 4 ตัวรวบรวมข้อมูลขยะสนับสนุนการรวบรวมพื้นหลังสำหรับวัตถุทั้งสามรุ่น สิ่งนี้ควรลดผลกระทบด้านประสิทธิภาพของการรวบรวมขยะในเกมอย่างมีประสิทธิภาพ ลิงค์ที่เกี่ยวข้อง: geekswithblogs.net/sdorman/archive/2008/11/07/…
Mike Strobel

นักสะสมขยะกำลังพัฒนาและตามที่ระบุไว้โดย Mike Strobel มีบางส่วนที่อยู่ในการผลิตซึ่งเกือบกำจัดหลุมฝังศพนี้
Sam Harwell

2
ทั้ง C # และ Java ไม่ได้รับการคอมไพล์ไปยังรหัสเครื่องดั้งเดิม C # รวบรวม MSIL และ Java เป็น bytecode การรวบรวมขยะจะไม่หยุดชั่วคราว "นาน" แต่อาจให้ "hiccups"
Cloudanger

2

ข้อผิดพลาดที่ใหญ่อย่างหนึ่งที่ฉันเห็นจากการทำเกมด้วยภาษาเช่นนี้ (หรือใช้เครื่องมือเช่น XNA, TorqueX engine ฯลฯ ) คือคุณจะต้องเจอกับทีมคนดีที่มีความเชี่ยวชาญที่จำเป็นในการสร้างเกมที่เทียบเท่า จะค่อนข้างง่ายต่อการค้นหาผู้คนใน C ++ และ OpenGL / DirectX

อุตสาหกรรมเกม dev ยังคงเป็นที่แพร่หลายอย่างมากใน C ++ เนื่องจากเครื่องมือและท่อส่วนใหญ่ที่ใช้ในการผลักดันเกมเล็ก ๆ ที่มีขนาดใหญ่หรือขัดเงาถูกเขียนขึ้นใน C ++ และเท่าที่ฉันรู้ชุด dev ทางการทั้งหมดที่คุณสามารถ รับสำหรับ XBox, PS3 และ Wii เปิดตัวเฉพาะกับความเข้ากันได้กับ C ++ (ชุดเครื่องมือ XBox อาจมีการจัดการมากขึ้นในปัจจุบันทุกคนรู้เพิ่มเติมหรือไม่)

หากคุณต้องการพัฒนาเกมสำหรับคอนโซลตอนนี้คุณจะได้ XNA และ C # บน XBox และจากนั้นจะอยู่ในส่วนของไลบรารีเกมที่เรียกว่า XBox Live Indie Games ผู้ที่ชนะการแข่งขันและอื่น ๆ ได้รับเลือกให้เข้าเกมเพื่อ XBox Live Arcade ที่แท้จริง นอกเหนือจากแผนการสร้างเกมสำหรับพีซี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.