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

เกริ่นนำ

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

ภาพหน้าจอของการแสดงผลแบบเต็มหน้าจอ
ภาพหน้าจอของปุ่ม 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 เพื่อปรับขนาดพื้นที่เกมและวางไว้ตรงกลางหน้าต่าง

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

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

ขนาดขององค์ประกอบย่อยของ GameArea ในหน่วยพิกเซล
ภาพที่ 1: ขนาดขององค์ประกอบย่อยของ GameArea ในหน่วยพิกเซล

การแปลค่าเหล่านี้เป็นเปอร์เซ็นต์ทำให้ภาพพิมพ์แคนวาสมีความกว้าง 100% และความสูง 100% (ของ GameArea ไม่ใช่หน้าต่าง) หาร 24 x 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;

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

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 วางมุมซ้ายบนของ GameArea div ไว้ที่กึ่งกลางของหน้าต่างอยู่แล้ว ดังนั้นจึงเป็นจุดศูนย์กลางของพื้นที่เกมในหน้าต่าง ดังนี้

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

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

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

สุดท้าย คุณต้องการทำให้ขนาดของภาพวาดบนผืนผ้าใบตรงกับความกว้างและความสูงใหม่ โปรดทราบว่าโค้ดเกมที่เหลือจะต้องแยกขนาดของเครื่องมือเกมออกจากมิติข้อมูลการวาดของ Canvas เพื่อให้เหมาะสมกับความละเอียดของ Canvas แบบไดนามิก

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;
}

แต่ตอนนี้คุณต้องการให้ปรับอัตโนมัติทุกครั้งที่มีการปรับขนาดหน้าต่าง หรือในกรณีที่อุปกรณ์เคลื่อนที่มีการเปลี่ยนการวางแนวหน้าจอ จัดการเหตุการณ์เหล่านี้โดยให้เหตุการณ์เหล่านี้เรียกใช้ฟังก์ชัน optimizeGame() ของคุณ ดังนี้

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

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

สรุป

Gopherwood Studios ได้ใช้โครงสร้างนี้ในเวอร์ชันต่างๆ กับเกม HTML5 ทั้งหมดของเรา และพิสูจน์แล้วว่ามีประโยชน์อย่างมากสำหรับการรองรับหน้าจอที่มีความละเอียดหลายระดับและอุปกรณ์เคลื่อนที่ต่างๆ นอกจากนี้ เบราว์เซอร์แบบเต็มหน้าจอยังช่วยให้ประสบการณ์การเล่นเกมแบบสมจริงคล้ายกับเกมบนเดสก์ท็อปแบบเดิมมากกว่าเกมที่เล่นบนเบราว์เซอร์หลายๆ เกม เรามุ่งหวังที่จะมีนวัตกรรมอื่นๆ ในเกมบนเว็บเพิ่มเข้ามาเนื่องจาก HTML5 และเทคโนโลยีเว็บมีการพัฒนาอย่างต่อเนื่อง