Khi bạn cắm bộ điều khiển, bạn nhấn nút, di chuyển cần điều khiển, bóp cò… và với tư cách là nhà phát triển, bạn không thấy điều gì trong số đó. Chắc chắn là trình duyệt đang nhận nó, nhưng trừ khi bạn đang ghi các số trong bảng điều khiển, nếu không nó sẽ vô hình. Đó là vấn đề đau đầu với API Gamepad. Nó đã tồn tại được nhiều năm và thực sự khá mạnh mẽ. Bạn có thể đọc các nút, gậy, trình kích hoạt, tác phẩm. Nhưng hầu hết mọi người không chạm vào nó. Tại sao? Bởi vì không có phản hồi. Không có bảng điều khiển trong công cụ dành cho nhà phát triển. Không có cách nào rõ ràng để biết liệu bộ điều khiển có làm như bạn nghĩ hay không. Cảm giác như đang bay mù vậy. Điều đó khiến tôi khó chịu đến mức phải xây dựng một công cụ nhỏ: Trình gỡ lỗi gamepad Cascade. Thay vì nhìn chằm chằm vào đầu ra của bảng điều khiển, bạn sẽ có được chế độ xem tương tác trực tiếp của bộ điều khiển. Nhấn một cái gì đó và nó phản ứng trên màn hình. Và với CSS Cascade Layers, các kiểu được sắp xếp hợp lý nên việc gỡ lỗi sẽ dễ dàng hơn. Trong bài đăng này, tôi sẽ chỉ cho bạn lý do tại sao việc gỡ lỗi bộ điều khiển lại khó đến vậy, CSS giúp dọn dẹp nó như thế nào và cách bạn có thể xây dựng trình gỡ lỗi trực quan có thể sử dụng lại cho các dự án của riêng mình.

Ngay cả khi bạn có thể đăng nhập tất cả chúng, bạn sẽ nhanh chóng nhận được thư rác không thể đọc được trên bảng điều khiển. Ví dụ: [0,0,1,0,0,0,5,0,...] [0,0,0,0,1,0,0,...] [0,0,1,0,0,0,0,...]

Bạn có thể cho biết nút nào đã được nhấn không? Có thể, nhưng chỉ sau khi bạn căng mắt và thiếu một vài thông tin đầu vào. Vì vậy, không, việc gỡ lỗi không hề dễ dàng khi đọc dữ liệu đầu vào. Vấn đề 3: Thiếu cấu trúc Ngay cả khi bạn kết hợp một trình hiển thị nhanh, các kiểu có thể nhanh chóng trở nên lộn xộn. Các trạng thái mặc định, hoạt động và gỡ lỗi có thể chồng lên nhau và nếu không có cấu trúc rõ ràng, CSS của bạn sẽ trở nên giòn và khó mở rộng. Lớp CSS Cascade có thể giúp ích. Họ nhóm các kiểu thành các “lớp” được sắp xếp theo mức độ ưu tiên, vì vậy bạn ngừng đấu tranh về tính đặc hiệu và đoán, “Tại sao kiểu gỡ lỗi của tôi không hiển thị?” Thay vào đó, bạn duy trì những mối quan tâm riêng biệt:

Đế: Tiêu chuẩn của bộ điều khiển, hình thức ban đầu. Hoạt động: Điểm nổi bật cho các nút được nhấn và di chuyển gậy. Gỡ lỗi: Lớp phủ dành cho nhà phát triển (ví dụ: phần đọc số, hướng dẫn, v.v.).

Nếu chúng ta định nghĩa các lớp trong CSS theo cách này, chúng ta sẽ có: /*Ưu tiên thấp nhất đến cao nhất*/ @layer cơ sở, hoạt động, gỡ lỗi;

@lớp cơ sở { /* ... */ }

@layer đang hoạt động { /* ... */ }

@layer gỡ lỗi { /* ... */ }

Bởi vì mỗi lớp có thể dự đoán được nên bạn luôn biết quy tắc nào sẽ thắng. Khả năng dự đoán đó làm cho việc gỡ lỗi không chỉ dễ dàng hơn mà còn thực sự có thể quản lý được. Chúng tôi đã giải quyết vấn đề (đầu vào vô hình, lộn xộn) và cách tiếp cận (trình gỡ lỗi trực quan được xây dựng bằng Cascade Layers). Bây giờ chúng ta sẽ thực hiện quy trình từng bước để xây dựng trình gỡ lỗi. Khái niệm trình gỡ lỗi Cách dễ nhất để hiển thị đầu vào ẩn là chỉ cần vẽ nó lên màn hình. Đó là những gì trình gỡ lỗi này làm. Các nút, trình kích hoạt và cần điều khiển đều có hình ảnh trực quan.

Nhấn A: Một vòng tròn sáng lên. Đẩy cây gậy: Vòng tròn trượt xung quanh. Bóp cò nửa chừng: Một thanh đầy một nửa.

Bây giờ bạn không nhìn chằm chằm vào số 0 và 1 mà thực sự đang xem bộ điều khiển phản ứng trực tiếp. Tất nhiên, khi bạn bắt đầu thêm các trạng thái như mặc định, nhấn, thông tin gỡ lỗi, thậm chí có thể là chế độ ghi, CSS sẽ bắt đầu lớn hơn và phức tạp hơn. Đó là lúc các lớp xếp tầng có ích. Đây là một ví dụ rút gọn: @lớp cơ sở { .nút { nền: #222; bán kính đường viền: 50%; chiều rộng: 40px; chiều cao: 40px; } }

@layer đang hoạt động { .button.press { nền: #0f0; /*xanh tươi*/ } }

@layer gỡ lỗi { .button::sau { nội dung: attr(data-value); cỡ chữ: 12px; màu sắc: #fff; } }

Thứ tự lớp quan trọng: cơ sở → hoạt động → gỡ lỗi.

cơ sở vẽ bộ điều khiển. xử lý hoạt động trạng thái nhấn. gỡ lỗi ném vào lớp phủ.

Chia nhỏ như thế này có nghĩa là bạn không đang tham gia vào các cuộc chiến tranh đặc thù kỳ lạ. Mỗi lớp đều có vị trí của nó và bạn luôn biết điều gì sẽ thắng. Xây dựng nó ra Trước tiên hãy đưa thứ gì đó lên màn hình. Nó không cần phải đẹp mắt - chỉ cần tồn tại để chúng ta có thứ gì đó để làm việc.

Trình gỡ lỗi xếp tầng của gamepad

A
B
X

Trình gỡ lỗi không hoạt động

Đó thực sự chỉ là những chiếc hộp. Chưa thú vị lắm nhưng nó giúp chúng ta xử lý sau bằng CSS và JavaScript. Được rồi, tôi đang sử dụng các lớp xếp tầng ở đây vì nó giúp sắp xếp mọi thứ khi bạn thêm nhiều trạng thái hơn. Đây là một bước vượt qua khó khăn:

/* ====================================== THIẾT LẬP LỚP CASCADE Vấn đề thứ tự: cơ sở → hoạt động → gỡ lỗi ======================================*/

/* Xác định trước thứ tự lớp */ @layer cơ sở, hoạt động, gỡ lỗi;

/* Lớp 1: Kiểu cơ sở - giao diện mặc định */ @lớp cơ sở { .nút { nền: #333; bán kính đường viền: 50%; chiều rộng: 70px; chiều cao: 70px; hiển thị: linh hoạt; biện minh-nội dung: trung tâm; căn chỉnh các mục: giữa; }

.tạm dừng { chiều rộng: 20px; chiều cao: 70px; nền: #333; hiển thị: khối nội tuyến; } }

/* Lớp 2: Trạng thái hoạt động - xử lý các nút được nhấn */ @layer đang hoạt động { .button.active { nền: #0f0; /* Màu xanh sáng khi nhấn */ biến đổi: tỷ lệ (1.1); /* Phóng to nút này lên một chút */ }

.pause.active { nền: #0f0; biến đổi: tỉ lệY(1.1); /* Kéo giãn theo chiều dọc khi nhấn */ } }

/* Lớp 3: Lớp phủ gỡ lỗi - thông tin nhà phát triển */ @layer gỡ lỗi { .button::sau { nội dung: attr(data-value); /*Hiển thị giá trị số*/ cỡ chữ: 12px; màu sắc: #fff; } }

Cái hay của phương pháp này là mỗi lớp đều có mục đích rõ ràng. Lớp cơ sở không bao giờ có thể ghi đè hoạt động và hoạt động không bao giờ có thể ghi đè gỡ lỗi, bất kể tính đặc hiệu. Điều này giúp loại bỏ các cuộc chiến về tính đặc hiệu CSS thường gây khó khăn cho các công cụ gỡ lỗi. Bây giờ có vẻ như một số cụm đang nằm trên nền tối. Thành thật mà nói, không quá tệ.

Thêm JavaScript Thời gian JavaScript. Đây là nơi bộ điều khiển thực sự làm điều gì đó. Chúng tôi sẽ xây dựng điều này từng bước một. Bước 1: Thiết lập quản lý trạng thái Đầu tiên, chúng ta cần các biến để theo dõi trạng thái của trình gỡ lỗi: // ====================================== // QUẢN LÝ NHÀ NƯỚC // ======================================

hãy chạy = false; // Theo dõi xem trình gỡ lỗi có hoạt động không hãy để rafId; // Lưu trữ ID requestAnimationFrame để hủy

Các biến này kiểm soát vòng lặp hoạt ảnh liên tục đọc đầu vào gamepad. Bước 2: Lấy tài liệu tham khảo DOM Tiếp theo, chúng tôi nhận được các tham chiếu đến tất cả các thành phần HTML mà chúng tôi sẽ cập nhật: // ====================================== // TÀI LIỆU THAM KHẢO THÀNH PHẦN DOM // ======================================

const btnA = document.getElementById("btn-a"); const btnB = document.getElementById("btn-b"); const btnX = document.getElementById("btn-x"); const tạm dừng1 = document.getElementById("pause1"); const tạm dừng2 = document.getElementById("pause2"); const status = document.getElementById("status");

Việc lưu trữ các tham chiếu này ở phía trước sẽ hiệu quả hơn việc truy vấn DOM nhiều lần. Bước 3: Thêm dự phòng bàn phím Để thử nghiệm mà không có bộ điều khiển vật lý, chúng tôi sẽ ánh xạ các phím trên bàn phím thành các nút: // ====================================== // KEYBOARD FALLBACK (để kiểm tra không có bộ điều khiển) // ======================================

const keyMap = { "a": btnA, "b": btnB, "x": btnX, "p": [pause1, tạm dừng2] // Phím 'p' điều khiển cả hai thanh tạm dừng };

Điều này cho phép chúng tôi kiểm tra giao diện người dùng bằng cách nhấn các phím trên bàn phím. Bước 4: Tạo vòng cập nhật chính Đây là nơi điều kỳ diệu xảy ra. Chức năng này chạy liên tục và đọc trạng thái gamepad: // ====================================== // VÒNG CẬP NHẬT GAMEPAD CHÍNH // ======================================

chức năng cập nhậtGamepad() { // Nhận tất cả các gamepad được kết nối const gamepads = navigator.getGamepads(); nếu (!gamepads) quay trở lại;

// Sử dụng gamepad được kết nối đầu tiên const gp = tay cầm chơi game[0];

nếu (gp) { // Cập nhật trạng thái nút bằng cách chuyển đổi lớp "hoạt động" btnA.classList.toggle("active", gp.buttons[0].press); btnB.classList.toggle("active", gp.buttons[1].press); btnX.classList.toggle("active", gp.buttons[2].press);

// Xử lý nút tạm dừng (nút chỉ số 9 trên hầu hết các bộ điều khiển) const tạm dừngPressed = gp.buttons[9].pressed; tạm dừng1.classList.toggle ("hoạt động", tạm dừngPressed); tạm dừng2.classList.toggle ("hoạt động", tạm dừngPressed);

// Xây dựng danh sách các nút đang được nhấn để hiển thị trạng thái hãy nhấn = []; gp.buttons.forEach((btn, i) => { nếu (btn.ép)ép.push("Nút " + i); });

// Cập nhật văn bản trạng thái nếu nhấn bất kỳ nút nào if (ép.length > 0) { status.textContent = "Đã nhấn: " + đã nhấn.join(", "); } }

// Tiếp tục vòng lặp nếu trình gỡ lỗi đang chạy nếu (đang chạy) { rafId = requestAnimationFrame(updateGamepad); } }

Phương thức classList.toggle() thêm hoặc xóa lớp đang hoạt động dựa trên việc nút có được nhấn hay không, điều này sẽ kích hoạt các kiểu lớp CSS của chúng ta. Bước 5: Xử lý sự kiện bàn phím Những trình xử lý sự kiện này giúp cho tính năng dự phòng bàn phím hoạt động: // ====================================== // XỬ LÝ SỰ KIỆN BÀN PHÍM // ======================================

document.addEventListener("keydown", (e) => { if (keyMap[e.key]) { // Xử lý một hoặc nhiều phần tử if (Array.isArray(keyMap[e.key])) { keyMap[e.key].forEach(el => el.classList.add("active")); } khác { keyMap[e.key].classList.add("active"); } status.textContent = "Đã nhấn phím: " + e.key.toUpperCase(); } });

document.addEventListener("keyup", (e) => { if (keyMap[e.key]) { // Xóa trạng thái hoạt động khi phím được nhả if (Array.isArray(keyMap[e.key])) { keyMap[e.key].forEach(el => el.classList.remove("active")); } khác { keyMap[e.key].classList.remove("active"); } status.textContent = "Khóa đã được giải phóng: " + e.key.toUpperCase(); } });

Bước 6: Thêm điều khiển Bắt đầu/Dừng Cuối cùng, chúng ta cần một cách để bật và tắt trình gỡ lỗi: // ====================================== // BẬT/TẮT GỠ LỖI // ======================================

document.getElementById("toggle").addEventListener("click", () => { đang chạy = !đang chạy; // Lật trạng thái đang chạy

nếu (đang chạy) { status.textContent = "Trình gỡ lỗi đang chạy..."; cập nhậtGamepad(); // Bắt đầu vòng lặp cập nhật } khác { status.textContent = "Trình gỡ lỗi không hoạt động"; cancelAnimationFrame(rafId); // Dừng vòng lặp } });

Đúng vậy, nhấn một nút và nó sẽ phát sáng. Đẩy cây gậy và nó di chuyển. Thế thôi. Một điều nữa: giá trị thô. Đôi khi bạn chỉ muốn nhìn thấy những con số chứ không phải ánh sáng.

Ở giai đoạn này, bạn sẽ thấy:

Một bộ điều khiển trên màn hình đơn giản, Các nút phản ứng khi bạn tương tác với chúng và Một bản đọc gỡ lỗi tùy chọn hiển thị các chỉ số nút được nhấn.

Để làm cho điều này bớt trừu tượng hơn, đây là bản demo nhanh về phản ứng của bộ điều khiển trên màn hình trong thời gian thực:

Bây giờ, nhấn Bắt đầu ghi sẽ ghi lại mọi thứ cho đến khi bạn nhấn Dừng ghi. 2. Xuất dữ liệu sang CSV/JSON Khi chúng tôi có nhật ký, chúng tôi sẽ muốn lưu nó.

Bước 1: Tạo Trình trợ giúp tải xuống Đầu tiên, chúng ta cần một hàm trợ giúp xử lý việc tải tệp xuống trong trình duyệt: // ====================================== // TRỢ GIÚP TẢI XUỐNG TẬP TIN // ======================================

hàm downloadFile(tên file, nội dung, type = "text/plain") { // Tạo một đốm màu từ nội dung const blob = Blob mới([nội dung], { type }); const url = URL.createObjectURL(blob);

// Tạo liên kết tải xuống tạm thời và nhấp vào nó const a = document.createElement("a"); a.href = url; a.download = tên tập tin; a.click();

// Dọn dẹp URL đối tượng sau khi tải xuống setTimeout(() => URL.revokeObjectURL(url), 100); }

Hàm này hoạt động bằng cách tạo Blob (đối tượng lớn nhị phân) từ dữ liệu của bạn, tạo URL tạm thời cho dữ liệu đó và nhấp vào liên kết tải xuống theo chương trình. Việc dọn dẹp đảm bảo chúng ta không bị rò rỉ bộ nhớ. Bước 2: Xử lý việc xuất JSON JSON hoàn hảo để bảo toàn cấu trúc dữ liệu hoàn chỉnh:

// ====================================== // XUẤT DƯỚI JSON // ======================================

document.getElementById("export-json").addEventListener("click", () => { // Kiểm tra xem có gì cần xuất không if (!frames.length) { console.warn("Không có bản ghi nào để xuất."); trở lại; }

// Tạo tải trọng với siêu dữ liệu và khung tải trọng const = { đã tạoAt: ngày mới().toISOString(), khung };

// Tải xuống dưới dạng JSON được định dạng tải xuốngTệp( "gamepad-log.json", JSON.stringify(tải trọng, null, 2), "ứng dụng/json" ); });

Định dạng JSON giữ mọi thứ có cấu trúc và dễ dàng phân tích cú pháp, lý tưởng để tải lại vào công cụ dành cho nhà phát triển hoặc chia sẻ với đồng đội. Bước 3: Xử lý xuất CSV Để xuất CSV, chúng ta cần làm phẳng dữ liệu phân cấp thành hàng và cột:

//====================================== // XUẤT DƯỚI CSV // ======================================

document.getElementById("export-csv").addEventListener("click", () => { // Kiểm tra xem có gì cần xuất không if (!frames.length) { console.warn("Không có bản ghi nào để xuất."); trở lại; }

// Xây dựng hàng tiêu đề CSV (cột cho dấu thời gian, tất cả các nút, tất cả các trục) const headerButtons = Frames[0].buttons.map((_, i) => btn${i}); const headerAxes = frame[0].axes.map((_, i) => axis${i}); const header = ["t", ...headerButtons, ...headerAxes].join(",") + "\n";

// Xây dựng các hàng dữ liệu CSV const row = frame.map(f => { const btnVals = f.buttons.map(b => b.value); return [f.t, ...btnVals, ...f.axes].join(","); }).join("\n");

// Tải xuống dưới dạng CSV downloadFile("gamepad-log.csv", tiêu đề + hàng, "text/csv"); });

CSV rất hữu ích cho việc phân tích dữ liệu vì nó mở trực tiếp trong Excel hoặc Google Trang tính, cho phép bạn tạo biểu đồ, lọc dữ liệu hoặc phát hiện các mẫu một cách trực quan. Bây giờ các nút xuất đã có, bạn sẽ thấy hai tùy chọn mới trên bảng điều khiển: Xuất JSON và Xuất CSV. JSON rất phù hợp nếu bạn muốn đưa nhật ký thô trở lại công cụ phát triển của mình hoặc xem xét cấu trúc. Mặt khác, CSV mở thẳng vào Excel hoặc Google Trang tính để bạn có thể lập biểu đồ, lọc hoặc so sánh các dữ liệu đầu vào. Hình dưới đây cho thấy bảng điều khiển trông như thế nào với các điều khiển bổ sung đó.

3. Hệ thống chụp nhanh Đôi khi bạn không cần bản ghi đầy đủ mà chỉ cần một “ảnh chụp màn hình” nhanh về trạng thái đầu vào. Đó là lúc nút Chụp nhanh sẽ giúp ích.

Và JavaScript:

// ====================================== // CHỤP ẢNH CHỤP // ======================================

document.getElementById("snapshot").addEventListener("click", () => { // Nhận tất cả các gamepad được kết nối const miếng đệm = navigator.getGamepads(); const activePads = [];

// Lặp lại và ghi lại trạng thái của từng gamepad được kết nối for (const gp của miếng đệm) { nếu (!gp) tiếp tục; // Bỏ qua các ô trống

activePads.push({ id: gp.id, // Tên/model bộ điều khiển dấu thời gian: performance.now(), các nút: gp.buttons.map(b => ({ ép: b.ép, giá trị: b.value })), trục: [...gp.axes] }); }

// Kiểm tra xem có tìm thấy gamepad nào không if (!activePads.length) { console.warn("Không có gamepad nào được kết nối để chụp nhanh."); cảnh báo ("Không tìm thấy bộ điều khiển!"); trở lại; }

// Đăng nhập và thông báo cho người dùng console.log("Ảnh chụp nhanh:", activePads); cảnh báo (Ảnh chụp nhanh! Đã chụp (các) bộ điều khiển ${activePads.length}.); });

Ảnh chụp nhanh đóng băng trạng thái chính xác của bộ điều khiển của bạn tại một thời điểm. 4. Phát lại đầu vào ma Bây giờ là phần thú vị: phát lại đầu vào ma. Thao tác này sẽ lấy nhật ký và phát lại một cách trực quan như thể một trình phát ảo đang sử dụng bộ điều khiển.

JavaScript để phát lại: // ====================================== // PHÁT LẠI GHOST // ======================================

document.getElementById("replay").addEventListener("click", () => { // Đảm bảo chúng ta có bản ghi để phát lại if (!frames.length) { Alert("Không có bản ghi để phát lại!"); trở lại; }

console.log("Bắt đầu phát lại ghost...");

// Theo dõi thời gian phát lại được đồng bộ hóa hãy bắt đầuTime = performance.now(); đặt frameIndex = 0;

// Phát lại vòng lặp hoạt ảnh bước chức năng() { const bây giờ = performance.now(); const đã trôi qua = bây giờ - startTime;

// Xử lý tất cả các khung hình đáng lẽ phải xảy ra vào lúc này while (frameIndex < Frames.length && Frames[frameIndex].t <= đã trôi qua) { const frame = khung [frameIndex];

// Cập nhật giao diện người dùng với trạng thái nút đã ghi btnA.classList.toggle("active", frame.buttons[0].press); btnB.classList.toggle("active", frame.buttons[1].press); btnX.classList.toggle("active", frame.buttons[2].press);

// Hiển thị trạng thái cập nhật hãy nhấn = []; frame.buttons.forEach((btn, i) => { if (btn.press) đã nhấn.push("Nút " + i); }); if (ép.length > 0) { status.textContent = "Ghost: " + press.join(", "); }

khung Index++; }

// Tiếp tục lặp nếu có nhiều khung hơn if (frameIndex < frame.length) { requestAnimationFrame(bước); } khác { console.log("Phát lạixong."); status.textContent = "Phát lại hoàn tất"; } }

// Bắt đầu phát lại bước(); });

Để việc gỡ lỗi thực tế hơn một chút, tôi đã thêm tính năng phát lại ma. Sau khi ghi lại một phiên, bạn có thể nhấn phát lại và xem giao diện người dùng hoạt động, gần giống như một trình phát ảo đang chạy bảng điều khiển. Nút Replay Ghost mới hiển thị trong bảng điều khiển cho việc này.

Nhấn Ghi, loay hoay với bộ điều khiển một chút, dừng rồi phát lại. Giao diện người dùng chỉ lặp lại mọi thứ bạn đã làm, giống như một bóng ma theo dõi thông tin đầu vào của bạn. Tại sao phải bận tâm với những tính năng bổ sung này?

Ghi/xuất giúp người kiểm tra dễ dàng hiển thị chính xác những gì đã xảy ra. Ảnh chụp nhanh đóng băng trong một khoảnh khắc, cực kỳ hữu ích khi bạn đang truy tìm các lỗi kỳ lạ. Ghost replay rất phù hợp cho các hướng dẫn, kiểm tra khả năng truy cập hoặc chỉ so sánh các thiết lập điều khiển cạnh nhau.

Tại thời điểm này, nó không chỉ là một bản demo gọn gàng nữa mà còn là thứ bạn thực sự có thể đưa vào hoạt động. Các trường hợp sử dụng trong thế giới thực Bây giờ chúng tôi đã có trình gỡ lỗi này có thể làm được rất nhiều việc. Nó hiển thị thông tin đầu vào trực tiếp, ghi lại nhật ký, xuất chúng và thậm chí phát lại nội dung. Nhưng câu hỏi thực sự là: ai thực sự quan tâm? Điều này hữu ích cho ai? Nhà phát triển trò chơi Bộ điều khiển là một phần công việc, nhưng việc gỡ lỗi chúng? Thường là một cơn đau. Hãy tưởng tượng bạn đang thử nghiệm một combo trò chơi đối kháng, như ↓ → + đấm. Thay vì cầu nguyện, bạn nhấn nút đó hai lần theo cách tương tự, bạn ghi âm một lần và phát lại. Xong. Hoặc bạn trao đổi nhật ký JSON với đồng đội để kiểm tra xem mã nhiều người chơi của bạn có phản ứng tương tự trên máy của họ hay không. Điều đó thật lớn lao. Người thực hành khả năng tiếp cận Cái này gần với trái tim tôi. Không phải ai cũng chơi với bộ điều khiển “tiêu chuẩn”. Bộ điều khiển thích ứng đôi khi phát ra những tín hiệu lạ. Với công cụ này, bạn có thể thấy chính xác những gì đang xảy ra. Giáo viên, nhà nghiên cứu, bất cứ ai. Họ có thể lấy nhật ký, so sánh hoặc phát lại các dữ liệu đầu vào cạnh nhau. Đột nhiên, những thứ vô hình trở nên hiển nhiên. Kiểm tra đảm bảo chất lượng Người kiểm tra thường viết những ghi chú như “Tôi đã nhấn nút ở đây và nó bị hỏng”. Không hữu ích lắm. Bây giờ? Họ có thể nắm bắt các máy ép chính xác, xuất nhật ký và gửi đi. Không cần đoán. nhà giáo dục Nếu bạn đang tạo video hướng dẫn hoặc video trên YouTube, phát lại bóng ma là vàng. Theo nghĩa đen, bạn có thể nói: “Đây là những gì tôi đã làm với bộ điều khiển” trong khi giao diện người dùng hiển thị điều đó đang diễn ra. Làm cho cách giải thích rõ ràng hơn. Ngoài trò chơi Và vâng, đây không chỉ là về trò chơi. Mọi người đã sử dụng bộ điều khiển cho robot, dự án nghệ thuật và giao diện trợ năng. Cùng một vấn đề mọi lúc: trình duyệt thực sự nhìn thấy gì? Với điều này, bạn không cần phải đoán. Kết luận Việc gỡ lỗi đầu vào của bộ điều khiển luôn có cảm giác như bị mù. Không giống như DOM hoặc CSS, không có trình kiểm tra tích hợp sẵn cho gamepad; nó chỉ là những con số thô trong bảng điều khiển, dễ bị lẫn lộn trong tiếng ồn. Với vài trăm dòng HTML, CSS và JavaScript, chúng tôi đã xây dựng một thứ gì đó khác biệt:

Trình gỡ lỗi trực quan giúp hiển thị các đầu vào vô hình. Một hệ thống CSS phân lớp giúp giao diện người dùng luôn sạch sẽ và có thể sửa lỗi. Một tập hợp các cải tiến (ghi, xuất, chụp nhanh, phát lại ma) nâng nó từ bản demo lên công cụ dành cho nhà phát triển.

Dự án này cho thấy bạn có thể tiến xa đến đâu bằng cách kết hợp sức mạnh của Nền tảng web với một chút sáng tạo trong Lớp CSS Cascade. Công cụ tôi vừa giải thích toàn bộ là nguồn mở. Bạn có thể sao chép repo GitHub và tự mình thử nó. Nhưng quan trọng hơn, bạn có thể biến nó thành của riêng mình. Thêm các lớp của riêng bạn. Xây dựng logic phát lại của riêng bạn. Tích hợp nó với nguyên mẫu trò chơi của bạn. Hoặc thậm chí sử dụng nó theo những cách mà tôi chưa từng tưởng tượng. Để giảng dạy, khả năng tiếp cận hoặc phân tích dữ liệu. Vào cuối ngày, đây không chỉ là việc gỡ lỗi gamepad. Đó là việc làm sáng tỏ những đầu vào ẩn và mang lại cho các nhà phát triển sự tự tin khi làm việc với phần cứng mà web vẫn chưa hoàn toàn nắm bắt được. Vì vậy, hãy cắm bộ điều khiển của bạn, mở trình chỉnh sửa và bắt đầu thử nghiệm. Bạn có thể ngạc nhiên về những gì trình duyệt và CSS của bạn thực sự có thể đạt được.

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