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

บทนำ

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

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

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

Google Doodle วิ่งข้ามรั้วปี 2012
Google Doodle วิ่งข้ามรั้วปี 2012

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

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

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

Browser Support

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

Source

ใช้เกมแพดใดได้บ้าง

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

เกมแพด
เกมแพด

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

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

ใน Chrome

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

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

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

var gamepadSupportAvailable = Modernizr.gamepads;

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

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

อย่างไรก็ตาม เมื่อคุณผ่านอุปสรรคแรกไปได้ (ขออภัย…) ก็ยังมีอุปสรรคอื่นๆ รออยู่อีก

การจัดทำแบบสำรวจ

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

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

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

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

/**
 * 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.)
},

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

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 (ขวาสุดหรือล่างสุด)

แบบแอนะล็อกหรือแบบแยกส่วน

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

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

การกดปุ่มและการเคลื่อนไหวของสติ๊ก

กิจกรรม

ในบางกรณี เช่น เกมจำลองการบิน การตรวจสอบและตอบสนองต่อตำแหน่งของจอยสติ๊กหรือการกดปุ่มอย่างต่อเนื่องนั้นเหมาะสมกว่า… แต่สำหรับสิ่งต่างๆ เช่น ดูเดิล 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 วิ่งข้ามรั้วปี 2012

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

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

    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 แทนที่จะฝังไว้ในตัว โดยลูปการสำรวจของเราจะสังเคราะห์เหตุการณ์การกดปุ่มและปล่อยปุ่มที่จำเป็น (พร้อม 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 วินาทีใช่ไหม จัดมาเลย

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