Cách chính xác để trừu tượng Bộ điều khiển XBox


12

Tôi đã có bộ điều khiển XBox360 mà tôi muốn sử dụng làm đầu vào cho một ứng dụng.

Những gì tôi không thể làm việc là cách thực hành tốt nhất để thể hiện điều này thông qua một giao diện.

Đằng sau hậu trường, lớp xử lý (các) bộ điều khiển phụ thuộc vào trạng thái nút bỏ phiếu.

Ban đầu tôi đã thử một cái gì đó liên kết:

Event ButtonPressed() as ButtonEnum

nơi ButtonEnumđã ButtonRed, ButtonStart, vv ...

Điều này hơi hạn chế ở chỗ nó chỉ hỗ trợ nhấn nút, không giữ / mẫu (nhấn hai lần, v.v.)

Ý tưởng tiếp theo là chỉ cần hiển thị trạng thái nút cho ứng dụng, vd

Property RedPressed as Boolean
Property StartPressed as Boolean
Property Thumb1XAxis as Double

Điều này rất linh hoạt nhưng thực sự nó buộc quá nhiều công việc vào ứng dụng và yêu cầu ứng dụng phải thăm dò ý kiến ​​- Tôi muốn điều khiển sự kiện nếu có thể.

Tôi đã xem xét thêm nhiều sự kiện, ví dụ:

Event ButtonPressed(Button as ButtonEnum)
Event ButtonPressedTwice(Button as ButtonEnum)
Event ButtonHeldStart(Button as ButtonEnum)
Event ButtonHeldEnd(Button as ButtonEnum)

nhưng điều này có vẻ hơi lộn xộn và là một nỗi đau thực sự trên màn hình "Nút Bind".

Ai đó có thể vui lòng chỉ cho tôi cách "chính xác" để xử lý đầu vào từ bộ điều khiển.

Lưu ý: Tôi đang sử dụng SlimDX bên trong lớp thực hiện giao diện. Điều này cho phép tôi đọc trạng thái rất dễ dàng. Bất kỳ giải pháp thay thế nào sẽ giải quyết vấn đề của tôi cũng được đánh giá cao

Câu trả lời:


21

Không có một ánh xạ hoàn hảo nào mang lại cho bạn một sự trừu tượng hóa cụ thể về nền tảng, bởi vì rõ ràng hầu hết các định danh có ý nghĩa đối với bộ điều khiển 360 đều sai đối với bộ điều khiển PlayStation (A thay vì X, B thay vì Circle). Và tất nhiên một bộ điều khiển Wii là một thứ khác hoàn toàn.

Cách hiệu quả nhất mà tôi đã tìm thấy để giải quyết vấn đề này là sử dụng ba lớp thực hiện. Lớp dưới hoàn toàn là nền tảng / bộ điều khiển cụ thể và biết có bao nhiêu nút kỹ thuật số và trục tương tự có sẵn. Đây là lớp này biết cách thăm dò trạng thái phần cứng và lớp này nhớ rõ trạng thái trước đó đủ để biết khi nào một nút vừa được nhấn, hoặc liệu nó có bị giảm nhiều hơn một lần hay không, hoặc nó không được nhấn . Khác với điều đó là ngu ngốc - một lớp trạng thái thuần túy đại diện cho một loại bộ điều khiển duy nhất. Giá trị thực sự của nó là trừu tượng hóa sự khó chịu của việc truy vấn trạng thái bộ điều khiển ra khỏi lớp giữa.

Lớp giữa là ánh xạ điều khiển thực tế từ các nút thực đến các khái niệm trò chơi (ví dụ A -> Jump). Chúng tôi gọi chúng là các xung thay vì các nút, vì chúng không còn bị ràng buộc với một loại bộ điều khiển cụ thể. Ở lớp này, bạn có thể ánh xạ lại các điều khiển (trong quá trình phát triển hoặc trong thời gian chạy theo lệnh của người dùng). Mỗi nền tảng có ánh xạ điều khiển riêng tới các xung ảo . Bạn không thể và không nên cố gắng thoát khỏi điều này. Mỗi bộ điều khiển là duy nhất và cần ánh xạ riêng. Các nút có thể ánh xạ tới nhiều xung (tùy thuộc vào chế độ trò chơi) và nhiều nút có thể ánh xạ tới cùng một xung (ví dụ: A và X đều tăng tốc, cả B và Y đều giảm tốc). Ánh xạ xác định tất cả điều đó,

Lớp trên là lớp trò chơi. Nó cần sự thúc đẩy và không quan tâm đến việc chúng được tạo ra như thế nào. Có thể chúng đến từ bộ điều khiển, hoặc bản ghi của bộ điều khiển hoặc có thể chúng đến từ AI. Ở cấp độ này, bạn không quan tâm. Điều bạn quan tâm là có một xung Jump mới, hoặc xung lực Tăng tốc đã tiếp tục, hoặc xung lực lặn có giá trị 0,35 tích tắc này.

Với loại hệ thống này, bạn viết lớp dưới cùng một lần cho mỗi bộ điều khiển. Lớp trên là nền tảng độc lập. Mã cho lớp giữa chỉ cần được viết một lần, nhưng dữ liệu (ánh xạ lại) cần được làm lại cho mỗi nền tảng / bộ điều khiển.


Đây có vẻ như là một cách tiếp cận rất sạch sẽ và thanh lịch. Cảm ơn bạn!
Cơ bản

1
Rất đẹp. Tốt hơn nhiều so với của tôi: P
Jordaan Mylonas

3
Trừu tượng rất đẹp. Nhưng hãy cẩn thận khi thực hiện: không tạo và hủy đối tượng xung mới cho mọi hành động của người dùng. Sử dụng gộp. Người thu gom rác sẽ cảm ơn bạn.
grega g

Chắc chắn rồi. Một mảng tĩnh có kích thước đến số lượng xung đồng thời tối đa hầu như luôn là lựa chọn tốt nhất; vì hầu như luôn luôn bạn chỉ muốn một phiên bản của mỗi xung hoạt động tại một thời điểm. Thông thường mảng đó chỉ có một vài mục trong đó, vì vậy nó rất nhanh để lặp lại.
MrCranky

@grega cảm ơn cả hai bạn - Tôi đã không nghĩ về điều đó.
Cơ bản

1

Thành thật mà nói, tôi muốn nói rằng giao diện tối ưu sẽ phụ thuộc rất nhiều vào cách sử dụng trong trò chơi. Tuy nhiên, đối với kịch bản sử dụng chung, tôi đề xuất kiến ​​trúc hai lớp tách biệt các cách tiếp cận dựa trên sự kiện và bỏ phiếu.

Tầng thấp hơn có thể được coi là tầng "dựa trên bỏ phiếu" và hiển thị trạng thái hiện tại của một nút. Một giao diện như vậy có thể chỉ đơn giản có 2 chức năng GetAnalogState(InputIdentifier)GetDigitalState(InputIdentifier)trong đó InputIdentifiermột giá trị được liệt kê đại diện cho nút, trình kích hoạt hoặc thanh nào bạn đang kiểm tra. (Chạy GetAnalogState cho một nút sẽ trả về 1.0 hoặc 0.0 và chạy GetDigitalState cho một thanh tương tự sẽ trả về true nếu vượt quá ngưỡng đặt trước hoặc sai khác).

Tầng thứ hai sau đó sẽ sử dụng tầng thấp hơn để tạo các sự kiện khi thay đổi trạng thái và cho phép các thành phần đăng ký gọi lại (Sự kiện C # rất vinh quang). Các cuộc gọi lại này sẽ bao gồm các sự kiện cho báo chí, phát hành, nhấn, kéo dài, v.v. Đối với một thanh tương tự, bạn có thể bao gồm các cử chỉ, ví dụ QCF cho một trò chơi chiến đấu. Số lượng sự kiện được hiển thị sẽ phụ thuộc vào mức độ chi tiết của sự kiện bạn muốn gửi đi. Bạn chỉ có thể bắn đơn giản ButtonStateChanged(InputIdentifier)nếu bạn muốn xử lý mọi thứ khác theo logic riêng.

Vì vậy, nếu bạn cần kiểm tra trạng thái hiện tại của nút đầu vào hoặc thanh điều khiển, hãy kiểm tra tầng dưới. Nếu bạn chỉ muốn tắt một chức năng khi có sự kiện đầu vào, hãy đăng ký gọi lại từ tầng thứ hai.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.