Lè ou ploge yon kontwolè, ou kraze bouton, deplase baton yo, rale deklannche yo ... epi kòm yon pwomotè, ou pa wè okenn nan li. Navigatè a ap chèche li, asire w, men sof si w ap antre nimewo nan konsole a, li envizib. Sa a tèt fè mal ak Gamepad API a. Li te alantou pou ane, epi li aktyèlman trè pwisan. Ou ka li bouton, baton, deklanche, travay yo. Men, pifò moun pa manyen li. Poukisa? Paske pa gen okenn fidbak. Pa gen panèl nan zouti devlopè. Pa gen yon fason klè pou konnen si kontwolè a menm ap fè sa ou panse. Li santi tankou vole avèg. Sa te boulvèse m ase pou konstwi yon ti zouti: Gamepad Cascade Debugger. Olye pou yo fikse sou pwodiksyon konsole, ou jwenn yon vi, entèaktif gade nan kontwolè a. Peze yon bagay epi li reyaji sou ekran an. Ak CSS Cascade Layers, estil yo rete òganize, kidonk li pi pwòp pou debogaj. Nan pòs sa a, mwen pral montre w poukisa kontwolè debogaj yo se yon doulè konsa, ki jan CSS ede netwaye li, ak ki jan ou ka bati yon debogaj vizyèl ki kapab itilize ankò pou pwòp pwojè ou yo.
Menm si ou kapab konekte yo tout, ou pral byen vit fini ak spam konsole ki pa lizib. Pou egzanp: [0,0,1,0,0,0.5,0,...] [0,0,0,0,1,0,0,...] [0,0,1,0,0,0,0,...]
Èske ou ka di ki bouton yo te peze? Petèt, men se sèlman apre w fin fatige je ou epi ou manke kèk entrées. Se konsa, non, debogaj pa rive fasil lè li rive lekti entrées. Pwoblèm 3: Mank Estrikti Menm si ou jete ansanm yon visualizer rapid, estil yo ka byen vit vin sal. Eta defo, aktif, ak debug ka sipèpoze, epi san yon estrikti klè, CSS ou vin frajil ak difisil pou pwolonje. CSS Cascade Layers ka ede. Yo gwoupe estil yo an "kouch" ki bay lòd pa priyorite, kidonk ou sispann goumen espesifik ak devine, "Poukisa style debug mwen an pa montre?" Olye de sa, ou kenbe enkyetid separe:
Baz: estanda kontwolè a, premye aparans. Aktif: Pwen esansyèl pou bouton bourade ak baton deplase. Debug: Superpositions pou devlopè (egzanp, lekti nimerik, gid, ak sou sa).
Si nou ta defini kouch nan CSS dapre sa a, nou ta genyen: /* pi ba a pi gwo priyorite */ @layer baz, aktif, debug;
@kouch baz { /* ... */ }
@kouch aktif { /* ... */ }
@kouch debug { /* ... */ }
Paske chak kouch anpile yon fason previzib, ou toujou konnen ki règ genyen. Previzibilite sa a fè debogaj pa sèlman pi fasil, men aktyèlman jere. Nou te kouvri pwoblèm nan (envizib, opinyon sal) ak apwòch la (yon debugger vizyèl bati ak Cascade Layers). Koulye a, nou pral mache nan pwosesis etap pa etap yo bati debogaj la. Konsèp debogaj la Fason ki pi fasil pou fè opinyon kache vizib se jis trase li sou ekran an. Se sa deboge sa a fè. Bouton, deklannche, ak joysticks tout jwenn yon vizyèl.
Peze A: Yon sèk limen. Bouche baton an: Sèk la glise alantou. Rale yon deklanche mwatye: Yon ba ranpli mwatye.
Koulye a, ou pa ap fikse nan 0s ak 1s, men aktyèlman ap gade kontwolè a reyaji ap viv. Natirèlman, yon fwa ou kòmanse anpile sou eta tankou default, bourade, enfòmasyon debug, petèt menm yon mòd anrejistreman, CSS la kòmanse vin pi gwo ak pi konplèks. Sa a kote kouch kaskad vini an sou la men. Isit la se yon egzanp dezabiye: @kouch baz { .bouton { background: #222; fwontyè-reyon: 50%; lajè: 40px; wotè: 40px; } }
@kouch aktif { .bouton.peze { background: #0f0; /* vèt klere */ } }
@kouch debug { .bouton::apre { kontni: attr (done-valè); font-size: 12px; koulè: #fff; } }
Lòd kouch la enpòtan: baz → aktif → debug.
baz trase kontwolè a. aktif okipe eta bourade. debug lanse sou superpositions.
Kraze li tankou sa a vle di ou pa ap goumen lagè spesifik etranj. Chak kouch gen plas li, epi ou toujou konnen sa ki genyen. Bati li soti Ann jwenn yon bagay sou ekran an premye. Li pa bezwen gade byen - jis bezwen egziste pou nou gen yon bagay pou travay avèk.
Gamepad Cascade Debugger
Sa a se literalman jis bwat. Pa enteresan ankò, men li ban nou manch yo pwan pita ak CSS ak JavaScript. Oke, mwen itilize kouch kaskad isit la paske li kenbe bagay yo òganize yon fwa ou ajoute plis eta. Isit la se yon pas ki graj:
/* ==================================== ENFÒMASYON KOCH KASkad Lòd zafè: baz → aktif → debug ==================================== */
/* Defini lòd kouch davans */ @layer baz, aktif, debug;
/* Kouch 1: Styles baz - aparans default */ @kouch baz { .bouton { background: #333; fwontyè-reyon: 50%; lajè: 70px; wotè: 70px; ekspozisyon: flex; jistifye-kontni: sant; aliman-atik: sant; }
.poz { lajè: 20px; wotè: 70px; background: #333; ekspozisyon: inline-blòk; } }
/* Kouch 2: Eta aktif - okipe bouton bourade */ @kouch aktif { .bouton.active { background: #0f0; /* Vèt klere lè w peze */ transfòme: echèl(1.1); /* Yon ti kras elaji bouton an */ }
.pause.active { background: #0f0; transfòme: scaleY(1.1); /* Detire vètikal lè w peze */ } }
/* Kouch 3: Debug superpositions - enfòmasyon sou pwomotè */ @kouch debug { .bouton::apre { kontni: attr (done-valè); /* Montre valè nimerik la */ font-size: 12px; koulè: #fff; } }
Bote apwòch sa a se ke chak kouch gen yon objektif klè. Kouch debaz la pa janm ka pase sou desizyon aktif, ak aktif pa janm ka pase sou desizyon debug, kèlkeswa espesifik. Sa a elimine lagè spesifik CSS ki anjeneral malfezan zouti debogaj. Koulye a, li sanble ke kèk grap yo chita sou yon background nwa. Onètman, pa twò mal.
Ajoute JavaScript la JavaScript tan. Sa a se kote kontwolè a aktyèlman fè yon bagay. Nou pral bati etap sa a pa etap. Etap 1: Mete kanpe Jesyon Eta a Premyèman, nou bezwen varyab pou swiv eta debogaj la: // ==================================== // JESYON LETA // ====================================
kite kouri = fo; // Tracks si debogaj la aktif kite rafId; // Sere ID demannAnimationFrame pou anile
Varyab sa yo kontwole bouk animasyon ki kontinyèlman li opinyon gamepad. Etap 2: Gen tan pwan referans DOM Apre sa, nou jwenn referans a tout eleman HTML nou pral mete ajou: // ==================================== // REFERANS ELEMAN DOM // ====================================
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"); estati const = document.getElementById("estati");
Sere referans sa yo davans pi efikas pase demann DOM a repete. Etap 3: Ajoute Klavye Fallback Pou tès san yon kontwolè fizik, nou pral kat klavye kle nan bouton: // ==================================== // KEYBOARD FALLBACK (pou tès san yon kontwolè) // ====================================
const keyMap = { "yon": btnA, "b": btnB, "x": btnX, "p": [pause1, pause2] // 'p' kle kontwole tou de ba poz };
Sa a pèmèt nou teste UI a lè nou peze kle sou yon klavye. Etap 4: Kreye Bouk Mizajou prensipal la Men kote majik la rive. Fonksyon sa a kouri kontinyèlman epi li eta gamepad: // ==================================== // PRINCIPAL GAMEPAD UPDATE LOOP // ====================================
fonksyon updateGamepad () { // Jwenn tout gamepads ki konekte yo const gamepads = navigator.getGamepads(); si (!gamepads) retounen;
// Sèvi ak premye gamepad ki konekte const gp = gamepads[0];
si (gp) { // Mizajou bouton eta yo lè w chanje klas "aktif". btnA.classList.toggle ("aktif", gp.buttons[0].pressed); btnB.classList.toggle ("aktif", gp.buttons[1].pressed); btnX.classList.toggle("aktif", gp.buttons[2].pressed);
// Manyen bouton poz (bouton endèks 9 sou pifò contrôleur) const pausePressed = gp.buttons[9].pressed; pause1.classList.toggle("aktif", pausePressed); pause2.classList.toggle("aktif", pausePressed);
// Bati yon lis bouton kounye a peze pou ekspozisyon estati a kite peze = []; gp.buttons.forEach((btn, i) => { si (btn.pressed)pressed.push ("Bouton " + i); });
// Mete ajou tèks estati si nenpòt bouton yo peze if (pressed.length > 0) { status.textContent = "Prese: " + pressed.join(", "); } }
// Kontinye bouk la si debugger ap kouri si (kouri) { rafId = requestAnimationFrame(actualizeGamepad); } }
Metòd classList.toggle() ajoute oswa retire klas aktif la ki baze sou si bouton an peze, ki deklannche estil kouch CSS nou an. Etap 5: Manyen Evènman Klavye Oditè evènman sa yo fè sekou klavye a travay: // ==================================== // KLAVYE EVENMAN HANDERERS // ====================================
document.addEventListener("keydown", (e) => { si (keyMap[e.key]) { // Manyen yon sèl oswa plizyè eleman si (Array.isArray(keyMap[e.key])) { keyMap[e.key].forEach(el => el.classList.add("aktif")); } lòt bagay { keyMap[e.key].classList.add("aktif"); } status.textContent = "Kle peze: " + e.key.toUpperCase (); } });
document.addEventListener("keyup", (e) => { si (keyMap[e.key]) { // Retire eta aktif lè yo lage kle si (Array.isArray(keyMap[e.key])) { keyMap[e.key].forEach(el => el.classList.remove("aktif")); } lòt bagay { keyMap[e.key].classList.remove("aktif"); } status.textContent = "Kle lage: " + e.key.toUpperCase(); } });
Etap 6: Ajoute Start/Stop Kontwòl Finalman, nou bezwen yon fason pou aktive debugger la ak sou: // ==================================== // DEBUGGER ON/OFF // ====================================
document.getElementById ("toggle").addEventListener ("klike", () => { kouri = !kouri; // Flip eta kouri a
si (kouri) { status.textContent = "Deboge ap kouri..."; updateGamepad(); // Kòmanse bouk aktyalizasyon an } lòt bagay { status.textContent = "Deboge inaktif"; cancelAnimationFrame(rafId); // Sispann bouk la } });
Se konsa, wi, peze yon bouton epi li klere. Pouse baton an epi li deplase. Se sa. Yon lòt bagay: valè kri. Pafwa ou jis vle wè nimewo, pa limyè.
Nan etap sa a, ou ta dwe wè:
Yon senp kontwolè sou ekran, Bouton ki reyaji pandan w ap kominike avèk yo, epi Yon lekti debug si ou vle ki montre endis bouton peze yo.
Pou fè sa a mwens abstrè, isit la nan yon demonstrasyon rapid nan kontwolè sou ekran an reyaji an tan reyèl:
Koulye a, peze Start Recording journal tout bagay jiskaske ou frape Stop Recording. 2. Ekspòte Done nan CSV/JSON Yon fwa nou gen yon boutèy demi lit, nou pral vle sove li.
Etap 1: Kreye Èd Download la Premyèman, nou bezwen yon fonksyon asistan ki okipe telechaje dosye nan navigatè a: // ==================================== // DOSYE DOWNLOAD HELPER // ====================================
fonksyon downloadFile (non fichye, kontni, kalite = "tèks/plenn") { // Kreye yon blob nan kontni an const blob = nouvo blob([kontni], {tip}); const url = URL.createObjectURL (blob);
// Kreye yon lyen telechaje tanporè epi klike sou li const a = document.createElement ("a"); a.href = url; a.download = non fichye; a.klike ();
// Netwaye URL objè a apre telechaje setTimeout(() => URL.revokeObjectURL(url), 100); }
Fonksyon sa a travay lè li kreye yon Blob (binè gwo objè) apati done ou yo, jenere yon URL tanporè pou li, epi klike sou yon lyen download. Netwayaj la asire nou pa koule memwa. Etap 2: Manyen ekspòtasyon JSON JSON pafè pou konsève estrikti done konplè:
// ==================================== // Ekspòtasyon kòm JSON // ====================================
document.getElementById("export-json").addEventListener("klike", () => { // Tcheke si gen anyen pou ekspòte if (!frames.length) { console.warn("Pa gen okenn anrejistreman ki disponib pou ekspòte."); retounen; }
// Kreye yon chaj ak metadata ak ankadreman chaj konstan = { createdAt: new Date().toISOString(), ankadreman };
// Telechaje kòm fòma JSON downloadFile( "gamepad-log.json", JSON.stringify (chaj, nil, 2), "aplikasyon/json" ); });
Fòma JSON a kenbe tout bagay estriktire ak fasil analize, sa ki fè li ideyal pou chaje tounen nan zouti dev oswa pataje ak koekipye. Etap 3: Manch CSV ekspòtasyon Pou ekspòtasyon CSV, nou bezwen plati done yo yerarchize nan ranje ak kolòn:
//===================================== // Ekspòtasyon kòm CSV // ====================================
document.getElementById("export-csv").addEventListener("klike", () => { // Tcheke si gen anyen pou ekspòte if (!frames.length) { console.warn("Pa gen okenn anrejistreman ki disponib pou ekspòte."); retounen; }
// Bati ranje header CSV (kolòn pou timestamp, tout bouton, tout aks) const headerButtons = ankadreman[0].buttons.map((_, i) => btn${i}); const headerAxes = ankadreman[0].axes.map((_, i) => aks${i}); const header = ["t", ...headerButtons, ...headerAxes].join(",") + "\n";
// Bati ranje done CSV konst ranje = frames.map (f => { const btnVals = f.buttons.map(b => b.value); retounen [f.t, ...btnVals, ...f.axes].join(","); }).join ("\n");
// Telechaje kòm CSV downloadFile("gamepad-log.csv", header + ranje, "tèks/csv"); });
CSV se briyan pou analiz done paske li louvri dirèkteman nan Excel oswa Google Sheets, ki pèmèt ou kreye tablo, filtre done, oswa modèl tach vizyèlman. Kounye a ke bouton ekspòtasyon yo nan, ou pral wè de nouvo opsyon sou panèl la: Export JSON ak Export CSV. JSON se bèl si ou vle voye jete anvan tout koreksyon boutèy la tounen nan zouti dev ou oswa pike nan estrikti a. CSV, nan lòt men an, ouvè tou dwat nan Excel oswa Google Sheets pou ou ka fè tablo, filtre, oswa konpare entrées. Figi sa a montre ki jan panèl la sanble ak kontwòl siplemantè sa yo.
3. Sistèm Snapshot Pafwa ou pa bezwen yon anrejistreman konplè, jis yon "ekran" rapid nan eta opinyon yo. Se la yon bouton Pran Snapshot ede.
Ak JavaScript la:
// ==================================== // PRAN SNAPSHOT // ====================================
document.getElementById("snapshot").addEventListener("klike", () => { // Jwenn tout gamepads ki konekte yo const pads = navigator.getGamepads (); const activePads = [];
// Boukle epi pran eta chak gamepad ki konekte pou (konst gp nan kousinen) { si (!gp) kontinye; // Sote fant vid yo
activePads.push({ id: gp.id, // Non/modèl kontwolè timestamp: performance.now (), bouton: gp.buttons.map(b => ({ bourade: b.pressed, valè: b.valè })), aks: [...gp.axes] }); }
// Tcheke si yo te jwenn nenpòt gamepad si (!activePads.length) { console.warn("Pa gen okenn gamepad ki konekte pou snapshot."); alert ("Okenn kontwolè pa detekte!"); retounen; }
// Log epi notifye itilizatè console.log("Snapshot:", activePads); alèt(Snapshot te pran! Te kaptire ${activePads.length} kontwolè(yo).); });
Snapshots jele eta egzak kontwolè w la nan yon moman nan tan. 4. Fantom Antre Replay Koulye a, pou yon sèl la plezi: fantom opinyon reparèt. Sa a pran yon boutèy demi lit ak jwe li tounen vizyèlman tankou si yon jwè fantom te itilize kontwolè a.
JavaScript pou repete: // ==================================== // REPLAY GHOST // ====================================
document.getElementById("replay").addEventListener("klike", () => { // Asire nou gen yon anrejistreman pou nou rejoue if (!frames.length) { alert("Pa gen anrejistreman pou rejouer!"); retounen; }
console.log("Kòmanse reparèt fantom...");
// Track distribisyon pou lektur senkronize kite startTime = performance.now (); kite frameIndex = 0;
// Rejou bouk animasyon etap fonksyon () { const kounye a = performance.now (); const elapsed = kounye a - startTime;
// Pwosesis tout ankadreman ki ta dwe rive kounye a pandan (frameIndex < frames.length && frames[frameIndex].t <= pase) { konst ankadreman = ankadreman [frameIndex];
// Mete ajou UI ak eta bouton anrejistre yo btnA.classList.toggle("aktif", frame.buttons[0].pressed); btnB.classList.toggle("aktif", frame.buttons[1].pressed); btnX.classList.toggle("aktif", frame.buttons[2].pressed);
// Mete ajou ekspozisyon estati kite peze = []; frame.buttons.forEach((btn, i) => { si (btn.pressed) pressed.push ("Bouton " + i); }); if (pressed.length > 0) { status.textContent = "Fantom: " + pressed.join(", "); }
frameIndex++; }
// Kontinye bouk si gen plis ankadreman if (frameIndex < frames.length) { demandAnimationFrame(etap); } lòt bagay { console.log("Rejouerfini."); status.textContent = "Replay konplè"; } }
// Kòmanse reparèt la etap(); });
Pou fè debogaj yon ti jan plis pratik, mwen te ajoute yon reparèt fantom. Yon fwa ou te anrejistre yon sesyon, ou ka frape repete epi gade UI a aji, prèske tankou yon jwè fantom ap kouri pad la. Yon nouvo bouton Replay Ghost parèt nan panèl la pou sa.
Frape Dosye, dezòd ak kontwolè a yon ti jan, sispann, Lè sa a, repete. UI a jis eko tout sa ou te fè, tankou yon fantom ki swiv opinyon ou yo. Poukisa deranje ak siplemantè sa yo?
Anrejistreman/ekspòtasyon fè li fasil pou tèsteur yo montre egzakteman sa ki te pase. Snapshots friz yon ti moman nan tan, trè itil lè w ap kouri dèyè pinèz enpè. Replay Ghost se gwo pou leson patikilye, chèk aksè, oswa jis konpare konfigirasyon kontwòl kòt a kòt.
Nan pwen sa a, li pa jis yon Demo pwòp ankò, men yon bagay ou ta ka aktyèlman mete nan travay. Ka itilize nan mond reyèl la Koulye a, nou te gen debogaj sa a ki ka fè anpil. Li montre opinyon ap viv, anrejistre mòso bwa, ekspòte yo, e menm rejoue bagay. Men, vrè kesyon an se: ki moun ki aktyèlman sousye? Pou ki moun sa a itil? Devlopè jwèt Kontwolè yo fè pati travay la, men debogaj yo? Anjeneral yon doulè. Imajine w ap teste yon konbo jwèt batay, tankou ↓ → + kout pyen. Olye pou w priye, ou peze li menm jan an de fwa, ou anrejistre li yon fwa, epi rejoue li. Fè. Oswa ou chanje mòso bwa JSON ak yon koekipye pou tcheke si kòd multijoueurs ou reyaji menm jan an sou machin yo. Sa gwo. Praktisyonè aksesiblite Yon sèl sa a pre nan kè m '. Se pa tout moun jwe ak yon kontwolè "estanda". Kontwolè adaptatif voye jete siyal etranj pafwa. Avèk zouti sa a, ou ka wè egzakteman sa k ap pase. Pwofesè, chèchè, nenpòt moun. Yo ka pwan mòso bwa, konpare yo, oswa rejouer entrain kòt a kòt. Menm lè a, bagay envizib vin evidan. Tès Asirans Kalite Testatè yo anjeneral ekri nòt tankou "Mwen kraze bouton isit la epi li kraze." Pa trè itil. Kounye a? Yo ka pran laprès egzak yo, ekspòte boutèy la, epi voye li. Pa gen devine. Edikatè Si w ap fè leson patikilye oswa videyo YouTube, replay fantom se lò. Ou ka literalman di, "Men sa mwen te fè ak kontwolè a," pandan y ap UI a montre sa k ap pase. Fè eksplikasyon yo pi klè. Pi lwen pase jwèt Epi wi, sa a se pa sèlman sou jwèt. Moun yo te itilize contrôleur pou robo, pwojè atizay, ak koòdone aksè. Menm pwoblèm chak fwa: ki sa navigatè a aktyèlman wè? Avèk sa a, ou pa bezwen devine. Konklizyon Debogaj yon opinyon kontwolè te toujou santi tankou vole avèg. Kontrèman ak DOM la oswa CSS, pa gen okenn enspektè bati-an pou gamepads; li jis nimewo anvan tout koreksyon nan konsole a, fasil pèdi nan bri a. Avèk kèk santèn liy HTML, CSS, ak JavaScript, nou bati yon bagay diferan:
Yon debogaj vizyèl ki fè entrain envizib vizib. Yon sistèm CSS kouch ki kenbe UI pwòp epi debogaj. Yon seri amelyorasyon (anrejistreman, ekspòte, snapshots, reparèt fantom) ki elve li soti nan Demo nan zouti pwomotè.
Pwojè sa a montre ki jan lwen ou ka ale nan melanje pouvwa Platfòm Entènèt la ak yon ti kreyativite nan CSS Cascade Layers. Zouti mwen jis eksplike nan antye li se sous louvri. Ou ka klonaj repo GitHub la epi eseye li pou tèt ou. Men, pi enpòtan an, ou ka fè li pwòp ou a. Ajoute kouch pwòp ou yo. Bati pwòp lojik reparèt ou. Entegre li ak pwototip jwèt ou a. Oswa menm sèvi ak li nan fason mwen pa te imajine. Pou ansèyman, aksè, oswa analiz done. Nan fen jounen an, sa a se pa sèlman sou debogaj gamepads. Li se sou klere yon limyè sou entrées kache, epi bay devlopè yo konfyans nan travay ak pyès ki nan konpitè ke entènèt la toujou pa konplètman anbrase. Se konsa, ploge kontwolè ou a, louvri editè ou a, epi kòmanse fè eksperyans. Ou ta ka sezi nan sa navigatè ou a ak CSS ou ka vrèman akonpli.