Ten sam statek na każdym ekranie
Dzienny ranking jest sprawiedliwy tylko wtedy, gdy przelot przez ten sam odcinek jaskini jest jednakowo trudny na starym małym telefonie, tablecie 144 Hz i w przeglądarce na komputerze. Oto czego to wymagało i czego nie udało mi się zrównać.
Wpis o codziennej jaskini dotyczył uczynienia świata identycznym dla każdego gracza. Ten dotyczy drugiej połowy sprawiedliwości: sprawienia, by statek zachowywał się identycznie. Istnieją dwa oddzielne sposoby, w jakie urządzenie może zmienić sposób rozgrywki, i wymagają one dwóch oddzielnych poprawek. Jeden to częstotliwość odświeżania ekranu. Drugi to rozmiar ekranu.
Problem pierwszy: częstotliwość odświeżania
Statek ma pozycję i prędkość. W każdej klatce grawitacja lub ciąg zmienia prędkość, a prędkość zmienia pozycję. Oczywisty sposób, by to zapisać, to:
vy += accel * dt; // update velocity
py += vy * dt; // then move by the NEW velocity
Wygląda niegroźnie, ale jest subtelnie błędny. Druga linia udaje, że statek już spędził całą klatkę, poruszając się z prędkością na koniec klatki. Jeśli statek przyspiesza, to przekracza to o połowę accel × dt² w każdej pojedynczej klatce. Haczyk polega na tym, że dt, długość klatki, jest inna na każdym urządzeniu, więc przekroczenie też jest inne, a statek leciał nieco inną trasą przy każdej częstotliwości odświeżania.
Zmierzyłem to przy przytrzymanym ciągu przez pół sekundy. Dokładna odpowiedź to 225 pikseli. Stary integrator dawał 228 przy 144 Hz, 232 przy 60 Hz i 240 przy 30 Hz. Trzy urządzenia, trzy różne odległości, przy tym samym wejściu.
Poprawką jest reguła trapezów, która wykorzystuje średnią z prędkości przed i po klatce:
const vyPrev = vy;
vy += accel * dt;
py += (vyPrev + vy) * 0.5 * dt; // average speed over the frame
Dla stałego przyspieszenia jest to dokładne, niezależnie od długości klatki. Odtworzenie identycznego harmonogramu wejścia daje teraz rozrzut 0,000 pikseli w zakresie od 12 do 144 Hz. Wcześniej było to 4,1 piksela. Test sprawdza obie połowy: że nowy integrator zgadza się przy wszystkich częstotliwościach odświeżania oraz że stary rzeczywiście się rozjeżdżał, więc jeśli ktoś to cofnie, test się nie powiedzie, zamiast by ranking po cichu dryfował.
Dwa uczciwe zastrzeżenia
To nie zamknęło różnicy w wyniku między częstotliwościami odświeżania. Spodziewałem się tego. Symulowany pilot nadal zdobywał około jedną trzecią więcej punktów przy 144 Hz niż przy 60 Hz, nawet potem. Ta różnica to nie fizyka. To rozdzielczość wejścia: kciuk może zmienić się z przytrzymania na puszczenie tylko na granicy klatki, więc szybszy ekran naprawdę daje dokładniejszą kontrolę. Żaden integrator tego nie naprawi, a bot, który odwraca swoje wejście co klatkę, wyolbrzymia to w porównaniu z człowiekiem. Fizyczna połowa jest teraz dokładna, a reszta to właściwość sprzętu.
Przy 60 Hz to bardzo lekkie osłabienie. Półsekundowe wznoszenie pokonuje teraz 225 pikseli zamiast 232. Zostawiłem to bez rekompensaty. Gdyby test na prawdziwym urządzeniu kiedykolwiek uznał statek za ospały, dźwignią jest stała ciągu, około 3% więcej przywróciłoby stary półsekundowy manewr. To dobry moment, by powiedzieć, że ciąg był już wcześniej dwukrotnie zmieniany na podstawie opinii graczy, a ta historia jest powodem, dla którego jestem ostrożny, dotykając go.
Problem drugi: wysokość ekranu
Grawitacja w pikselach na sekundę do kwadratu oznacza zupełnie coś innego na telefonie o wysokości 375 punktów i tablecie o wysokości 520 punktów. Gdyby stałe były takie same, to samo wznoszenie przekraczałoby dużo mniejszą część ekranu na tablecie, a gra wydawałaby się cięższa.
Dlatego stałe są zdefiniowane względem wysokości referencyjnej 440 punktów, wysokości w orientacji poziomej największego iPhone'a, gdzie odczucie gry zostało dostrojone i przetestowane. Na każdym innym ekranie grawitacja, ciąg i prędkość graniczna są mnożone przez H / 440. Ponieważ połowa szczeliny korytarza również skaluje się z wysokością, każda trajektoria jest geometrycznie podobna do referencyjnej: ten sam ułamek korytarza pokonywany na sekundę, ten sam czas na przejście z jednej ściany na drugą, ta sama odczuwalna responsywność. Większy ekran otrzymuje bardziej strome przyspieszenie w pikselach, a mniejszy łagodniejsze, celowo.
Wiąże się to z regułą dla całego przyszłego kodu: wszystko, co rozumuje o ruchu pionowym, musi opierać się na proporcjach. Ułamek prędkości granicznej, ułamek wysokości. Nigdy surowa stała w pikselach na sekundę porównywana z prędkością statku, ponieważ ta liczba jest poprawna tylko na jednym urządzeniu. Jeśli literał jest nieunikniony, mnoży się go przez tę samą skalę.
Wersja webowa przestrzega tej samej reguły. Build przeglądarkowy ogranicza swoje płótno do 956 na 440, tego samego rozmiaru co ten referencyjny telefon, więc gra w przeglądarce jest dokładną kopią pikselową i fizyczną tamtej. Wcześniejszy build webowy miał swój własny oddzielny mnożnik odczucia, który istniał tylko po to, by zwalczać miękkość spowodowaną innym limitem, i został usunięty, gdy limit zaczął się zgadzać.
Problem trzeci: szerokość ekranu
Wysokość to oś pionowa. Szerokość to oś pozioma i jest bardziej subtelna. Przeszkody są rozmieszczone w stałych odległościach w świecie. Jaskinia przewija się z prędkością, która zawiera czynnik szerokości ekranu. Więc na szerszym ekranie te same przeszkody mijają szybciej w kategoriach ekranu, a czas, jaki masz na zareagowanie na każdą z nich, spada proporcjonalnie do szerokości.
To był prawdziwy wyciek. Duży tablet z Androidem o szerokości około 1280 punktów stawał wobec wspólnej jaskini z prędkością mniej więcej 1,75 raza większą niż mały telefon. Dlatego szerokość jest ograniczona do 956 punktów na każdej platformie, czyli szerokości najszerszego iPhone'a w orientacji poziomej. Urządzenie szersze niż to dostaje czarne pasy po lewej i prawej stronie. Nie ma to żadnego efektu na iPhone'ach i ogranicza tylko duże urządzenia z Androidem oraz przeglądarki na komputerach.
Limit ma nienaprawioną pozostałość. Promień kolizji gracza skaluje się z szerokością, podczas gdy korytarz skaluje się z wysokością, więc na bardziej kwadratowym tablecie statek jest nieco mniejszy względem szczeliny niż na telefonie, mniej więcej o 20% bardziej wybaczający. Naprawienie tego oznacza zmianę hitboxa, co jest zmianą odczucia wymagającą własnego playtestu, a błąd idzie w wybaczającym kierunku, więc może poczekać.
Testowanie sprawiedliwości zamiast jej zakładania
Nic z tego nie jest widoczne podczas grania. Nie da się poczuć kilku pikseli dryfu i nikt nie gra w tę samą jaskinię na sześciu urządzeniach naraz. Dlatego każde twierdzenie ma test, który je odtwarza: test fizyki całkuje stałe wejście przy częstotliwościach odświeżania od 12 do 144 Hz, a test jaskini odtwarza prawdziwe generatory na sześciu rozmiarach urządzeń i porównuje wynik bajt po bajcie. Z mojego doświadczenia wynika, że nietestowana właściwość sprawiedliwości już po cichu się zepsuła.
Krótko mówiąc, TUNL jest sprawiedliwy między ekranami na trzy oddzielne sposoby (częstotliwość odświeżania, wysokość i szerokość), każdy z inną przyczyną, inną poprawką i inną pozostałością. Możesz sam zobaczyć wynik, na dowolnym posiadanym urządzeniu, w dzisiejszej jaskini.