Wejście sterowane odpytywaniem a zdarzeniem

19

Zajmuję się tworzeniem gry metodą odpytywania dla metody wprowadzania. Jednak teraz, gdy zagłębiam się w menu gry i inne elementy interfejsu użytkownika, stwierdzam, że prawdopodobnie chciałbym mieć dane sterowane zdarzeniami. Być może nawet posiadanie obu, używanie zdarzeń sterowanych dla interfejsu użytkownika i odpytywanie dla wejścia „świata”. Jestem ciekawy, jaka jest najlepsza droga.

Definiuję sondowanie jako: każdą pętlę aktualizacji sprawdzam, które klawisze są wciśnięte, gdzie znajduje się mysz, naciśnięte przyciski, a następnie je przeglądam i wykonuję działania na podstawie zebranych informacji.

Zdarzenie definiuję jako zdarzenie oparte na: przerwaniu, gdy zdarzenie ma miejsce, a przerwanie jest wyzwalane i blok kodu jest uruchamiany na podstawie zdarzenia.

Czy uważasz, że najlepiej jest kierować się wszystkimi zdarzeniami, wszystkimi ankietami, czy też połączenie obu jest dopuszczalne? Jeśli masz plusy i minusy, proszę wymienić je. Dzięki.

EDYTOWAĆ

Gra jest oparta na Javie / OpenGL, więc zostanie wydana na Windows / Mac / Linux. Możliwość rozszerzenia tego na urządzenia mobilne jest niska. Gra jest w stylu RTS, trzecia osoba w 3D.

EDYCJA 2

Nadal nie jestem do końca zadowolony ze sposobu, w jaki to zaimplementowałem, ale zmierzam do przechwytywania zdarzeń w moim interfejsie użytkownika, a jeśli nie są one obsługiwane przez żaden z moich składników interfejsu, przekazuję zdarzenie do „Świat” do wybierania / selekcji. Coś jak:

@Override  
private boolean handleEvent(Event event) {  
    if(hud.handleEvent(event)) {  
        return true;  
    }  
    return WORLD.handleEvent(event);  
}

W ten sposób nie dostaję kliknięć przez interfejs użytkownika, aby wybrać obiekty za przyciskami, a co nie.

Obecnie moje sterowanie kamerą wciąż opiera się na odpytywaniu, i wydaje się, że na razie działa, ale mogę to później zaktualizować.

Doceniam wszystkie odpowiedzi, przepraszam, że mogłem wybrać tylko jedną!

MichaelHouse
źródło
6
Nie jestem pewien w Javie, ale ogólnie zawsze musisz sondować dane wejściowe. Możesz wtedy publikować zdarzenia, gdy rzeczy się zmieniają, ale wciąż jest to oparte na systemie odpytywania.
James
Moim zdaniem najważniejszym punktem zainteresowania jest zaprojektowanie pętli zdarzeń, która nie byłaby obciążona żadnymi innymi obciążeniami niż kolekcja danych wejściowych. Pozwól, że wyjaśnię: system operacyjny wykona przerwanie sterowane danymi wejściowymi i potraktuje je w globalnym „wątku wejściowym”, a następnie ten wątek systemu operacyjnego przekieruje wiadomości do aktualnie aktywnej aplikacji i zapisze dane wywiadowcze w kolejce komunikatów. Kolejka komunikatów musi zostać odpytana przez PeekMessage lub GetMessage. Najszybszym sposobem na uzyskanie tego jest użycie GetMessage i pozwolenie, aby harmonogram Cię obudził, a następnie możesz bardzo dokładnie oznaczyć datownik.
v.oddou

Odpowiedzi:

17

To zależy od wymagań twojej gry i sprzętu. Większość gier jest zwykle zainteresowana zmianami stanu wejściowego, tj. Użytkownik naciska klawisz ognia, a broń zaczyna strzelać, użytkownik zwalnia klawisz ognia, a broń przestaje strzelać, użytkownik naciska klawisz ruchu i zaczyna się poruszać, zwalnia klawisz ruchu i przestaje się poruszać itd., więc system wprowadzania sterowany zdarzeniami ma w tych przypadkach największy sens, ponieważ informacje są już w odpowiednim formacie. Ponadto na platformie Windows już odbierasz zdarzenia dotyczące zmian stanu klawiatury i myszy, więc często jest to konwersja 1: 1 ze zdarzeń wejściowych niskiego poziomu na zdarzenia gier wysokiego poziomu. Dzięki sondowaniu często trzeba ręcznie generować takie zdarzenia, porównując stan między bieżącą a ostatnią klatką. Zasadniczo „które przyciski są teraz wciśnięte?”

To powiedziawszy, na niektórych platformach utknąłeś na wejściach z ankietami na niskim poziomie i nie ma możliwości obejrzenia się od krawędzi. Jednak zawsze osiągałem najlepsze wyniki, wykorzystując zdarzenia dla całej logiki wysokiego poziomu, ponieważ w naturalny sposób działają te systemy.

Skyler York
źródło
Dzięki, zamieściłem dodatkowe informacje na temat platformy i celu gry.
MichaelHouse
1
Zauważ, że GetAsyncKeyStatejest to prosty sposób na użycie odpytywania w Win32.
Macke,
Derp, zadałem pytanie w komentarzach Nate'a Brossa, z którym masz tu do czynienia, więc chyba poprawię to. Czy wszystkie komputery oferują przerwanie sprzętowe 1: 1 w związku ze zdarzeniem związanym z klawiaturą systemu operacyjnego i jakie platformy są ograniczone do odpytywania niskiego poziomu?
michael.bartnett
@Macke: czasami programy antywirusowe zgłaszają programy korzystające z tego interfejsu API, ponieważ mogą otrzymywać naciśnięcia klawiszy z całego systemu globalnego, umożliwiając w ten sposób złośliwe rejestrowanie klawiatury. Najbardziej niesamowity artykuł na ten temat w całym Internecie (wiem o tym) to: securelist.com/analysis/publications/36358/…
v.oddou
7

Nie widzę powodu, dla którego nie możesz zrobić obu i uzyskać to, co najlepsze z obu światów.

Zdarzenia wejściowe są generowane przez odpytywanie (na pewnym poziomie sterownik odpytuje sprzęt, aby zobaczyć, w jakim jest stanie), a ponieważ główna pętla odpytuje wszystkie urządzenia wejściowe, możesz łatwo wdrożyć własne. Coś prostego, takiego jak poniżej, używałem w przeszłości.

mouseInput = GetMouse();
kbInput = GetKeyboard();


// refactor this out to its own method if it makes sense
if menuState == Showing
    if mouseInput.LeftButton == State.Pressed
        LeftButton(mouseInput.X, mouseInput.Y)

// rest of game input code processing

void LeftButton(int x, int y)
{
    // left button event handler
}

Wiem, że zdefiniowałeś zdarzenia jako zakłócenia, a to, co tu umieściłem, nie jest „oparte na prawdziwych zdarzeniach”, ale nie rozumiem, co nie daje ci powyższe, że zakłócenia dają - większość użytkowników nie zauważy utrata pojedynczej klatki, chyba że gra działa z bardzo małą liczbą klatek.

Nate
źródło
1
Jestem ciekaw natury otrzymywania danych wejściowych z urządzeń. Czy zdarzenia klawiatury wysyłane przez system operacyjny są wynikiem odpytywania na poziomie sterownika urządzenia? Czy zdarzenie na klawiaturze odpowiada przerwaniu? A może występują przerwania, ale system operacyjny buforuje je i wysyła, gdy uzna to za stosowne?
michael.bartnett
Nie jestem pewien, jak działa na tym poziomie, ale jest to najbardziej podstawowe, niektóre programy działają w pętli i sprawdzają stan klawiatury i porównują ją z poprzednim stanem, jeśli zmiana ulegnie zmianie.
Nate
5

Istnieją tutaj dwa różne problemy:

  1. Jak odczytujesz dane wejściowe użytkownika z systemu operacyjnego / sprzętu?

  2. Jak przetwarzasz dane wejściowe użytkownika w silniku?

Jeśli chodzi o czytanie, zależy to wyraźnie od platformy i rodzaju danych, które chcesz przeczytać. Zauważ, że łatwo jest przekonwertować jedną rzecz na drugą w warstwie wejściowej. (Tj. Odpytuje i emituje zdarzenia do silnika lub nasłuchuje zdarzeń i emituje stan do silnika).

Do przetwarzania istnieje kilka różnych opcji:

  • W przypadku kontroli ruchu gracza (i podobnych schematów) odpytywanie może być prostsze, ponieważ trzeba ponownie obliczyć prędkość każdej klatki. Jest bardzo prawdopodobne, że Twoja wewnętrzna pętla będzie oparta na sondowaniu:

    tj. coś podobnego speed += 1 if button.down else -1; clamp(speed, 0, 42);

  • W przypadku zdarzeń dyskretnych (pocisk ognia, gra pauzy, teleportacja na drugą stronę planety) przetwarzanie zdarzeń jest preferowane, w przeciwnym razie twój kod będzie pełen maybeLaunchMissile(key_state);połączeń, a to po prostu ... źle, dobrze. ;)

Mam nadzieję, że to pomoże.

Macke
źródło