29 คะแนน โดย GN⁺ 2024-04-27 | 13 ความคิดเห็น | แชร์ทาง WhatsApp
  • ต่อข้ออ้างที่ว่าเมื่อคุ้นเคยกับ Rust แล้วปัญหาทุกอย่างจะหายไป
    • ถึงจะคุ้นกับ Rust มากขึ้น ปัญหาเชิงรากฐานก็ไม่ได้หายไป
    • เกมคือ state machine ที่ซับซ้อนและความต้องการเปลี่ยนตลอด จึงไม่เข้ากับธรรมชาติของ Rust ที่ตายตัวและตรวจสอบเข้มงวดเกินไป
    • ปัญหาที่ต้องรีแฟกเตอร์โค้ดอยู่ตลอดเป็นสิ่งที่สร้างขึ้นมาเอง
  • ปัญหาการรีแฟกเตอร์ครั้งใหญ่ที่เกิดจาก borrow checker
    • Rust บังคับให้ต้องรีแฟกเตอร์บ่อยกว่าภาษาอื่น
    • เมื่อความต้องการของเกมเปลี่ยนบ่อย ก็ต้องคอยสู้กับ borrow checker และจำเป็นต้องปรับโครงสร้างโค้ดใหม่
    • ยากจะเห็นด้วยกับข้ออ้างที่ว่าการรีแฟกเตอร์จะทำให้ได้โค้ดที่ดี เพราะโค้ดที่ดีเกิดจากการวนซ้ำไอเดียและลองผิดลองถูก
  • การทำให้มีชั้นอ้อม (Indirection) แก้ปัญหาได้แค่บางส่วนและทำให้ประสิทธิภาพการพัฒนาลดลง
    • หากใช้ indirection เพื่อแก้ปัญหา borrow checker ตรรกะของโค้ดจะถูกแยกออกและซับซ้อนขึ้น
    • ในเกมมีทั้งเหตุการณ์ที่เชื่อมโยงกัน จังหวะเวลาเฉพาะ และการจัดการสถานะจำนวนมาก ซึ่ง indirection ทำให้สิ่งเหล่านี้ยากขึ้น
    • ใน Rust แม้แต่โค้ดง่าย ๆ ก็ต้องเขียนยืดยาวเพื่อรองรับ indirection
  • ECS(Entity-Component-System) กำลังแก้ปัญหาผิดจุด
    • ข้อดีของ ECS ที่แท้จริงคือข้อดีของ generational arena
    • มอง ECS ได้จากหลายมุม เช่น dynamic composition, structure of arrays, วิธีแก้ปัญหา Rust borrow checker, dynamically created generational arenas
    • แต่ก็ยังน่าสงสัยว่า ECS คือวิธีที่เหมาะสมที่สุดสำหรับการพัฒนาเกมหรือไม่ เพราะควรใส่ใจกับตรรกะของเกมมากกว่าประสิทธิภาพหรือ composition
  • ระบบแบบทำให้เป็นทั่วไป (Generalized systems) ไม่ได้นำไปสู่เกมเพลย์ที่สนุก
    • หากใช้ระบบที่ทั่วไปเกินไป เกมเพลย์ที่ได้มักน่าเบื่อ
    • เกมที่ดีต้องออกแบบปฏิสัมพันธ์เชิงรายละเอียดอย่างระมัดระวัง ซิงก์ VFX ทำ playtest และทดลองซ้ำ ๆ รวมถึงปล่อยให้เร็วเพื่อรับฟีดแบ็ก
    • Rust ยึดถือคุณค่าที่ไม่เหมาะกับการทำต้นแบบอย่างรวดเร็วและการวนซ้ำ (iteration)
  • สิ่งสำคัญของการพัฒนาเกมคือการทำต้นแบบและวนซ้ำอย่างรวดเร็ว แต่คุณค่าของ Rust กลับอยู่คนละด้าน
    • แก่นของการพัฒนาเกมคือเกมและประสบการณ์การเล่น ไม่ใช่โค้ดที่ไม่มีวันแครช
    • ความสามารถในการบำรุงรักษาโค้ดเกมไม่ใช่คุณค่าที่สำคัญมากนักสำหรับเกมอินดี้ สิ่งสำคัญคือความเร็วในการวนซ้ำ (iteration speed)
    • Rust หมกมุ่นกับการหลีกเลี่ยงปัญหาจนพลาดสิ่งที่สำคัญกว่า
  • Procedural macros ยังห่างไกลจาก reflection มาก
    • ในการพัฒนาเกมต้องเขียนโค้ดหลายด้าน ทั้งโค้ดระบบ โค้ดเกมเพลย์ UI VFX เสียง และเครื่องมือ
    • ใน Rust แม้แต่การ "แสดงผลออบเจ็กต์" แบบง่าย ๆ ก็ต้องเขียนโค้ดเองหรือสร้าง procedural macros
    • Procedural macros มีข้อจำกัดมากกว่า declarative macros มาก และยังใช้เวลาคอมไพล์นานกว่า
    • Reflection ของ C# ใช้งานง่ายมาก และช่วยให้พัฒนาได้เร็วเมื่อประสิทธิภาพไม่ใช่ประเด็นสำคัญ
  • Hot reloading มีบทบาทสำคัญต่อการเพิ่มความเร็วในการวนซ้ำ
    • Hot reloading มีประโยชน์มากกับ immediate mode UI/การวาดภาพ การดีบัก และการปรับจูนค่าคงที่ของเกมเพลย์
    • Rust ก็มี hot-lib-reloader แต่ยังไม่สมบูรณ์ และต้องอาศัยการวางแผนกับการมองล่วงหน้า จึงจำกัดการใช้งานเชิงสร้างสรรค์
    • นักพัฒนาเกมต้องการ tooling ที่อยู่ในระดับสูงกว่าการรีโหลด struct แบบธรรมดา
  • Abstraction ไม่ใช่ทางเลือก แต่เป็นสิ่งจำเป็น
    • ตัวอย่างจริง) หากต้องให้ทำงานต่างกันตามสถานะของ UI ใน Rust อาจต้องรีแฟกเตอร์หรือไม่ก็ clone อย่างหนัก
    • หลายครั้งไม่ได้เปลี่ยน business logic แต่เปลี่ยนโค้ดเพื่อทำให้คอมไพเลอร์พอใจ
    • Rust ไม่มีระบบชนิดแบบโครงสร้าง เช่น "ชนิดที่มีฟิลด์เหล่านี้" จึงต้องแก้โค้ดหลายจุดเวลารีแฟกเตอร์
  • สถานการณ์ GUI ของ Rust แย่มาก
    • สิ่งสำคัญในเกม UI ไม่ใช่ data binding หรือ reactive update แต่คือการปรับแต่งรูปลักษณ์
    • สิ่งที่เกม UI ต้องการคือ GUI ที่สวยงาม สไปรต์ที่ปรับแต่งได้ แอนิเมชัน vector shape อนุภาค เอฟเฟกต์ และแฟลช
    • ตอนนี้ยังไม่มีไลบรารี Rust ที่ออกแบบมาเฉพาะสำหรับเกม GUI
  • Orphan rule ควรเป็นตัวเลือกที่ปิดได้
    • Orphan rule ลดประสิทธิภาพการพัฒนาอย่างมากเพื่อแลกกับความปลอดภัย
    • ในโค้ดแอปพลิเคชันที่ไม่ใช่ไลบรารี ควรสามารถปิด orphan rule ได้
  • เวลาคอมไพล์ดีขึ้นแล้ว แต่ถ้าใช้ proc macros ก็ยังช้าอยู่
    • Proc macros อย่าง serde ทำให้เวลาคอมไพล์เพิ่มขึ้นมาก
    • หาก incremental build ใช้เวลาเกิน 20-30 วินาที จะปรับจูนรายละเอียดได้ยากมาก
  • ระบบนิเวศการพัฒนาเกมด้วย Rust ให้ความรู้สึกว่าถูกโหมเกินจริง
    • คนที่กำลังทำเกมจริง ๆ มีไม่มาก
    • หลายโปรเจกต์ที่หน้าเว็บหรือ README ดูโดดเด่นและมีชื่อเสียง แท้จริงแล้วอาจไม่เป็นเช่นนั้น
    • ถ้าอยากทำเกมจริง แนะนำ godot-rust อย่ายึดติดกับโซลูชัน Rust ล้วน ๆ และควรอาศัยเอนจินที่โตเต็มที่แล้ว
  • เกมเป็น single-threaded ดังนั้นเหตุผลที่บอกว่าสถานะ global ไม่สะดวกจึงไม่ถูกต้อง
    • การใช้สถานะ global ใน Rust ทำได้ลำบากมาก (static mut, AtomicRefCell, Rc เป็นต้น)
    • แต่ต่างจากบริการแบ็กเอนด์ เกมส่วนใหญ่เป็น single-threaded ทั้งหมด จึงไม่จำเป็นต้องมีความลำบากแบบนี้
    • มองว่าการที่ Bevy นำระบบขนานเข้ามาเป็นความผิดพลาด แม้ทำเพื่อประสิทธิภาพ แต่กลับเพิ่มความไม่สะดวก เช่น ผู้ใช้ต้องคอยระบุลำดับเองตลอด
  • Dynamic borrow checking ทำให้เกิดแครชที่คาดไม่ถึงหลังการรีแฟกเตอร์
    • จากการใช้ hecs มา 2 ปี พบกรณีที่ query ซ้อนทับกันจนเกิดแครชอยู่บ่อย
    • แม้ใช้ RefCell หากมี .borrow_mut() จากสองจุดก็เกิดแครชแบบไม่คาดคิดได้
    • ปัญหาไม่ใช่ว่าโค้ดแย่ แต่เป็นเพราะ Rust บังคับให้ต้องรีแฟกเตอร์โดยไม่จำเป็น
    • RefCell มีประโยชน์ในเกม แต่ Rust ทำให้ใช้งานมันได้ยากเกินไป
  • ความยืดหยุ่นของออบเจ็กต์ Context ยังไม่พอ
    • เพราะใช้สถานะ global ได้ยาก ใน Rust จึงนิยมรวม reference ไว้ในออบเจ็กต์ context แล้วส่งต่อ
    • แต่ถ้ายืมใช้เพียงบางฟิลด์ ก็อาจเกิด compile error จาก partial borrow
    • แม้จะบอกให้แยก Context และเปลี่ยนโครงสร้าง แต่สิ่งที่อยากทำจริง ๆ คือ logic ของเกม การต้องเปลี่ยนโครงสร้างเพื่อเอาใจคอมไพเลอร์จึงเป็นการเสียเวลา

ข้อดีของ Rust

  • ถ้าคอมไพล์ผ่านแล้ว โดยทั่วไปก็มักทำงานได้ดี โดยเฉพาะกับเครื่องมือ CLI การประมวลผลข้อมูล และการเขียนอัลกอริทึม
  • ให้ประสิทธิภาพที่ดีได้โดยแทบไม่ต้องออกแรงมาก มีประสบการณ์ว่าเร็วกว่า C# ราว 1.5~2.5 เท่า
  • Enum ถูกออกแบบมาได้ดี
  • ด้วย Rust analyzer ทำให้ประสบการณ์ใช้งาน IDE ดีขึ้นมาก
  • ระบบ Trait ทำมาได้ดีมาก ถ้าผ่อนคลาย orphan rule ลงสักหน่อยจะใช้งานได้กว้างกว่านี้มาก

ความเห็นของ GN⁺

  • แม้ความเห็นต่อ Rust จะค่อนข้างเป็นลบโดยรวม แต่เมื่อเป็นข้อสรุปที่ผู้เขียนได้จากการลองมาหลายทาง ก็น่าจะต้องรับฟังอย่างจริงจัง โดยเฉพาะประเด็นที่ว่าความเป็นจริงเชิงปฏิบัติและความเร็วในการพัฒนาสำคัญเพียงใดในโดเมนการพัฒนาเกม และ Rust ยังขาดในด้านนั้นอยู่มากพอสมควร

  • เห็นด้วยว่าความปลอดภัยที่ Rust มุ่งเน้น บางครั้งอาจลดประสิทธิภาพการพัฒนาอย่างรุนแรง เวลาลงมือเขียน Rust มักมีหลายกรณีที่ต้องใช้เวลาไปกับการทำให้คอมไพเลอร์พอใจมากกว่าการพัฒนาตรรกะจริง ๆ ซึ่งดูจะมาจากธรรมชาติที่ Rust เป็นภาษาซึ่งเชี่ยวชาญด้าน system programming โดยพื้นฐาน

  • ในทางกลับกัน การพัฒนาเกมส่วนใหญ่เกิดในสภาพแวดล้อมแบบ single-threaded และให้ความสำคัญกับการทำต้นแบบและการวนซ้ำอย่างรวดเร็ว ดังนั้นการตรวจความปลอดภัยที่เข้มเกินไปอาจกลับกลายเป็นโทษ โดยเฉพาะเคยได้ยินบ่อยถึงประสบการณ์ที่หลายคนพยายามทำเกมด้วย Rust ในช่วงแรกแล้วไปไม่รอด ดูเหมือนว่าปัญหาเชิงรากฐานเหล่านั้นก็ยังไม่ได้รับการแก้ไขมากนัก

  • แน่นอนว่าเอนจินเกมยุคใหม่อย่าง Bevy ช่วยให้การพัฒนาเกมด้วย Rust สะดวกขึ้นบ้าง แต่ก็ยังห่างไกลจากระดับของเอนจินที่โตเต็มที่อย่าง Unity หรือ Godot มาก ดังที่บทความนี้ชี้ให้เห็น การใช้ Rust ควบคู่กับเอนจินที่มีอยู่แล้วอาจเป็นทางเลือกที่สมจริงกว่าการสร้างทุกอย่างขึ้นมาแบบ Rust ล้วน

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

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

13 ความคิดเห็น

 
coremaker 2024-04-29

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

มันไม่ได้เหมาะกับการพัฒนาให้เสร็จอย่างรวดเร็ว แต่เหมาะกับการพัฒนาให้ถูกต้องแม่นยำมากกว่า
ดังนั้นจึงไม่ค่อยเหมาะกับโปรเจกต์ที่มีคำขอเพิ่มเติมจากผู้ใช้เกิดขึ้นบ่อยและต้องนำไปทำจริง

ถึงอย่างนั้นก็ตาม ที่ยังคาดหวังให้มี UI library ออกมา
ก็น่าจะเป็นเพราะความรู้สึกคาดหวังว่า ถ้ามีเพียง UI เล็ก ๆ ที่เรียบง่ายซึ่งทำงานอยู่บนโค้ดที่แข็งแกร่ง ก็จะทำให้สามารถนำไปใช้ประโยชน์ได้ดีขึ้นมาก

 
kandk 2024-04-29

ผมไม่เคยทำเกมมาก่อนเลยไม่ค่อยรู้เท่าไร แต่ดูเหมือนว่า
อาจเลือกภาษาไม่เหมาะตั้งแต่แรก หรือถ้าการพัฒนาแบบวนรอบรวดเร็วสำคัญก็ควรเลือกภาษาระดับสคริปต์..
หรือไม่ก็อาจยังไม่มีความเข้าใจเชิงลึกเกี่ยวกับระบบมากพอ
ต่อให้เลือก C++ ก็คงเจอปัญหาคล้าย ๆ กันอยู่ดีครับ

 
cosine20 2024-04-29

ใช่แล้ว ถ้าเลือก C++ ก็ยังมีตัวเลือกอย่าง Unreal อยู่เหมือนกัน...

 
cosine20 2024-04-29

ทุกวันนี้ผมเริ่มรู้สึกว่า ภาษาระดับเนทีฟอย่าง Rust หรือ C++ ดูจะเหมาะกับการพัฒนามิดเดิลแวร์อย่างเกมเอนจิน มากกว่าการพัฒนาเกมไคลเอนต์เสียอีก
ก็เหมือนกับที่แทบไม่มีกรณีของการทำฟูลสแตกเว็บด้วยภาษาระดับเนทีฟนั่นแหละครับ

 
kandk 2024-04-29

มันเป็นภาษาที่ถูกสร้างมาสำหรับจุดประสงค์แบบนั้นตั้งแต่แรกอยู่แล้ว เพื่อมาแทนที่ C++
ดูเหมือนว่าบทความจะกลายเป็นบทความวิจารณ์ตัวภาษาไปเสียแล้ว

 
cosine20 2024-04-29

ใช่ครับ เดิมทีเริ่มต้นขึ้นมาเพื่อปรับปรุงเอนจินภายในของ Firefox ใช่ไหมครับ?
เนื้อหาให้ความรู้สึกประมาณว่าไปลองพัฒนาด้วย Rust ในสายงานที่ไม่ค่อยเข้ากับมันนักแบบยาครอบจักรวาล แล้วก็เลยลำบากอยู่พอสมควร ฮ่าๆ

 
mammal 2024-04-29

เห็นด้วย 100% ครับ สำหรับเกมลอจิก ภาษาโปรแกรมที่มีประสิทธิภาพในการพัฒนาสูงดูจะเหมาะกับกรณีการใช้งานมากกว่า

 
edunga1 2024-04-28

ฉันเพิ่งอยู่ในช่วงเริ่มต้นใช้ Rust เลยรู้สึกอินพอสมควรครับ
พอมีการเปลี่ยนแปลงเรื่อง borrowing ก็ต้องแก้โค้ดเยอะมากจนทรมานเลยครับ
ต่างจาก python หรือ javascript ที่มีการแสดงออกแบบแฝงอยู่เยอะ Rust มีแนวโน้มจะเขียนแบบชัดเจน จนบางทีกลายเป็นโค้ดที่ยืดยาว และยังทำให้โปรแกรมเมอร์ต้องตัดสินใจหลายอย่างจนรู้สึกเหนื่อยด้วยครับ
ถึงอย่างนั้น แนวคิดที่ภาษาอื่นไม่มีใน Rust ก็ยังสดใหม่และสนุกมากครับ

ถ้าไม่มี Rust Analyzer หรือ GitHub Copilot ผมคงถอดใจไปตั้งแต่แรกแล้วครับ

 
botplaysdice 2024-04-28

สมกับที่ว่าการพัฒนาเกมเป็นงานฮาร์ดคอร์จริงๆ...

 
steamb23 2024-04-28

แทนที่จะเขียนทุกอย่างตั้งแต่แกนหลักไปจนถึงฟรอนต์ด้วย Rust
ถ้าเขียนแกนหลักด้วย Rust แล้วผสานใช้ภาษาที่มีประสิทธิภาพในการพัฒนาสูงกว่า เหมือน Unity หรือเกมเอนจินอื่น ๆ จะเป็นอย่างไร?

 
bus710 2024-04-28

ก็คงช่วยไม่ได้ เพราะมันมีด้านที่บังคับกรอบค่อนข้างมากอยู่แล้ว

 
[ความคิดเห็นนี้ถูกซ่อน]
 
GN⁺ 2024-04-27
ความคิดเห็นจาก Hacker News

แชร์ประสบการณ์พัฒนาไคลเอนต์เมตาเวิร์สพร้อมชี้ให้เห็นปัญหาของ Rust

  • แทบไม่มีกรณีตัวอย่างของการพัฒนาเกม 3D ขนาดใหญ่ด้วย Rust
  • การรีแฟกเตอร์และการเชื่อมส่วนต่างๆ ของโปรแกรมเข้าด้วยกันเป็นเรื่องที่ทรมาน
  • ระบบเรนเดอร์เกือบจะใช้ได้เหมาะสม แต่สแตกยังไม่สมบูรณ์และเชื่อถือไม่ได้
  • ระบบ GUI 2D ยังอ่อน และต้องใช้โค้ดมากเกินไปต่อ dialog box หนึ่งอัน
  • เห็นด้วยกับปัญหาที่ระบบ async แผ่ขยายไปยังขอบเขตที่ไม่จำเป็น

ในฐานะนักพัฒนาเกมที่มีประสบการณ์ 20 ปี มองว่า Rust ไม่เหมาะกับการพัฒนาเกม

  • โค้ดเกมเพลย์ต้องยืดหยุ่น และต้องมี edge case มากมายเพื่อสร้างเกมที่น่าสนใจ
  • เวลา compile มีความสำคัญ และจำเป็นต้องเปลี่ยนโครงสร้างบ่อย
  • ECS มีประโยชน์กับบางระบบ แต่ใช้งานกับโค้ดเกมเพลย์หรือ UI ได้ยาก

ระบบนิเวศการพัฒนาเกมด้วย Rust กำลังพึ่งพากระแส hype มากเกินไป

  • เคยลองพัฒนาเกมด้วย Rust แต่เจอประสบการณ์ที่แย่มากทันที
  • เวลา compile ที่ช้า, การดาวน์โหลดแพ็กเกจขนาดใหญ่, และความยากของตัว Rust เอง เป็นต้น
  • แม้จะมีการอ้างว่าเครื่องมืออื่นไม่ปลอดภัยเท่า Rust แต่ในเกม ปัญหา memory safety แทบไม่เคยเป็นปัญหาใหญ่

เปรียบเทียบประสบการณ์พัฒนาเกมด้วย Bevy, Unity และ Godot

  • ตอนนี้ยากจะเข้าใจว่าทำไมถึงเลือก Rust สำหรับพัฒนาเกม
  • การยัดทุกอย่างลงใน ECS กลับขัดขวางการพัฒนาเกมเพลย์ที่สนุก
  • เมื่อพิจารณาประสิทธิภาพของพีซีสมัยใหม่ ก็ไม่จำเป็นต้องกังวลกับการ optimize แบบ multi-threading มากเกินไป

ภาษา Nim อาจเหมาะกับการพัฒนาเกมมากกว่า Rust

  • ไม่คอยขัดขวางนักพัฒนาและรองรับ hot reloading

Rust ดูเป็นภาษาที่เคร่งและบังคับวิธีเขียนโปรแกรมแบบเฉพาะทาง

  • ให้ความสำคัญกับ memory safety เหนือสิ่งอื่นใด แต่ในการพัฒนาเกมมันไม่ได้มีประโยชน์มากนัก
  • ภาษาที่เหมาะกับการพัฒนาเกมควรมี productivity สูง ประสิทธิภาพเหมาะสม และเหมาะสำหรับโปรแกรมเมอร์ฝีมือดีที่กล้ารับความเสี่ยง

เดโม tooling ของ Allen Blomquist แสดงให้เห็นว่า feedback loop ในการพัฒนาสำคัญมาก

  • Rust ไม่สามารถให้สภาพแวดล้อมการทำงานที่ต้องการได้ จึงกลับไปใช้ Unity อีกครั้ง

ปัญหาพื้นฐานของ Rust คือการละทิ้ง object-oriented และโน้มเอียงไปทาง functional programming

  • อาจช่วยได้ในคอร์ระดับล่างสุด แต่ไม่เหมาะกับระดับบน

สำหรับการพัฒนาเกม Rust คือหนึ่งในตัวเลือกที่แย่ที่สุด

  • คุณค่าของ Rust ที่มุ่งหาความถูกต้อง ความปลอดภัย และโค้ดที่สมบูรณ์แบบ ไม่สอดคล้องกับการพัฒนาเกม
  • เกมมีอายุสั้นและรอบการพัฒนาก็สั้น คุณภาพโค้ดจึงไม่ใช่สิ่งสำคัญมากนัก
  • อาจมีประโยชน์กับการพัฒนา game engine แต่ควรใช้ร่วมกับ scripting language ที่ยืดหยุ่นสูง

ระหว่างเขียนโค้ดด้วยภาษา D พบว่าการเปลี่ยน data layout ทำได้ง่ายกว่า C มาก

  • การสลับระหว่าง reference type กับ value type ทำได้ยากใน C แต่ทำได้ง่ายใน D