CHƯƠNG IV. SCENE VÀ SCENEMANAGE

Link Source code HD không che: https://goo.gl/umSsHA 
Các bạn nên mở sources code vừa đọc vừa so sánh với tut này vì mình sẽ giải thích những gì trong sources code.

1. Sơ lược về Scene

  • Ở tut trước là về Sprite và đặt ra câu hỏi làm sao để vẽ được nhiều Sprite lên và quản lý nó một cách trơn chu, có thể tương tác với bàn phím, chuột và xử lý đến va chạm,…thì Scene sẽ giúp ta xử lý những việc này tốt hơn.
  • Scene có thể hiểu là 1 cảnh hay 1 màn trong game. Một game sẽ tập hợp nhiều scene lại như scene về điểm cao, scene chọn người chơi, scene chơi game,… hình dưới đây là 2 scene: Menu và scene play game.




2. Scene

  • Mình thêm class Scene vào folder GameConponents và SceneManager vào folder GameControllers, việc phân chia folder này giúp cho chúng ta dễ dàng quản lý các class hơn. Các bạn vừa mở source code vừa đọc vì mình sẽ giải thích các thuộc tính và hàm quan trọng dưới đây. Phần Input mình sẽ nói thêm ở phần sau

  • Scene là một abstract class và sử dụng Design Pattern là Abstract Factory. Scene chỉ dùng cho kế thừa nên hàm khởi tạo sẽ có scope là protected.

  • Thuộc tính:
    • D3DCOLOR mBackColor: màu nền của Scene, khi Clear surface sẽ dùng màu của scene hiện tại để Clear. Mình sẽ thay đổi tham số truyền vào ở class Game (file Game.cpp) ở đoạn clear của device.

  • Hàm:
    • virtual void LoadContent(): hàm này dùng để khởi tạo các biến của Scene. Khi bạn tạo Scene mới kế thừa Scene thì nên gọi hàm này trong hàm khởi tạo.

    • virtual void Update(float dt): hàm update được gọi trong lúc update của class Game (được gọi trong vòng lặp game). Tham số truyền vào là khoảng thời gian gọi giữa 2 frame được tính bằng giây. Chính là cái biến delta trong vòng lặp của class Game, sử dụng cho việc tính vận tốc của vật, đếm thời gian (VD: như cứ 1s thì sinh quái vật lúc này sẽ dùng 1 biến khác cộng dồn biến dt này lại đến khi nào được 1s thì sẽ gọi hàm).

    • virtual void Draw(): hàm vẽ những Sprite sẽ được vẽ trong này bằng cách gọi hàm Draw của sprite trong này. Hàm này sẽ được gọi sau mỗi lần update scene.


    • virtual void OnKeyUp(int keyCode): giống như hàm OnKeyDown nhưng được gọi khi có phím được nhả ra.
    • virtual void OnMouseDown(float x, float y): gọi khi có sự kiện chuột được nhấn xuống. 
    • D3DCOLOR GetBackcolor(): Lấy màu nền của Scene để sử dụng cho việc Clear màu.

3. SceneManager

  • SceneManager sẽ có nhiệm vụ quản lý Scene hiện tại và chuyển đổi các Scene. Là 1 class Singleton nên hàm Constructor sẽ có scope là private.

  • Thuộc tính:
    • static SceneManager *mInstace: vì là class Singleton nên sẽ có 1 instance dạng static để nắm giữ thông tin xuyên suốt game loop.
    • Scene *mCurrentScene: Scene hiện tại đang được update và vẽ lên màn hình.

  • Hàm:
    • static SceneManager *GetInstance(): lấy Instance của SceneManager, thì instance này sẽ tồn tại từ đầu cho đến cuối game loop.
    • Scene* GetCurrentScene(): hàm return Scene hiện tại.
    • void Update(float dt): hàm update này sẽ được gọi liên tục với tần xuất phụ thuộc vào FPS của game (60 FPS thì 1 giây gọi 60 lần). trong hàm này sẽ gọi hàm update của Scene hiện tại và update những thông tin ngoài scene nếu có.
    • void ReplaceScene(Scene *scene): Thay thế Scene hiện tại bằng 1 Scene khác. Trước khi thay thế sẽ xóa đi scene cũ để trách tình trạng leak memory.

 4. Tạo 1 Scene

  • Mình tạo 1 Scene tên là DemoScene và nhét nó vào folder Scenes, folder này sẽ chứa các Scene của game. Vì là 1 Scene nên nó sẽ kế thừa class Scene, các bạn nhớ include đầy đủ class vào mới kế thừa được (Có thể xem source của DemoScene).

  • Mình sẽ override lại các hàm cần thiết đó là:
    • void LoadContent(): hàm này như mình nói ở trên sẽ được gọi lúc khởi tạo Scene để khởi tạo các biến, mình có tạo 1 vector các Sprite và 1 biến mTimeCounter được sử dụng để tính toán thời gian thay đổi tọa độ của sprite.

    • void Update(float dt): hàm kế thừa từ Scene, mình đã giải thích ở trên, hàm này mình sẽ cộng dồn thời gian của biến đếm mTimeCounter và khi được 1 giây mình sẽ thay đổi tọa độ của các Sprite.

    • void Draw(): hàm vẽ được gọi sau mỗi lần update, hàm Draw() của các Sprite sẽ được gọi ở đây.

    • Có 2 biến là: vector chứa các Sprite và biến mTimeCounter mình đã giải thích công dụng ở trên. Nội dung các hàm mình có viết comment rất rõ ràng trong source code các bạn xem trong đó để tham khảo thêm.

  • Chỉnh sửa class Game
    • Sau khi tạo Scene, SceneManager chỉ phải gọi chúng trong vòng lặp game, và như ở tut các tut trước thì vòng lặp game được mình cài đặt trong class Game và giờ chúng ta sẽ gọi hàm cần thiết trong class Game này.Mình sẽ xóa hết Sprite trong class Game đã tạo ra ở tut trước vì Sprite bây giờ chúng ta sẽ vẽ ở Scene, class Game này chỉ thực hiện vẽ và update toàn bộ Scene.

    • Hàm Constructor: chúng ta sẽ tạo 1 Scene mới bằng cách gọi hàm ReplaceScene, nếu Scene không được khởi tạo thì sẽ bị crash và không có Scene nào được vẽ lên. SceneManager::GetInstance()->ReplaceScene(new DemoScene()); . Mình tạo mới DemoScene đã tạo ở bên trên.

    • Hàm Render: Mình sẽ tạo con trỏ nắm giữ Scene hiện tại để lấy màu backcolor của Scene dùng cho việc Clear Surface bằng màu của backcolor này. Và mình sẽ gọi hàm Draw của scene này lên. (các bạn xem thêm trong source code nhé).


auto scene = SceneManager::GetInstance()->GetCurrentScene();
device->Clear(0, NULL, D3DCLEAR_TARGET, scene->GetBackcolor(), 0.0f, 0);
…..
scene->Draw();


Hàm Update(float dt): hàm này mình sẽ gọi hàm update của Scene hiện tại.
SceneManager::GetInstance()->GetCurrentScene()->Update(dt)

  Tổng kết

Việc tạo Scene và SceneManager sẽ giúp ta dễ quản lý và chia nhỏ các khung cảnh của game hơn. Các Sprite sẽ được quản lý update và vẽ trong các Scene giúp ta kiểm soát được bộ nhớ tốt hơn, và việc tạo Scene đã được đơn giản hóa nhờ việc kế thừa class Scene (cái này gọi là Abstract Factory trong Design Pattern). Mỗi lần muốn tạo ra một màn game mới thì bạn chỉ việc tạo class và cho nó kế thừa class Scene và override lại các hàm nào cần thiết.
Share on Google Plus

About Lộc Thọ

This is a short description in the author block about the author. You edit it by entering text in the "Biographical Info" field in the user admin panel.
    Blogger Comment
    Facebook Comment

0 Comment:

Post a Comment