กรณีศึกษา - การปรับขนาดเกม HTML5 โดยอัตโนมัติ

บทนำ

ในช่วงฤดูร้อนปี 2010 เราได้สร้างเกม Sand Trap ซึ่งเป็นเกมที่เราเข้าร่วมการแข่งขันเกม HTML5 สำหรับโทรศัพท์มือถือ แต่โทรศัพท์มือถือส่วนใหญ่จะแสดงเฉพาะบางส่วนของเกมหรือทำให้เกมมีขนาดเล็กเกินไปจนเล่นไม่ได้เลย เราจึงตัดสินใจปรับให้เกมปรับความละเอียดให้เข้ากับความละเอียดใดก็ได้อย่างลื่นไหล หลังจากเขียนโปรแกรมใหม่และใช้แนวคิดที่ระบุไว้ในบทความนี้ เราจึงได้เกมที่ปรับขนาดได้กับเบราว์เซอร์สมัยใหม่ทุกประเภท ไม่ว่าจะเป็นบนเดสก์ท็อปหรืออุปกรณ์เคลื่อนที่

ภาพหน้าจอของ Thwack แบบเต็มหน้าจอ
ภาพหน้าจอของ Thwack ที่เล็กลงในหน้าต่างเบราว์เซอร์

แนวทางนี้ได้ผลดีกับเกม Sand Trap เราจึงใช้วิธีการเดียวกันกับเกมล่าสุดอย่าง Thwack! เกมจะปรับความละเอียดของหน้าจอโดยอัตโนมัติให้พอดีกับทั้งหน้าต่างแบบเต็มหน้าจอและแบบกำหนดเอง ดังที่แสดงในภาพหน้าจอด้านล่าง

การใช้งานนี้ต้องใช้ทั้ง CSS และ JavaScript การใช้ CSS เพื่อขยายเต็มหน้าจอนั้นง่ายมาก แต่ CSS ไม่อนุญาตให้คุณรักษาสัดส่วนความกว้างต่อความสูงไว้เหมือนเดิมเพื่อป้องกันการยืดผืนผ้าใบและพื้นที่เกม ตรงนี้เองที่ JavaScript จะเข้ามามีบทบาท คุณสามารถปรับขนาดองค์ประกอบเอกสารใหม่ด้วย JavaScript และเรียกให้เหตุการณ์การปรับขนาดในหน้าต่างแสดง

การเตรียมหน้าเว็บ

ขั้นตอนแรกคือการกําหนดพื้นที่ในหน้าเว็บที่เกมจะเล่น หากรวมเป็นบล็อก div คุณจะวางแท็กอื่นๆ หรือองค์ประกอบ Canvas ไว้ภายในได้ การตั้งค่าอย่างถูกต้องจะทำให้องค์ประกอบย่อยเหล่านี้รับการขยายขนาดของบล็อก div หลัก

หากพื้นที่เกมของคุณแบ่งออกเป็น 2 ส่วน ได้แก่ พื้นที่เล่นและพื้นที่เก็บคะแนน พื้นที่ดังกล่าวอาจมีลักษณะดังนี้

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

เมื่อคุณมีโครงสร้างเอกสารพื้นฐานแล้ว คุณสามารถกำหนดคุณสมบัติ CSS ให้กับองค์ประกอบเหล่านี้เพื่อเตรียมพร้อมสำหรับการปรับขนาด พร็อพเพอร์ตี้ CSS หลายรายการสําหรับ "gameArea" จะได้รับการจัดการโดย JavaScript โดยตรง แต่ให้ตั้งค่าพร็อพเพอร์ตี้ CSS อื่นๆ 2-3 รายการที่เริ่มต้นด้วยบล็อก div ของ gameArea หลักเพื่อให้พร็อพเพอร์ตี้ดังกล่าวทํางาน

#gameArea {
 
position: absolute;
 
left:     50%;
 
top:      50%;
}

ซึ่งจะวางมุมซ้ายบนของภาพพิมพ์แคนวาสไว้ตรงกลางของหน้าจอ ฟังก์ชันการปรับขนาดอัตโนมัติของ JavaScript ที่อธิบายไว้ในส่วนถัดไปจะจัดการคุณสมบัติ CSS เพิ่มเติมเพื่อปรับขนาดพื้นที่เกมและจัดกึ่งกลางในหน้าต่าง

เนื่องจากระบบจะปรับขนาดพื้นที่เกมโดยอัตโนมัติตามขนาดของหน้าต่าง คุณจึงไม่ต้องกำหนดขนาดเป็นพิกเซลสำหรับองค์ประกอบย่อยของบล็อก div gameArea แต่ให้กำหนดเป็นเปอร์เซ็นต์แทน ค่าพิกเซลไม่อนุญาตให้องค์ประกอบภายในปรับขนาดตาม div หลักเมื่อมีการทําการเปลี่ยนแปลง อย่างไรก็ตาม คุณอาจต้องเริ่มต้นด้วยพิกเซล แล้วแปลงเป็นเปอร์เซ็นต์เมื่อได้เลย์เอาต์ที่ต้องการ

ในตัวอย่างนี้ ให้เริ่มต้นด้วยพื้นที่เกมที่มีความสูง 300 พิกเซลและกว้าง 400 พิกเซล ภาพพิมพ์แคนวาสครอบคลุมพื้นที่เกมทั้งหมด และแผงสถิติแบบโปร่งแสงครึ่งหนึ่งจะวิ่งไปตามด้านล่างที่สูง 24 พิกเซล ดังที่แสดงในรูปที่ 1

ขนาดขององค์ประกอบย่อย gameArea เป็นพิกเซล
รูปที่ 1: ขนาดขององค์ประกอบย่อย gameArea เป็นพิกเซล

การแปลงค่าเหล่านี้เป็นเปอร์เซ็นต์จะทำให้ Canvas มีความกว้าง 100% และสูง 100% (ของ gameArea ไม่ใช่หน้าต่าง) การหาร 24 ด้วย 300 จะให้ค่าความสูงของแผงสถิติที่ 8% และเนื่องจากแผงจะครอบคลุมพื้นที่ด้านล่างของเกม ความกว้างของแผงก็จะเท่ากับ 100% ด้วยเช่นกัน ดังที่เห็นในรูปที่ 2

มิติข้อมูลขององค์ประกอบย่อย gameArea เป็นเปอร์เซ็นต์
รูปที่ 2: มิติข้อมูลของอีลิเมนต์ย่อย gameArea เป็นเปอร์เซ็นต์

เมื่อกําหนดขนาดของพื้นที่เกมและองค์ประกอบย่อยแล้ว คุณสามารถรวมพร็อพเพอร์ตี้ CSS ขององค์ประกอบภายใน 2 รายการเข้าด้วยกันได้ดังนี้

#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

การปรับองค์ประกอบ gameArea ให้พอดีกับหน้าต่างโดยคงสัดส่วนภาพไว้
รูปที่ 3: การปรับองค์ประกอบ gameArea ให้พอดีกับหน้าต่างโดยคงสัดส่วนภาพไว้

หากรูปร่างของพื้นที่เกมที่ต้องการกว้างกว่ารูปร่างของหน้าต่าง (และความสูงสั้นกว่า) คุณจะต้องเติมเต็มพื้นที่ในแนวนอนของหน้าต่างและเว้นขอบด้านบนและด้านล่าง ในทำนองเดียวกัน หากรูปร่างของพื้นที่เกมที่ต้องการสูงกว่ารูปร่างของหน้าต่าง (และความกว้างแคบกว่า) คุณจะต้องเติมเต็มพื้นที่ในแนวตั้งของหน้าต่างและเว้นขอบด้านซ้ายและขวา

โดยทดสอบอัตราส่วนความกว้างต่อความสูงที่ต้องการเทียบกับอัตราส่วนความกว้างต่อความสูงของหน้าต่างปัจจุบัน แล้วทำการปรับเปลี่ยนตามความเหมาะสม ดังนี้

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 วางมุมซ้ายบนของ div gameArea ไว้ที่กึ่งกลางของหน้าต่างแล้ว ดังนั้นการใส่ CSS ต่อไปนี้จะวางพื้นที่เกมไว้ตรงกลางหน้าต่าง

gameArea.style.marginTop = (-newHeight / 2) + 'px';
gameArea
.style.marginLeft = (-newWidth / 2) + 'px';

นอกจากนี้ คุณยังควรปรับขนาดแบบอักษรโดยอัตโนมัติด้วย หากองค์ประกอบย่อยทั้งหมดใช้ em คุณก็เพียงตั้งค่าพร็อพเพอร์ตี้ CSS fontSize ของบล็อก div gameArea เป็นค่าที่กําหนดโดยขนาดของบล็อก

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 และเทคโนโลยีเว็บพัฒนาต่อไป