Xử lý hệ thống đầu vào bàn phím


13

Lưu ý: Tôi phải thăm dò ý kiến, thay vì thực hiện các cuộc gọi lại vì các giới hạn API (SFML). Tôi cũng xin lỗi vì thiếu tiêu đề 'đàng hoàng'.

Tôi nghĩ rằng tôi có hai câu hỏi ở đây; Làm thế nào để đăng ký đầu vào tôi nhận được, và phải làm gì với nó.

Xử lý đầu vào

Tôi đang nói về việc thực tế bạn đã đăng ký rằng phím 'A' đã được nhấn, ví dụ, và cách thực hiện từ đó.

Tôi đã thấy một mảng của toàn bộ bàn phím, đại loại như:

bool keyboard[256]; //And each input loop check the state of every key on the keyboard

Nhưng điều này có vẻ không hiệu quả. Chẳng hạn, bạn không chỉ ghép phím 'A' với 'người chơi di chuyển sang trái', mà còn kiểm tra mọi phím, 30-60 lần một giây.

Sau đó tôi đã thử một hệ thống khác chỉ tìm kiếm các phím mà nó muốn.

std::map< unsigned char, Key> keyMap; //Key stores the keycode, and whether it's been pressed. Then, I declare a load of const unsigned char called 'Quit' or 'PlayerLeft'.
input->BindKey(Keys::PlayerLeft, KeyCode::A); //so now you can check if PlayerLeft, rather than if A.

Tuy nhiên, vấn đề với điều này là bây giờ tôi không thể gõ tên, mà không phải liên kết từng khóa.

Sau đó, tôi có vấn đề thứ hai, mà tôi thực sự không thể nghĩ ra một giải pháp tốt cho:

Gửi đầu vào

Bây giờ tôi biết rằng phím A đã được nhấn hoặc playerLeft là đúng. Nhưng làm thế nào để tôi đi từ đây?

Tôi nghĩ về việc kiểm tra if(input->IsKeyDown(Key::PlayerLeft) { player.MoveLeft(); }
cặp vợ chồng này đầu vào rất lớn cho các thực thể và tôi thấy nó khá lộn xộn. Tôi muốn người chơi tự xử lý chuyển động của mình khi được cập nhật. Tôi nghĩ rằng một số loại hệ thống sự kiện có thể hoạt động, nhưng tôi không biết làm thế nào để đi với nó. (Tôi nghe thấy tín hiệu và khe cắm tốt cho loại công việc này, nhưng dường như nó rất chậm và tôi không thể thấy nó phù hợp như thế nào).

Cảm ơn.

Câu trả lời:


7

Những gì tôi sẽ làm là sử dụng mẫu quan sát viên và có một lớp đầu vào duy trì một danh sách các cuộc gọi lại hoặc các đối tượng xử lý đầu vào. Các đối tượng khác có thể tự đăng ký với hệ thống đầu vào để được thông báo khi một số điều xảy ra. Có nhiều loại cuộc gọi lại khác nhau mà bạn có thể đăng ký, dựa trên loại sự kiện đầu vào mà người quan sát muốn được thông báo. Đây có thể là mức độ thấp như 'phím x bị giảm / tăng' hoặc cụ thể hơn về trò chơi như 'một sự kiện nhảy / bắn / di chuyển đã xảy ra'.

Nói chung, các đối tượng trò chơi có một thành phần xử lý đầu vào chịu trách nhiệm đăng ký chính nó với lớp đầu vào và cung cấp các phương thức để xử lý các sự kiện mà nó quan tâm. Đối với chuyển động, tôi có một thành phần di chuyển đầu vào có phương thức di chuyển (x, y). Nó tự đăng ký với hệ thống đầu vào và được thông báo về các sự kiện chuyển động (trong đó x và y sẽ là -1 và 0 để biểu thị di chuyển sang trái), thành phần động lực sau đó thay đổi tọa độ đối tượng trò chơi mẹ dựa trên hướng di chuyển và vận tốc của đối tượng.

Tôi không biết đây có phải là một giải pháp tốt hay không nhưng nó hiệu quả với tôi cho đến nay. Đặc biệt, nó cho phép tôi cung cấp các loại hệ thống đầu vào khác nhau ánh xạ tới cùng các sự kiện trò chơi logic để nút gamepad x và không gian bàn phím tạo ra một sự kiện nhảy chẳng hạn (phức tạp hơn một chút, cho phép người dùng gán lại phím ánh xạ).


Điều này chắc chắn làm tôi quan tâm; thành phần đầu vào sẽ tự đăng ký cho một số sự kiện nhất định (một cái gì đó như các thanh ghi playerInput 'trái', 'phải', v.v.) hoặc mọi thành phần đầu vào đã đăng ký sẽ nhận được tất cả tin nhắn?
Vịt Cộng sản

Nó thực sự phụ thuộc vào yêu cầu của bạn và cách bạn muốn thực hiện nó. Trong trường hợp của tôi, người nghe tự đăng ký cho các sự kiện cụ thể và thực hiện giao diện xử lý đầu vào thích hợp. Có mọi thành phần đầu vào nhận tất cả các tin nhắn sẽ hoạt động, nhưng định dạng tin nhắn cần phải chung chung hơn những gì tôi có.
Firas Assaad

5

Tôi nghĩ rằng cuộc thảo luận của OP đang kết hợp nhiều thứ lại với nhau và vấn đề có thể được đơn giản hóa đáng kể bằng cách phá vỡ nó một chút.

Đề xuất của tôi:

Giữ mảng trạng thái của các phím. Không có lệnh gọi API để có được toàn bộ trạng thái bàn phím cùng một lúc phải không? (Hầu hết công việc của tôi là trên bảng điều khiển và ngay cả trên Windows cho bộ điều khiển được kết nối, bạn sẽ có được toàn bộ trạng thái bộ điều khiển cùng một lúc.) Trạng thái phím của bạn là bản đồ "cứng" trên các phím của bàn phím. Chưa được dịch là tốt nhất, tuy nhiên bạn sẽ dễ dàng sử dụng API nhất.

Sau đó giữ một vài mảng song song cho biết khóa có tăng khung này hay không, một mảng khác chỉ ra rằng nó bị hỏng và một phần ba để chỉ đơn giản là khóa bị "xuống". Có thể ném vào một bộ đếm thời gian để bạn có thể theo dõi thời gian khóa đã ở trạng thái hiện tại.

Tiếp theo tạo một phương thức để tạo ánh xạ các khóa cho các hành động. Bạn sẽ muốn làm điều này một vài lần. Một lần cho công cụ UI (và chú ý truy vấn ánh xạ Windows vì bạn không thể giả sử scancode khi bạn nhấn 'A' sẽ cung cấp điểm A trên máy tính của người dùng). Một cái khác cho mỗi "chế độ" trong trò chơi. Đây là ánh xạ của mã khóa đến hành động. Bạn có thể làm điều này một vài cách, một cách là giữ một enum được sử dụng bởi hệ thống nhận, một cách khác sẽ là một con trỏ hàm chỉ ra hàm được gọi khi thay đổi trạng thái. Thậm chí có thể là một sự kết hợp của cả hai, tùy thuộc vào mục tiêu và nhu cầu của bạn. Với các "chế độ" này, bạn có thể đẩy và bật chúng lên ngăn xếp chế độ điều khiển, với các cờ cho phép đầu vào bị bỏ qua để tiếp tục đi xuống ngăn xếp hoặc bất cứ điều gì.

Cuối cùng, xử lý những hành động quan trọng bằng cách nào đó. Đối với chuyển động bạn có thể muốn làm một cái gì đó khó khăn, dịch 'W' xuống có nghĩa là "tiến về phía trước", nhưng nó không cần phải là một giải pháp nhị phân; bạn có thể có "W giảm" có nghĩa là "tăng vận tốc lên X cho đến khi tối đa là Y" và "W tăng" thành "giảm vận tốc theo Z cho đến khi chạm 0". Nói chung - bạn muốn "giao diện điều khiển bộ điều khiển trong các hệ thống trò chơi" của bạn khá hẹp; thực hiện tất cả các bản dịch chính ở một nơi và sau đó sử dụng kết quả của việc đó ở mọi nơi khác. Điều này trái ngược với việc kiểm tra trực tiếp để xem liệu Spacebar có được nhấn ngẫu nhiên ở bất kỳ vị trí nào trong mã hay không, bởi vì nếu ở một vị trí ngẫu nhiên nào đó, nó có thể sẽ bị tấn công vào một thời điểm ngẫu nhiên khi bạn không muốn và bạn chỉ không ' Tôi muốn đối phó với điều đó ...

Tôi thực sự ghét việc thiết kế theo các mẫu và tôi nghĩ rằng các thành phần mang lại chi phí phát triển nhiều hơn là tốt, vì vậy đó là lý do tại sao tôi không đề cập đến. Các mô hình sẽ xuất hiện nếu chúng được định sẵn, cũng như các thành phần, nhưng việc bắt đầu thực hiện ngay từ đầu sẽ chỉ làm phức tạp cuộc sống của bạn.


Bạn có nghĩ rằng đó là loại bẩn để liên kết các sự kiện với khung đồ họa? Tôi nghĩ rằng nên được tách ra.
Jo So

Ý tôi là, tôi hiểu rằng trong hầu hết các trường hợp, trình phát sẽ chậm hơn các nút đầu vào so với card đồ họa sẽ phát ra các khung, nhưng thực sự chúng phải độc lập và trên thực tế chúng dành cho các loại sự kiện khác, giống như các loại sự kiện được thu thập từ mạng .
Jo So

Thật; không có lý do tại sao bỏ phiếu bàn phím (hoặc thiết bị đầu vào khác) không thể chạy ở tốc độ khác với màn hình. Thật vậy, nếu bạn thăm dò ý kiến ​​đầu vào ở tần số 100Hz thì bạn có thể cung cấp trải nghiệm kiểm soát người dùng thực sự nhất quán bất kể tần suất cập nhật phần cứng video. Bạn sẽ phải khéo léo hơn một chút về cách bạn xử lý dữ liệu của mình (liên quan đến việc chốt, v.v.) nhưng nó sẽ làm cho mọi thứ như cử chỉ trở nên dễ dàng hơn để làm cho nhất quán.
dash-tom-bang

3

Trong SFML, bạn có các khóa theo thứ tự chúng đã được nhấn với loại sự kiện KeyPress. Bạn xử lý từng khóa trong một thời gian (getNextEvent ()).

Vì vậy, nếu phím được nhấn nằm trong Khóa-> Bản đồ hành động của bạn, hãy chạy hành động tương ứng và nếu không, hãy chuyển tiếp nó tới bất kỳ tiện ích / công cụ nào có thể cần đến nó.

Về câu hỏi thứ hai của bạn, tôi khuyên bạn nên giữ nó như thế này vì nó giúp điều chỉnh lối chơi của bạn dễ dàng hơn. Nếu bạn sử dụng tín hiệu hoặc như vậy, bạn sẽ phải tạo một vị trí cho "RunKeyDown" và một vị trí khác cho "JumpKeySlot". Nhưng điều gì xảy ra nếu trong trò chơi của bạn, một hành động đặc biệt được thực hiện khi cả hai được nhấn?

Nếu bạn muốn giải mã đầu vào và các thực thể, bạn có thể đặt đầu vào của mình thành Trạng thái (RunKey = true, FireKey = false, ...) và gửi nó đến người chơi như bạn gửi bất kỳ sự kiện nào khác cho AI của bạn.


Tôi không xử lý các sự kiện bàn phím với sf :: Event, thay vì sf :: Input, vì đó là IIRC phát hiện thời gian thực. Tôi đã cố gắng giữ nó như là bất khả tri API nhất có thể. : P (Câu hỏi, đó là)
Vịt Cộng sản

1
Nhưng tôi nghĩ rằng điểm mà Calvin1602 đang đưa ra là tuyên bố ban đầu của bạn trong câu hỏi "Tôi phải thăm dò ý kiến, thay vì gọi lại vì giới hạn API (SFML)" là không đúng; bạn có các sự kiện, vì vậy bạn có thể đưa ra một cuộc gọi lại khi bạn xử lý một sự kiện.
Kylotan

3

Giải pháp chính xác thường là sự kết hợp của hai phương pháp bạn thảo luận:

Đối với chức năng chơi trò chơi với một bộ phím được xác định trước, việc bỏ phiếu cho mọi khung hình là hoàn toàn phù hợp và bạn chỉ nên bỏ phiếu cho các phím thực sự bị ràng buộc với một cái gì đó. Điều này thực sự tương tự như cách bạn sẽ truy vấn đầu vào của bộ điều khiển trong trò chơi console, nó sẽ hoàn toàn bỏ phiếu đặc biệt là khi nói đến các thiết bị đầu vào tương tự. Trong quá trình chơi trò chơi chung, bạn có thể muốn bỏ qua các sự kiện nhấn phím và chỉ sử dụng bỏ phiếu.

Khi nói đến việc nhập dữ liệu cho những thứ như tên, bạn nên chuyển trò chơi sang chế độ xử lý đầu vào khác. Chẳng hạn, ngay khi lời nhắc "nhập tên của bạn" xuất hiện, bạn có thể sửa đổi những gì bạn nhập mã. Nó có thể lắng nghe các sự kiện nhấn phím thông qua một số giao diện gọi lại hoặc bạn có thể bắt đầu bỏ phiếu cho mỗi phím nếu được yêu cầu. Hóa ra, thông thường trong quá trình gõ các sự kiện bạn không quan tâm nhiều đến hiệu suất, vì vậy việc bỏ phiếu sẽ không tệ đến thế.

Vì vậy, bạn muốn sử dụng bỏ phiếu chọn lọc cho đầu vào trò chơi và xử lý sự kiện cho đầu vào gõ tên (hoặc tất cả bỏ phiếu bàn phím nếu không có xử lý sự kiện).


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.