Link Source code HD không che: https://goo.gl/7B1jlk
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. Tiled map và cách hoạt động
- Map là thành phần trong thể thiếu trong các game platform. Và chúng ta phải tạo map làm sao cho hiệu suất tốt và tiết kiệm tài nguyên nhân. Tiled map sử dụng việc vẽ map bằng cách dùng các tile (Các ô hình ảnh) trên 1 tấm ảnh lớn (tile set) để vẽ lên. Những phần hình ảnh giống nhau sẽ chỉ sử dụng 1 hình ảnh để vẽ nên sẽ tiết kiệm được rất nhiều tài nguyên máy.
- Một Tileset sẽ là 1 hình chứa các thành phần của map như những viên gạch,… và các phần này sẽ nằm trong 1 hình vuông có size thường là 16 x 16 hoặc 32 x 32, Tilemap sẽ chứa thông tin mảng 1 chiều chứa thông tin của tile, số 0 thì sẽ để trống không vẽ và các số kia tương ứng với vị trí trên tileset. Như với chuỗi ma trận ở dưới với tileset bên trên thì sẽ được hình như ở dưới.
1,2,3,13,14,14,15,4,5,6,
7,8,9,0,0,0,0,10,11,12,
0,0,0,0,0,0,0,0,0,0
Map này có size là 10 x 10 tileset. Map sẽ được tính size bằng số tileset nên trong code phải nhân với size của Tile mới ra đúng chiều dài, chiều rộng của map theo pixel.
- Nếu bạn muốn tìm hiểu sâu hơn và cách sử dụng Tilemap thì xem thêm ở đây: https://www.stdio.vn/articles/read/195/tao-tilemap-trong-cocos2d-x-3xx
- Vì phải code đoạn vẽ map và thông tin map nên nhiều chức năng trong map này sẽ không dùng được như xoay tile, flip tile, hay ảnh động đều không dùng được. Nếu muốn dùng được thì các bạn phải tự code thêm.
- Framework của mình đọc được file map của tmx được làm bằng Tiled map editor download tại đây: http://www.mapeditor.org/
2. Cài đặt thư viện
- Để có thể đọc được file tmx (được làm bằng Tiledmap Editor) thì mình sẽ cần thư viện đọc file xml ở đây là tinyxml, thư viện dịch map ra thành các thành phần như tile, layer,… và thư viện zlib dùng để giải nén và giải mã của tmx (ở dạng compresses zlib base64) thì những phần mềm đó mình mò mẫm được trên mạng chứ không nhớ rõ source ở đâu.
- Thư viện đọc map mình để hết trong folder MapReader. Với rất nhiều class đã được xây dựng sẵn mình chỉ việc sử dụng lại.
- Thêm linker đến zlib (thư viện nén và giải nén). Bạn nhấp chuột phải vào project -> properties -> Linker -> Input -> additional Dependencies thêm vào zlib.lib
- Sửa Calling Convention để tránh bị lỗi không thấy thư viện của zlib
- Thêm thư viện vào, mình có thêm ở trong source code rồi.
3. Đọc file map và xử lý bằng code
- Mình có tạo class GameMap được đặt trong folder GameComponents. Class này sẽ tạo và đọc map tmx tham số truyền vào lúc khởi tạo là đường dẫn đến map. Khi làm việc với file tmx bạn nhớ chú ý đường dẫn của tileset. Nếu đường dẫn sai thì map sẽ không được vẽ lên. Như của mình để file trong folder Resource thì sẽ có đường dẫn như bên dưới.
- Vì mình sẽ dựa vào đường dẫn này để load ảnh vào 1 Sprite. Tiếp theo mình sẽ giải thích các thuộc tính và hàm cần thiết.
- Thuộc tính:
- Tmx::Map *mMap: chứa toàn bộ thông tin của map như tile, tileset, layer,… bạn có thể vào class Map ở file TmxMap xem thêm thông tin của class này.
- std::map<int, Sprite*> mListTileset: chứa danh sách các TileSet vì 1 map có thể được tạo thành từ nhiều tileset, và ta sẽ chọn từng vùng tile với size tùy chỉnh trên đó nên dùng Sprite có Source Rect sẽ cắt được những hình này. Việc dùng chung 1 texture cũng sẽ tăng hiệu suất ở card đồ họa hơn (giảm thiểu được draw call).
- Hàm:
- GameMap(char* filePath): hàm khởi tạo truyền vào đường dẫn của map.
- Tmx::Map* GetMap(): hàm này trả về thông tin của map, có thể dùng ở các Scene tùy vào mục đích của bạn
- int GetWidth()
- int GetHeight()
- int GetTileWidth()
- int GetTileHeight(): Đây là những hàm lấy thông tin như chiều dài, chiều rộng của map, kích thước của tile. Bạn có thể xem source code để thấy rõ hơn.
- void LoadMap(char* filePath): từ thông tin ảnh truyền vào hàm này sẽ tạo đối tượng tmx::Map và khởi tạo các tileset từ thông tin map nhận được.
- void Draw(): hàm vẽ map lên màn hình. Chúng ta sẽ tính toán vùng cần vẽ, tileset cần vẽ và vị trí tile trong tileset để vẽ trong hàm này. Cách thức hoạt động chúng ta sẽ chạy 1 vòng for để vẽ các layer của map lên:
for (size_t i = 0; i < mMap->GetNumTileLayers(); i++)
{
…….
}
Mình sẽ kiểm tra xem layer nào chúng ta không hiển thị (visible = false) thì sẽ bỏ qua không vẽ lên, những layer như thế này thường chứa thông tin về object.
Tiếp đến mình sẽ quét map từ trái sang phải và từ trên xuống dưới để kiểm tra từng ô tại đó xem có vẽ tile không, nếu có thì sẽ vec tileset đó lên.
for (size_t m = 0; m < layer->GetHeight(); m++)
{
for (size_t n = 0; n < layer->GetWidth(); n++)
{
int tilesetIndex = layer->GetTileTilesetIndex(n, m);
………
}
}
Mình sẽ lấy index của tile giống như bạn lát gạch cho nên nhà thì mỗi ô vuông tương ứng với 1 tile được lát lên hoặc để trống. Height và Width của layer chính là số tile của layer đó. Index của tilleset ở vị trí (n, m) nếu mà = -1 thì chỗ đó để trống và ta không vẽ lên. Chi tiết giống như ở dưới hình (n, m là giá trị giống như trong source code).
Sau khi có được tile index thì mình sẽ tính toán source rect của Sprite chứa tileset để vẽ nó lên, chú ý là tileindex sẽ có giá trị từ 1 còn giá trị tileid sẽ có giá trị từ 0. Mình sẽ lấy tile có index bằng 12 trên hình làm ví dụ. Vì tile index là 12 nên lấy id của tile sẽ có giá trị là 11.tiếp đến Mình sẽ tính toán tìm xem tile nằm ở hàng thứ mấy bằng cách tính lấy số id chia cho chiều rộng của Tileset (tính theo số tile chứ không phải pixel) lấy phần nguyên.
int y = tileID / tileSetWidth;
(11 / 6 = 2) => tile nằm ở hàng thứ 1 (hàng được đánh số thừ số 0)
int x = tileID - y * tileSetWidth;
(11 – 1 * 6) => tile nằm ở cột thứ 5 (cột cũng được đánh số từ số 0)
Vậy với id = 11 thì ứng với index số 12 trên tileset nằm ở hàng thứ 1 và cột thứ 5. Vậy từ x, y ta tìm được vị trí top-left của Source Rect:
sourceRECT.top = y * tileHeight; // (1 * 32 = 32)
sourceRECT.bottom = sourceRECT.top + tileHeight; // (32 + 32 = 64)
sourceRECT.left = x * tileWidth; // (5 * 32 = 150)
sourceRECT.right = sourceRECT.left + tileWidth; // (150 + 32 = 182)
4. Load map
Phần tạo và load map mình có làm trong DemoScene các bạn xem source code để rõ hơn nhé.
GameMap *mMap;
mMap = new GameMap("Resources/untitled.tmx");
…..
mMap->Draw();
0 Comment:
Post a Comment