CHƯƠNG V. ANIMATION

Link Source code HD không che: https://goo.gl/LqNyPh 
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ề Animation

  • Animation là một quá trình tạo ra các ảo giác về chuyển động hay thay đổi trạng thái thông qua diễn xuất ở tốc độ cao một chuỗi các hình ảnh tĩnh, trong đó với mỗi hình ảnh lại có một sự thay đổi rất nhỏ so với hình ảnh trước đó. 

  • Trong game animation là không thể thiếu như việc chuyển động của những viên gạch, các trạng thái chạy, nhảy của mario, hiệu ứng bay của những viên đạn,…

  • Bình thường trong game mình có biết 2 loại animation đó là animation khung xương (skeletal) và animation frame by frame. Framework của mình sẽ sử dụng frame by frame animation vì nó dễ thực hiện và resource của các game này xưa được thiết kế dùng cho kĩ thuật frame by frame.

2. Animation sử dụng frame by frame

  • Frame by frame nghĩa là chúng ta sẽ thay đổi hình ảnh của nhân vật 1 cách liên tục để làm chúng ta cảm thấy nhân vật đang chuyển động. Mỗi frame sẽ tương ứng với một ảnh, tuy nhiên để tăng hiệu suất và tiếp kiệm bộ nhớ thì chúng ta sẽ dùng 1 tấm ảnh to chứa các frame với size bằng nhau, mỗi frame là 1 cử chỉ tại 1 thời điểm của nhân vật. Và lúc này thuộc tính Source Rect của Sprite sẽ được dùng đến và mỗi Source Rect sẽ tương ứng với một frame.
  • Class Animation đã được mình tạo và thêm vào folder GameComponents, các bạn có thể mở Source code lên xem. Animation của mình sẽ kế thừa Sprite vì tính chất giống Sprite chỉ có việc thay đổi Source Rect trong update để tạo cảm giác chuyển động.
  • Class Animation của mình sẽ nắm 1 hình ảnh to, trong đó có chứa các frame của animation, thì mình sẽ cần các thông tin về số cột của hình, số hàng của hình, tổng số frame và thời gian chuyển đổi của mỗi frame.
C:\Users\locth\AppData\Local\Microsoft\Windows\INetCacheContent.Word\animation.png
  • Thuộc tính:
    • Int mRows: số hàng của hình ảnh
    • Int mColums: số cột của hình ảnh
    • Int mCurrentIndex: số frame hiện tại có giá trị từ 0 -> tổng số frame – 1, frame sẽ chạy theo thứ tự từ trái sang phải và từ trên xuống dưới.
    • Int mCurrentRow: số hàng hiện tại vì hình ảnh có thể có nhiều hàng, dùng biến này để lưu hàng hiện tại để tính toán ra Source Rect cần lấy.
    • Int mCurrentColumn: giống biến trên nhưng dùng cho cột.
    • Int mFrameWidth: chiều rộng của frame
    • Int mFrameHeight: chiều cao của frame
    • Int mTotalFrame: tổng số frame của animation
    • float mTimePerFrame: số thời gian để chuyển frame (VD bằng 1 thì 1 giây sẽ chuyển frame 1 lần)
    • Int mCurrentTotalTime: biến đếm thời gian, nếu biến này lớn hơn hoặc bằng mTimePerFrame thì sẽ thực hiện tính toán chuyển frame và reset lại thời gian đếm.
    • Sprite *mSprite: animation sẽ nắm giữ 1 sprite để chọn vùng Source Rect mà vẽ sprite này lên.
    • RECT mRect: thông tin hình chữ nhật của frame hiện tại.



  • Hàm:
    • Animation(const char* filePath, int totalFrame, int rows, int columns, float timePerFrame = 0.1f, D3DCOLOR colorKey = NULL): hàm này sẽ set đường dẫn của hình ảnh và các tham số cần thiết đã nêu ở phần thuộc tính. Tham số timePerFrame sẽ có giá trị mặc nhiên là 0.1 (tức là 0.1s sẽ chuyển frame 1 lần). Hàm này sẽ gọi hàm initWithAnimation(…) để khởi tạo, hàm init dùng chủ yếu cho việc kế thừa sẽ gọi hàm này chứ k phải copy code lại trong Constructor.
    • virtual void Update(float dt): hàm update việc tính toán thời gian chuyển frame, cột hiện tại, hàng hiện tại, set Source Rect cho Sprite,… sẽ được thực hiện trong này. Là hàm ảo vì sử dụng cho kế thừa sau này. Hàm update của chúng ra sẽ thay đổi vị trí của Source Rect vì Width, Height của nó đã được tính toán lúc khởi tạo (Xem hình ở dưới). Vị trí ban đầu của Source Rect sẽ là (0, 0) trong hàm update chúng ta sẽ cộng thời gian của mCurrentTotalTime đến khi bằng mTimePerFrame thì chúng ta tính toán chuyển frame thay đổi Source Rect đến vị trí tiếp theo (nếu đang ở vị trí cuối cùng thì quay lại từ đầu). Mỗi lần chuyển frame thì vị trí cột hiện tại (mCurrentColumn) sẽ được tăng lên đến khi lớn hơn số column của animation thì ta sẽ tăng vị trí hàng (mCurrentRow) và cho mCurrentColumn về 0. VD: như index đang ở vị trí ô số 4 (column = 3, row = 0) thì frame tiếp theo là số 5 lúc này vị trí Column là 0 và vị trí Row là 1 (Column, Row được Đánh số bắt đầu từ 0). Lúc này cách tính toán Source Rect như sau:
mRect.left = mCurrentColumn * mFrameWidth;
     mRect.right = mRect.left + mFrameWidth; 
     mRect.top = mCurrentRow * mFrameHeight; 
     mRect.bottom = mRect.top + mFrameHeight;
C:\Users\locth\AppData\Local\Microsoft\Windows\INetCacheContent.Word\animation update.png
    • void Draw(D3DXVECTOR3 position = D3DXVECTOR3(), RECT sourceRect = RECT(), D3DXVECTOR2 scale = D3DXVECTOR2(), D3DXVECTOR2 transform = D3DXVECTOR2(), float angle = 0, D3DXVECTOR2 rotationCenter = D3DXVECTOR2(), D3DXCOLOR colorKey = D3DCOLOR_XRGB(255, 255, 255)): hàm draw này chức năng tương tự hàm draw của Sprite. Gọi hàm Draw của class cha (Sprite)

3. Tạo animation

  • Mình thêm 1 hình ảnh vào trong folder Resources là goldbrick.png chứa 4 frames là hình ảnh chuyển động của gold brick trong mario.

  • Việc tạo và khởi tạo Animation cũng giống như Sprite tuy nhiên phải gọi hàm update của animation trong hàm Update của Scene thì mới có thể chuyển frame của animation được và cũng phải gọi hàm Draw của animation trong hàm Draw của Scene. Mình có tạo và dùng animation trong DemoScene của source code.

Animation *mGoldBlock;
…….
mGoldBlock = new Animation("Resources/goldbrick.png", 4, 1, 4, 0.15);
mGoldBlock->SetPosition(GameGlobal::GetWidth() / 2, GameGlobal::GetHeight() / 2);
mGoldBlock->SetScale(D3DXVECTOR2(2, 2));
…….
mGoldBlock->Update(dt);
…….
mGoldBlock->Draw();

Tổng kết

Animation là thành phần không thể thiếu trong mỗi game, nó làm cho game sinh động hơn và frame by frame là phương pháp dễ làm nhưng bù lại nó sẽ tốn bộ nhớ và không mượt bằng Skeletal Animation (cái này thì lại ngốn xử lý của CPU) và việc triển khai cũng khó hơn frame by frame.
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