Obsługa UI dowolnymi urządzeniami — chować kursor czy nie?

Obsługa UI dowolnymi urządzeniami — chować kursor czy nie?
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około godziny
  • Lokalizacja:Tuchów
  • Postów:12168
2

Kończę klepać kod obsługi UI w swoim silniku, na liście TODO zostało mi jeszcze kilka pozycji, w tym ta dotycząca kursora myszy. Nie mam bogatego doświadczenia z graniem w bardziej nowoczesne tytuły, dlatego potrzebuję porady w tej sprawie.

Otóż kernel UI, w obecnej formie, pozwala obsługiwać główne menu dowolnym urządzeniem — myszą, klawiaturą i gamepadami. Jeśli kursor znajduje się w obrębie kontenera UI, aktualizator sprawdza czy jakaś kontrolka znajduje się pod kursorem — jeśli tak to ją fokusuje i przekazuje jej zdarzenia myszy (ruch kursora, klikanie, scrollowanie itd.). Jeśli pod kursorem nie ma żadnej kontrolki, to żadna nie jest aktywna (nie ma fokusu) — jeśli kontrolka była sfokusowana, ale kursor wyjechał poza jej obszar, to traci ona fokus.

Ogólnie chodzi o to, że jeśli gracz rusza myszą i coś klika/scrolluje, to kontener UI będzie posiadał sfokusowaną (aktywną) kontrolkę tylko wtedy, gdy kursor nad jakąś kontrolką się znajduje. Jeśli kursor jest nad pustym obszarem kontenera, to nie ma fokusu.

Teraz zostało mi jeszcze dodać flagę, aby gdy mysz jest w użyciu i gracz wciśnie klawisz lub coś na gamepadzie, to mysz się deaktywuje, kursor się chowa i od tego momentu input myszy jest ignorowany. W ten sposób, jeśli gracz będzie chciał grać np. tylko gamepadem, będzie sobie sterował UI za pomocą gamepada (lub pomagał sobie klawiaturą), a kursor myszy nie będzie mu przeszkadzał (będzie ukryty).


Według mnie, jeśli ktoś nie chce używać myszy, bo woli klawiaturę lub gamepady, to kursor powinien być stale niewidoczny. Aby jednak móc w dowolnym momencie skorzystać z myszy, wystarczy ją ruszyć lub kliknąć, kursor się pokaże i kontener UI sfokusuje to co jest pod kursorem (jeśli nie ma pod nim kontrolki to usunie fokus z kontenera).

I tutaj mam pytanie — dla mnie takie zachowanie jest bardzo dobre, a dla was?

Mogę zrobić tak, że kursor myszy będzie stale widoczny i będzie zmieniał fokus tylko jeśli wjedzie się nim w obszar innej kontrolki niż aktualnie sfokusowana. Widziałem, że tak to działa w kilku grach, jednak są to gry, w które trzeba grać myszą. Moja gra taką nie będzie — gamepady i klawiatura będą najlepsze do grania, ale mapper dopuszcza użycie myszy dla praktycznie dowolnej akcji (w tym chodzenia). Jeśli więc gracz będzie chciał grać np. mysz+klawiatura, to nie ma problemu — wtedy obsługa wszystkich menu myszą będzie idealna, wręcz obowiązkowa.

Jak to widzicie? Wolelibyście cały czas widzieć kursor czy żeby był ukryty, jeśli nie chcielibyście używać myszy? A podczas korzystania z myszy w menu, wolelibyście aby mysz umożliwiała tylko aktywację kontrolki pod kursorem, czy aby też deaktywowała kontrolkę, jeśli przesunie się go w puste miejsce kontenera UI?


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
axelbest
  • Rejestracja:ponad 17 lat
  • Ostatnio:około 17 godzin
  • Lokalizacja:Warszawa
  • Postów:2251
3

Ja bym to widział tak:
Kursor ma być widoczny tylko wtedy gdy gramy na klawiaturze/myszce. Zmiana schematu powinna następować w locie:

  1. Gram padem - widzę sterowanie dopasowane pod pada - nie widzę kursora (co najwyżej hovery nad opcjami/elementami gry)
  2. Grając padem - postanawiam odłożyć go na bok, macham myszką - sterowanie dopasowuje się do myszki (lub/i klawiatury) - kursor jest widoczny
  3. Biorę pada do ręki - naciskam dowolny przycisk - sterowanie przestawia się z powrotem na pada - kursora nie widać.

Spotkałem się z takim podejściem w wielu grach na steamie i lepszej opcji nie widzę.

edytowany 1x, ostatnio: axelbest
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około godziny
  • Lokalizacja:Tuchów
  • Postów:12168
0

Tutaj chodzi o obsługę głównego menu i wszystkich innych menu, które mają być obsługiwane dowolnym urządzeniem, bez uwzględniania mappingu (przypisanych triggerów do akcji gry). Np. każde ogólne menu może być sterowane klawiszami strzałek oraz Esc i Enter, jeśli chodzi o gamepady to nawigacja D-Padem lub gałkami analogowymi, a wybór i cofanie przyciskami 1 i 2 (opcjonalnie 3 i 4). Może też być myszą, tak samo jak w powłoce Windows — ruch kursora, klikanie, capturing itd.

axelbest napisał(a):

Spotkałem się z takim podejściem w wielu grach na steamie i lepszej opcji nie widzę.

Do czasu aż zechcesz pograć retro-kontrolerem, który np. posiada tylko D-Pad i sześć przycisków. Ciekawe jak te genialne, automatyczne mappery przypiszą do takiego funkcje gry. A będzie jeszcze ciekawiej, jeśli — tak jak w przypadku moich retro-kontrolerów — wszystkie posiadają ten sam numer Vendor i Product oraz identyczną nazwę, przez co nie da się ich odróżnić z poziomu software'u, choć mają różną liczbę osi i przycisków.


Zapytałem was o opinię dotyczącą tego, czy lepiej by było gdyby kursor znikał, gdy nawiguje się klawiaturą/gamepadami, czy lepiej by było gdyby był cały czas widoczny (i czy kursor w pustym miejscu kontenera ma deaktywować kontrolki czy nie). Proszę, abyście się skupili na zachowaniu kursora myszy, bo opinie na ten temat będą mi pomocne, nie na mapperze.

Z drugiej strony, już na początku prac nad tym silnikiem ustanowiłem, że nie będę korzystał z żadnych automatycznych mapperów, tym bardziej, że są one z założenia niepoprawne i problematyczne. Mapper własnego pomysłu mam już zaimplementowany i z niego nie zrezygnuję. Ten wątek dotyczy tylko zachowania kursora myszy w trakcie obsługi UI.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 5x, ostatnio: flowCRANE
T3
  • Rejestracja:ponad 4 lata
  • Ostatnio:6 miesięcy
  • Postów:687
0
axelbest napisał(a):
  1. Gram padem - widzę sterowanie dopasowane pod pada - nie widzę kursora (co najwyżej hovery nad opcjami/elementami gry)
  2. Grając padem - postanawiam odłożyć go na bok, macham myszką - sterowanie dopasowuje się do myszki (lub/i klawiatury) - kursor jest widoczny
  3. Biorę pada do ręki - naciskam dowolny przycisk - sterowanie przestawia się z powrotem na pada - kursora nie widać.

Tak jak tutaj napisane, tak to się aktualnie robi i takiego rozwiązania oczekiwaliby gracze

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około godziny
  • Lokalizacja:Tuchów
  • Postów:12168
0

Czyli automatyczne pokazywanie i ukrywanie kursora wg was i innych jest spodziewane. Spoko.

Pozostaje jeszcze druga kwestia — czy ruch kursora nad pustym obszarem ma deaktywować aktualnie aktywną kontrolkę, czy powinna ona być cały czas aktywna, dotąd, aż kursor najedzie na inną kontrolkę. IMO pierwsza opcja, czyli dezaktywacja kontrolki, gdy kursor opuści jej obszar, jest intuicyjna.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
Spine
  • Rejestracja:około 22 lata
  • Ostatnio:5 minut
  • Postów:6653
1

Ja u siebie nie wchodziłem aż w takie szczegóły, ale robiłem tak jak mi najwygodniej i to jak to finalnie działa jest tylko konsekwencją mojej radosnej twórczości.

Kursor pokazuje się tylko w menu oraz podczas pauzy.
Kiedy najadę kursorem na przycisk to ma on focus, który może się tylko zmienić gdy najadę kursorem na inny przycisk lub użyję klawisza nawigacji.
Kiedy kursor znajduje się nad przyciskiem, klawisze nawigacji wtedy nie mają efektu.

Filmik z gierki:

BTW. w starych gierkach (NES) twórcy poszli o krok dalej i kursor myszy jest poruszany przy użyciu innych kontrolerów ;)
np.:

To by wiele ułatwiało, bo bindingi nawigacji byś po prostu podpiął pod zmianę pozycji wirtualnego kursora.


🕹️⌨️🖥️🖱️🎮
edytowany 6x, ostatnio: Spine
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około godziny
  • Lokalizacja:Tuchów
  • Postów:12168
1
Spine napisał(a):

Ja u siebie nie wchodziłem aż w takie szczegóły, ale robiłem tak jak mi najwygodniej i to jak to finalnie działa jest tylko konsekwencją mojej radosnej twórczości.

Dla mnie wchodzenie w szczegóły jest codziennością — dbam o każdy. ;)

Kursor pokazuje się tylko w menu oraz podczas pauzy.

U mnie tak samo by to działało, ale tylko wtedy, gdy gracz lub któryś z dwóch graczy ma przypisane akcje do triggerów myszy (i jej ruchu). Wtedy wejście w któreś główne menu spowoduje automatyczne pokazanie się kursora.

Po drugie, musi to też działać w trakcie gry. Jeśli któryś gracz ma przypisane akcje do myszy, to wejście w zasobnik z przedmiotami (wąskie menu, wysuwane z boku) również będzie sterowane za pomocą myszy, więc kursor też powinien się sam pokazywać i, dodatkowo, być obsługiwanym bez uwzględnienia mappingu (lewy przycisk służy do klikania, nieważne która akcja jest pod niego podpięta i czy w ogóle).

Kiedy najadę kursorem na przycisk to ma on focus, który może się tylko zmienić gdy najadę kursorem na inny przycisk lub użyję klawisza nawigacji.
Kiedy kursor znajduje się nad przyciskiem, klawisze nawigacji wtedy nie mają efektu.

Oglądnąłem twoje demo — fajnie to działa. Tyle że u ciebie kursor jest widoczny cały czas, nawet jeśli użyje się klawiatury. Podobnie działa menu np. w Nuclear Throne, tyle że tam jest ciut inaczej, bo jeśli kursor jest nad kontrolką i wciśnie się klawisz, to fokus się przenosi. Jeśli ruszy się myszą to nic się nie dzieje, kontrolka pod kursorem nie dostaje fokusu. Dopiero po zabraniu kursora znad tej nieaktywnej kontrolki i najechaniu na nią jeszcze raz, otrzyma ona fokus.

BTW. w starych gierkach (NES) twórcy poszli o krok dalej i kursor myszy jest poruszany przy użyciu innych kontrolerów ;)

[...]

To by wiele ułatwiało, bo bindingi nawigacji byś po prostu podpiął pod zmianę pozycji wirtualnego kursora.

Dałoby się to zrobić, np. używać prawej gałki analogowej do obsługi kursora. Ale nie wiem czy jest sens, skoro zdecydowanie szybciej da się przenieść fokus używając D-Pada lub gałki analogowej po prostu przeskakując po kontrolkach.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 3x, ostatnio: flowCRANE
T3
  • Rejestracja:ponad 4 lata
  • Ostatnio:6 miesięcy
  • Postów:687
0
furious programming napisał(a):

Pozostaje jeszcze druga kwestia — czy ruch kursora nad pustym obszarem ma deaktywować aktualnie aktywną kontrolkę, czy powinna ona być cały czas aktywna, dotąd, aż kursor najedzie na inną kontrolkę. IMO pierwsza opcja, czyli dezaktywacja kontrolki, gdy kursor opuści jej obszar, jest intuicyjna.

Tylko pierwsza opcja, tak aktualnie się robi.
Jeśli byłaby druga opcja, to jakie byłoby działanie, jeżeli najedziesz na przycisk, a później poza niego, np. na tło i kliknalbys LMB? Skoro byłby ciągle podświetlony jakiś przycisk, to wydawałoby się, że musiałaby się zadziać wtedy taka sama akcja, jakbyś kliknął w przycisk, a to byłoby mylące

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około godziny
  • Lokalizacja:Tuchów
  • Postów:12168
0
tmk3 napisał(a):

Tylko pierwsza opcja, tak aktualnie się robi.

Druga opcja też jest używana — dlatego właśnie dopytuję.

Jeśli byłaby druga opcja, to jakie byłoby działanie, jeżeli najedziesz na przycisk, a później poza niego, np. na tło i kliknalbys LMB? Skoro byłby ciągle podświetlony jakiś przycisk, to wydawałoby się, że musiałaby się zadziać wtedy taka sama akcja, jakbyś kliknął w przycisk, a to byłoby mylące

Jeśli mam kursor nad kontrolką i wyjadę poza obszar, to ta kontrolka się nie odznacza. Jeśli kliknę w pusty obszar, to zostaje wykonana akcja tej aktywnej kontrolki. Dziwne to, ale w niektórych przypadkach nawet działa to sensownie.

Np. w Nuclear Throne tak to działa. Co kilka poziomów pokazuje się ekran z wyborem jednej spośród czterech losowych mutacji — cztery karty są wyświetlone na dole. Można najechać kursorem na jedną z nich i kliknąć w nią, aby ją wybrać. Druga opcja — klawiszami kierunku (np. WSAD) ustawić fokus na wybranej karcie i kliknąć w pustym miejscu — też zostanie wybrana aktywna karta. I o ile przydatne to jest na tym ekranie, tak niestety dokładnie tak samo działa to w menu głównym, co przyprawiało mnie o ból głowy — nie mogłem za bardzo ogarnąć co się dzieje. Dopiero po dłuższej chwili sprawdziłem jak to działa i ogarnąłem. Tego typu dziwactw chcę uniknąć.


Dla mnie intuicyjne jest to, że jeśli kursor jest nad kontrolką to ta się aktywuje, a jeśli się go zabierze znad niej to się deaktywuje — na razie tak to mam zaimplementowane (pomijając obsługę mouse capture, bo to specjalny ficzer). Tak samo dla mnie intuicyjne jest to, że kliknięcie w coś powinno być zaliczane, jeśli nad kontrolką wcisnę i puszczę przycisk myszy, nie przesuwając za bardzo kursora, a tym bardziej nie zabierając go znad obszaru kontrolki.

Problem pojawia się wtedy, gdy kursor zabierze się w puste miejsce i wciśnie coś na klawiaturze/gamepadzie. Nie ma sfokusowanej kontrolki, więc trzeba nową jakoś wyznaczyć. Obecnie mam to zrobione tak, że aktywuje się ta najbliżej środka obszaru kontenera UI (ignorując kontrolki ukryte, zablokowane i te, które nie akceptują fokusu) — działa to dość fajnie, efekt jest intuicyjny. Wszystko dlatego, że kontener może być większy niż widoczny obszar na ekranie i to pozwala aktywować coś co jest widoczne na ekranie.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 5x, ostatnio: flowCRANE
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)