Když připojíte ovladač, mačkáte tlačítka, pohybujete páčkami, mačkáte spoušť… a jako vývojář nic z toho nevidíte. Prohlížeč to jistě sbírá, ale pokud nezaznamenáváte čísla do konzole, je to neviditelné. To je ta bolest hlavy s Gamepad API. Existuje už roky a je to vlastně docela silné. Můžete číst tlačítka, páčky, spouště, díla. Ale většina lidí se toho nedotkne. Proč? Protože neexistuje žádná zpětná vazba. Žádný panel ve vývojářských nástrojích. Žádný jasný způsob, jak zjistit, zda ovladač vůbec dělá to, co si myslíte. Je to jako létání naslepo. To mě dost štvalo, abych vytvořil malý nástroj: Gamepad Cascade Debugger. Namísto zírání na výstup konzoly získáte živý, interaktivní pohled na ovladač. Stiskněte něco a na obrazovce to reaguje. A s kaskádovými vrstvami CSS zůstávají styly uspořádané, takže je čistší ladit. V tomto příspěvku vám ukážu, proč je ladění řadičů taková bolest, jak to CSS pomáhá vyčistit a jak můžete vytvořit znovu použitelný vizuální ladicí program pro své vlastní projekty.

I když je všechny dokážete přihlásit, rychle skončíte s nečitelným spamem na konzole. Například: [0,0,1,0,0,0,5,0,...] [0,0,0,0,1,0,0,...] [0,0,1,0,0,0,0,...]

Můžete říct, jaké tlačítko bylo stisknuto? Možná, ale až po namáhání očí a vynechání pár vstupů. Takže ne, ladění není snadné, pokud jde o čtení vstupů. Problém 3: Nedostatek struktury I když dáte dohromady rychlý vizualizér, styly se mohou rychle zamotat. Výchozí, aktivní a ladicí stavy se mohou překrývat a bez jasné struktury se vaše CSS stane křehkým a těžko se rozšíří. Pomoci mohou kaskádové vrstvy CSS. Seskupují styly do „vrstev“, které jsou seřazeny podle priority, takže přestanete bojovat se specifičností a hádat: „Proč se můj styl ladění nezobrazuje?“ Místo toho si udržujete oddělené starosti:

Základna: Standardní, počáteční vzhled ovladače. Aktivní: Zvýraznění pro stisknutá tlačítka a posunuté páčky. Ladění: Překryvy pro vývojáře (např. číselné údaje, vodítka atd.).

Pokud bychom měli definovat vrstvy v CSS podle tohoto, měli bychom: /* od nejnižší po nejvyšší prioritu */ @layer base, active, debug;

@layer base { /* ... */ }

@layer active { /* ... */ }

@layer debug { /* ... */ }

Protože se každá vrstva skládá předvídatelně, vždy víte, která pravidla vyhrávají. Díky této předvídatelnosti je ladění nejen snazší, ale také zvládnutelné. Pokryli jsme problém (neviditelný, chaotický vstup) a přístup (vizuální debugger vytvořený pomocí kaskádových vrstev). Nyní si krok za krokem projdeme proces sestavení ladicího programu. Koncept Debuggeru Nejjednodušší způsob, jak zviditelnit skrytý vstup, je jednoduše jej nakreslit na obrazovku. To dělá tento debugger. Tlačítka, spouštěče a joysticky mají vizuální podobu.

Stiskněte A: Rozsvítí se kruh. Pošťouchnutí tyče: Kruh klouže. Stiskněte spoušť do poloviny: Pruh se naplní do poloviny.

Nyní se nedíváte na 0 a 1, ale ve skutečnosti sledujete, jak ovladač reaguje živě. Samozřejmě, jakmile začnete hromadit stavy jako výchozí, stisknuté, informace o ladění, možná dokonce režim nahrávání, CSS se začne zvětšovat a komplexněji. To je místo, kde se kaskádové vrstvy hodí. Zde je zkrácený příklad: @layer base { .button { pozadí: #222; hraniční rádius: 50 %; šířka: 40px; výška: 40px; } }

@layer active { .stisknuto.tlačítko { pozadí: #0f0; /* jasně zelená */ } }

@layer debug { .button::after { obsah: attr(data-hodnota); velikost písma: 12px; barva: #fff; } }

Na pořadí vrstev záleží: základ → aktivní → ladění.

základna kreslí ovladač. aktivní zpracovává stisknuté stavy. ladění hodí na překryvy.

Když to takhle rozbijete, znamená to, že nebojujete proti zvláštním válkám. Každá vrstva má své místo a vždy víte, co vyhrává. Budování It Out Nejprve dáme něco na obrazovku. Nemusí to vypadat dobře – jen musí existovat, abychom měli s čím pracovat.

Gamepad Cascade Debugger

A
B
X

Debugger není aktivní

To jsou doslova jen krabice. Zatím to není vzrušující, ale umožňuje nám to později uchopit pomocí CSS a JavaScriptu. Dobře, používám zde kaskádové vrstvy, protože to udržuje věci organizované, jakmile přidáte další stavy. Zde je drsný průchod:

/* ==================================== NASTAVENÍ KASKÁDOVÝCH VRSTVENÍ Na pořadí záleží: základ → aktivní → ladění ==================================== */

/* Definovat pořadí vrstev předem */ @layer base, active, debug;

/* Vrstva 1: Základní styly - výchozí vzhled */ @layer base { .button { pozadí: #333; hraniční rádius: 50 %; šířka: 70px; výška: 70px; displej: flex; justify-content: center; align-items: center; }

.pause { šířka: 20px; výška: 70px; pozadí: #333; displej: inline-block; } }

/* Vrstva 2: Aktivní stavy - zpracovává stisknutá tlačítka */ @layer active { .button.active { pozadí: #0f0; /* Jasně zelená při stisknutí */ transformace: měřítko(1.1); /* Mírně zvětší tlačítko */ }

.pause.active { pozadí: #0f0; transformace: scaleY(1.1); /* Při stisknutí se vertikálně roztáhne */ } }

/* Vrstva 3: Ladění překryvných vrstev – informace pro vývojáře */ @layer debug { .button::after { obsah: attr(data-hodnota); /* Zobrazí číselnou hodnotu */ velikost písma: 12px; barva: #fff; } }

Krása tohoto přístupu spočívá v tom, že každá vrstva má jasný účel. Základní vrstva nemůže nikdy přepsat aktivní a aktivní nikdy nemůže přepsat ladění, bez ohledu na specifičnost. To eliminuje války specifičnosti CSS, které obvykle sužují ladicí nástroje. Nyní to vypadá, že nějaké shluky sedí na tmavém pozadí. Upřímně, není to špatné.

Přidání JavaScriptu Čas JavaScriptu. Tady ovladač skutečně něco dělá. Toto vytvoříme krok za krokem. Krok 1: Nastavení správy stavu Nejprve potřebujeme proměnné ke sledování stavu ladicího programu: // ==================================== // VEDENÍ STÁTU // ====================================

nechat běžet = false; // Sleduje, zda je ladicí program aktivní nechat rafId; // Uloží ID requestAnimationFrame pro zrušení

Tyto proměnné řídí smyčku animace, která nepřetržitě čte vstup gamepadu. Krok 2: Získejte reference DOM Dále získáme odkazy na všechny prvky HTML, které budeme aktualizovat: // ==================================== // REFERENCE PRVKU 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"); const status = document.getElementById("status");

Ukládání těchto odkazů dopředu je efektivnější než opakované dotazování na DOM. Krok 3: Přidejte záložní klávesnici Pro testování bez fyzického ovladače namapujeme klávesy klávesnice na tlačítka: // ==================================== // KEYBOARD FALLBACK (pro testování bez ovladače) // ====================================

const keyMap = { "a": btnA, "b": btnB, "x": btnX, "p": [pause1, pause2] // Klávesa 'p' ovládá oba pruhy pauzy };

To nám umožňuje otestovat uživatelské rozhraní stisknutím kláves na klávesnici. Krok 4: Vytvořte hlavní aktualizační smyčku Tady se děje kouzlo. Tato funkce běží nepřetržitě a čte stav gamepadu: // ==================================== // HLAVNÍ SMYČKA AKTUALIZACÍ GAMEPADU // ====================================

function updateGamepad() { // Získejte všechny připojené gamepady const gamepads = navigator.getGamepads(); if (!gamepads) return;

// Použijte první připojený gamepad const gp = gamepady[0];

if (gp) { // Aktualizujte stavy tlačítka přepnutím třídy "aktivní". btnA.classList.toggle("aktivní", gp.tlačítka[0].stisknuto); btnB.classList.toggle("aktivní", gp.tlačítka[1].stisknuto); btnX.classList.toggle("aktivní", gp.tlačítka[2].stisknuto);

// Ovládejte tlačítko pauzy (index tlačítka 9 na většině ovladačů) const pauzaStisknuto = gp.tlačítka[9].stisknuto; pause1.classList.toggle("active", pausePressed); pause2.classList.toggle("aktivní", pausePressed);

// Vytvoří seznam aktuálně stisknutých tlačítek pro zobrazení stavu nechat stisknuto = []; gp.buttons.forEach((btn, i) => { pokud (btn.stisknuto)pressed.push("Tlačítko " + i); });

// Aktualizace textu stavu, pokud je stisknuto nějaké tlačítko if (stisknuta.délka > 0) { status.textContent = "Stisknuto: " + stisknuto.join(", "); } }

// Pokračujte ve smyčce, pokud je spuštěn debugger if (běh) { rafId = requestAnimationFrame(updateGamepad); } }

Metoda classList.toggle() přidá nebo odebere aktivní třídu podle toho, zda bylo stisknuto tlačítko, což spustí naše styly vrstev CSS. Krok 5: Zvládněte události klávesnice Tyto posluchače událostí umožňují fungování záložní klávesnice: // ==================================== // OVLÁDAČE AKCÍ NA KLÁVESNICE // ====================================

document.addEventListener("keydown", (e) => { if (keyMap[e.key]) { // Zpracování jednoho nebo více prvků if (Array.isArray(keyMap[e.key])) { keyMap[e.key].forEach(el => el.classList.add("aktivní")); } jinak { keyMap[e.key].classList.add("aktivní"); } status.textContent = "Stisknuta klávesa: " + e.key.toUpperCase(); } });

document.addEventListener("keyup", (e) => { if (keyMap[e.key]) { // Odebere aktivní stav při uvolnění klávesy if (Array.isArray(keyMap[e.key])) { keyMap[e.key].forEach(el => el.classList.remove("aktivní")); } jinak { keyMap[e.key].classList.remove("aktivní"); } status.textContent = "Klíč uvolněn: " + e.key.toUpperCase(); } });

Krok 6: Přidejte ovládání Start/Stop Nakonec potřebujeme způsob, jak debugger zapnout a vypnout: // ==================================== // ZAPNUTÍ/VYPNUTÍ DEBUGGERU // ====================================

document.getElementById("toggle").addEventListener("click", () => { běží = !běží; // Překlopení běžícího stavu

if (běh) { status.textContent = "Běží ladicí program..."; updateGamepad(); // Spustí aktualizační smyčku } jinak { status.textContent = "Debugger neaktivní"; cancelAnimationFrame(rafId); // Zastavení smyčky } });

Takže ano, stiskněte tlačítko a svítí. Zatlačte na páku a ona se pohne. to je vše. Ještě jedna věc: hrubé hodnoty. Někdy prostě chcete vidět čísla, ne světla.

V této fázi byste měli vidět:

Jednoduchý ovladač na obrazovce, Tlačítka, která reagují při interakci s nimi, a Volitelné ladění zobrazující indexy stisknutých tlačítek.

Aby to nebylo tak abstraktní, zde je rychlá ukázka ovladače na obrazovce, který reaguje v reálném čase:

Nyní stisknutím Spustit nahrávání zaznamenáte vše, dokud nestisknete tlačítko Zastavit nahrávání. 2. Export dat do CSV/JSON Jakmile budeme mít protokol, budeme ho chtít uložit.

Krok 1: Vytvořte pomocníka pro stahování Nejprve potřebujeme pomocnou funkci, která zvládne stahování souborů v prohlížeči: // ==================================== // POMOCNÍK PRO STAŽENÍ SOUBORU // ====================================

function downloadFile(název souboru, obsah, typ = "text/prostý") { // Vytvoří objekt blob z obsahu const blob = new Blob([obsah], { typ }); const url = URL.createObjectURL(blob);

// Vytvořte dočasný odkaz ke stažení a klikněte na něj const a = document.createElement("a"); a.href = url; a.download = název souboru; a.click();

// Po stažení vyčistí adresu URL objektu setTimeout(() => URL.revokeObjectURL(url), 100); }

Tato funkce funguje tak, že z vašich dat vytvoříte objekt Blob (binární velký objekt), vygenerujete pro něj dočasnou adresu URL a programově kliknete na odkaz ke stažení. Čištění zajišťuje, že nepropustíme paměť. Krok 2: Zvládněte export JSON JSON je ideální pro zachování kompletní datové struktury:

// ==================================== // EXPORTOVAT JAKO JSON // ====================================

document.getElementById("export-json").addEventListener("click", () => { // Zkontrolujte, zda je něco k exportu if (!frames.length) { console.warn("Žádný záznam není k dispozici pro export."); návrat; }

// Vytvořte datovou část s metadaty a snímky const payload = { createdAt: new Date().toISOString(), rámy };

// Stáhnout ve formátu JSON stáhnout soubor( "gamepad-log.json", JSON.stringify(payload, null, 2), "application/json" ); });

Formát JSON udržuje vše strukturované a snadno analyzovatelné, takže je ideální pro načítání zpět do vývojářských nástrojů nebo sdílení se spoluhráči. Krok 3: Zvládněte export CSV Pro exporty CSV potřebujeme sloučit hierarchická data do řádků a sloupců:

//==================================== // EXPORTOVAT JAKO CSV // ====================================

document.getElementById("export-csv").addEventListener("click", () => { // Zkontrolujte, zda je něco k exportu if (!frames.length) { console.warn("Žádný záznam není k dispozici pro export."); návrat; }

// Sestavení řádku záhlaví CSV (sloupce pro časové razítko, všechna tlačítka, všechny osy) const headerButtons = frames[0].buttons.map((_, i) => btn${i}); const headerAxes = snímky[0].axes.map((_, i) => axis${i}); const header = ["t", ...headerButtons, ...headerAxes].join(",") + "\n";

// Sestavení datových řádků CSV const rows = frames.map(f => { const btnVals = f.buttons.map(b => b.value); return [f.t, ...btnVals, ...f.axes].join(","); }).join("\n");

// Stáhnout jako CSV downloadFile("gamepad-log.csv", záhlaví + řádky, "text/csv"); });

CSV je skvělý pro analýzu dat, protože se otevírá přímo v Excelu nebo Tabulkách Google a umožňuje vizuálně vytvářet grafy, filtrovat data nebo rozpoznávat vzory. Nyní, když jsou tlačítka exportu vložena, uvidíte na panelu dvě nové možnosti: Exportovat JSON a Exportovat CSV. JSON je pěkný, pokud chcete hodit nezpracovaný protokol zpět do svých vývojářských nástrojů nebo se šťourat do struktury. Na druhou stranu CSV se otevírá přímo do Excelu nebo Tabulek Google, takže můžete vytvářet grafy, filtrovat nebo porovnávat vstupy. Následující obrázek ukazuje, jak panel vypadá s těmito doplňkovými ovládacími prvky.

3. Snapshot System Někdy nepotřebujete úplný záznam, jen rychlý „snímek obrazovky“ stavů vstupu. V tom pomáhá tlačítko Pořídit snímek.

A JavaScript:

// ==================================== // VYTVOŘTE SNÍMEK // ====================================

document.getElementById("snapshot").addEventListener("click", () => { // Získejte všechny připojené gamepady const pads = navigator.getGamepads(); const activePads = [];

// Projděte a zaznamenejte stav každého připojeného gamepadu for (const gp of pads) { if (!gp) pokračovat; // Přeskočí prázdné pozice

activePads.push({ id: gp.id, // název/model řadiče časové razítko: performance.now(), tlačítka: gp.buttons.map(b => ({ lisovaný: b.lisovaný, hodnota: b.hodnota })), osy: [...gp.axes] }); }

// Zkontrolujte, zda nebyly nalezeny nějaké gamepady if (!activePads.length) { console.warn("Pro snímek nejsou připojeny žádné gamepady."); alert("Nedetekován žádný ovladač!"); návrat; }

// Přihlaste se a upozorněte uživatele console.log("Snapshot:", activePads); alert(Snímek pořízen! Zachyceno ${activePads.length} ovladač(ů).); });

Snímky zmrazí přesný stav vašeho ovladače v jednom okamžiku. 4. Přehrání Ghost Input Nyní k té zábavě: přehrání vstupu duchů. To vezme záznam a přehraje jej vizuálně, jako kdyby ovladač používal fantomový hráč.

JavaScript pro přehrání: // ==================================== // PŘEHRÁVÁNÍ DUCHA // ====================================

document.getElementById("replay").addEventListener("click", () => { // Ujistěte se, že máme nahrávku k přehrání if (!frames.length) { alert("Žádný záznam k přehrání!"); návrat; }

console.log("Spouštění přehrávání duchů...");

// Časování stopy pro synchronizované přehrávání nech startTime = performance.now(); nech frameIndex = 0;

// Přehrání smyčky animace function step() { const now = performance.now(); const elapsed = now - startTime;

// Zpracujte všechny snímky, které se již měly vyskytnout while (frameIndex < frames.length && frames[frameIndex].t <= elapsed) { const frame = frames[frameIndex];

// Aktualizace uživatelského rozhraní se zaznamenanými stavy tlačítek btnA.classList.toggle("aktivní", frame.buttons[0].stisknuto); btnB.classList.toggle("aktivní", rám.tlačítka[1].stisknuto); btnX.classList.toggle("aktivní", rám.tlačítka[2].stisknuto);

// Aktualizace zobrazení stavu nechat stisknuto = []; frame.buttons.forEach((btn, i) => { if (btn.pressed) pressed.push("Button " + i); }); if (stisknuta.délka > 0) { status.textContent = "Duch: " + pressed.join(", "); }

frameIndex++; }

// Pokračujte ve smyčce, pokud existuje více snímků if (frameIndex < frames.length) { requestAnimationFrame(krok); } jinak { console.log("Přehrát znovuhotovo."); status.textContent = "Přehrávání dokončeno"; } }

// Spusťte přehrávání krok(); });

Aby bylo ladění trochu více praktické, přidal jsem přehrání duchů. Jakmile nahrajete relaci, můžete stisknout Replay a sledovat, jak to uživatelské rozhraní hraje, téměř jako fantomový hráč spouští pad. Za tímto účelem se na panelu zobrazí nové tlačítko Replay Ghost.

Stiskněte Record, trochu se pohrajte s ovladačem, zastavte se a poté znovu přehrajte. Uživatelské rozhraní prostě odráží vše, co jste udělali, jako duch sledující vaše vstupy. Proč se obtěžovat těmito doplňky?

Záznam/export usnadňuje testerům ukázat, co se přesně stalo. Snímky na okamžik zamrznou, což je velmi užitečné, když honíte podivné brouky. Přehrávání Ghost je skvělé pro tutoriály, kontroly přístupnosti nebo jen pro porovnání nastavení ovládání vedle sebe.

V tuto chvíli už to není jen úhledné demo, ale něco, co byste mohli skutečně uvést do provozu. Případy použití v reálném světě Nyní máme tento debugger, který toho dokáže hodně. Zobrazuje živé vstupy, zaznamenává protokoly, exportuje je a dokonce přehrává věci. Ale skutečná otázka zní: koho to vlastně zajímá? Pro koho je to užitečné? Vývojáři her Řadiče jsou součástí práce, ale ladit je? Obvykle bolest. Představte si, že testujete kombinovanou bojovou hru, například ↓ → + úder. Místo modlitby jste to dvakrát stiskli stejným způsobem, jednou to nahráli a přehráli. Hotovo. Nebo si vyměníte protokoly JSON se spoluhráčem, abyste zkontrolovali, zda váš kód pro více hráčů na jejich počítači reaguje stejně. To je obrovské. Odborníci na přístupnost Tento je mému srdci blízký. Ne každý hraje se „standardním“ ovladačem. Adaptivní ovladače občas vydávají divné signály. Pomocí tohoto nástroje můžete přesně vidět, co se děje. Učitelé, výzkumníci, kdokoli. Mohou uchopit protokoly, porovnat je nebo přehrát vstupy vedle sebe. Najednou se neviditelné věci stanou jasnými. Testování kvality Testeři obvykle píší poznámky jako „zde jsem rozmačkal tlačítka a rozbilo se to“. Není moc užitečné. Teď? Mohou zachytit přesné lisy, exportovat protokol a odeslat jej. Žádné hádání. Pedagogové Pokud vytváříte návody nebo videa na YouTube, přehrávání duchů je zlato. Můžete doslova říci: „Tady jsem udělal s ovladačem“, zatímco uživatelské rozhraní ukazuje, že se to děje. Dělá vysvětlení mnohem jasnější. Beyond Games A ano, není to jen o hrách. Lidé používají ovladače pro roboty, umělecké projekty a rozhraní pro usnadnění. Pokaždé stejný problém: co prohlížeč vlastně vidí? Díky tomu nemusíte hádat. Závěr Ladění vstupu ovladače mi vždy připadalo jako létání naslepo. Na rozdíl od DOM nebo CSS zde není žádný vestavěný inspektor pro gamepady; jsou to jen hrubá čísla v konzoli, která se snadno ztratí v hluku. S několika stovkami řádků HTML, CSS a JavaScript jsme vytvořili něco jiného:

Vizuální debugger, který zviditelní neviditelné vstupy. Vrstvený CSS systém, který udržuje uživatelské rozhraní čisté a laditelné. Sada vylepšení (nahrávání, export, snímky, přehrávání duchů), které jej povyšují z dema na vývojářský nástroj.

Tento projekt ukazuje, jak daleko můžete zajít smícháním výkonu webové platformy s trochou kreativity v kaskádových vrstvách CSS. Nástroj, který jsem právě vysvětlil, je open-source. Můžete naklonovat úložiště GitHub a vyzkoušet si to sami. Ale co je důležitější, můžete si to udělat sami. Přidejte své vlastní vrstvy. Vytvořte si vlastní logiku přehrávání. Integrujte jej do svého herního prototypu. Nebo ho dokonce použít způsoby, které jsem si nepředstavoval. Pro výuku, dostupnost nebo analýzu dat. Na konci dne to není jen o ladění gamepadů. Jde o to posvítit si na skryté vstupy a dát vývojářům sebevědomí při práci s hardwarem, který web stále plně nepodporuje. Takže zapojte ovladač, otevřete editor a začněte experimentovat. Možná budete překvapeni, co váš prohlížeč a vaše CSS skutečně dokážou.

You May Also Like

Enjoyed This Article?

Get weekly tips on growing your audience and monetizing your content — straight to your inbox.

No spam. Join 138,000+ creators. Unsubscribe anytime.

Create Your Free Bio Page

Join 138,000+ creators on Seemless.

Get Started Free