ເມື່ອທ່ານສຽບຕົວຄວບຄຸມ, ທ່ານກົດປຸ່ມ, ຍ້າຍໄມ້, ດຶງຕົວກະຕຸ້ນ ... ແລະໃນຖານະນັກພັດທະນາ, ທ່ານບໍ່ເຫັນມັນໃດໆ. ຕົວທ່ອງເວັບເລືອກມັນ, ແນ່ນອນ, ແຕ່ເວັ້ນເສຍແຕ່ວ່າທ່ານກໍາລັງບັນທຶກຕົວເລກຢູ່ໃນ console, ມັນເບິ່ງບໍ່ເຫັນ. ນັ້ນແມ່ນຄວາມເຈັບຫົວກັບ Gamepad API. ມັນເປັນເວລາຫຼາຍປີ, ແລະຕົວຈິງແລ້ວມັນມີອໍານາດຫຼາຍ. ທ່ານສາມາດອ່ານປຸ່ມ, ໄມ້, ຜົນກະທົບ, ການເຮັດວຽກ. ແຕ່ຄົນສ່ວນໃຫຍ່ບໍ່ແຕະຕ້ອງມັນ. ເປັນຫຍັງ? ເນື່ອງຈາກວ່າບໍ່ມີຄວາມຄິດເຫັນ. ບໍ່ມີແຜງຢູ່ໃນເຄື່ອງມືນັກພັດທະນາ. ບໍ່ມີວິທີທີ່ຈະແຈ້ງທີ່ຈະຮູ້ວ່າຜູ້ຄວບຄຸມຍັງເຮັດຕາມທີ່ທ່ານຄິດຫຼືບໍ່. ມັນຮູ້ສຶກຄືກັບບິນຕາບອດ. ສິ່ງນັ້ນເຮັດໃຫ້ຂ້ອຍສາມາດສ້າງເຄື່ອງມືເລັກນ້ອຍ: Gamepad Cascade Debugger. ແທນທີ່ຈະເບິ່ງຜົນຜະລິດ console, ທ່ານຈະໄດ້ຮັບການສົດໃສ, ການໂຕ້ຕອບຂອງການຄວບຄຸມ. ກົດບາງສິ່ງບາງຢ່າງແລະມັນ reacts ໃນຫນ້າຈໍ. ແລະດ້ວຍ CSS Cascade Layers, ຮູບແບບຕ່າງໆຍັງຄົງເປັນລະບຽບ, ສະນັ້ນມັນສະອາດກວ່າທີ່ຈະດີບັກ. ໃນບົດຂຽນນີ້, ຂ້ອຍຈະສະແດງໃຫ້ເຈົ້າເຫັນວ່າເປັນຫຍັງຕົວຄວບຄຸມການດີບັກຈຶ່ງເປັນຄວາມເຈັບປວດ, ວິທີທີ່ CSS ຊ່ວຍເຮັດຄວາມສະອາດມັນ, ແລະວິທີທີ່ເຈົ້າສາມາດສ້າງຕົວແກ້ບັນຫາສາຍຕາທີ່ໃຊ້ຄືນໄດ້ສໍາລັບໂຄງການຂອງເຈົ້າເອງ.
ເຖິງແມ່ນວ່າທ່ານສາມາດບັນທຶກພວກມັນທັງຫມົດ, ທ່ານຈະສິ້ນສຸດດ້ວຍ spam console ທີ່ບໍ່ສາມາດອ່ານໄດ້ຢ່າງໄວວາ. ຕົວຢ່າງ: [0,0,1,0,0,0.5,0,...] [0,0,0,0,1,0,0,...] [0,0,1,0,0,0,0,...]
ທ່ານສາມາດບອກໄດ້ວ່າກົດປຸ່ມໃດ? ບາງທີ, ແຕ່ວ່າພຽງແຕ່ຫຼັງຈາກ straining ຕາຂອງທ່ານແລະຂາດການປ້ອນຂໍ້ມູນຈໍານວນຫນ້ອຍຫນຶ່ງ. ດັ່ງນັ້ນ, ບໍ່, debugging ບໍ່ໄດ້ມາໄດ້ຢ່າງງ່າຍດາຍໃນເວລາທີ່ມັນມາກັບການອ່ານວັດສະດຸປ້ອນ. ບັນຫາທີ 3: ຂາດໂຄງສ້າງ ເຖິງແມ່ນວ່າທ່ານຈະຖິ້ມຮູບພາບໄວຮ່ວມກັນ, ຮູບແບບຕ່າງໆສາມາດສັບສົນໄດ້ໄວ. ຄ່າເລີ່ມຕົ້ນ, ການເຄື່ອນໄຫວ, ແລະສະຖານະດີບັກສາມາດທັບຊ້ອນກັນໄດ້, ແລະໂດຍບໍ່ມີໂຄງສ້າງທີ່ຊັດເຈນ, CSS ຂອງທ່ານຈະກາຍເປັນທີ່ແຕກຫັກແລະຍາກທີ່ຈະຂະຫຍາຍອອກ. CSS Cascade Layers ສາມາດຊ່ວຍໄດ້. ພວກເຂົາຈັດກຸ່ມຮູບແບບຕ່າງໆເຂົ້າໄປໃນ "ຊັ້ນ" ທີ່ຖືກຈັດລໍາດັບຄວາມສໍາຄັນ, ດັ່ງນັ້ນເຈົ້າຈຶ່ງຢຸດເຊົາການຕໍ່ສູ້ກັບຄວາມສະເພາະແລະການຄາດເດົາ, "ເປັນຫຍັງຮູບແບບການດີບັກຂອງຂ້ອຍບໍ່ສະແດງ?" ແທນທີ່ຈະ, ທ່ານຮັກສາຄວາມກັງວົນແຍກຕ່າງຫາກ:
ພື້ນຖານ: ມາດຕະຖານຂອງຜູ້ຄວບຄຸມ, ຮູບລັກສະນະເບື້ອງຕົ້ນ. ເຄື່ອນໄຫວ: ຈຸດເດັ່ນສຳລັບປຸ່ມກົດ ແລະ ໄມ້ທີ່ຖືກຍ້າຍ. Debug: ການວາງຊ້ອນກັນສໍາລັບນັກພັດທະນາ (ເຊັ່ນ: ການອ່ານຕົວເລກ, ຄໍາແນະນໍາ, ແລະອື່ນໆ).
ຖ້າພວກເຮົາກໍານົດຊັ້ນໃນ CSS ຕາມນີ້, ພວກເຮົາຈະມີ: /* ຕ່ຳສຸດເຖິງບູລິມະສິດສູງສຸດ */ @layer base, active, debug;
@layer base { /* ... */ }
@layer ເຄື່ອນໄຫວຢູ່ { /* ... */ }
@layer debug { /* ... */ }
ເນື່ອງຈາກວ່າແຕ່ລະຊັ້ນ stacks ຄາດຄະເນ, ທ່ານສະເຫມີຮູ້ວ່າກົດລະບຽບໃດຊະນະ. ການຄາດເດົານັ້ນເຮັດໃຫ້ການດີບັກບໍ່ພຽງແຕ່ງ່າຍຂຶ້ນ, ແຕ່ຕົວຈິງແລ້ວສາມາດຈັດການໄດ້. ພວກເຮົາໄດ້ກວມເອົາບັນຫາ (ເບິ່ງເຫັນບໍ່ໄດ້, ການປ້ອນຂໍ້ມູນ messy) ແລະວິທີການ (ການແກ້ໄຂການແກ້ໄຂຮູບພາບທີ່ສ້າງດ້ວຍ Cascade Layers). ຕອນນີ້ພວກເຮົາຈະຍ່າງຜ່ານຂະບວນການເທື່ອລະກ້າວເພື່ອສ້າງຕົວດີບັກ. ແນວຄວາມຄິດຂອງ Debugger ວິທີທີ່ງ່າຍທີ່ສຸດທີ່ຈະເຮັດໃຫ້ການປ້ອນຂໍ້ມູນທີ່ເຊື່ອງໄວ້ສາມາດເຫັນໄດ້ຄືພຽງແຕ່ແຕ້ມມັນຢູ່ໃນຫນ້າຈໍ. ນັ້ນແມ່ນສິ່ງທີ່ດີບັກນີ້ເຮັດ. ປຸ່ມ, ຕົວກະຕຸ້ນ, ແລະ joysticks ລ້ວນແຕ່ໄດ້ຮັບການເບິ່ງເຫັນ.
ກົດ A: ວົງມົນໄຟຂຶ້ນ. ຈູດໄມ້: ວົງມົນເລື່ອນໄປມາ. ດຶງກະຕຸ້ນເຄິ່ງຫນຶ່ງ: ແຖບເຮັດໃຫ້ເຄິ່ງຫນຶ່ງ.
ດຽວນີ້ເຈົ້າບໍ່ໄດ້ເບິ່ງ 0s ແລະ 1s, ແຕ່ຕົວຈິງແລ້ວການເບິ່ງຕົວຄວບຄຸມມີປະຕິກິລິຍາສົດໆ. ແນ່ນອນ, ເມື່ອທ່ານເລີ່ມຕົ້ນການລວບລວມຢູ່ໃນລັດຕ່າງໆເຊັ່ນຄ່າເລີ່ມຕົ້ນ, ກົດ, ຂໍ້ມູນດີບັກ, ບາງທີແມ່ນຮູບແບບການບັນທຶກ, CSS ຈະເລີ່ມມີຂະຫນາດໃຫຍ່ແລະສັບສົນຫຼາຍ. ນັ້ນແມ່ນບ່ອນທີ່ຊັ້ນ cascade ມາສະດວກ. ນີ້ແມ່ນຕົວຢ່າງທີ່ຖອດອອກໄດ້: @layer base { .ປຸ່ມ { ພື້ນຫລັງ: #222; border-radius: 50%; width: 40px; ຄວາມສູງ: 40px; } }
@layer ເຄື່ອນໄຫວຢູ່ { .button.pressed { ພື້ນຫຼັງ: #0f0; /*ສີຂຽວສົດ*/ } }
@layer debug { .ປຸ່ມ::ຫຼັງຈາກ { ເນື້ອໃນ: attr(data-value); font-size: 12px; ສີ: #ffff; } }
ລຳດັບຊັ້ນແມ່ນສຳຄັນ: ພື້ນຖານ → ເຄື່ອນໄຫວ → ດີບັກ.
ຖານ draws ຄວບຄຸມ. ການຈັດການທີ່ມີການເຄື່ອນໄຫວທີ່ກົດດັນ. debug ຖິ້ມໃສ່ overlays.
ການແຕກແຍກແບບນີ້ໝາຍຄວາມວ່າເຈົ້າບໍ່ໄດ້ຕໍ່ສູ້ກັບສົງຄາມສະເພາະທີ່ແປກປະຫຼາດ. ແຕ່ລະຊັ້ນມີສະຖານທີ່ຂອງມັນ, ແລະທ່ານສະເຫມີຮູ້ວ່າສິ່ງທີ່ຊະນະ. ການກໍ່ສ້າງມັນອອກ ໃຫ້ເອົາບາງສິ່ງບາງຢ່າງໃນຫນ້າຈໍກ່ອນ. ມັນບໍ່ຈໍາເປັນທີ່ຈະເບິ່ງດີ - ພຽງແຕ່ຕ້ອງການເພື່ອໃຫ້ພວກເຮົາມີບາງສິ່ງບາງຢ່າງທີ່ຈະເຮັດວຽກຮ່ວມກັບ.
Gamepad Cascade Debugger
ນັ້ນແມ່ນພຽງແຕ່ກ່ອງ. ຍັງບໍ່ຕື່ນເຕັ້ນເທື່ອ, ແຕ່ມັນເຮັດໃຫ້ພວກເຮົາຈັບມືໃນພາຍຫຼັງດ້ວຍ CSS ແລະ JavaScript. ຕົກລົງ, ຂ້ອຍກໍາລັງໃຊ້ຊັ້ນ cascade ຢູ່ທີ່ນີ້ເພາະວ່າມັນຈັດລະບຽບຮຽບຮ້ອຍເມື່ອທ່ານເພີ່ມລັດເພີ່ມເຕີມ. ນີ້ແມ່ນທາງຜ່ານທີ່ຫຍຸ້ງຍາກ:
/* ==================================== ການຕິດຕັ້ງຊັ້ນ CASCADE ຄໍາສັ່ງເລື່ອງ: ພື້ນຖານ → active → debug ================================================== */
/* ກໍານົດລະດັບຊັ້ນຫນ້າ */ @layer base, active, debug;
/* ຊັ້ນ 1: ຮູບແບບພື້ນຖານ - ລັກສະນະເລີ່ມຕົ້ນ */ @layer base { .ປຸ່ມ { ພື້ນຫລັງ: #333; border-radius: 50%; width: 70px; ຄວາມສູງ: 70px; ຈໍສະແດງຜົນ: flex; justify-content: ສູນ; align-items: ສູນ; }
.ຢຸດ { width: 20px; ຄວາມສູງ: 70px; ພື້ນຫລັງ: #333; ຈໍສະແດງຜົນ: inline-block; } }
/* Layer 2: Active states - handles pressed buttons */ @layer ເຄື່ອນໄຫວຢູ່ { .button.active { ພື້ນຫຼັງ: #0f0; /* ສີຂຽວສົດໃສເມື່ອກົດ */ ການຫັນປ່ຽນ: ຂະໜາດ(1.1); /* ຂະຫຍາຍປຸ່ມເລັກນ້ອຍ */ }
.pause.active { ພື້ນຫຼັງ: #0f0; ການຫັນປ່ຽນ: scaleY(1.1); /* ຢຽດຕາມແນວຕັ້ງເມື່ອກົດ */ } }
/* Layer 3: Debug overlays - ຂໍ້ມູນຜູ້ພັດທະນາ */ @layer debug { .ປຸ່ມ::ຫຼັງຈາກ { ເນື້ອໃນ: attr(data-value); /* ສະແດງໃຫ້ເຫັນຄ່າຕົວເລກ */ font-size: 12px; ສີ: #ffff; } }
ຄວາມງາມຂອງວິທີການນີ້ແມ່ນວ່າແຕ່ລະຊັ້ນມີຈຸດປະສົງທີ່ຊັດເຈນ. ຊັ້ນພື້ນຖານບໍ່ສາມາດ override active ໄດ້, ແລະ active ບໍ່ສາມາດ override debug, ບໍ່ວ່າຈະເປັນສະເພາະໃດຫນຶ່ງ. ນີ້ກໍາຈັດສົງຄາມສະເພາະຂອງ CSS ທີ່ປົກກະຕິແລ້ວເຄື່ອງມືດີບັ໊ກ plague. ຕອນນີ້ເບິ່ງຄືວ່າບາງກຸ່ມກຳລັງນັ່ງຢູ່ເທິງພື້ນຫຼັງທີ່ມືດ. ດ້ວຍຄວາມຊື່ສັດ, ບໍ່ຮ້າຍແຮງເກີນໄປ.
ເພີ່ມ JavaScript ເວລາ JavaScript. ນີ້ແມ່ນບ່ອນທີ່ຕົວຄວບຄຸມຕົວຈິງເຮັດບາງສິ່ງບາງຢ່າງ. ພວກເຮົາຈະສ້າງຂັ້ນຕອນນີ້ໂດຍຂັ້ນຕອນ. ຂັ້ນຕອນທີ 1: ຕັ້ງຄ່າການຄຸ້ມຄອງລັດ ກ່ອນອື່ນ ໝົດ, ພວກເຮົາຕ້ອງການຕົວແປເພື່ອຕິດຕາມສະຖານະຂອງ debugger: // =================================== // ການຄຸ້ມຄອງລັດ // ===================================
ໃຫ້ແລ່ນ = false; // ຕິດຕາມວ່າຕົວດີບັກແມ່ນເຮັດວຽກຫຼືບໍ່ ໃຫ້ rafId; // ເກັບຮັກສາ requestAnimationFrame ID ສໍາລັບການຍົກເລີກ
ຕົວແປເຫຼົ່ານີ້ຄວບຄຸມວົງການອະນິເມຊັນທີ່ອ່ານການປ້ອນຂໍ້ມູນຂອງ gamepad ຢ່າງຕໍ່ເນື່ອງ. ຂັ້ນຕອນທີ 2: Grab DOM References ຕໍ່ໄປ, ພວກເຮົາໄດ້ຮັບການອ້າງອີງເຖິງອົງປະກອບ HTML ທັງຫມົດທີ່ພວກເຮົາຈະປັບປຸງ: // =================================== // DOM Element References // ===================================
const btnA = document.getElementById("btn-a"); const btnB = document.getElementById("btn-b"); const btnX = document.getElementById("btn-x"); const pause1 = document.getElementById("pause1"); const pause2 = document.getElementById("pause2"); const status = document.getElementById("ສະຖານະ");
ການເກັບຮັກສາເອກະສານອ້າງອີງເຫຼົ່ານີ້ຢູ່ທາງຫນ້າແມ່ນມີປະສິດທິພາບຫຼາຍກ່ວາການສອບຖາມ DOM ເລື້ອຍໆ. ຂັ້ນຕອນທີ 3: ເພີ່ມ Keyboard Fallback ສຳລັບການທົດສອບໂດຍບໍ່ມີຕົວຄວບຄຸມທາງດ້ານຮ່າງກາຍ, ພວກເຮົາຈະຕັ້ງປຸ່ມແປ້ນພິມໃສ່ປຸ່ມຕ່າງໆ: // =================================== // KEYBOARD FALLBACK (ສໍາລັບການທົດສອບໂດຍບໍ່ມີການຄວບຄຸມ) // ===================================
const keyMap = { "a": btnA, "b": btnB, "x": btnX, "p": [pause1, pause2] // ປຸ່ມ 'p' ຄວບຄຸມທັງສອງແຖບຢຸດຊົ່ວຄາວ };
ນີ້ເຮັດໃຫ້ພວກເຮົາທົດສອບ UI ໂດຍການກົດປຸ່ມເທິງແປ້ນພິມ. ຂັ້ນຕອນທີ 4: ສ້າງ Main Update Loop ນີ້ແມ່ນບ່ອນທີ່ magic ເກີດຂຶ້ນ. ຟັງຊັນນີ້ເຮັດວຽກຢ່າງຕໍ່ເນື່ອງແລະອ່ານສະຖານະ gamepad: // =================================== // MAIN GAMEPAD ອັບເດດ LOOP // ===================================
function updateGamepad() { // ເອົາ gamepads ທີ່ເຊື່ອມຕໍ່ທັງໝົດ const gamepads = navigator.getGamepads(); ຖ້າ (!gamepads) ກັບຄືນມາ;
// ໃຊ້ gamepad ທໍາອິດທີ່ເຊື່ອມຕໍ່ const gp = gamepads[0];
ຖ້າ (gp) { // ປັບປຸງປຸ່ມລັດໂດຍການສະຫຼັບຊັ້ນ "ການເຄື່ອນໄຫວ". btnA.classList.toggle("active", gp.buttons[0].pressed); btnB.classList.toggle("active", gp.buttons[1].pressed); btnX.classList.toggle("active", gp.buttons[2].pressed);
// ຈັດການປຸ່ມຢຸດຊົ່ວຄາວ (ປຸ່ມດັດຊະນີ 9 ໃນຕົວຄວບຄຸມສ່ວນໃຫຍ່) const pausePressed = gp.buttons[9].pressed; pause1.classList.toggle("active", pausePressed); pause2.classList.toggle("active", pausePressed);
// ສ້າງບັນຊີລາຍຊື່ຂອງປຸ່ມກົດໃນປັດຈຸບັນສໍາລັບການສະແດງສະຖານະພາບ ໃຫ້ກົດ = []; gp.buttons.forEach((btn, i) => { ຖ້າ (btn.pressed)pressed.push("ປຸ່ມ " + i); });
// ປັບປຸງຂໍ້ຄວາມສະຖານະຖ້າປຸ່ມໃດຖືກກົດ ຖ້າ (pressed.length > 0) { status.textContent = "ກົດ: " + pressed.join(", "); } }
// ສືບຕໍ່ການ loop ຖ້າດີບັກກໍາລັງແລ່ນ ຖ້າ (ແລ່ນ) { rafId = requestAnimationFrame(updateGamepad); } }
ວິທີທີ່ classList.toggle() ເພີ່ມ ຫຼືລຶບຫ້ອງຮຽນທີ່ໃຊ້ໄດ້ໂດຍອີງໃສ່ວ່າປຸ່ມຖືກກົດ, ເຊິ່ງກະຕຸ້ນຮູບແບບຊັ້ນຂໍ້ມູນ CSS ຂອງພວກເຮົາ. ຂັ້ນຕອນທີ 5: ຈັດການເຫດການແປ້ນພິມ ຜູ້ຟັງເຫດການເຫຼົ່ານີ້ເຮັດໃຫ້ແປ້ນພິມຫຼຸດລົງເຮັດວຽກ: // =================================== // ຕົວຈັດການເຫດການຄີບອດ // ===================================
document.addEventListener("keydown", (e) => { ຖ້າ (keyMap[e.key]) { // ຈັດການອົງປະກອບດຽວຫຼືຫຼາຍ ຖ້າ (Array.isArray(keyMap[e.key])) { keyMap[e.key].forEach(el => el.classList.add("active")); } ອື່ນ { keyMap[e.key].classList.add("active"); } status.textContent = "ປຸ່ມກົດ: " + e.key.toUpperCase(); } });
document.addEventListener("keyup", (e) => { ຖ້າ (keyMap[e.key]) { // ລົບສະຖານະການເຄື່ອນໄຫວເມື່ອລະຫັດຖືກປ່ອຍອອກມາ ຖ້າ (Array.isArray(keyMap[e.key])) { keyMap[e.key].forEach(el => el.classList.remove("active")); } ອື່ນ { keyMap[e.key].classList.remove("active"); } status.textContent = "ລະຫັດອອກ: " + e.key.toUpperCase(); } });
ຂັ້ນຕອນທີ 6: ເພີ່ມການຄວບຄຸມ Start / Stop ສຸດທ້າຍ, ພວກເຮົາຕ້ອງການວິທີທີ່ຈະປິດ/ເປີດ debugger ໄດ້: // =================================== // ເປີດ/ປິດການດີບັກ // ===================================
document.getElementById("toggle").addEventListener("ຄລິກ", () => { ແລ່ນ = !ແລ່ນ; // ພິກສະຖານະການແລ່ນ
ຖ້າ (ແລ່ນ) { status.textContent = "Debugger ແລ່ນ..."; updateGamepad(); // ເລີ່ມການອັບເດດ loop } ອື່ນ { status.textContent = "Debugger inactive"; cancelAnimationFrame(rafId); // ຢຸດ loop ໄດ້ } });
ແລ້ວ, ກົດປຸ່ມຫນຶ່ງແລະມັນສະຫວ່າງ. ຍູ້ໄມ້ແລະມັນຍ້າຍ. ນັ້ນແມ່ນມັນ. ອີກອັນຫນຶ່ງ: ມູນຄ່າວັດຖຸດິບ. ບາງຄັ້ງທ່ານພຽງແຕ່ຕ້ອງການເບິ່ງຕົວເລກ, ບໍ່ແມ່ນໄຟ.
ໃນຂັ້ນຕອນນີ້, ທ່ານຄວນເບິ່ງ:
ຕົວຄວບຄຸມໃນຫນ້າຈໍງ່າຍດາຍ, ປຸ່ມທີ່ມີປະຕິກິລິຍາໃນຂະນະທີ່ທ່ານພົວພັນກັບພວກມັນ, ແລະ ການອ່ານການແກ້ບັນຫາທາງເລືອກທີ່ສະແດງດັດຊະນີປຸ່ມກົດ.
ເພື່ອເຮັດໃຫ້ມັນບໍ່ມີຕົວຕົນໜ້ອຍລົງ, ນີ້ແມ່ນຕົວຢ່າງໄວຂອງຕົວຄວບຄຸມໃນໜ້າຈໍທີ່ຕອບສະໜອງໃນເວລາຈິງ:
ໃນປັດຈຸບັນ, ກົດ Start Recording ບັນທຶກທຸກສິ່ງທຸກຢ່າງຈົນກ່ວາທ່ານມົນຕີຢຸດການບັນທຶກ. 2. ການສົ່ງອອກຂໍ້ມູນໄປຍັງ CSV/JSON ເມື່ອພວກເຮົາມີບັນທຶກ, ພວກເຮົາຈະຕ້ອງການບັນທຶກມັນ.
ຂັ້ນຕອນທີ 1: ສ້າງຕົວຊ່ວຍການດາວໂຫຼດ ກ່ອນອື່ນ ໝົດ, ພວກເຮົາຕ້ອງການ ໜ້າ ທີ່ຜູ້ຊ່ວຍທີ່ຈັດການກັບການດາວໂຫລດໄຟລ໌ໃນ browser: // =================================== // ໄຟລ໌ດາວໂຫຼດຜູ້ຊ່ວຍ // ===================================
function downloadFile(ຊື່ໄຟລ໌, ເນື້ອໃນ, ປະເພດ = "ຂໍ້ຄວາມ/ທຳມະດາ") { // ສ້າງ blob ຈາກເນື້ອຫາ const blob = ໃຫມ່ Blob([ເນື້ອຫາ], { ປະເພດ }); const url = URL.createObjectURL(blob);
// ສ້າງລິ້ງດາວໂຫລດຊົ່ວຄາວແລະຄລິກໃສ່ມັນ const a = document.createElement("a"); a.href = url; a.download=ຊື່ໄຟລ໌; a.click();
// ເຮັດຄວາມສະອາດ URL ວັດຖຸຫຼັງຈາກດາວໂຫລດ setTimeout(() => URL.revokeObjectURL(url), 100); }
ຟັງຊັນນີ້ເຮັດວຽກໂດຍການສ້າງ Blob (ວັດຖຸຂະຫນາດໃຫຍ່ສອງ) ຈາກຂໍ້ມູນຂອງທ່ານ, ການສ້າງ URL ຊົ່ວຄາວສໍາລັບມັນ, ແລະໂຄງການຄລິກໃສ່ການເຊື່ອມຕໍ່ດາວໂຫລດ. ການອະນາໄມໃຫ້ແນ່ໃຈວ່າພວກເຮົາບໍ່ຮົ່ວໄຫລຂອງຫນ່ວຍຄວາມຈໍາ. ຂັ້ນຕອນທີ 2: ຈັດການ JSON Export JSON ແມ່ນດີເລີດສໍາລັບການຮັກສາໂຄງສ້າງຂໍ້ມູນຄົບຖ້ວນສົມບູນ:
// =================================== // ສົ່ງອອກເປັນ JSON // ===================================
document.getElementById("export-json").addEventListener("click", () => { // ກວດເບິ່ງວ່າມີສິ່ງໃດທີ່ຈະສົ່ງອອກ ຖ້າ (!frames.length) { console.warn("ບໍ່ມີການບັນທຶກທີ່ຈະສົ່ງອອກ."); ກັບຄືນ; }
// ສ້າງ payload ກັບ metadata ແລະກອບ const payload = { createdAt: new Date().toISOSTring(), ກອບ };
// ດາວໂຫຼດເປັນຮູບແບບ JSON ດາວໂຫລດໄຟລ໌( "gamepad-log.json", JSON.stringify(payload, null, 2), "application/json" ); });
ຮູບແບບ JSON ຮັກສາທຸກຢ່າງທີ່ມີໂຄງສ້າງ ແລະສາມາດວິເຄາະໄດ້ງ່າຍ, ເຮັດໃຫ້ມັນເຫມາະສົມສໍາລັບການໂຫຼດກັບໄປຫາເຄື່ອງມື dev ຫຼືແບ່ງປັນກັບເພື່ອນຮ່ວມທີມ. ຂັ້ນຕອນທີ 3: ຈັດການການສົ່ງອອກ CSV ສໍາລັບການສົ່ງອອກ CSV, ພວກເຮົາຈໍາເປັນຕ້ອງແປຂໍ້ມູນລໍາດັບຊັ້ນເຂົ້າໄປໃນແຖວແລະຖັນ:
//================================================== // ສົ່ງອອກເປັນ CSV // ===================================
document.getElementById("export-csv").addEventListener("click", () => { // ກວດເບິ່ງວ່າມີສິ່ງໃດທີ່ຈະສົ່ງອອກ ຖ້າ (!frames.length) { console.warn("ບໍ່ມີການບັນທຶກທີ່ຈະສົ່ງອອກ."); ກັບຄືນ; }
// ສ້າງແຖວສ່ວນຫົວ CSV (ຖັນສຳລັບເວລາ, ປຸ່ມທັງໝົດ, ທຸກແກນ) const headerButtons = frames[0].buttons.map((_, i) => btn${i}); const headerAxes = frames[0].axes.map((_, i) => axis${i}); const header = ["t", ...headerButtons, ...headerAxes].join(",") + "\n";
// ສ້າງແຖວຂໍ້ມູນ CSV const rows = frames.map(f => { const btnVals = f.buttons.map(b => b.value); ກັບຄືນ [f.t, ...btnVals, ...f.axes].join(","); }).ເຂົ້າຮ່ວມ("\n");
// ດາວໂຫຼດເປັນ CSV downloadFile("gamepad-log.csv", header + rows, "text/csv"); });
CSV ແມ່ນດີເລີດສໍາລັບການວິເຄາະຂໍ້ມູນເພາະວ່າມັນເປີດໂດຍກົງໃນ Excel ຫຼື Google Sheets, ຊ່ວຍໃຫ້ທ່ານສ້າງຕາຕະລາງ, ການກັ່ນຕອງຂໍ້ມູນ, ຫຼືຮູບແບບຈຸດ. ໃນປັດຈຸບັນທີ່ປຸ່ມສົ່ງອອກແມ່ນຢູ່ໃນ, ທ່ານຈະເຫັນສອງທາງເລືອກໃຫມ່ໃນກະດານ: ສົ່ງອອກ JSON ແລະສົ່ງອອກ CSV. JSON ແມ່ນດີຖ້າທ່ານຕ້ອງການຖິ້ມບັນທຶກດິບກັບຄືນສູ່ເຄື່ອງມື dev ຂອງທ່ານຫຼືຖອກໃສ່ໂຄງສ້າງ. ໃນທາງກົງກັນຂ້າມ, CSV ເປີດໂດຍກົງໃນ Excel ຫຼື Google Sheets ເພື່ອໃຫ້ທ່ານສາມາດສ້າງຕາຕະລາງ, ການກັ່ນຕອງ, ຫຼືປຽບທຽບການປ້ອນຂໍ້ມູນ. ຕົວເລກຕໍ່ໄປນີ້ສະແດງໃຫ້ເຫັນວ່າແຜງເບິ່ງຄືແນວໃດກັບການຄວບຄຸມພິເສດເຫຼົ່ານັ້ນ.
3. ລະບົບ Snapshot ບາງຄັ້ງທ່ານບໍ່ຕ້ອງການບັນທຶກເຕັມ, ພຽງແຕ່ "ຮູບຫນ້າຈໍ" ຢ່າງໄວວາຂອງສະຖານະການປ້ອນຂໍ້ມູນ. ນັ້ນແມ່ນບ່ອນທີ່ປຸ່ມ Take Snapshot ຊ່ວຍໄດ້.
ແລະ JavaScript:
// =================================== // ເອົາ SNAPSHOT // ===================================
document.getElementById("snapshot").addEventListener("ຄລິກ", () => { // ເອົາ gamepads ທີ່ເຊື່ອມຕໍ່ທັງໝົດ const pads = navigator.getGamepads(); const activePads = [];
// Loop ຜ່ານແລະເກັບກໍາສະຖານະຂອງແຕ່ລະ gamepad ທີ່ເຊື່ອມຕໍ່ ສໍາລັບ (const gp ຂອງ pads) { ຖ້າ (!gp) ສືບຕໍ່; // ຂ້າມຊ່ອງຫວ່າງ
activePads.push({ id: gp.id, // ຊື່ຕົວຄວບຄຸມ/ແບບຈໍາລອງ timestamp: performance.now(), ປຸ່ມ: gp.buttons.map(b => ({ ກົດດັນ: b.pressed, ຄ່າ: b.value })), ແກນ: [...gp.axes] }); }
// ກວດເບິ່ງວ່າມີ gamepads ໃດ ຖ້າ (!activePads.length) { console.warn("ບໍ່ມີ gamepads ເຊື່ອມຕໍ່ສໍາລັບການ snapshot."); alert("ບໍ່ພົບຕົວຄວບຄຸມ!"); ກັບຄືນ; }
// ບັນທຶກແລະແຈ້ງຜູ້ໃຊ້ console.log("ພາບຖ່າຍ:", activePads); alert(ຖ່າຍພາບແລ້ວ! Captured ${activePads.length} controller(s)); });
Snapshots ຢຸດສະຖານະທີ່ແນ່ນອນຂອງຕົວຄວບຄຸມຂອງທ່ານໃນເວລາດຽວ. 4. Ghost Input Replay ໃນປັດຈຸບັນສໍາລັບການມ່ວນຊື່ນຫນຶ່ງ: ghost input replay. ນີ້ໃຊ້ເວລາບັນທຶກແລະຫຼິ້ນມັນກັບສາຍຕາຄືກັບວ່າຜູ້ນ phantom ກໍາລັງໃຊ້ຕົວຄວບຄຸມ.
JavaScript ສໍາລັບການຫຼິ້ນຄືນ: // =================================== // GHOST REPLAY // ===================================
document.getElementById("replay").addEventListener("click", () => { // ໃຫ້ແນ່ໃຈວ່າພວກເຮົາມີບັນທຶກເພື່ອຫຼິ້ນຄືນ ຖ້າ (!frames.length) { alert("ບໍ່ມີການບັນທຶກການຫຼິ້ນຄືນ!"); ກັບຄືນ; }
console.log("ກຳລັງເລີ່ມການຫຼິ້ນຜີຄືນ...");
// ຕິດຕາມເວລາສຳລັບການຫຼິ້ນທີ່ຊິ້ງແລ້ວ ໃຫ້ startTime = performance.now(); ໃຫ້ frameIndex = 0;
// ຣີວິວພາບເຄື່ອນໄຫວຄືນໃໝ່ ຂັ້ນຕອນການທໍາງານ () { const now = performance.now(); const elapsed = ໃນປັດຈຸບັນ - startTime;
// ປະມວນຜົນເຟຣມທັງໝົດທີ່ຄວນຈະເກີດຂຶ້ນໃນຕອນນີ້ ໃນຂະນະທີ່ (frameIndex < frames.length && frames[frameIndex].t <= ຜ່ານໄປ) { const frame = ກອບ[frameIndex];
// ອັບເດດ UI ດ້ວຍປຸ່ມທີ່ບັນທຶກໄວ້ btnA.classList.toggle("active", frame.buttons[0].pressed); btnB.classList.toggle("active", frame.buttons[1].pressed); btnX.classList.toggle("active", frame.buttons[2].pressed);
// ອັບເດດສະຖານະສະແດງ ໃຫ້ກົດ = []; frame.buttons.forEach((btn, i) => { if (btn.pressed) pressed.push("ປຸ່ມ" + i); }); ຖ້າ (pressed.length > 0) { status.textContent = "ຜີ: " + pressed.join(", "); }
frameIndex++; }
// ສືບຕໍ່ loop ຖ້າມີກອບເພີ່ມເຕີມ ຖ້າ (frameIndex < frames.length) { requestAnimationFrame(ຂັ້ນຕອນ); } ອື່ນ { console.log("ຫຼິ້ນຄືນສໍາເລັດ." status.textContent = "ຫຼິ້ນຄືນສໍາເລັດ"; } }
// ເລີ່ມການຫຼິ້ນຄືນ ຂັ້ນຕອນ(); });
ເພື່ອເຮັດໃຫ້ການດີບັ໊ກແບບມືຫຼາຍຂື້ນ, ຂ້ອຍໄດ້ເພີ່ມການຫຼິ້ນຜີຄືນ. ເມື່ອທ່ານໄດ້ບັນທຶກເຊດຊັນ, ທ່ານສາມາດຕີ replay ແລະເບິ່ງ UI ປະຕິບັດມັນອອກ, ເກືອບຄືກັບຜູ້ນ phantom ແລ່ນ pad ໄດ້. ປຸ່ມ Replay Ghost ໃໝ່ຈະສະແດງຢູ່ໃນແຜງສໍາລັບການນີ້.
ກົດບັນທຶກ, ລົບກວນຕົວຄວບຄຸມເລັກນ້ອຍ, ຢຸດ, ຈາກນັ້ນຫຼິ້ນຄືນ. UI ພຽງແຕ່ສະທ້ອນທຸກສິ່ງທີ່ທ່ານເຮັດ, ຄືກັບຜີທີ່ຕິດຕາມຂໍ້ມູນຂອງທ່ານ. ເປັນຫຍັງຈຶ່ງເບື່ອກັບສິ່ງພິເສດເຫຼົ່ານີ້?
ການບັນທຶກ/ການສົ່ງອອກເຮັດໃຫ້ມັນງ່າຍສໍາລັບຜູ້ທົດສອບທີ່ຈະສະແດງສິ່ງທີ່ເກີດຂຶ້ນຢ່າງແທ້ຈິງ. ພາບຖ່າຍຄ້າງໄວ້ໃນເວລາສັ້ນໆ, ມີປະໂຫຍດຫຼາຍເມື່ອທ່ານກຳລັງໄລ່ແມງໄມ້ແປກໆ. Ghost replay ແມ່ນດີເລີດສໍາລັບການສອນ, ການກວດສອບການເຂົ້າເຖິງ, ຫຼືພຽງແຕ່ປຽບທຽບການຕັ້ງຄ່າການຄວບຄຸມຂ້າງຄຽງ.
ໃນຈຸດນີ້, ມັນບໍ່ແມ່ນພຽງແຕ່ຕົວຢ່າງທີ່ສະອາດອີກຕໍ່ໄປ, ແຕ່ບາງສິ່ງບາງຢ່າງທີ່ເຈົ້າສາມາດປະຕິບັດໄດ້. ກໍລະນີການນໍາໃຊ້ທີ່ແທ້ຈິງໃນໂລກ ດຽວນີ້ພວກເຮົາມີຕົວດີບັກທີ່ສາມາດເຮັດໄດ້ຫຼາຍຢ່າງ. ມັນສະແດງໃຫ້ເຫັນການປ້ອນຂໍ້ມູນສົດ, ບັນທຶກການບັນທຶກ, ສົ່ງອອກໃຫ້ເຂົາເຈົ້າ, ແລະແມ້ກະທັ້ງ replays stuff. ແຕ່ຄໍາຖາມທີ່ແທ້ຈິງແມ່ນ: ໃຜສົນໃຈແທ້ໆ? ອັນນີ້ມີປະໂຫຍດສຳລັບໃຜ? ນັກພັດທະນາເກມ ການຄວບຄຸມແມ່ນສ່ວນຫນຶ່ງຂອງວຽກ, ແຕ່ການແກ້ບັນຫາໃຫ້ເຂົາເຈົ້າ? ປົກກະຕິແລ້ວເຈັບ. ລອງນຶກພາບວ່າເຈົ້າກຳລັງທົດສອບຄອມໂບເກມຕໍ່ສູ້, ເຊັ່ນ: ↓ → + punch. ແທນທີ່ຈະອະທິຖານ, ທ່ານໄດ້ກົດມັນແບບດຽວກັນສອງຄັ້ງ, ທ່ານບັນທຶກມັນຄັ້ງດຽວ, ແລະ replay ມັນ. ສຳເລັດແລ້ວ. ຫຼືທ່ານປ່ຽນບັນທຶກ JSON ກັບເພື່ອນຮ່ວມທີມເພື່ອກວດເບິ່ງວ່າລະຫັດຜູ້ຫຼິ້ນຫຼາຍຄົນຂອງທ່ານມີປະຕິກິລິຍາອັນດຽວກັນຢູ່ໃນເຄື່ອງຂອງເຂົາເຈົ້າຫຼືບໍ່. ນັ້ນແມ່ນໃຫຍ່. ຜູ້ປະຕິບັດການຊ່ວຍເຂົ້າເຖິງ ອັນນີ້ຢູ່ໃກ້ກັບຫົວໃຈຂອງຂ້ອຍ. ບໍ່ແມ່ນທຸກຄົນຫຼິ້ນກັບຕົວຄວບຄຸມ "ມາດຕະຖານ". ຕົວຄວບຄຸມການປັບຕົວໄດ້ຖິ້ມສັນຍານແປກໆບາງຄັ້ງ. ດ້ວຍເຄື່ອງມືນີ້, ທ່ານສາມາດເບິ່ງໄດ້ຢ່າງແທ້ຈິງສິ່ງທີ່ເກີດຂຶ້ນ. ຄູອາຈານ, ນັກຄົ້ນຄວ້າ, ໃຜກໍ່ຕາມ. ພວກເຂົາສາມາດຈັບບັນທຶກ, ປຽບທຽບພວກມັນ, ຫຼື replay inputs ຂ້າງຄຽງ. ທັນໃດນັ້ນ, ສິ່ງທີ່ເບິ່ງບໍ່ເຫັນຈະກາຍເປັນທີ່ຊັດເຈນ. ການທົດສອບການຮັບປະກັນຄຸນນະພາບ ປົກກະຕິແລ້ວນັກທົດສອບຈະຂຽນບັນທຶກເຊັ່ນ: "ຂ້ອຍຂັດປຸ່ມທີ່ນີ້ແລະມັນແຕກ." ບໍ່ມີປະໂຫຍດຫຼາຍ. ດຽວນີ້? ພວກເຂົາເຈົ້າສາມາດເກັບກໍາກົດທີ່ແນ່ນອນ, ສົ່ງອອກບັນທຶກ, ແລະສົ່ງອອກ. ບໍ່ມີການຄາດເດົາ. ການສຶກສາ ຖ້າເຈົ້າກຳລັງສ້າງບົດສອນ ຫຼືວິດີໂອ YouTube, ການຫຼິ້ນຜີຄືນແມ່ນເປັນຄຳ. ທ່ານສາມາດເວົ້າໄດ້ຢ່າງແທ້ຈິງວ່າ, "ນີ້ແມ່ນສິ່ງທີ່ຂ້ອຍເຮັດກັບຕົວຄວບຄຸມ," ໃນຂະນະທີ່ UI ສະແດງໃຫ້ເຫັນວ່າມັນເກີດຂຶ້ນ. ເຮັດໃຫ້ຄໍາອະທິບາຍທີ່ຊັດເຈນຂຶ້ນ. Beyond Games ແລະແມ່ນແລ້ວ, ນີ້ບໍ່ແມ່ນພຽງແຕ່ກ່ຽວກັບເກມ. ປະຊາຊົນໄດ້ໃຊ້ຕົວຄວບຄຸມສໍາລັບຫຸ່ນຍົນ, ໂຄງການສິລະປະ, ແລະການໂຕ້ຕອບການຊ່ວຍເຂົ້າເຖິງ. ບັນຫາດຽວກັນທຸກໆຄັ້ງ: ຕົວຈິງແລ້ວຕົວທ່ອງເວັບແມ່ນຫຍັງ? ດ້ວຍສິ່ງນີ້, ທ່ານບໍ່ ຈຳ ເປັນຕ້ອງຄາດເດົາ. ສະຫຼຸບ ການດີບັກການປ້ອນຂໍ້ມູນຂອງຕົວຄວບຄຸມມີຄວາມຮູ້ສຶກຄືກັບບິນຕາບອດຢູ່ສະເໝີ. ບໍ່ເຫມືອນກັບ DOM ຫຼື CSS, ບໍ່ມີຕົວກວດສອບໃນຕົວສໍາລັບ gamepads; ມັນເປັນພຽງແຕ່ຕົວເລກດິບໃນ console, ສູນເສຍໄດ້ງ່າຍໃນສິ່ງລົບກວນ. ດ້ວຍສອງສາມຮ້ອຍແຖວຂອງ HTML, CSS, ແລະ JavaScript, ພວກເຮົາໄດ້ສ້າງສິ່ງທີ່ແຕກຕ່າງກັນ:
ເຄື່ອງດີບັ໊ກທາງສາຍຕາທີ່ເຮັດໃຫ້ການປ້ອນຂໍ້ມູນເບິ່ງບໍ່ເຫັນ. ລະບົບ CSS ເປັນຊັ້ນທີ່ຮັກສາ UI ສະອາດ ແລະສາມາດແກ້ບັນຫາໄດ້. ຊຸດການປັບປຸງ (ການບັນທຶກ, ການສົ່ງອອກ, ພາບຖ່າຍ, ການຫຼິ້ນຄືນຜີ) ທີ່ຍົກລະດັບມັນຈາກການສາທິດໄປສູ່ເຄື່ອງມືນັກພັດທະນາ.
ໂຄງການນີ້ສະແດງໃຫ້ເຫັນວ່າທ່ານໄປໄດ້ໄກປານໃດໂດຍການປະສົມພະລັງງານຂອງເວທີເວັບໄຊຕ໌ທີ່ມີຄວາມຄິດສ້າງສັນເລັກນ້ອຍໃນ CSS Cascade Layers. ເຄື່ອງມືທີ່ຂ້າພະເຈົ້າພຽງແຕ່ອະທິບາຍທັງຫມົດແມ່ນ open-source. ທ່ານສາມາດ clone repo GitHub ແລະລອງມັນດ້ວຍຕົວທ່ານເອງ. ແຕ່ສໍາຄັນກວ່ານັ້ນ, ທ່ານສາມາດເຮັດໃຫ້ມັນເປັນຂອງຕົນເອງ. ເພີ່ມຊັ້ນຂໍ້ມູນຂອງທ່ານເອງ. ສ້າງເຫດຜົນ replay ຂອງທ່ານເອງ. ປະສົມປະສານມັນກັບຕົ້ນແບບເກມຂອງທ່ານ. ຫຼືແມ້ກະທັ້ງໃຊ້ມັນໃນວິທີທີ່ຂ້ອຍບໍ່ໄດ້ຈິນຕະນາການ. ສໍາລັບການສອນ, ການເຂົ້າເຖິງ, ຫຼືການວິເຄາະຂໍ້ມູນ. ໃນຕອນທ້າຍຂອງມື້, ນີ້ບໍ່ແມ່ນພຽງແຕ່ກ່ຽວກັບການ debugging gamepads. ມັນແມ່ນກ່ຽວກັບການສ່ອງແສງໃສ່ວັດສະດຸທີ່ເຊື່ອງໄວ້, ແລະໃຫ້ນັກພັດທະນາມີຄວາມໝັ້ນໃຈໃນການເຮັດວຽກກັບຮາດແວທີ່ເວັບຍັງບໍ່ຍອມຮັບຢ່າງເຕັມທີ່. ດັ່ງນັ້ນ, ສຽບຕົວຄວບຄຸມຂອງທ່ານ, ເປີດບັນນາທິການຂອງທ່ານ, ແລະເລີ່ມທົດລອງ. ທ່ານອາດຈະຕົກຕະລຶງໃນສິ່ງທີ່ຕົວທ່ອງເວັບແລະ CSS ຂອງທ່ານສາມາດເຮັດໄດ້ຢ່າງແທ້ຈິງ.