I Built Coroutines for My Game Engine, Then Didn't Use Them
ผมสร้างระบบ generator coroutine สำหรับ game engine ของผม มันมีโค้ดเพียง 122 บรรทัดและมี 12 tests มันช่วยแก้ปัญหา callback hell และทำให้สคริปต์ดูเหมือนการทำงานแบบเส้นตรง
จากนั้นผมตัดสินใจไม่ใช้มันสำหรับ game logic แต่เลือกใช้ Finite State Machine (FSM) แทน
และนี่คือเหตุผลครับ
บทเรียนส่วนใหญ่มักมองข้ามปัญหาใหญ่สองประการของการใช้ generator ในเกมแบบ real-time นั่นคือ เรื่องหน่วยความจำ (memory) และการบันทึกข้อมูล (saving)
- Memory Pressure
ทุกครั้งที่คุณเรียก
.next()บน generator ตัว JavaScript engine จะสร้าง object ใหม่ขึ้นมา ซึ่ง object นี้จะเก็บค่าปัจจุบันและสถานะเอาไว้
ใน game loop ที่รันด้วยความเร็ว 60 FPS สิ่งนี้จะสร้างภาระในการทำ garbage collection อย่างต่อเนื่อง engine ของผมใช้กฎ zero-allocation เพื่อรักษาประสิทธิภาพให้คงที่ แต่ generator กลับทำลายกฎนั้น เพราะมันสร้าง stream ของ object ขนาดเล็กขึ้นมาในทุกๆ เฟรม
- The Serialization Problem เกมจำเป็นต้องมีการเซฟและโหลด คุณต้องเปลี่ยนสถานะปัจจุบันของเกมให้กลายเป็นข้อมูล และเปลี่ยนข้อมูลนั้นกลับมาเป็นสถานะเดิม
คุณไม่สามารถทำ serialization กับ generator ที่หยุดพักอยู่ได้ เพราะสถานะของมันถูกเก็บไว้ใน internal engine slots ที่คุณไม่สามารถเข้าถึงได้ หากคุณพยายามจะเซฟ คุณจะได้ object ว่างเปล่าหรือเกิด error ขึ้น
Finite State Machine นั้นต่างออกไป เพราะสถานะเป็นเพียงแค่ string บน component เท่านั้น
- To save: เขียน string นั้นลงใน disk
- To load: อ่าน string นั้นแล้วสั่งให้ FSM เริ่มทำงานจากจุดนั้น
FSM ชนะไปเพราะมันจัดการกับสองสิ่งที่สำคัญที่สุดสำหรับเกมระดับมืออาชีพ นั่นคือ ประสิทธิภาพ (performance) และความคงทนของข้อมูล (persistence)
How to choose:
ตรรกะอยู่ใน main frame loop หรือไม่?
- No: ใช้ generator coroutine เหมาะมากสำหรับ flow ที่เกิดขึ้นครั้งเดียว เช่น การโหลด assets หรือการทำ onboarding
- Yes: ไปที่คำถามถัดไป
สถานะจำเป็นต้องคงอยู่หลังจากเซฟเกมหรือไม่?
- Yes: ใช้ Finite State Machine
- No: ไปที่คำถามถัดไป
คุณกำลังรันหลาย sequence พร้อมกันหรือไม่?
- Yes: ใช้ Finite State Machine
- No: ใช้ generator coroutine
Generator ไม่ใช่สิ่งที่ผิด แต่มันเป็นเครื่องมือที่ไม่เหมาะสำหรับ hot path จงใช้มันสำหรับงานเชื่อมต่อแบบ async แต่ใช้ FSM สำหรับ game logic ของคุณ
Source: https://dev.to/grzott/i-built-generator-coroutines-for-my-game-engine-then-didnt-use-them-o3g
