ใช้ async สำหรับสร้างฉาก now loading

ก่อนอื่นเกริ่นก่อนว่า ผมมีคลาสที่ชื่อว่า Scene สำหรับแต่ละฉากในหนึ่งเกม (ไม่รวมฉากย่อย ๆ อันนั้นต้องจัดการเอาเอง) โดยแต่ละฉากในเกมก็จะเป็นคลาสย่อยของคลาสนี้ และแต่ละฉากจะต้องรับหน้าที่สร้างฉากต่อไปหลังจากที่มันทำงานเสร็จแล้ว (ถูกเรียกผ่าน Scene::NextScene())

ทีนี้ ปัญหาคือ ถ้าเราให้ Scene::NextScene() โหลดฉากใหม่ขึ้นมา โปรเซสจะหยุดทำงานจนกว่าฉากนั้นจะโหลดเสร็จ ซึ่งอาจจะกินเวลานานมาก ๆ เราจึงต้องมีกลไกรองรับการโหลดรีซอร์สในอีกเธรดหนึ่งในขณะที่เธรดหลักจะยังวาดอะไรสักอย่างบนจอเพื่อบอกว่า “กำลังโหลดไฟล์อยู่ รอเดี๋ยว” อยู่ ผมก็เลยสร้างคลาสชื่อว่า LoaderScene ขึ้นมา (โค๊ดอยู่ข้างท้าย)

คลาสนี้เองก็เป็นคลาสที่สืบทอดมาจาก Scene อีกต่อหนึ่ง ตัวมันเองไม่ได้ทำอะไรมากมาย แค่เรียกใช้ฟังก์ชั่น std::async ภายใน std::async ผมก็สั่งให้มันสร้างวัตถุใหม่ออกมาในอีกเธรดหนึ่ง ตัว LoaderScene จะถูกแสดงผลบนจอจนกระทั่ง std::async ทำงานเสร็จ และมันจะบอกตัวโปรแกรมหลักที่เรียกมันว่ามันทำงานเสร็จเรีบร้อยแล้ว เพื่อให้โปรแกรมหลักเอาวัตถุใหม่ที่สร้างเสร็จแล้วไปใช้นั่นเอง

คลาสนี้จะไม่วาดอะไรบนจอ (แค่แสดงผลเป็นจอดำ ๆ) ถ้าเราต้องการให้มันแสดงผลอะไรสักอย่าง ก็สร้างคลาสย่อยขึ้นมาอีกอันนึง โดยระบุให้มันวาดอะไรสักอย่างบนจอ แค่นั้นเองไม่ยากใช่ไหมครับ 🙂

สำหรับโค๊ดเต็ม ๆ นั้นก็อยู่ข้างล่างนี่ล่ะครับ

#ifndef GAME_LOADERSCENE_H
#define GAME_LOADERSCENE_H

#include <future>
#include "./Scene.h"

namespace pgengine {

template <class S> class LoaderScene : public Scene {
public:
  LoaderScene() {
    future = std::async(std::launch::async, []() { return new S; });
  }

  virtual bool IsCompleted() {
    if (!future.valid())
      return false;
    auto status = future.wait_for(std::chrono::milliseconds(10));

    return status == std::future_status::ready;
  }

  Scene *NextScene() { return future.get(); }

private:
  std::future<S *> future;
};
}
#endif // LOADERSCENE_H

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องข้อมูลจำเป็นถูกทำเครื่องหมาย *

This site uses Akismet to reduce spam. Learn how your comment data is processed.