Mở đầu
Link bài viết Phần 1 tại đây
Tiếp nối phần đầu tiên trong hành trình xây dựng game Matrix, ở phần này, chúng ta sẽ đi sâu hơn vào cách mà giao diện người dùng (UI) của Matrix vận hành. Cùng khám phá các bước thiết kế, cách thức các thành phần giao diện tương tác với nhau và làm thế nào để mang đến trải nghiệm trực quan, mượt mà cho người chơi. Hãy cùng bắt đầu nhé!
Giao diện
Để xây dựng giao diện cho trò chơi Matrix, đội ngũ chúng tôi đã sử dụng package konvajs, một thư viện mạnh mẽ giúp tạo và quản lý canvas trong React.
Như mọi người đã biết, bàn chơi của Matrix có kích thước 9x9, nhưng chỉ có 27 điểm đặt block (3 hàng và 9 cột). Nhiệm vụ của người chơi là kéo và thả các khối block vào đúng vị trí trong bảng như mô tả dưới đây:
Do số lượng điểm đặt block có giới hạn, để tránh việc người chơi đặt sai vị trí, hệ thống sẽ ghi nhận tọa độ của block khi người chơi thả chuột. Sau đó, chúng tôi sử dụng các công thức tính toán để xác định ô gần nhất và tự động đặt block vào đó.
Vậy làm sao để có thể tính toán được vị trí mà người chơi muốn đặt thì cùng chúng tôi xuống phần dưới để biết rõ hơn nhé.
Tọa độ của các ô trong board
Thông tin bàn chơi
Ở đây, chúng tôi đã dựa trên tọa độ của x và y của bàn chơi được tạo ra từ konvajs
. Bạn hãy tưởng tượng vị trí a
của board là vị trí (a,a)
cho đến cuối hàng là ô 8a
với tọa độ (ax,ay)
tiếp tục như vậy ta sẽ có tọa độ của từng ô trong board.
Từ logic trên ta sẽ thu được tọa độ của map như sau:
(a, a) | (ax, a) | (2ax, a) | (3ax, a) | ... | (8ax, a) |
---|---|---|---|---|---|
(a, ay) | (ax, ay) | (2ax, ay) | (3ax, ay) | ... | (8ax, ay) |
(a, 2ay) | (ax, 2ay) | (2ax, 2ay) | (3ax, 2ay) | ... | (8ax, 2ay) |
(a, 3ay) | (ax, 3ay) | (2ax, 3ay) | (3ax, 3ay) | ... | (8ax, 3ay) |
(a, 4ay) | (ax, 4ay) | (2ax, 4ay) | (3ax, 4ay) | ... | (8ax, 4ay) |
(a, 5ay) | (ax, 5ay) | (2ax, 5ay) | (3ax, 5ay) | ... | (8ax, 5ay) |
(a, 6ay) | (ax, 6ay) | (2ax, 6ay) | (3ax, 6ay) | ... | (8ax, 6ay) |
(a, 7ay) | (ax, 7ay) | (2ax, 7ay) | (3ax, 7ay) | ... | (8ax, 7ay) |
(a, 8ay) | (ax, 8ay) | (2ax, 8ay) | (3ax, 8ay) | ... | (8ax, 8ay) |
- Với:
- x = width của block.
- y = height của block.
- a = tọa độ khởi đầu của bàn đấu.
Logic kéo thả
- Để tăng trải nghiệm của người dung, thì việc để người dùng không phải kéo đúng vị trí mà chỉ cần kéo gần đúng vị trí thì chúng tôi đã tính toán tọa độ của block để cho ra vị trí gần với block đó được thả nhất:
1. Công Thức:
const diffX = target.x() + BASE_SIZE * 0.25 - BASE_SIZE * 0.5;
const diffY = target.y() + BASE_SIZE * 0.5 - BASE_SIZE * 1.5; const x = Math.round(diffX / BASE_SIZE);
const y = Math.round(diffY / 3 / BASE_SIZE);
target.x()
vàtarget.y()
là tọa độ cuối cùng của block khi được kéo thả vào bàn chơi.BASE_SIZE
là kích thước của mỗi ô vuông trong bàn (9x9), tức là chiều rộng và chiều cao của block 1x1.diffX
vàdiffY
: Là sự chênh lệch giữa vị trí của block và ô gần nhất trong bàn, được điều chỉnh bằng các hằng số để đảm bảo căn giữa block.
2. Giới Hạn Tọa Độ
Khi block được kéo và thả vào bàn, tọa độ target.x() và target.y() phải nằm trong giới hạn của bàn chơi, cụ thể:
-
Xác định phạm vi ngang (X):
- Tọa độ
x
của block nằm trong khoảng:a <= target.x() <= 8ax
, trong đóa
là tọa độ bắt đầu của hàng và8ax
là tọa độ kết thúc của hàng.
- Tọa độ
-
Xác định phạm vi dọc (Y):
- Tương tự như với trục X, tọa độ Y của block sẽ nằm trong khoảng:
a <= target.y() < 8ay
.
- Tương tự như với trục X, tọa độ Y của block sẽ nằm trong khoảng:
3. Tính Toán Sự Chênh Lệch
Công thức tính diffX
và diffY
đảm bảo rằng:
diffX
nằm trong khoảng:na + BASE_SIZE * 0.25 <= diffX <= (n + 1)ax + BASE_SIZE * 0.25
(như hình 2).diffY
nằm trong khoảng tương tự cho trục Y:na + BASE_SIZE * 1.5 <= diffY <= (n+2)ay + BASE_SIZE * 1.5
Khi áp dụng hàm Math.round(diffX / BASE_SIZE)
và Math.round(diffY / 3 / BASE_SIZE)
, hệ thống sẽ làm tròn tọa độ về vị trí gần nhất trên bảng chơi. Điều này giúp xác định vị trí chính xác mà block được đặt vào ô n
trong bảng chơi (với n
là chỉ số của ô gần nhất).
Tất nhiên khi block được kéo ngoài bàn chơi thì sẽ được trả về vị trí ban đầu.
Tổng kết
Trong bài viết này, chúng ta đã khám phá cách đội ngũ phát triển xây dựng giao diện cho trò chơi Matrix, từ việc sử dụng KonvaJS để tạo nên một bàn chơi 9x9 đến việc triển khai logic kéo thả block một cách chính xác. Chúng tôi đã phân tích cách hệ thống ghi nhận tọa độ khi người chơi thả chuột và sử dụng công thức tính toán để xác định vị trí ô gần nhất, giúp người chơi dễ dàng tương tác với bàn chơi mà không gặp phải lỗi đặt sai vị trí.
Việc tính toán tọa độ này không chỉ nâng cao trải nghiệm người dùng, mà còn đảm bảo tính chính xác và mượt mà trong khi chơi game. Sự kết hợp giữa các công nghệ tiên tiến và tư duy logic đã tạo nên một giao diện trực quan, thân thiện và đáng tin cậy cho người chơi Matrix.
Hy vọng bài viết này giúp bạn có cái nhìn rõ hơn về cách hệ thống UI của Matrix vận hành và làm thế nào để các yếu tố tương tác như kéo thả block được thực hiện hiệu quả. Nếu bạn đang phát triển các trò chơi tương tự, việc áp dụng các phương pháp này sẽ mang lại sự chính xác và nâng cao trải nghiệm người dùng trong giao diện trò chơi của bạn.
© Tác giả: Software Engineer Giang Nguyen