जब आप किसी कंट्रोलर को प्लग इन करते हैं, तो आप बटनों को मैश करते हैं, स्टिक को हिलाते हैं, ट्रिगर्स को खींचते हैं... और एक डेवलपर के रूप में, आपको इनमें से कुछ भी दिखाई नहीं देता है। ब्राउज़र इसे उठा रहा है, निश्चित रूप से, लेकिन जब तक आप कंसोल में नंबर लॉग नहीं कर रहे हैं, यह अदृश्य है। गेमपैड एपीआई के साथ यही सिरदर्द है। यह वर्षों से चला आ रहा है, और यह वास्तव में बहुत शक्तिशाली है। आप बटन, स्टिक, ट्रिगर, कार्य पढ़ सकते हैं। लेकिन ज्यादातर लोग इसे छूते नहीं हैं. क्यों? क्योंकि कोई प्रतिक्रिया नहीं है. डेवलपर टूल में कोई पैनल नहीं. यह जानने का कोई स्पष्ट तरीका नहीं है कि नियंत्रक वैसा ही कर रहा है जैसा आप सोचते हैं। ऐसा लगता है जैसे मैं अंधा होकर उड़ रहा हूँ। इसने मुझे एक छोटा टूल बनाने के लिए काफी परेशान किया: गेमपैड कैस्केड डिबगर। कंसोल आउटपुट को घूरने के बजाय, आपको नियंत्रक का एक लाइव, इंटरैक्टिव दृश्य मिलता है। कुछ भी दबाओ और वह स्क्रीन पर प्रतिक्रिया करता है। और सीएसएस कैस्केड लेयर्स के साथ, शैलियाँ व्यवस्थित रहती हैं, इसलिए डीबग करना अधिक आसान होता है। इस पोस्ट में, मैं आपको दिखाऊंगा कि नियंत्रकों को डिबग करना इतना कठिन क्यों है, सीएसएस इसे साफ़ करने में कैसे मदद करता है, और आप अपनी परियोजनाओं के लिए पुन: प्रयोज्य विज़ुअल डिबगर कैसे बना सकते हैं।
यहां तक कि अगर आप उन सभी को लॉग करने में सक्षम हैं, तो भी आप जल्द ही अपठनीय कंसोल स्पैम के साथ समाप्त हो जाएंगे। उदाहरण के लिए: [0,0,1,0,0,0.5,0,...] [0,0,0,0,1,0,0,...] [0,0,1,0,0,0,0,...]
क्या आप बता सकते हैं कि कौन सा बटन दबाया गया था? हो सकता है, लेकिन केवल अपनी आंखों पर दबाव डालने और कुछ इनपुट छूटने के बाद। तो, नहीं, जब इनपुट पढ़ने की बात आती है तो डिबगिंग आसानी से नहीं होती है। समस्या 3: संरचना का अभाव यहां तक कि अगर आप एक त्वरित विज़ुअलाइज़र को एक साथ रखते हैं, तो शैलियाँ जल्दी से गड़बड़ हो सकती हैं। डिफ़ॉल्ट, सक्रिय और डिबग स्थितियाँ ओवरलैप हो सकती हैं, और स्पष्ट संरचना के बिना, आपका सीएसएस भंगुर हो जाता है और विस्तार करना कठिन हो जाता है। सीएसएस कैस्केड परतें मदद कर सकती हैं। वे शैलियों को "परतों" में समूहित करते हैं जिन्हें प्राथमिकता के आधार पर क्रमबद्ध किया जाता है, इसलिए आप विशिष्टता से लड़ना और अनुमान लगाना बंद कर देते हैं, "मेरी डिबग शैली क्यों नहीं दिख रही है?" इसके बजाय, आप अलग-अलग चिंताएँ बनाए रखते हैं:
आधार: नियंत्रक का मानक, प्रारंभिक स्वरूप। सक्रिय: दबाए गए बटनों और हिलाई गई छड़ियों के लिए हाइलाइट्स। डिबग: डेवलपर्स के लिए ओवरले (जैसे, संख्यात्मक रीडआउट, गाइड, और इसी तरह)।
यदि हमें इसके अनुसार सीएसएस में परतों को परिभाषित करना होता, तो हमारे पास होता: /* निम्नतम से उच्चतम प्राथमिकता*/ @लेयर बेस, सक्रिय, डीबग;
@लेयर बेस { /* ... */ }
@लेयर सक्रिय { /* ... */ }
@लेयर डीबग { /* ... */ }
चूँकि प्रत्येक परत पूर्वानुमानित रूप से ढेर होती है, आप हमेशा जानते हैं कि कौन सा नियम जीतता है। वह पूर्वानुमेयता डिबगिंग को न केवल आसान बनाती है, बल्कि वास्तव में प्रबंधनीय भी बनाती है। हमने समस्या (अदृश्य, गन्दा इनपुट) और दृष्टिकोण (कैस्केड लेयर्स के साथ निर्मित एक दृश्य डिबगर) को कवर किया है। अब हम डिबगर बनाने के लिए चरण-दर-चरण प्रक्रिया से गुजरेंगे। डिबगर अवधारणा छिपे हुए इनपुट को दृश्यमान बनाने का सबसे आसान तरीका बस उसे स्क्रीन पर खींचना है। यह डिबगर यही करता है। बटन, ट्रिगर और जॉयस्टिक सभी को एक दृश्य मिलता है।
A दबाएँ: एक वृत्त जलता है। छड़ी को कुरेदें: घेरा चारों ओर सरकता है। ट्रिगर को आधा खींचें: एक बार आधा भर जाता है।
अब आप 0s और 1s को नहीं देख रहे हैं, बल्कि वास्तव में नियंत्रक की प्रतिक्रिया को लाइव देख रहे हैं। बेशक, एक बार जब आप डिफ़ॉल्ट, दबाए गए, डीबग जानकारी, शायद रिकॉर्डिंग मोड जैसी स्थितियों पर ढेर लगाना शुरू कर देते हैं, तो सीएसएस बड़ा और अधिक जटिल होना शुरू हो जाता है। यहीं पर कैस्केड परतें काम आती हैं। यहां एक अलग-थलग उदाहरण दिया गया है: @लेयर बेस { .बटन { पृष्ठभूमि: #222; सीमा-त्रिज्या: 50%; चौड़ाई: 40px; ऊंचाई: 40px; } }
@लेयर सक्रिय { .बटन.दबाया गया { पृष्ठभूमि: #0f0; /*चमकीला हरा*/ } }
@लेयर डीबग { .बटन::बाद में { सामग्री: attr(डेटा-मूल्य); फ़ॉन्ट-आकार: 12px; रंग: #fff; } }
परत क्रम मायने रखता है: आधार → सक्रिय → डीबग।
आधार नियंत्रक खींचता है. सक्रिय हैंडल दबाए गए राज्य। डिबग ओवरले पर फेंकता है।
इसे इस तरह से तोड़ने का मतलब है कि आप अजीब विशिष्टता वाले युद्ध नहीं लड़ रहे हैं। प्रत्येक परत का अपना स्थान है, और आप हमेशा जानते हैं कि क्या जीतता है। इसका निर्माण करना आइए पहले स्क्रीन पर कुछ देखें। इसे अच्छा दिखने की ज़रूरत नहीं है - बस अस्तित्व में रहने की ज़रूरत है ताकि हमारे पास काम करने के लिए कुछ हो।
गेमपैड कैस्केड डिबगर
<बटन आईडी='टॉगल'>डीबग टॉगल करेंबटन>
वह वस्तुतः सिर्फ बक्से हैं। अभी तक रोमांचक नहीं है, लेकिन यह हमें सीएसएस और जावास्क्रिप्ट के साथ बाद में पकड़ने के लिए हैंडल देता है। ठीक है, मैं यहां कैस्केड परतों का उपयोग कर रहा हूं क्योंकि एक बार जब आप अधिक राज्य जोड़ते हैं तो यह सामान को व्यवस्थित रखता है। यहाँ एक कठिन मार्ग है:
/* ================================== कैस्केड परतें सेटअप आदेश मायने रखता है: आधार → सक्रिय → डिबग =================================== */
/* परत क्रम को पहले से परिभाषित करें */ @लेयर बेस, सक्रिय, डीबग;
/* परत 1: आधार शैलियाँ - डिफ़ॉल्ट उपस्थिति */ @लेयर बेस { .बटन { पृष्ठभूमि: #333; सीमा-त्रिज्या: 50%; चौड़ाई: 70px; ऊंचाई: 70px; प्रदर्शन: फ्लेक्स; औचित्य-सामग्री: केंद्र; संरेखित-आइटम: केंद्र; }
.रोकें { चौड़ाई: 20px; ऊंचाई: 70px; पृष्ठभूमि: #333; प्रदर्शन: इनलाइन-ब्लॉक; } }
/* परत 2: सक्रिय अवस्थाएँ - दबाए गए बटनों को संभालता है */ @लेयर सक्रिय { .बटन.सक्रिय { पृष्ठभूमि: #0f0; /* दबाने पर चमकीला हरा */ परिवर्तन: स्केल(1.1); /*बटन को थोड़ा बड़ा करता है*/ }
.रोकें.सक्रिय { पृष्ठभूमि: #0f0; परिवर्तन: स्केलवाई(1.1); /* दबाने पर लंबवत खिंचता है */ } }
/* परत 3: डिबग ओवरले - डेवलपर जानकारी */ @लेयर डीबग { .बटन::बाद में { सामग्री: attr(डेटा-मूल्य); /* संख्यात्मक मान दिखाता है */ फ़ॉन्ट-आकार: 12px; रंग: #fff; } }
इस दृष्टिकोण की सुंदरता यह है कि प्रत्येक परत का एक स्पष्ट उद्देश्य होता है। आधार परत कभी भी सक्रिय को ओवरराइड नहीं कर सकती है, और विशिष्टता की परवाह किए बिना सक्रिय कभी भी डिबग को ओवरराइड नहीं कर सकता है। यह सीएसएस विशिष्टता युद्धों को समाप्त करता है जो आमतौर पर डिबगिंग टूल को परेशान करते हैं। अब ऐसा लग रहा है कि कुछ गुच्छे गहरे रंग की पृष्ठभूमि पर बैठे हैं। ईमानदारी से कहूं तो बहुत बुरा नहीं है.
जावास्क्रिप्ट जोड़ना जावास्क्रिप्ट समय. यहीं पर नियंत्रक वास्तव में कुछ करता है। हम इसे चरण दर चरण बनाएंगे. चरण 1: राज्य प्रबंधन स्थापित करें सबसे पहले, हमें डिबगर की स्थिति को ट्रैक करने के लिए वेरिएबल्स की आवश्यकता है: // ================================== // राज्य प्रबंधन // ==================================
चलने दो = मिथ्या; // ट्रैक करता है कि डिबगर सक्रिय है या नहीं चलो rafId; //रद्दीकरण के लिए requestAnimationFrame ID को संग्रहीत करता है
ये वेरिएबल एनीमेशन लूप को नियंत्रित करते हैं जो गेमपैड इनपुट को लगातार पढ़ता है। चरण 2: DOM संदर्भ पकड़ें इसके बाद, हमें उन सभी HTML तत्वों के संदर्भ मिलेंगे जिन्हें हम अपडेट करेंगे: // ================================== // डोम तत्व संदर्भ // ==================================
const btnA = document.getElementById('btn-a'); const btnB = document.getElementById('btn-b'); const btnX = document.getElementById('btn-x'); स्थिरांक ठहराव1 = document.getElementById("pause1"); स्थिरांक ठहराव2 = document.getElementById("pause2"); स्थिरांक स्थिति = document.getElementById('status');
DOM को बार-बार क्वेरी करने की तुलना में इन संदर्भों को सामने संग्रहीत करना अधिक कुशल है। चरण 3: कीबोर्ड फ़ॉलबैक जोड़ें भौतिक नियंत्रक के बिना परीक्षण के लिए, हम कीबोर्ड कुंजियों को बटनों पर मैप करेंगे: // ================================== //कीबोर्ड फ़ॉलबैक (नियंत्रक के बिना परीक्षण के लिए) // ==================================
स्थिरांक keyMap = { "ए": बीटीएनए, "बी": बीटीएनबी, "एक्स": बीटीएनएक्स, "पी": [पॉज़1, पॉज़2] // 'पी' कुंजी दोनों पॉज़ बार को नियंत्रित करती है };
यह हमें कीबोर्ड पर कुंजी दबाकर यूआई का परीक्षण करने देता है। चरण 4: मुख्य अपडेट लूप बनाएं यहीं पर जादू होता है। यह फ़ंक्शन लगातार चलता रहता है और गेमपैड स्थिति पढ़ता है: // ================================== // मुख्य गेमपैड अपडेट लूप // ==================================
फ़ंक्शन अपडेटगेमपैड() { // सभी कनेक्टेड गेमपैड प्राप्त करें कॉन्स्ट गेमपैड = नेविगेटर.गेटगेमपैड(); यदि (!गेमपैड) वापसी;
// पहले कनेक्टेड गेमपैड का उपयोग करें कॉन्स्ट जीपी = गेमपैड्स[0];
अगर (जीपी) { // "सक्रिय" वर्ग को टॉगल करके अपडेट बटन बताता है btnA.classList.toggle("सक्रिय", gp.buttons[0].pressed); btnB.classList.toggle("सक्रिय", gp.buttons[1].pressed); btnX.classList.toggle('active', gp.buttons[2].pressed);
// पॉज़ बटन को हैंडल करें (अधिकांश नियंत्रकों पर बटन इंडेक्स 9) कॉन्स पॉज़प्रेस्ड = जीपी.बटन[9].प्रेस्ड; पॉज़1.क्लासलिस्ट.टॉगल('सक्रिय', पॉज़प्रेस्ड); पॉज़2.क्लासलिस्ट.टॉगल('सक्रिय', पॉज़प्रेस्ड);
// स्थिति प्रदर्शन के लिए वर्तमान में दबाए गए बटनों की एक सूची बनाएं चलो दबाया = []; gp.buttons.forEach((btn, i) => { यदि (btn.दबाया गया)pressed.push('बटन' + i); });
// यदि कोई बटन दबाया जाता है तो स्थिति टेक्स्ट अपडेट करें यदि (दबाया गया लंबाई > 0) { status.textContent = "दबाया गया:" + दबाया गया.जुड़ा हुआ(", "); } }
// यदि डिबगर चल रहा है तो लूप जारी रखें अगर (चल रहा है) { rafId = requestAnimationFrame(updateGamepad); } }
क्लासलिस्ट.टॉगल() विधि बटन दबाए जाने के आधार पर सक्रिय क्लास को जोड़ती या हटाती है, जो हमारी सीएसएस परत शैलियों को ट्रिगर करती है। चरण 5: कीबोर्ड ईवेंट प्रबंधित करें ये इवेंट श्रोता कीबोर्ड को फ़ॉलबैक कार्य में लाते हैं: // ================================== //कीबोर्ड इवेंट हैंडलर // ==================================
document.addEventListener("कीडाउन", (ई) => { अगर (कीमैप[ई.की]) { // एकल या एकाधिक तत्वों को संभालें यदि (Array.isArray(keyMap[e.key])) { keyMap[e.key].forEach(el => el.classList.add("active")); }अन्यथा{ keyMap[e.key].classList.add("सक्रिय"); } status.textContent = "कुंजी दबाई गई:" + e.key.toUpperCase(); } });
document.addEventListener("keyup", (e) => { अगर (कीमैप[ई.की]) { // कुंजी जारी होने पर सक्रिय स्थिति हटा दें यदि (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: स्टार्ट/स्टॉप नियंत्रण जोड़ें अंत में, हमें डिबगर को चालू और बंद करने का एक तरीका चाहिए: // ================================== // डिबगर को चालू/बंद टॉगल करें // ==================================
document.getElementById("toggle").addEventListener("क्लिक करें", () => { दौड़ना = !दौड़ना; // चल रही स्थिति को पलटें
अगर (चल रहा है) { status.textContent = "डीबगर चल रहा है..."; अपडेटगेमपैड(); // अपडेट लूप प्रारंभ करें }अन्यथा{ status.textContent = "डीबगर निष्क्रिय"; cancelAnimationFrame(rafId); // लूप बंद करो } });
तो हाँ, एक बटन दबाएँ और यह चमक उठेगा। छड़ी को धक्का दो और वह चल जाती है। इतना ही। एक और बात: कच्चे मूल्य। कभी-कभी आप केवल संख्याएँ देखना चाहते हैं, रोशनी नहीं।
इस स्तर पर, आपको यह देखना चाहिए:
एक साधारण ऑन-स्क्रीन नियंत्रक, बटन जो आपके उनके साथ इंटरैक्ट करने पर प्रतिक्रिया करते हैं, और दबाए गए बटन सूचकांक दिखाने वाला एक वैकल्पिक डिबग रीडआउट।
इसे कम सारगर्भित बनाने के लिए, यहां वास्तविक समय में प्रतिक्रिया करने वाले ऑन-स्क्रीन नियंत्रक का एक त्वरित डेमो दिया गया है:
अब, स्टार्ट रिकॉर्डिंग दबाने से सब कुछ लॉग हो जाता है जब तक कि आप स्टॉप रिकॉर्डिंग नहीं दबा देते। 2. सीएसवी/जेएसओएन को डेटा निर्यात करना एक बार जब हमारे पास लॉग होगा, तो हम उसे सहेजना चाहेंगे।
चरण 1: डाउनलोड हेल्पर बनाएं सबसे पहले, हमें एक सहायक फ़ंक्शन की आवश्यकता है जो ब्राउज़र में फ़ाइल डाउनलोड को संभाल सके: // ================================== // फ़ाइल डाउनलोड सहायक // ==================================
फ़ंक्शन डाउनलोड फ़ाइल (फ़ाइल नाम, सामग्री, प्रकार = "पाठ/सादा") { // सामग्री से एक ब्लॉब बनाएं कॉन्स्ट ब्लॉब = नया ब्लॉब([सामग्री], { प्रकार }); स्थिरांक url = URL.createObjectURL(blob);
// एक अस्थायी डाउनलोड लिंक बनाएं और उस पर क्लिक करें const a = document.createElement("a"); a.href = यूआरएल; a.डाउनलोड = फ़ाइल नाम; ए.क्लिक();
// डाउनलोड के बाद ऑब्जेक्ट यूआरएल साफ़ करें setTimeout(() => URL.revokeObjectURL(url), 100); }
यह फ़ंक्शन आपके डेटा से एक ब्लॉब (बाइनरी बड़ी ऑब्जेक्ट) बनाकर, इसके लिए एक अस्थायी यूआरएल उत्पन्न करके और प्रोग्रामेटिक रूप से एक डाउनलोड लिंक पर क्लिक करके काम करता है। सफ़ाई सुनिश्चित करती है कि हम मेमोरी लीक न करें। चरण 2: JSON निर्यात संभालें JSON संपूर्ण डेटा संरचना को संरक्षित करने के लिए एकदम सही है:
// ================================== // JSON के रूप में निर्यात करें // ==================================
document.getElementById("export-json").addEventListener("क्लिक करें", () => { // जांचें कि क्या निर्यात करने के लिए कुछ है यदि (!frames.length) { कंसोल.चेतावनी ("निर्यात के लिए कोई रिकॉर्डिंग उपलब्ध नहीं है।"); वापसी; }
// मेटाडेटा और फ़्रेम के साथ एक पेलोड बनाएं स्थिरांक पेलोड = { createAt: नई तिथि().toISOString(), तख्ते };
// स्वरूपित JSON के रूप में डाउनलोड करें डाउनलोडफ़ाइल( "गेमपैड-लॉग.जेसन", JSON.stringify(पेलोड, शून्य, 2), "एप्लिकेशन/जेएसओएन" ); });
JSON प्रारूप हर चीज़ को संरचित और आसानी से पार्स करने योग्य रखता है, जो इसे डेव टूल में वापस लोड करने या टीम के साथियों के साथ साझा करने के लिए आदर्श बनाता है। चरण 3: सीएसवी निर्यात संभालें सीएसवी निर्यात के लिए, हमें पदानुक्रमित डेटा को पंक्तियों और स्तंभों में समतल करना होगा:
//================================== // सीएसवी के रूप में निर्यात करें // ==================================
document.getElementById('export-csv').addEventListener('click',() => { // जांचें कि क्या निर्यात करने के लिए कुछ है यदि (!frames.length) { कंसोल.चेतावनी ("निर्यात के लिए कोई रिकॉर्डिंग उपलब्ध नहीं है।"); वापसी; }
// सीएसवी हेडर पंक्ति बनाएं (टाइमस्टैम्प, सभी बटन, सभी अक्षों के लिए कॉलम) const हेडरबटन = फ़्रेम[0].बटन.मैप((_, i) => btn${i}); const हेडरएक्सेस = फ़्रेम[0].axes.map((_, i) => axis${i}); स्थिरांक शीर्षलेख = ["t", ...headerButtons, ...headerAxes].join(",") + "\n";
// सीएसवी डेटा पंक्तियां बनाएं स्थिरांक पंक्तियाँ = फ़्रेम.मैप(f => { const btnVals = f.buttons.map(b => b.value); वापसी [f.t, ...btnVals, ...f.axes].join(","); }).जुड़ें('\n');
// सीएसवी के रूप में डाउनलोड करें डाउनलोडफ़ाइल ("गेमपैड-लॉग.सीएसवी", हेडर + पंक्तियाँ, "टेक्स्ट/सीएसवी"); });
सीएसवी डेटा विश्लेषण के लिए शानदार है क्योंकि यह सीधे एक्सेल या गूगल शीट्स में खुलता है, जिससे आप चार्ट, फ़िल्टर डेटा या स्पॉट पैटर्न को विज़ुअली बना सकते हैं। अब जब निर्यात बटन आ गए हैं, तो आपको पैनल पर दो नए विकल्प दिखाई देंगे: निर्यात JSON और निर्यात CSV। यदि आप कच्चे लॉग को अपने डेव टूल्स में वापस फेंकना चाहते हैं या संरचना के चारों ओर पोक करना चाहते हैं तो JSON अच्छा है। दूसरी ओर, सीएसवी सीधे एक्सेल या गूगल शीट्स में खुलता है ताकि आप इनपुट को चार्ट, फ़िल्टर या तुलना कर सकें। निम्नलिखित चित्र दिखाता है कि उन अतिरिक्त नियंत्रणों के साथ पैनल कैसा दिखता है।
3. स्नैपशॉट प्रणाली कभी-कभी आपको पूर्ण रिकॉर्डिंग की आवश्यकता नहीं होती है, बस इनपुट स्थितियों का एक त्वरित "स्क्रीनशॉट" होता है। यहीं पर स्नैपशॉट लें बटन मदद करता है।
और जावास्क्रिप्ट:
// ================================== // स्नैपशॉट लें // ==================================
document.getElementById("स्नैपशॉट").addEventListener("क्लिक करें", () => { // सभी कनेक्टेड गेमपैड प्राप्त करें स्थिरांक पैड = नेविगेटर.getGamepads(); स्थिरांक सक्रियपैड = [];
// प्रत्येक कनेक्टेड गेमपैड की स्थिति को लूप करें और कैप्चर करें (पैड के स्थिरांक जीपी) के लिए { यदि (!gp) जारी रखें; // खाली स्लॉट छोड़ें
सक्रियपैड.पुश({ आईडी: gp.id, // नियंत्रक का नाम/मॉडल टाइमस्टैम्प: Performance.now(), बटन: gp.buttons.map(b => ({ दबाया गया: बी.दबाया गया, मूल्य: बी.मूल्य })), अक्ष: [...gp.axes] }); }
// जांचें कि क्या कोई गेमपैड मिला है यदि (!activePads.length) { कंसोल.चेतावनी('स्नैपशॉट के लिए कोई गेमपैड कनेक्ट नहीं है।'); चेतावनी ("कोई नियंत्रक नहीं मिला!"); वापसी; }
// लॉग इन करें और उपयोगकर्ता को सूचित करें कंसोल.लॉग ("स्नैपशॉट:", एक्टिवपैड); चेतावनी(स्नैपशॉट लिया गया! कैप्चर किया गया ${activePads.length} कंट्रोलर); });
स्नैपशॉट एक समय में आपके नियंत्रक की सटीक स्थिति को स्थिर कर देते हैं। 4. घोस्ट इनपुट रिप्ले अब मनोरंजन के लिए: भूत इनपुट रीप्ले। यह एक लॉग लेता है और इसे दृश्य रूप से प्ले करता है जैसे कि कोई फैंटम प्लेयर नियंत्रक का उपयोग कर रहा हो।
रीप्ले के लिए जावास्क्रिप्ट: // ================================== // भूत रिप्ले // ==================================
document.getElementById("replay").addEventListener("क्लिक करें", () => { //सुनिश्चित करें कि हमारे पास दोबारा चलाने के लिए रिकॉर्डिंग है यदि (!frames.length) { चेतावनी ("फिर से चलाने के लिए कोई रिकॉर्डिंग नहीं!"); वापसी; }
कंसोल.लॉग ("भूत रीप्ले शुरू हो रहा है...");
// सिंक किए गए प्लेबैक के लिए ट्रैक टाइमिंग चलो प्रारंभ समय = प्रदर्शन.अब(); चलो फ्रेमइंडेक्स = 0;
//एनिमेशन लूप दोबारा चलाएं फ़ंक्शन चरण() { अभी स्थिरांक = प्रदर्शन.अभी(); स्थिरांक बीत गया = अब - प्रारंभ समय;
// उन सभी फ़्रेमों को संसाधित करें जो अब तक घटित हो जाने चाहिए थे
जबकि (frameIndex // रिकॉर्ड किए गए बटन की स्थिति के साथ यूआई को अपडेट करें
btnA.classList.toggle("सक्रिय", फ़्रेम.बटन[0].दबाया हुआ);
btnB.classList.toggle("सक्रिय", फ़्रेम.बटन[1].दबाया हुआ);
btnX.classList.toggle("सक्रिय", फ़्रेम.बटन[2].दबाया हुआ); // अद्यतन स्थिति प्रदर्शन
चलो दबाया = [];
फ़्रेम.बटन.forEach((btn, i) => {
अगर (बीटीएन.दबाया गया) दबाया गया.पुश('बटन' + i);
});
यदि (दबाया गया लंबाई > 0) {
status.textContent = "भूत:" + pressed.join(", ");
} फ़्रेमइंडेक्स++;
} // यदि अधिक फ्रेम हैं तो लूप जारी रखें
यदि (frameIndex // रीप्ले प्रारंभ करें
चरण();
}); डिबगिंग को थोड़ा और व्यावहारिक बनाने के लिए, मैंने एक घोस्ट रीप्ले जोड़ा। एक बार जब आप एक सत्र रिकॉर्ड कर लेते हैं, तो आप रीप्ले पर क्लिक कर सकते हैं और यूआई को इसे क्रियान्वित होते हुए देख सकते हैं, लगभग उसी तरह जैसे कोई फैंटम प्लेयर पैड चला रहा हो। इसके लिए पैनल में एक नया रीप्ले घोस्ट बटन दिखाई देता है। रिकॉर्ड को हिट करें, कंट्रोलर के साथ थोड़ा गड़बड़ करें, रुकें, फिर दोबारा चलाएं। यूआई आपके द्वारा किए गए हर काम को प्रतिध्वनित करता है, जैसे कोई भूत आपके इनपुट का अनुसरण कर रहा हो।
इन अतिरिक्त सुविधाओं से परेशान क्यों? रिकॉर्डिंग/निर्यात से परीक्षकों के लिए यह दिखाना आसान हो जाता है कि वास्तव में क्या हुआ था।
स्नैपशॉट एक पल के लिए स्थिर हो जाते हैं, जब आप अजीब बग का पीछा कर रहे हों तो यह बहुत उपयोगी होता है।
घोस्ट रीप्ले ट्यूटोरियल, एक्सेसिबिलिटी जांच, या केवल नियंत्रण सेटअप की साथ-साथ तुलना करने के लिए बहुत अच्छा है। इस बिंदु पर, यह अब केवल एक साफ-सुथरा डेमो नहीं है, बल्कि कुछ ऐसा है जिसे आप वास्तव में काम में ला सकते हैं।
वास्तविक दुनिया में उपयोग के मामले
अब हमें यह डिबगर मिल गया है जो बहुत कुछ कर सकता है। यह लाइव इनपुट दिखाता है, लॉग रिकॉर्ड करता है, उन्हें निर्यात करता है और यहां तक कि सामान को दोबारा चलाता है। लेकिन असली सवाल यह है: वास्तव में परवाह किसे है? यह किसके लिए उपयोगी है?
गेम डेवलपर्स
नियंत्रक कार्य का हिस्सा हैं, लेकिन उन्हें डिबग करना? आमतौर पर दर्द. कल्पना कीजिए कि आप ↓ → + पंच जैसे फाइटिंग गेम कॉम्बो का परीक्षण कर रहे हैं। प्रार्थना करने के बजाय, आपने इसे उसी तरह दो बार दबाया, आप इसे एक बार रिकॉर्ड करते हैं, और इसे दोबारा चलाते हैं। हो गया. या आप यह जांचने के लिए कि क्या आपका मल्टीप्लेयर कोड उनकी मशीन पर समान प्रतिक्रिया करता है, JSON लॉग को टीम के साथी के साथ स्वैप करते हैं। वह बहुत बड़ा है.
अभिगम्यता अभ्यासकर्ता
यह मेरे दिल के करीब है। हर कोई "मानक" नियंत्रक के साथ नहीं खेलता। अनुकूली नियंत्रक कभी-कभी अजीब संकेत फेंकते हैं। इस टूल से, आप देख सकते हैं कि वास्तव में क्या हो रहा है। शिक्षक, शोधकर्ता, कोई भी। वे लॉग पकड़ सकते हैं, उनकी तुलना कर सकते हैं, या इनपुट को एक साथ दोबारा चला सकते हैं। अचानक, अदृश्य चीजें स्पष्ट हो जाती हैं।
गुणवत्ता आश्वासन परीक्षण
परीक्षक आमतौर पर ऐसे नोट लिखते हैं जैसे "मैंने यहां बटनों को मसला और वह टूट गए।" बहुत मददगार नहीं. अब? वे सटीक प्रेस कैप्चर कर सकते हैं, लॉग निर्यात कर सकते हैं और उसे भेज सकते हैं। कोई अनुमान नहीं.
शिक्षक
यदि आप ट्यूटोरियल या यूट्यूब वीडियो बना रहे हैं, तो भूत रीप्ले सुनहरा है। आप सचमुच कह सकते हैं, "मैंने नियंत्रक के साथ यह किया," जबकि यूआई ऐसा होते हुए दिखाता है। स्पष्टीकरण को अधिक स्पष्ट बनाता है।
खेलों से परे
और हाँ, यह केवल खेलों के बारे में नहीं है। लोगों ने रोबोट, कला परियोजनाओं और एक्सेसिबिलिटी इंटरफेस के लिए नियंत्रकों का उपयोग किया है। हर बार एक ही समस्या: ब्राउज़र वास्तव में क्या देख रहा है? इससे आपको अंदाजा लगाने की जरूरत नहीं पड़ेगी.
निष्कर्ष
नियंत्रक इनपुट को डीबग करना हमेशा अंधाधुंध उड़ान भरने जैसा महसूस होता है। DOM या CSS के विपरीत, गेमपैड के लिए कोई अंतर्निहित इंस्पेक्टर नहीं है; यह कंसोल में केवल अपरिष्कृत संख्याएँ हैं, जो आसानी से शोर में खो जाती हैं।
HTML, CSS और JavaScript की कुछ सौ पंक्तियों के साथ, हमने कुछ अलग बनाया: एक विज़ुअल डिबगर जो अदृश्य इनपुट को दृश्यमान बनाता है।
एक स्तरित सीएसएस प्रणाली जो यूआई को साफ और डिबग करने योग्य रखती है।
संवर्द्धन का एक सेट (रिकॉर्डिंग, निर्यात, स्नैपशॉट, घोस्ट रीप्ले) जो इसे डेमो से डेवलपर टूल तक बढ़ाता है। यह प्रोजेक्ट दिखाता है कि सीएसएस कैस्केड लेयर्स में थोड़ी रचनात्मकता के साथ वेब प्लेटफ़ॉर्म की शक्ति को मिलाकर आप कितनी दूर तक जा सकते हैं।
जिस टूल के बारे में मैंने अभी पूरी तरह से समझाया है वह ओपन-सोर्स है। आप GitHub रेपो को क्लोन कर सकते हैं और इसे अपने लिए आज़मा सकते हैं।
लेकिन इससे भी महत्वपूर्ण बात यह है कि आप इसे अपना बना सकते हैं। अपनी खुद की परतें जोड़ें. अपना खुद का रीप्ले लॉजिक बनाएं। इसे अपने गेम प्रोटोटाइप के साथ एकीकृत करें। या फिर इसे उन तरीकों से भी उपयोग करें जिनकी मैंने कल्पना भी नहीं की थी। शिक्षण, पहुंच या डेटा विश्लेषण के लिए।
दिन के अंत में, यह केवल गेमपैड को डीबग करने के बारे में नहीं है। यह छिपे हुए इनपुट पर प्रकाश डालने और डेवलपर्स को हार्डवेयर के साथ काम करने का आत्मविश्वास देने के बारे में है जिसे वेब अभी भी पूरी तरह से स्वीकार नहीं कर पाया है।
तो, अपने नियंत्रक को प्लग इन करें, अपना संपादक खोलें और प्रयोग करना शुरू करें। आपको यह जानकर आश्चर्य हो सकता है कि आपका ब्राउज़र और आपका सीएसएस वास्तव में क्या हासिल कर सकता है।