- Tham gia
- 12/07/2016
- Bài viết
- 519
PHẦN 1 - RENDER VỊ TRÍ
I. Lý thuyết chung
Map được cấu tạo bởi một mảng byte 2 chiều, 128x128 = 16K byte, cứ mỗi một byte là một pixel, giá trị tương ứng với màu.
Nhiệm vụ của bạn là cứ mỗi tick, bạn tạo thành một mảng byte 2 chiều rồi render nó vào canvas của map.
Guide này sẽ hướng dẫn các bạn render background map có sẵn, để làm minimap chuyên dụng cho minigames, chứ không hướng dẫn auto render như minimap vanilla của minecraft chuyên dụng cho survival.
II. Các bước thực hiện
A. Cách tạo custom renderer (xem trước)
Mặc định mỗi vanilla map sẽ có một hoặc nhiều renderer, mỗi renderer sẽ có chức năng vẽ canvas tương ứng với map đó.
Đoạn code dưới đây sẽ quen thuộc đối với ai từng nghiên cứu MapView của bukkit
pastebin.com
B. Tạo background byte arrays
1. Background map
Như đã nói guide này sẽ hướng dẫn các bạn render từ background có sẵn của arena, nhiệm vụ của các bạn là thiết kế background cho arena của mình, với tỉ lệ 1 block = 4 pixels. Các bạn có thể mở arena của mình bằng mineways sẽ được cấu trúc map nhìn từ trên cao xuống, zoom lên 2x copy vào photoshop và chỉnh sửa, tỉa tót các thứ.
Ở bước này bạn sẽ xác định góc trên cùng bên trái của background sẽ nằm ở tọa độ nào trên arena. Cách xác định rất đơn giản, ví dụ trong hình mình sẽ lấy tâm bomb site A làm mốc, gọi X1 là tọa độ X, Y1 là tọa độ Z của block tâm bomb site A trong minecraft.
Tiếp theo ta xác định block đó nằm ở tọa độ bao nhiêu trên mặt ảnh background, bằng cách mở bằng paint, rê chuột vào block đó, gọi X2 là tọa độ X, Y2 là tọa độ Y của block đó trên mặt ảnh.
Từ đó ta có X = X1-(X2/2), Z = Y1-(Y2/2), nghĩa là tọa độ 0,0 trên mặt ảnh background sẽ tương ứng với tọa độ X Z trên world Minecraft mà nó đại diện.
3. Chuyển background sang byte arrays
Ta sẽ tạo một class GameMap lưu lại byte array của background này, và lấy nó ra khi cần.
pastebin.com
Từ đoạn code trên ta sẽ có được background của map được lưu dưới dạng byte arrays.
C. Render canvas mỗi tick dựa trên vị trí người chơi
Lưu ý: Từ phần này trở đi, khi chuyển đổi X Z của vị trí thực sang X Y của vị trí trên bản đồ mình thường dùng cast vào int trong bài hướng dẫn này, các bạn nên dùng Math.round thay vì cast về int để vị trí có độ chính xác cao hơn, hạn chế glitch và vỡ map khi xoay.
Mỗi player sẽ có một runnable chạy mỗi tick ở luồng ngoài (asynchronously).
Đây là class RendererTask, hàm run của RendererTask sẽ chạy mỗi tick để vẽ canvas
pastebin.com
Và đây là cách khởi tạo RendererTask, khởi tạo trong custom renderer mà bạn đã tạo ở mục A.
pastebin.com
Vậy là xong, bạn tạo RendererTask với dữ liệu là player, canvas lấy từ renderer. RendererTask sẽ vẽ canvas mỗi tick, và server sẽ hiển thị canvas đó cho người chơi.
Từ những gì ở trên, nếu bạn đọc và hiểu những gì mình hướng dẫn thì bạn đã có thể render background của map lên mapcanvas, tâm của map canvas sẽ là vị trí người chơi tương ứng trên background. Và background cũng sẽ xoay theo hướng nhìn của người chơi.
Hết phần 1, ai có gì không hiểu có thể comment.
PHẦN 2 - RENDER PHẦN TỬ
I. Lý thuyết chungTại phần này mình sẽ hướng dẫn các bạn cho các chi tiết lên bản đồ, ví dụ như đồng đội, địch nằm trong tầm nhìn đồng đội, C4, vị trí chết, v.v...
Bạn sẽ quét các phần tử mà bạn cần cho vào bản đồ bên trong class RendererTask.
Lưu ý: Tùy vào tính chất của game mà bạn quyết định phần tử nào được ưu tiên, những phần tử được thêm vào sau lên bản đồ sẽ đè lên và che đi những phần tử được thêm vào trước đó.
II. Các bước thực hiện
A. Biểu tượng bản đồ
Đây là class để lưu trữ các biểu tượng cần thiết để đưa vào bản đồ
pastebin.com
Vẽ biểu tượng lên bản đồ
pastebin.com
B. Skin người chơi
Mỗi player sẽ có một mảng byte 8x8 đại diện cho skin của họ, đây là một hàm mẫu để lấy mảng byte đó từ hệ thống skin riêng của mình, lấy texture value rồi chuyển lôi cái đầu của skin ra từ texture value.
Đoạn code này áp dụng cho hệ thống skin riêng biệt của MineFS, các bạn có thể lấy texture từ hệ thống skin của các bạn, hoặc lấy trực tiếp từ acc premium trên Mojang. Về khoản này thì mình sẽ không hướng dẫn, các bạn tự tìm hiểu cách lấy texture value.
pastebin.com
C. Chuyển đổi vị trí thực sang vị trí bản đồ
Đây là class MapPosition để biểu diễn một vị trí trên bản đồ, và một hàm static khởi tạo vị trí bản đồ tương ứng với vị trí thực (location)
pastebin.com
D. Vị trí phần tử trực tiếp (realtime element location)
Vị trí trực tiếp là vị trí sẽ thay đổi liên tục trong mỗi tick của RendererTask, renderer sẽ liên tục quét vị trí các phần tử bạn muốn.
Bạn có thể thấy hàm g.renderMap(p, map, x, y, rad) tại cuối hàm run trong class RendererTask, đây chính là hàm có nhiệm vụ render các phần tử trên bản đồ, tùy vào loại game mà cách render khác nhau.
Đây là một ví dụ về render phần tử trong chế độ đặt bom
pastebin.com
E. Vị trí phần tử lưu trữ (cached element location)
Một số loại phần tử đặc thù như vị trí chết, vị trí địch trên radar, nếu chạy trực tiếp trong renderertask chúng sẽ gây hao tốn CPU vì phải loop liên tục, cho nên một cách hiệu quả hơn đó là cache, ta sẽ chạy một async task khác mỗi giây để quét và lưu lại những phần tử cần hiển thị trên bản đồ.
1. Lưu trữ
Đây là class MapItem để biểu diễn 1 phần tử trên map
pastebin.com
Sau đó ta sẽ tạo một list MapItem trong class GameMap
synchronizedList là một phương pháp an toàn luồng cho list, do list này sẽ được truy xuất từ nhiều luồng (async task) khác nhau. Khi sử dụng synchronizedList, mỗi lần for loop (iterate) list này bạn cần đưa nó vào khối lệnh synchonized (xem mục 3.)
2. Quét & đưa vào lưu trữ
Chế độ quét theo task. Task này sẽ chạy mỗi giây, các phần tử mà task này quét được sẽ tồn tại trên bản đồ trong vòng một giây, trong một giây đó vị trí sẽ cố định không đổi
pastebin.com
Vị trí chết, đoạn code dưới đây sẽ đưa vị trí chết vào cache và sẽ tồn tại trên bản đồ trong vòng 3 giây.
3. Render phần tử đã lưu trữ lên map
Đây là hàm drawItems được gọi trong hàm Game#renderMap
pastebin.com










sync cũng được mà dễ tuột tps
e chả hiểu cái củ lạc gì hết á
