Nghiên cứu điển hình – Tự động đổi kích thước Trò chơi HTML5

Derek Detweiler
Derek Detweiler

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 trong một cuộc thi về trò chơi HTML5 dành cho điện thoại di động. Nhưng hầu hết điện thoại di động chỉ hiển thị một phần của trò chơi hoặc làm cho trò chơi trở nên quá nhỏ — khiến trò chơi hoàn toàn không chơi được. Vì vậy, chúng tôi đã tự tin điều chỉnh trò chơi sao cho phù hợp với mọi độ phân giải. Sau khi lập trình lại 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 để bàn hay thiết bị di động.

Ảnh chụp màn hình toàn màn hình của thwack
ảnh chụp màn hình thwack nhỏ hơn trong cửa sổ trình duyệt

Phương pháp này hoạt động hiệu quả đối với Sand Trap, vì vậy chúng tôi đã sử dụng cùng một phương pháp trên trò chơi mới nhất, Thwack!. Trò chơi tự động điều chỉnh độ phân giải màn hình cho 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ư minh hoạ trong ảnh chụp màn hình dưới đây.

Việc triển khai bắt buộc này là tận dụng lợi thế của cả CSS và JavaScript. Việc sử dụng CSS để lấp đầy toàn bộ màn hình là không quan trọng, nhưng CSS không cho phép bạn duy trì cùng một tỷ lệ giữa chiều rộng và chiều cao để ngăn việc kéo giãn canvas và khu vực trò chơi. Đây chính là lúc JavaScript phát huy tác dụng. Bạn có thể thay đổi tỷ lệ các phần tử tài liệu bằng JavaScript và kích hoạt việc đổi kích thước 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 bạn bao gồm thẻ này dưới dạng một khối div, bạn có thể đặt các thẻ khác hoặc phần tử canvas vào đó. Bằng cách thiết lập đúng cách, các phần tử con này sẽ kế thừa tỷ lệ của khối div mẹ.

Nếu bạn có hai phần cho khu vực trò chơi, một khu vực chơi và một khu vực lưu giữ điểm số, hai phần đó sẽ có dạng như sau:

<div id="gameArea">
  <canvas id="gameCanvas"></canvas>
  <div id="statsPanel"></div>
</div>

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 vài thuộc tính CSS để chuẩn bị cho việc đổi kích thước. Nhiều thuộc tính CSS cho “gameArea” bị JavaScript thao tác trực tiếp, 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 chính:

#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 ở 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 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 thay đổi kích thước theo kích thước của cửa sổ, nên bạn không cần kích thước tính bằng pixel cho các phần tử con của khối gameArea div; thay vào đó, bạn muốn kích thước 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 nó thay đổi. Tuy nhiên, có thể hữu ích khi bắt đầu với pixel và sau đó chuyển đổi chúng thành tỷ lệ phần trăm sau khi đã có bố cục bạn thích.

Trong ví dụ này, hãy bắt đầu bằng vùng trò chơi có chiều cao là 300 pixel và chiều rộng là 400 pixel. Canvas bao phủ toàn bộ khu vực trò chơi và một bảng số liệu thống kê bán trong suốt chạy dọc theo phần đáy với chiều cao 24 pixel, như trong Hình 1.

Kích thước của các phần tử con gameArea tính bằng pixel
Hình 1: Kích thước của các phần tử con gameArea tính bằng pixel

Dịch các giá trị này thành tỷ lệ phần trăm làm cho canvas sẽ có chiều rộng 100% và chiều cao 100% (của gameArea, không phải cửa sổ). Chia 24 cho 300 cho chiều cao của bảng thống kê là 8%, và vì nó 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 nó cũng sẽ là 100%, như trong Hình 2.

Kích thước của các phần tử con gameArea tính theo tỷ lệ phần trăm
Hình 2: Kích thước của các phần tử con gameArea tính theo tỷ lệ phần trăm

Bây giờ, bạn đã xác định kích thước của khu vực trò chơi và các phần tử con của nó, bạn có thể đặt 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ý cửa sổ được đổi kích thước. Trước tiên, hãy lấy thông tin tham chiếu đến phần tử tài liệu gameArea chính.

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 và chiều cao. Sử dụng tham khảo trước đó của bạn về vùng trò chơi rộng 400 pixel và cao 300 pixel, bạn biết rằng bạn muốn đặt tỷ lệ khung hình ở mức rộng 4 đơn vị và chiều cao 3 đơn vị.

var widthToHeight = 4 / 3;

Hàm này được gọi mỗi khi cửa sổ được đổi kích thước, nên bạn cũng cần lấy kích thước mới của cửa sổ để đ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 các thuộc tính innerWidth và internalHeight của cửa sổ.

var newWidth = window.innerWidth;
var newHeight = window.innerHeight;

Giống như bạn đã xác định tỷ lệ chiều rộng và chiều cao bạn muốn, bây giờ bạn có thể xác định tỷ lệ chiều rộng và 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 sẽ lấp đầy màn hình theo chiều dọc hay chiều ngang, như minh hoạ trong Hình 3.

Điều chỉnh phần tử gameArea vào cửa sổ trong khi vẫn duy trì tỷ lệ khung hình
Hình 3: Điều chỉnh phần tử gameArea vào cửa sổ trong khi vẫn duy trì tỷ lệ khung hình

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à chừa lề dọc theo phần trên cùng và dưới cùng. 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 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à chừa lề dọc theo bên trái và bên phải.

Để thực hiện việc này, hãy thử nghiệm tỷ lệ chiều rộng và chiều cao mong muốn của bạn với tỷ lệ chiều rộng và chiều cao của cửa sổ hiện tại và thực hiện các điều chỉnh 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';
}

Bây giờ, bạn đã điều chỉnh chiều rộng và chiều cao của vùng trò chơi, bạn cần căn giữa mọi thứ lên bằng cách đặt lề âm ở phía trên cùng chiếm một nửa chiều cao và ở bên trái là 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 điều 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 cần tự động điều chỉnh cỡ chữ. Nếu bạn có tất cả các phần tử con sử dụng em, bạn có thể chỉ cần đặt thuộc tính CSS fontSize của khối div gameArea thành giá trị được xác định theo kích thước của nó.

gameArea.style.fontSize = (newWidth / 400) + 'em';

Cuối cùng, bạn cần làm cho kích thước của bản vẽ canvas khớp với chiều rộng và chiều cao mới. 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;

Hàm đổi kích thước hoàn chỉnh sẽ 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 cửa sổ được đổi kích thước hoặc, trong trường hợp của thiết bị di động, hướng màn hình được thay đổi. Hãy xử lý các sự kiện này bằng cách yêu cầu chúng gọi hàm AdjustGame() như sau:

window.addEventListener('resize', resizeGame, false);
window.addEventListener('orientationchange', resizeGame, false);

Nếu bạn đổi kích thước cửa sổ quá rộng hoặc hướng màn hình theo chiều dọc thì tức là bạn đang đặt chiều rộng bằng 100% cửa sổ và nếu cửa sổ được đổi kích thước quá rộng hoặc hướng màn hình theo chiều ngang, thì bạn đang đặt chiều cao bằng 100% cửa sổ. Kích thước còn lại được định kích thước theo tỷ lệ khung hình giữa chiều rộng và 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à nó chứng minh rất hữu ích trong việc thích ứng với nhiều độ phân giải màn hình và các thiết bị di động khác nhau. Ngoài ra, với sự hỗ trợ của trình duyệt toàn màn hình, trải nghiệm chơi trò chơi trên web của chúng tôi gần giống với cách chơi trò chơi truyền thống trên máy tính để bàn hơn so với các trò chơi dựa trên trình duyệt. Chúng tôi mong muốn có thêm nhiều cải tiến trong trò chơi web khi công nghệ HTML5 và web tiếp tục phát triển.