Giới thiệu
Vào mùa hè năm 2010, chúng tôi đã tạo ra Sand Trap, một trò chơi mà chúng tôi đã tham gia một cuộc thi về trò chơi HTML5 dành cho điện thoại di động. Tuy nhiên, hầu hết điện thoại di động chỉ hiển thị một phần trò chơi hoặc làm trò chơi quá nhỏ, khiến người chơi không thể chơi được. Vì vậy, chúng tôi đã tự mình điều chỉnh trò chơi để phù hợp với mọi độ phân giải. Sau khi lập trình lại một chút và sử dụng các ý tưởng được nêu trong bài viết này, chúng tôi đã có một trò chơi có thể mở rộng trên mọi trình duyệt hiện đại, cho dù trò chơi đó chạy trên máy tính hay thiết bị di động.


Phương pháp này hoạt động hiệu quả với Sand Trap, vì vậy, chúng tôi đã sử dụng phương pháp tương tự cho trò chơi mới nhất của mình, Thwack!. Trò chơi tự động điều chỉnh độ phân giải màn hình để vừa với cả cửa sổ toàn màn hình và cửa sổ có kích thước tuỳ chỉnh, như trong ảnh chụp màn hình bên dưới.
Để triển khai điều này, bạn cần tận dụng cả CSS và JavaScript. Việc sử dụng CSS để lấp đầy toàn bộ màn hình là điều không quan trọng, nhưng CSS không cho phép bạn duy trì cùng một tỷ lệ chiều rộng với chiều cao để tránh kéo giãn canvas và khu vực trò chơi. Đó là lúc JavaScript xuất hiện. Bạn có thể điều chỉnh lại tỷ lệ các phần tử tài liệu bằng JavaScript và kích hoạt tính năng đổi kích thước trên các sự kiện cửa sổ.
Chuẩn bị trang
Bước đầu tiên là chỉ định khu vực trên trang nơi trò chơi sẽ diễn ra. Nếu thêm phần tử này dưới dạng khối div, bạn có thể đặt các thẻ khác hoặc phần tử canvas trong đó. Bằng cách thiết lập chính xác, các phần tử con này sẽ kế thừa tỷ lệ của khối div mẹ.
Nếu khu vực trò chơi của bạn có hai phần, một khu vực chơi và một khu vực tính điểm, thì khu vực trò chơi có thể có dạng như sau:
<div id="gameArea">
<canvas id="gameCanvas"></canvas>
<div id="statsPanel"></div>
</div>
Sau khi có cấu trúc tài liệu cơ bản, bạn có thể cung cấp cho các phần tử này một số thuộc tính CSS để chuẩn bị đổi kích thước. Nhiều thuộc tính CSS cho "gameArea" được JavaScript trực tiếp thao tác, nhưng để các thuộc tính này hoạt động, hãy thiết lập một số thuộc tính CSS khác bắt đầu bằng khối div gameArea mẹ:
#gameArea {
position: absolute;
left: 50%;
top: 50%;
}
Thao tác này sẽ đặt góc trên cùng bên trái của canvas vào chính giữa màn hình. Hàm tự động đổi kích thước JavaScript được mô tả trong phần tiếp theo sẽ thao tác với các thuộc tính CSS bổ sung để đổi kích thước khu vực trò chơi và căn giữa khu vực đó trong cửa sổ.
Vì khu vực trò chơi được tự động đổi kích thước theo kích thước của cửa sổ, nên bạn không muốn kích thước tính bằng pixel cho các phần tử con của khối div gameArea; thay vào đó, bạn muốn kích thước tính theo tỷ lệ phần trăm. Giá trị pixel không cho phép các phần tử bên trong điều chỉnh theo tỷ lệ với div mẹ khi div mẹ thay đổi. Tuy nhiên, bạn nên bắt đầu bằng pixel rồi chuyển đổi thành phần trăm sau khi có bố cục mà bạn muốn.
Đối với ví dụ này, hãy bắt đầu với khu vực trò chơi có chiều cao 300 pixel và chiều rộng 400 pixel. Canvas bao phủ toàn bộ khu vực trò chơi và một bảng thống kê bán trong suốt chạy dọc theo đáy có chiều cao 24 pixel, như minh hoạ trong Hình 1.

Việc chuyển đổi các giá trị này thành phần trăm sẽ làm cho canvas có chiều rộng 100% và chiều cao 100% (của gameArea, chứ không phải cửa sổ). Khi chia 24 cho 300, bạn sẽ có chiều cao của bảng thống kê là 8%. Vì bảng này sẽ bao phủ phần dưới cùng của khu vực trò chơi, nên chiều rộng của bảng này cũng sẽ là 100%, như trong Hình 2.

Giờ đây, khi đã xác định được kích thước của khu vực trò chơi và các phần tử con của khu vực đó, bạn có thể kết hợp các thuộc tính CSS cho hai phần tử bên trong như sau:
#gameCanvas {
width: 100%;
height: 100%;
}
#statsPanel {
position: absolute;
width: 100%;
height: 8%;
bottom: 0;
opacity: 0.8;
}
Đổi kích thước trò chơi
Bây giờ, bạn đã sẵn sàng tạo một hàm để xử lý việc đổi kích thước cửa sổ. Trước tiên, hãy lấy thông tin tham chiếu đến phần tử tài liệu gameArea mẹ.
var gameArea = document.getElementById('gameArea');
Vì bạn không quan tâm đến chiều rộng hoặc chiều cao chính xác, nên thông tin tiếp theo bạn cần đặt là tỷ lệ chiều rộng trên chiều cao. Dựa vào thông tin tham khảo trước đó về khu vực trò chơi có chiều rộng 400 pixel và chiều cao 300 pixel, bạn biết rằng bạn muốn đặt tỷ lệ khung hình ở mức 4 đơn vị chiều rộng và 3 đơn vị chiều cao.
var widthToHeight = 4 / 3;
Vì hàm này được gọi bất cứ khi nào kích thước cửa sổ thay đổi, nên bạn cũng muốn lấy kích thước mới của cửa sổ để có thể điều chỉnh kích thước của trò chơi cho phù hợp. Bạn có thể tìm thấy thông tin này bằng cách sử dụng thuộc tính innerWidth và innerHeight của cửa sổ.
var newWidth = window.innerWidth;
var newHeight = window.innerHeight;
Cũng giống như khi xác định tỷ lệ chiều rộng/chiều cao mà bạn muốn, giờ đây, bạn có thể xác định tỷ lệ chiều rộng/chiều cao hiện tại của cửa sổ:
var newWidthToHeight = newWidth / newHeight;
Điều này cho phép bạn quyết định xem trò chơi sẽ lấp đầy màn hình theo chiều dọc hay chiều ngang, như trong Hình 3.

Nếu hình dạng khu vực trò chơi mong muốn rộng hơn hình dạng cửa sổ (và chiều cao ngắn hơn), bạn cần lấp đầy cửa sổ theo chiều ngang và để lại lề dọc theo đầu và cuối. Tương tự, nếu hình dạng khu vực trò chơi mong muốn cao hơn hình dạng của cửa sổ (và chiều rộng hẹp hơn), bạn cần lấp đầy cửa sổ theo chiều dọc và để lề dọc theo bên trái và bên phải.
Để thực hiện việc này, hãy kiểm tra tỷ lệ chiều rộng/chiều cao mong muốn với tỷ lệ chiều rộng/chiều cao của cửa sổ hiện tại và điều chỉnh cho phù hợp như sau:
if (newWidthToHeight > widthToHeight) {
// window width is too wide relative to desired game width
newWidth = newHeight * widthToHeight;
gameArea.style.height = newHeight + 'px';
gameArea.style.width = newWidth + 'px';
} else { // window height is too high relative to desired game height
newHeight = newWidth / widthToHeight;
gameArea.style.width = newWidth + 'px';
gameArea.style.height = newHeight + 'px';
}
Giờ đây, khi đã điều chỉnh chiều rộng và chiều cao của khu vực trò chơi, bạn cần căn giữa mọi thứ bằng cách đặt lề âm ở trên cùng bằng một nửa chiều cao và ở bên trái bằng một nửa chiều rộng. Hãy nhớ rằng CSS đã đặt góc trên cùng bên trái của div gameArea ở chính giữa cửa sổ, vì vậy, phần này sẽ căn giữa khu vực trò chơi trong cửa sổ:
gameArea.style.marginTop = (-newHeight / 2) + 'px';
gameArea.style.marginLeft = (-newWidth / 2) + 'px';
Bạn cũng nên tự động điều chỉnh cỡ chữ. Nếu tất cả các phần tử con đều sử dụng em, bạn chỉ cần đặt thuộc tính CSS fontSize của khối div gameArea thành một giá trị được xác định theo kích thước của khối đó.
gameArea.style.fontSize = (newWidth / 400) + 'em';
Cuối cùng, bạn muốn các kích thước của bản vẽ trên canvas khớp với chiều rộng và chiều cao mới. Xin lưu ý rằng phần còn lại của mã trò chơi phải tách biệt kích thước công cụ phát triển trò chơi với kích thước bản vẽ canvas để phù hợp với độ phân giải canvas động.
var gameCanvas = document.getElementById('gameCanvas');
gameCanvas.width = newWidth;
gameCanvas.height = newHeight;
Vì vậy, hàm đổi kích thước đã hoàn chỉnh có thể có dạng như sau:
function resizeGame() {
var gameArea = document.getElementById('gameArea');
var widthToHeight = 4 / 3;
var newWidth = window.innerWidth;
var newHeight = window.innerHeight;
var newWidthToHeight = newWidth / newHeight;
if (newWidthToHeight > widthToHeight) {
newWidth = newHeight * widthToHeight;
gameArea.style.height = newHeight + 'px';
gameArea.style.width = newWidth + 'px';
} else {
newHeight = newWidth / widthToHeight;
gameArea.style.width = newWidth + 'px';
gameArea.style.height = newHeight + 'px';
}
gameArea.style.marginTop = (-newHeight / 2) + 'px';
gameArea.style.marginLeft = (-newWidth / 2) + 'px';
var gameCanvas = document.getElementById('gameCanvas');
gameCanvas.width = newWidth;
gameCanvas.height = newHeight;
}
Bây giờ, bạn muốn các điều chỉnh này được thực hiện tự động bất cứ khi nào kích thước cửa sổ thay đổi hoặc trong trường hợp thiết bị di động, hướng màn hình thay đổi. Xử lý các sự kiện này bằng cách yêu cầu các sự kiện này gọi hàm resizeGame() như sau:
window.addEventListener('resize', resizeGame, false);
window.addEventListener('orientationchange', resizeGame, false);
Nếu cửa sổ được đổi kích thước quá cao hoặc hướng màn hình là dọc, thì bạn đang đặt chiều rộng là 100% của cửa sổ. Còn nếu cửa sổ được đổi kích thước quá rộng hoặc hướng màn hình là ngang, thì bạn đang đặt chiều cao là 100% của cửa sổ. Phương diện còn lại được định cỡ theo tỷ lệ khung hình chiều rộng trên chiều cao được xác định trước.
Tóm tắt
Gopherwood Studios đã sử dụng các phiên bản của cấu trúc này cho tất cả các trò chơi HTML5 của chúng tôi và cấu trúc này đã chứng minh là rất hữu ích trong việc hỗ trợ nhiều độ phân giải màn hình và nhiều thiết bị di động. Ngoài ra, nhờ sự trợ giúp của trình duyệt toàn màn hình, trò chơi trên web của chúng tôi mang lại trải nghiệm sống động hơn, giống với trò chơi trên máy tính truyền thống hơn so với nhiều trò chơi dựa trên trình duyệt. Chúng tôi mong muốn có thêm nhiều đổi mới trong trò chơi trên web khi HTML5 và các công nghệ web tiếp tục phát triển.