Uwaga: muszę sondować, a nie wywoływać oddzwanianie z powodu ograniczeń API (SFML). Przepraszam również za brak „przyzwoitego” tytułu.
Myślę, że mam tutaj dwa pytania; jak zarejestrować otrzymywane informacje i co z nimi zrobić.
Obsługa danych wejściowych
Mówię o tym po tym, jak zarejestrowałeś, że klawisz „A” został naciśnięty, na przykład, i jak to zrobić od tego momentu.
Widziałem tablicę całej klawiatury, coś w stylu:
bool keyboard[256]; //And each input loop check the state of every key on the keyboard
Ale to wydaje się nieefektywne. Nie tylko przykładasz klawisz „A” do „gracza poruszającego się w lewo”, ale sprawdza on każdy klawisz 30–60 razy na sekundę.
Następnie wypróbowałem inny system, który szukał tylko pożądanych kluczy.
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.
Jednak problem polega na tym, że nie mogę teraz wpisać nazwy bez konieczności wiązania każdego klucza.
Następnie mam drugi problem, który nie jest w stanie wymyślić dobrego rozwiązania dla:
Wysyłanie danych wejściowych
Wiem teraz, że klawisz A został naciśnięty lub że playerLeft jest prawdziwy. Ale jak mam stąd wyjść?
Pomyślałem o sprawdzeniu
if(input->IsKeyDown(Key::PlayerLeft) { player.MoveLeft(); }
To bardzo łączy dane wejściowe z istotami i uważam, że jest to dość bałagan. Wolałbym, żeby gracz sam sobie poradził, gdy zostanie zaktualizowany. Myślałem, że jakiś system wydarzeń może działać, ale nie wiem, jak się z tym pogodzić. (Słyszałem, że sygnały i automaty były dobre do tego rodzaju pracy, ale najwyraźniej są bardzo powolne i nie widzę, jak by to pasowało).
Dzięki.
źródło
Myślę, że dyskusja PO łączy wiele rzeczy i że problem można znacznie uprościć, rozbijając go nieco.
Moja sugestia:
Zachowaj tablicę stanów kluczy. Czy nie ma wywołania API, aby uzyskać jednocześnie cały stan klawiatury? (Większość mojej pracy dotyczy konsoli, a nawet w systemie Windows dla podłączonego kontrolera uzyskujesz cały stan kontrolera naraz.) Twoje stany klawiszy są „twardą” mapą na klawiszach klawiatury. Nieprzetłumaczone jest najlepsze, ale najłatwiej uzyskać je z interfejsów API.
Następnie zachowaj kilka równoległych tablic wskazujących, czy klucz poszedł w górę tej ramki, inny wskazujący, że spadł, a trzeci, aby wskazać po prostu, że klucz jest „opuszczony”. Może wrzuć licznik czasu, abyś mógł śledzić, jak długo klucz był w obecnym stanie.
Następnie utwórz metodę tworzenia mapowania kluczy do akcji. Będziesz chciał to zrobić kilka razy. Raz, aby uzyskać informacje o interfejsie użytkownika (i staraj się przeszukiwać mapowania Windows, ponieważ nie możesz założyć, że scancode po naciśnięciu „A” da A na komputerze użytkownika). Kolejny dla każdego „trybu” w grze. Są to odwzorowania kodów klawiszy na działania. Możesz to zrobić na kilka sposobów, jednym z nich byłoby zachowanie wyliczenia używanego przez system odbierający, innym byłby wskaźnik funkcji wskazujący funkcję, która ma zostać wywołana przy zmianie stanu. Może nawet hybryda tych dwóch, w zależności od twoich celów i potrzeb. Za pomocą tych „trybów” możesz przesuwać je i umieszczać na stosie trybu kontrolera, z flagami, które pozwalają na ignorowanie danych wejściowych, aby nadal zmniejszać stos lub cokolwiek innego.
Wreszcie, jakoś poradzić sobie z tymi kluczowymi działaniami. W przypadku ruchu możesz chcieć zrobić coś trudnego, przetłumaczyć „W” w dół, co oznacza „posunąć się do przodu”, ale nie musi to być rozwiązanie binarne; możesz mieć „W jest w dół” oznacza „zwiększać prędkość o X, aż do wartości maksymalnej Y”, a „W jest w górę”, aby być „zmniejszać prędkość o Z, aż osiągnie zero”. Mówiąc ogólnie - chcesz, aby Twój „interfejs obsługi kontrolerów w systemach gier” był dość wąski; wykonaj wszystkie kluczowe tłumaczenia w jednym miejscu, a następnie użyj ich wyników wszędzie indziej. Jest to w przeciwieństwie do bezpośredniego sprawdzania, czy klawisz spacji jest naciskany w dowolnym miejscu w kodzie, ponieważ jeśli jest w losowym miejscu, prawdopodobnie zostanie trafiony w dowolnym momencie, gdy nie chcesz, a po prostu nie chcę sobie z tym poradzić ...
Naprawdę nie znoszę projektowania wzorów i myślę, że komponenty przynoszą więcej kosztów rozwoju niż pożytku, dlatego nie wspomniałem o żadnym z nich. Wzory pojawią się, jeśli są przeznaczone, podobnie jak komponenty, ale wyruszenie do zrobienia jednego z nich od samego początku tylko skomplikuje twoje życie.
źródło
W SFML masz klucze w kolejności, w jakiej zostały naciśnięte z typem zdarzenia KeyPressed. Przetwarzasz każdy klucz na chwilę (getNextEvent ()).
Więc jeśli wciśnięty klawisz znajduje się na twojej mapie Klucz-> Akcja, uruchom odpowiednią akcję, a jeśli nie, przekaż ją do dowolnego widżetu / rzeczy, które mogą jej potrzebować.
Jeśli chodzi o twoje drugie pytanie, polecam zachować je w ten sposób, ponieważ ułatwia to ulepszenie rozgrywki. Jeśli używasz takich sygnałów, musisz utworzyć miejsce dla „RunKeyDown” i drugie dla „JumpKeySlot”. Ale co się stanie, jeśli w grze zostanie wykonana specjalna akcja po naciśnięciu obu przycisków?
Jeśli chcesz zdekorelować dane wejściowe i byty, możesz ustawić dane wejściowe jako Stan (RunKey = true, FireKey = false, ...) i wysłać je do odtwarzacza, tak jak wysyłasz dowolne inne zdarzenie do AI.
źródło
Prawidłowe rozwiązanie jest często kombinacją dwóch omawianych metod:
W przypadku funkcji rozgrywki z predefiniowanym zestawem kluczy odpytywanie każdej klatki jest całkowicie odpowiednie i należy sprawdzać tylko te klucze, które są rzeczywiście powiązane z czymś. Jest to w rzeczywistości analogiczne do zapytania o dane wejściowe kontrolera w grze na konsolę. Będzie to całkowicie odpytywanie, szczególnie jeśli chodzi o analogowe urządzenia wejściowe. Podczas ogólnej gry prawdopodobnie chcesz zignorować zdarzenia naciśnięcia klawisza i po prostu użyć odpytywania.
Jeśli chodzi o wpisywanie danych wejściowych takich jak nazwy, powinieneś przełączyć grę w inny tryb obsługi danych wejściowych. Na przykład, gdy tylko pojawi się monit „wpisz swoje imię”, możesz zmodyfikować kod wejściowy. Może nasłuchiwać zdarzeń naciśnięcia klawisza za pośrednictwem interfejsu oddzwaniania lub w razie potrzeby można rozpocząć odpytywanie każdego klawisza. Okazuje się, że zazwyczaj podczas pisania na klawiaturze i tak nie zależy ci na wydajności, więc odpytywanie nie będzie takie złe.
Tak więc chcesz używać selektywnego odpytywania do wprowadzania danych do gry i obsługi zdarzeń do wprowadzania nazw (lub całego odpytywania klawiatury, jeśli obsługa zdarzeń nie jest dostępna).
źródło
Bardzo podoba mi się odpowiedź dash-tom-bang, naprawdę podkreśla niektóre aspekty, o których należy pamiętać przy projektowaniu systemu wejściowego.
Chciałbym dodać mały samouczek, na który natknąłem się w tym samym kierunku (w tym konteksty wejściowe, 3 warstwy, ...):
http://www.gamedev.net/blog/355/entry-2250186-designing-a-robust-input-handling-system-for-games/
źródło