簡介
2010 年夏天,我們製作了「Sand Trap」遊戲,並參加行動裝置 HTML5 遊戲競賽。但大多數手機都只顯示部分遊戲畫面,或是將遊戲縮小到無法操作的程度。因此,我們決定自行調整遊戲,讓遊戲能流暢地調整至任何解析度。經過一些重新編寫程式和運用本文所述的構想後,我們製作的遊戲便可在任何新式瀏覽器中執行,無論是桌上型電腦或行動裝置皆可。


這種方法在《Sand Trap》中運作良好,因此我們在最新遊戲《Thwack!》中也採用了相同的方法。遊戲會自動調整螢幕解析度,以便配合全螢幕和自訂大小的視窗,如以下螢幕截圖所示。
實作這項功能時,必須同時運用 CSS 和 JavaScript。使用 CSS 填滿整個畫面很簡單,但 CSS 不允許您維持相同的寬高比,以免畫布和遊戲區域拉長。這時 JavaScript 就能派上用場。您可以使用 JavaScript 重新調整文件元素的比例,並觸發視窗事件的大小調整功能。
準備網頁
第一步是指定網頁上遊戲的顯示區域。如果您將這個元素做為 div 區塊加入,則可以在其中放置其他標記或畫布元素。只要正確設定,這些子元素就會繼承父項 div 區塊的縮放比例。
如果遊戲區域包含兩個部分,即遊戲區和記分區,則可能會像這樣:
<div id="gameArea">
<canvas id="gameCanvas"></canvas>
<div id="statsPanel"></div>
</div>
有了基本的文件結構後,您可以為這些元素提供一些 CSS 屬性,以便準備調整大小。許多「gameArea」的 CSS 屬性會直接由 JavaScript 操控,但為了讓這些屬性運作,請設定幾個其他 CSS 屬性,並以父項 gameArea div 區塊開始:
#gameArea {
position: absolute;
left: 50%;
top: 50%;
}
這樣一來,畫布的左上角就會位於螢幕中央。下一個章節所述的 JavaScript 自動調整大小函式會操控其他 CSS 屬性,藉此調整遊戲區大小,並將遊戲區置於視窗中央。
由於遊戲區會根據視窗的尺寸自動調整大小,因此請勿使用像素為單位的尺寸來設定 gameArea div 區塊的子項元素,而是應使用百分比。像素值不允許內部元素隨著父 div 的變更而縮放。不過,建議您先以像素為單位開始,然後在找到合適的版面配置後,再將像素轉換為百分比。
在本例中,遊戲區域的高度和寬度分別為 300 和 400 像素。畫布會覆蓋整個遊戲區域,並在底部顯示 24 像素高的半透明統計資料面板,如圖 1 所示。

將這些值轉換為百分比後,畫布的寬度和高度 (gameArea 的高度,而非視窗高度) 會變成 100%。將 24 除以 300 後,統計資料面板的高度為 8%,由於它會覆蓋遊戲區域的底部,因此寬度也會是 100%,如圖 2 所示。

既然您已確定遊戲區域及其子項元素的尺寸,現在可以將兩個內部元素的 CSS 屬性組合起來,如下所示:
#gameCanvas {
width: 100%;
height: 100%;
}
#statsPanel {
position: absolute;
width: 100%;
height: 8%;
bottom: 0;
opacity: 0.8;
}
調整遊戲大小
您現在可以建立函式,以便處理視窗的大小調整作業。首先,取得父項 gameArea 文件元素的參照。
var gameArea = document.getElementById('gameArea');
由於您不必關心確切的寬度或高度,因此下一個需要設定的資訊是寬高比。根據先前提到的遊戲區域寬度為 400 像素、高度為 300 像素,您知道要將顯示比例設為寬度 4 個單位、高度 3 個單位。
var widthToHeight = 4 / 3;
由於這個函式會在每次調整視窗大小時呼叫,因此您也需要擷取視窗的新尺寸,以便調整遊戲的尺寸以便配合。您可以使用視窗的 innerWidth 和 innerHeight 屬性來找出這項資訊。
var newWidth = window.innerWidth;
var newHeight = window.innerHeight;
就像您決定要使用的寬高比一樣,現在可以決定視窗目前的寬高比:
var newWidthToHeight = newWidth / newHeight;
這樣一來,您就能決定要讓遊戲以垂直或水平方式填滿螢幕,如圖 3 所示。

如果所需的遊戲區域形狀比視窗形狀寬 (且高度較短),您必須將視窗填滿,並在頂端和底部留出邊距。同樣地,如果所需的遊戲區域形狀高於視窗形狀 (且寬度較窄),您需要將視窗填滿,並在左右留出邊界。
如要這麼做,請使用目前視窗的寬高比,測試所需的寬高比,然後根據以下方式進行適當調整:
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';
}
調整遊戲區域的寬度和高度後,您需要將頂端和左側的負邊距設為高度和寬度的一半,以便將畫面置中。請注意,CSS 已將 gameArea div 的左上角置於視窗的正中央,因此這會將遊戲區域置於視窗中央:
gameArea.style.marginTop = (-newHeight / 2) + 'px';
gameArea.style.marginLeft = (-newWidth / 2) + 'px';
您也應該自動調整字型大小。如果所有子項元素都使用 em,您只需將 gameArea div 區塊的 fontSize CSS 屬性設為由其大小決定的值即可。
gameArea.style.fontSize = (newWidth / 400) + 'em';
最後,您要讓畫布繪圖的尺寸與新的寬度和高度相符。請注意,遊戲程式碼的其餘部分必須將遊戲引擎的尺寸與畫布繪圖尺寸分開,以便支援動態畫布解析度。
var gameCanvas = document.getElementById('gameCanvas');
gameCanvas.width = newWidth;
gameCanvas.height = newHeight;
因此,完成的調整大小函式可能會像這樣:
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;
}
接下來,您希望在調整視窗大小或變更行動裝置螢幕方向時,系統能自動進行這些調整。請讓這些事件呼叫 resizeGame() 函式,以便處理這些事件,如下所示:
window.addEventListener('resize', resizeGame, false);
window.addEventListener('orientationchange', resizeGame, false);
如果視窗的大小調整過高,或螢幕方向為直向,則視窗的寬度會調整為 100%;如果視窗的大小調整過寬,或螢幕方向為橫向,則視窗的高度會調整為 100%。系統會根據預先設定的寬高比,調整剩餘的尺寸。
摘要
Gopherwood Studios 已在所有 HTML5 遊戲中使用這類結構的版本,證明這類結構非常適合用於支援多種螢幕解析度和各種行動裝置。此外,透過全螢幕瀏覽器的輔助,我們的網頁遊戲能提供沉浸式體驗,與許多以瀏覽器為基礎的遊戲相比,更接近傳統桌上型遊戲。隨著 HTML5 和網頁技術持續進化,我們期待網頁遊戲能有更多創新。