กระโดดข้ามสิ่งกีดขวางด้วย Gamepad API

บทนำ

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

แต่เดี๋ยวก่อน หากต้องการรองรับเกมแพดในเว็บแอป คุณก็ไม่ต้องกังวล ไม่ได้แล้ว Gamepad API ใหม่ล่าสุดจะช่วยแก้ปัญหานี้ให้คุณได้ ซึ่งจะช่วยให้คุณใช้ JavaScript เพื่ออ่านสถานะของคอนโทรลเลอร์เกมแพดที่เชื่อมต่อกับคอมพิวเตอร์ได้ ฟีเจอร์นี้เพิ่งเปิดตัวไปเมื่อสัปดาห์ที่แล้วใน Chrome เวอร์ชัน 21 และกำลังจะพร้อมใช้งานใน Firefox ด้วย (ปัจจุบันมีให้บริการในรุ่นพิเศษ)

ซึ่งก็ถือว่าเหมาะเจาะมาก เพราะเมื่อเร็วๆ นี้เรามีโอกาสได้ใช้งานใน Google Doodle ของการแข่งขันวิ่งข้ามรั้วปี 2012 บทความนี้จะอธิบายสั้นๆ เกี่ยวกับวิธีที่เราเพิ่ม Gamepad API ลงใน Doodle และสิ่งที่เราได้เรียนรู้ระหว่างกระบวนการ

Google Doodle เกี่ยวกับการแข่งขันวิ่งควอเดลในปี 2012
Google Doodle 2012 เกี่ยวกับอุปสรรค

ผู้ทดสอบเกมแพด

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

เบราว์เซอร์ใดบ้างที่รองรับในปัจจุบัน

การรองรับเบราว์เซอร์

  • Chrome: 21.
  • Edge: 12.
  • Firefox: 29.
  • Safari: 10.1

แหล่งที่มา

สามารถใช้เกมแพดรุ่นใดได้บ้าง

โดยทั่วไปแล้ว เกมแพดสมัยใหม่ซึ่งระบบของคุณรองรับโดยกำเนิดจะใช้งานได้ เราได้ทดสอบเกมแพดต่างๆ จากตัวควบคุม USB ของแบรนด์อื่นใน PC, เกมแพด PlayStation 2 ที่เชื่อมต่อผ่านดองเกิลกับ Mac ไปจนถึงตัวควบคุมบลูทูธที่จับคู่กับโน้ตบุ๊ก Chrome OS

จอยเกม
เกมแพด

นี่คือรูปภาพตัวควบคุมบางส่วนที่เราใช้ทดสอบการวาดรูป "ใช่แม่ นี่เป็นสิ่งที่ฉันทำจริงๆ ที่ทำงาน" หากตัวควบคุมไม่ทำงานหรือมีการแมปการควบคุมไม่ถูกต้อง โปรดรายงานข้อบกพร่องเกี่ยวกับ Chrome หรือ Firefox (โปรดทดสอบในเบราว์เซอร์แต่ละเวอร์ชันใหม่ล่าสุดเพื่อตรวจสอบว่าปัญหาได้รับการแก้ไขแล้วหรือยัง)

ฟีเจอร์ที่ตรวจหา Gamepad API<

ทำได้ง่ายๆ ใน Chrome โดยทำดังนี้

var gamepadSupportAvailable = !!navigator.webkitGetGamepads || !!navigator.webkitGamepads;

ดูเหมือนว่าใน Firefox จะตรวจจับการดำเนินการนี้ไม่ได้ในตอนนี้ เนื่องจากทุกอย่างอิงตามเหตุการณ์ และตัวจัดการเหตุการณ์ทั้งหมดต้องแนบกับหน้าต่าง ซึ่งทำให้เทคนิคทั่วไปในการตรวจจับตัวจัดการเหตุการณ์ใช้งานไม่ได้

แต่เรามั่นใจว่าปัญหานี้เกิดขึ้นเพียงชั่วคราว Modernizr ที่ยอดเยี่ยมสุดๆ บอกคุณเกี่ยวกับ Gamepad API อยู่แล้ว เราจึงขอแนะนําให้ใช้ Modernizr สําหรับความต้องการในการตรวจจับในปัจจุบันและอนาคตทั้งหมด

var gamepadSupportAvailable = Modernizr.gamepads;

ดูข้อมูลเกี่ยวกับเกมแพดที่เชื่อมต่อ

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

เมื่อคุณผ่านด่านนั้นแล้ว (ขออภัย…) ยังมีด่านอื่นๆ รออยู่

การสำรวจ

การใช้งาน API ของ Chrome จะแสดงฟังก์ชัน navigator.webkitGetGamepads() ที่คุณสามารถใช้เพื่อดูรายการเกมแพดทั้งหมดที่เสียบเข้ากับระบบอยู่ในขณะนี้ พร้อมกับสถานะปัจจุบัน (ปุ่ม + แท่งบังคับ) ระบบจะแสดงผลเกมแพดแรกที่เชื่อมต่อเป็นรายการแรกในอาร์เรย์ และต่อๆ ไป

(การเรียกใช้ฟังก์ชันนี้เพิ่งแทนที่อาร์เรย์ที่คุณเข้าถึงได้โดยตรง navigator.webkitGamepads[] ตั้งแต่ช่วงต้นเดือนสิงหาคม 2012 การเข้าถึงอาร์เรย์นี้ยังคงจําเป็นใน Chrome 21 ส่วนการเรียกใช้ฟังก์ชันจะทํางานใน Chrome 22 ขึ้นไป นับจากนี้ไป การเรียกใช้ฟังก์ชันเป็นวิธีที่แนะนำในการใช้ API และจะทยอยให้บริการในเบราว์เซอร์ Chrome ที่ติดตั้งทั้งหมด)

ส่วนหนึ่งของข้อกำหนดที่นำมาใช้งานจนถึงตอนนี้กำหนดให้คุณตรวจสอบสถานะของเกมแพดเชื่อมต่ออยู่อย่างต่อเนื่อง (และเปรียบเทียบกับสถานะก่อนหน้า หากจำเป็น) แทนที่จะเรียกเหตุการณ์เมื่อเกิดการเปลี่ยนแปลง เราใช้ requestAnimationFrame() เพื่อตั้งค่าการสำรวจในลักษณะที่มีประสิทธิภาพและประหยัดแบตเตอรี่มากที่สุด สำหรับภาพวาดของเรา แม้ว่าจะมีลูป requestAnimationFrame() อยู่แล้วเพื่อรองรับภาพเคลื่อนไหว แต่เราก็สร้างลูปอีกอันที่แยกจากกันโดยสิ้นเชิง เนื่องจากเขียนโค้ดได้ง่ายกว่าและไม่ควรส่งผลต่อประสิทธิภาพแต่อย่างใด

รหัสจากผู้ทดสอบมีดังนี้

/**
 * Starts a polling loop to check for gamepad state.
 */
startPolling: function() {
    // Don't accidentally start a second loop, man.
    if (!gamepadSupport.ticking) {
    gamepadSupport.ticking = true;
    gamepadSupport.tick();
    }
},

/**
 * Stops a polling loop by setting a flag which will prevent the next
 * requestAnimationFrame() from being scheduled.
 */
stopPolling: function() {
    gamepadSupport.ticking = false;
},

/**
 * A function called with each requestAnimationFrame(). Polls the gamepad
 * status and schedules another poll.
 */
tick: function() {
    gamepadSupport.pollStatus();
    gamepadSupport.scheduleNextTick();
},

scheduleNextTick: function() {
    // Only schedule the next frame if we haven't decided to stop via
    // stopPolling() before.
    if (gamepadSupport.ticking) {
    if (window.requestAnimationFrame) {
        window.requestAnimationFrame(gamepadSupport.tick);
    } else if (window.mozRequestAnimationFrame) {
        window.mozRequestAnimationFrame(gamepadSupport.tick);
    } else if (window.webkitRequestAnimationFrame) {
        window.webkitRequestAnimationFrame(gamepadSupport.tick);
    }
    // Note lack of setTimeout since all the browsers that support
    // Gamepad API are already supporting requestAnimationFrame().
    }
},

/**
 * Checks for the gamepad status. Monitors the necessary data and notices
 * the differences from previous state (buttons for Chrome/Firefox,
 * new connects/disconnects for Chrome). If differences are noticed, asks
 * to update the display accordingly. Should run as close to 60 frames per
 * second as possible.
 */
pollStatus: function() {
    // (Code goes here.)
},

หากสนใจเฉพาะเกมแพด 1 ตัว การเรียกข้อมูลอาจทำได้ง่ายๆ ดังนี้

var gamepad = navigator.webkitGetGamepads && navigator.webkitGetGamepads()[0];

หากต้องการเพิ่มความฉลาดขึ้นอีกนิดหรือรองรับผู้เล่นมากกว่า 1 คนพร้อมกัน คุณจะต้องเพิ่มโค้ดอีก 2-3 บรรทัดเพื่อตอบสนองต่อสถานการณ์ที่ซับซ้อนมากขึ้น (เชื่อมต่อเกมแพด 2 ตัวขึ้นไป เกมแพดบางตัวตัดการเชื่อมต่อไปกลางคัน ฯลฯ) คุณสามารถดูแนวทางแก้ปัญหานี้ได้จากซอร์สโค้ดของฟังก์ชัน pollGamepads() ซึ่งเป็นโปรแกรมทดสอบ

กิจกรรม

Firefox ใช้วิธีอื่นที่ดีกว่าซึ่งอธิบายไว้ในข้อกำหนดของ Gamepad API แทนที่จะขอให้คุณทำการสำรวจ โดยจะแสดงเหตุการณ์ 2 รายการ ได้แก่ MozGamepadConnected และ MozGamepadDisconnected ซึ่งจะแสดงขึ้นทุกครั้งที่มีการเสียบเกมแพด (หรือที่แม่นยำกว่านั้นคือเสียบแล้ว "ประกาศ" ด้วยการกดปุ่มใดก็ได้) หรือถอดออก ระบบจะส่งออบเจ็กต์เกมแพดที่จะแสดงสถานะในอนาคตต่อไปเป็นพารามิเตอร์ .gamepad ของออบเจ็กต์เหตุการณ์

จากซอร์สโค้ดของตัวทดสอบ

/**
 * React to the gamepad being connected. Today, this will only be executed
 * on Firefox.
 */
onGamepadConnect: function(event) {
    // Add the new gamepad on the list of gamepads to look after.
    gamepadSupport.gamepads.push(event.gamepad);

    // Start the polling loop to monitor button changes.
    gamepadSupport.startPolling();

    // Ask the tester to update the screen to show more gamepads.
    tester.updateGamepads(gamepadSupport.gamepads);
},

สรุป

สุดท้าย ฟังก์ชันเริ่มต้นในโปรแกรมทดสอบที่รองรับทั้ง 2 วิธีจะมีลักษณะดังนี้

/**
 * Initialize support for Gamepad API.
 */
init: function() {
    // As of writing, it seems impossible to detect Gamepad API support
    // in Firefox, hence we need to hardcode it in the third clause.
    // (The preceding two clauses are for Chrome.)
    var gamepadSupportAvailable = !!navigator.webkitGetGamepads ||
        !!navigator.webkitGamepads ||
        (navigator.userAgent.indexOf('Firefox/') != -1);

    if (!gamepadSupportAvailable) {
    // It doesn't seem Gamepad API is available – show a message telling
    // the visitor about it.
    tester.showNotSupported();
    } else {
    // Firefox supports the connect/disconnect event, so we attach event
    // handlers to those.
    window.addEventListener('MozGamepadConnected',
                            gamepadSupport.onGamepadConnect, false);
    window.addEventListener('MozGamepadDisconnected',
                            gamepadSupport.onGamepadDisconnect, false);

    // Since Chrome only supports polling, we initiate polling loop straight
    // away. For Firefox, we will only do it if we get a connect event.
    if (!!navigator.webkitGamepads || !!navigator.webkitGetGamepads) {
        gamepadSupport.startPolling();
    }
    }
},

ข้อมูลเกมแพด

เกมแพดทุกตัวที่เชื่อมต่อกับระบบจะแสดงด้วยออบเจ็กต์ที่มีลักษณะดังนี้

id: "PLAYSTATION(R)3 Controller (STANDARD GAMEPAD Vendor: 054c Product: 0268)"
index: 1
timestamp: 18395424738498
buttons: Array[8]
    0: 0
    1: 0
    2: 1
    3: 0
    4: 0
    5: 0
    6: 0.03291
    7: 0
axes: Array[4]
    0: -0.01176
    1: 0.01961
    2: -0.00392
    3: -0.01176

ข้อมูลพื้นฐาน

ฟิลด์ด้านบน 2-3 ช่องคือข้อมูลเมตาแบบง่าย ดังนี้

  • id: คำอธิบายแบบข้อความของเกมแพด
  • index: จำนวนเต็มที่ใช้แยกความแตกต่างของเกมแพดต่างๆ ที่เชื่อมต่อกับคอมพิวเตอร์เครื่องหนึ่ง
  • timestamp: การประทับเวลาของการอัปเดตล่าสุดสำหรับสถานะของปุ่ม/แกน (ปัจจุบันรองรับเฉพาะใน Chrome)

ปุ่มและแท่งควบคุม

เกมแพดในปัจจุบันไม่ได้เหมือนกับที่ปู่ย่าของคุณอาจเคยใช้ช่วยเจ้าหญิงในปราสาทที่ไม่ถูกต้อง โดยทั่วไปแล้วเกมแพดจะมีปุ่มแยกต่างหากอย่างน้อย 16 ปุ่ม (บางปุ่มเป็นปุ่มแยก บางปุ่มเป็นปุ่มแอนะล็อก) นอกเหนือจากแท่งแอนะล็อก 2 แท่ง Gamepad API จะบอกคุณเกี่ยวกับปุ่มและแท่งอนาล็อกทั้งหมดที่ระบบปฏิบัติการรายงาน

เมื่อได้รับสถานะปัจจุบันในออบเจ็กต์เกมแพดแล้ว คุณจะเข้าถึงปุ่มผ่านอาร์เรย์ .buttons[] และเข้าถึงแท่งควบคุมผ่านอาร์เรย์ .axes[] ได้ ต่อไปนี้เป็นภาพสรุปของสิ่งที่ตรงกัน

แผนภาพเกมแพด
แผนภาพเกมแพด

ข้อกำหนดนี้ขอให้เบราว์เซอร์แมปปุ่ม 16 ปุ่มแรกและแกน 4 แกนกับสิ่งต่อไปนี้

gamepad.BUTTONS = {
    FACE_1: 0, // Face (main) buttons
    FACE_2: 1,
    FACE_3: 2,
    FACE_4: 3,
    LEFT_SHOULDER: 4, // Top shoulder buttons
    RIGHT_SHOULDER: 5,
    LEFT_SHOULDER_BOTTOM: 6, // Bottom shoulder buttons
    RIGHT_SHOULDER_BOTTOM: 7,
    SELECT: 8,
    START: 9,
    LEFT_ANALOGUE_STICK: 10, // Analogue sticks (if depressible)
    RIGHT_ANALOGUE_STICK: 11,
    PAD_TOP: 12, // Directional (discrete) pad
    PAD_BOTTOM: 13,
    PAD_LEFT: 14,
    PAD_RIGHT: 15
};

gamepad.AXES = {
    LEFT_ANALOGUE_HOR: 0,
    LEFT_ANALOGUE_VERT: 1,
    RIGHT_ANALOGUE_HOR: 2,
    RIGHT_ANALOGUE_VERT: 3
};

ปุ่มและแกนเพิ่มเติมจะต่อท้ายปุ่มและแกนด้านบน โปรดทราบว่าระบบไม่รับประกันว่าปุ่มทั้ง 16 ปุ่มหรือแกนทั้ง 4 แกนจะใช้งานได้ โปรดเตรียมพร้อมที่ปุ่มหรือแกนบางรายการจะใช้งานไม่ได้

ปุ่มสามารถมีค่าตั้งแต่ 0.0 (ไม่ได้กด) ถึง 1.0 (กดจนสุด) แกนจะอยู่ที่ -1.0 (ซ้ายสุดหรือบนสุด) ผ่าน 0.0 (ตรงกลาง) ไปจนถึง 1.0 (ขวาสุดหรือล่างสุด)

เป็นแบบอนาล็อกหรือแบบไม่ต่อเนื่อง

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

gamepad.ANALOGUE_BUTTON_THRESHOLD = .5;

gamepad.buttonPressed_ = function(pad, buttonId) {
    return pad.buttons[buttonId] &&
            (pad.buttons[buttonId] > gamepad.ANALOGUE_BUTTON_THRESHOLD);
};

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

gamepad.AXIS_THRESHOLD = .75;

gamepad.stickMoved_ = function(pad, axisId, negativeDirection) {
    if (typeof pad.axes[axisId] == 'undefined') {
    return false;
    } else if (negativeDirection) {
    return pad.axes[axisId] < -gamepad.AXIS_THRESHOLD;
    } else {
    return pad.axes[axisId] > gamepad.AXIS_THRESHOLD;
    }
};

การกดปุ่มและการเคลื่อนไหวของแท่งบังคับ

กิจกรรม

ในบางกรณี เช่น เกมจำลองการบิน การตรวจสอบและตอบสนองต่อตำแหน่งของแท่งบังคับหรือการกดปุ่มอย่างต่อเนื่องจะเหมาะสมกว่า แต่สำหรับสิ่งต่างๆ เช่น วาดภาพ Doodle ของ Hurdles 2012 ล่ะ คุณอาจสงสัยว่า "ทำไมฉันต้องตรวจสอบปุ่มทุกเฟรม" เหตุใดฉันจึงไม่ได้รับเหตุการณ์เหมือนกับที่รับสำหรับแป้นพิมพ์หรือเมาส์ขึ้น/ลง

ข่าวดีคือคุณทำเช่นนั้นได้ ข่าวร้ายคือ อยู่ในข้อกําหนด แต่ยังไม่มีการใช้งานในเบราว์เซอร์ใดเลย

การสำรวจ

ในระหว่างนี้ ทางออกของคุณคือการเปรียบเทียบสถานะปัจจุบันกับสถานะก่อนหน้า และเรียกใช้ฟังก์ชันหากเห็นความแตกต่าง เช่น

if (buttonPressed(pad, 0) != buttonPressed(oldPad, 0)) {
    buttonEvent(0, buttonPressed(pad, 0) ? 'down' : 'up');
}
for (var i in gamepadSupport.gamepads) {
    var gamepad = gamepadSupport.gamepads[i];

    // Don't do anything if the current timestamp is the same as previous
    // one, which means that the state of the gamepad hasn't changed.
    // This is only supported by Chrome right now, so the first check
    // makes sure we're not doing anything if the timestamps are empty
    // or undefined.
    if (gamepadSupport.prevTimestamps[i] &&
        (gamepad.timestamp == gamepadSupport.prevTimestamps[i])) {
    continue;
    }
    gamepadSupport.prevTimestamps[i] = gamepad.timestamp;

    gamepadSupport.updateDisplay(i);
}

แนวทางที่เน้นแป้นพิมพ์เป็นหลักใน Doodle ของ Hurdles ปี 2012

เนื่องจากหากไม่มีเกมแพด วิธีการป้อนข้อมูลที่ต้องการของ Doodle ประจำวันนี้คือแป้นพิมพ์ เราจึงตัดสินใจให้เกมแพดจำลองแป้นพิมพ์ให้ใกล้เคียงที่สุด ซึ่งหมายความว่ามีการตัดสินใจ 3 อย่างดังนี้

  1. โดโอเดิลต้องใช้ปุ่มเพียง 3 ปุ่มเท่านั้น คือ 2 ปุ่มสำหรับวิ่งและ 1 ปุ่มสำหรับกระโดด แต่เกมแพดมีปุ่มมากกว่านั้น เราจึงแมปปุ่มทั้งหมด 16 ปุ่มและแท่งควบคุม 2 แท่งที่ทราบไปยังฟังก์ชันตรรกะ 3 รายการดังกล่าวในลักษณะที่เราคิดว่าเหมาะสมที่สุด เพื่อให้ผู้ใช้วิ่งได้โดยกดปุ่ม A/B สลับกัน กดปุ่มที่ไหล่สลับกัน กดซ้าย/ขวาบนปุ่มบังคับทิศทาง หรือแกว่งแท่งควบคุมไปทางซ้ายและขวาอย่างรุนแรง (แน่นอนว่าการกดปุ่มบางปุ่มจะมีประสิทธิภาพมากกว่าปุ่มอื่นๆ) เช่น

    newState[gamepad.STATES.LEFT] =
        gamepad.buttonPressed_(pad, gamepad.BUTTONS.PAD_LEFT) ||
        gamepad.stickMoved_(pad, gamepad.AXES.LEFT_ANALOGUE_HOR, true) ||
        gamepad.stickMoved_(pad, gamepad.AXES.RIGHT_ANALOGUE_HOR, true),
    
    newState[gamepad.STATES.PRIMARY_BUTTON] =
        gamepad.buttonPressed_(pad, gamepad.BUTTONS.FACE_1) ||
        gamepad.buttonPressed_(pad, gamepad.BUTTONS.LEFT_SHOULDER) ||
        gamepad.buttonPressed_(pad, gamepad.BUTTONS.LEFT_SHOULDER_BOTTOM) ||
        gamepad.buttonPressed_(pad, gamepad.BUTTONS.SELECT) ||
        gamepad.buttonPressed_(pad, gamepad.BUTTONS.START) ||
        gamepad.buttonPressed_(pad, gamepad.BUTTONS.LEFT_ANALOGUE_STICK),
    
  2. เราถือว่าอินพุตแบบอนาล็อกแต่ละรายการเป็นอินพุตแบบไม่ต่อเนื่องโดยใช้ฟังก์ชันเกณฑ์ที่อธิบายไว้ก่อนหน้านี้

  3. เราถึงขั้นยึดอินพุตของเกมแพดเข้ากับ Doodle แทนที่จะฝังไว้เลย ลูปการสำรวจของเราจะสังเคราะห์เหตุการณ์ keydown และ keyup ที่จำเป็น (ที่มี keyCode ที่เหมาะสม) และส่งกลับไปยัง DOM

    // Create and dispatch a corresponding key event.
    var event = document.createEvent('Event');
    var eventName = down ? 'keydown' : 'keyup';
    event.initEvent(eventName, true, true);
    event.keyCode = gamepad.stateToKeyCodeMap_[state];
    gamepad.containerElement_.dispatchEvent(event);

เท่านี้ก็เรียบร้อย

กลเม็ดเคล็ดลับ

  • โปรดทราบว่าเกมแพดจะไม่ปรากฏในเบราว์เซอร์เลยก่อนที่จะมีการกดปุ่ม
  • หากคุณทดสอบเกมแพดในเบราว์เซอร์ต่างๆ พร้อมกัน โปรดทราบว่าจะมีเพียงเบราว์เซอร์เดียวที่ตรวจจับตัวควบคุมได้ หากคุณไม่ได้รับเหตุการณ์ใดๆ ให้ตรวจสอบว่าได้ปิดหน้าอื่นๆ ที่อาจใช้เหตุการณ์นั้นอยู่ นอกจากนี้ จากประสบการณ์ของเรา บางครั้งเบราว์เซอร์อาจ "ยึด" เกมแพดไว้แม้ว่าคุณจะปิดแท็บหรือออกจากเบราว์เซอร์แล้วก็ตาม บางครั้งการรีสตาร์ทระบบเป็นวิธีแก้ปัญหาเดียว
  • โปรดใช้ Chrome Canary และเวอร์ชันที่เทียบเท่าสำหรับเบราว์เซอร์อื่นๆ เสมอเพื่อให้ได้รับการสนับสนุนที่ดีที่สุด จากนั้นดำเนินการตามความเหมาะสมหากเห็นว่าเวอร์ชันเก่าทำงานแตกต่างจากเวอร์ชันล่าสุด

อนาคต

เราหวังว่าข้อมูลนี้จะเป็นประโยชน์ในการใช้งาน API ใหม่นี้ ซึ่งยังค่อนข้างไม่เสถียร แต่ก็สนุกมาก

นอกจากการรองรับ API ที่ขาดหายไป (เช่น เหตุการณ์) และการรองรับเบราว์เซอร์ที่กว้างขึ้นแล้ว เรายังหวังว่าจะเห็นสิ่งต่างๆ เช่น การควบคุมการสั่น การเข้าถึงไจโรสโคปในตัว เป็นต้น และการสนับสนุนเกมแพดประเภทต่างๆ มากขึ้น โปรดรายงานข้อบกพร่องใน Chrome และ/หรือรายงานข้อบกพร่องใน Firefox หากพบเกมแพดที่ทำงานไม่ถูกต้องหรือไม่ทำงานเลย

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

อ่านเพิ่มเติม