Zaczynając te badania, spodziewałem się znaleźć kilka interesujących eksperymentów z walką w przeglądarce. Zamiast tego trafiłem na znacznie szerszy ekosystem: prawdziwe prototypy gier akcji z perspektywy trzeciej osoby, z namierzaniem celu, rozgałęzionymi drzewami kombinacji, perfekcyjnym parowaniem, niewrażliwością podczas uniku, systemami postawy, atakami w powietrzu, sygnalizowaniem ataków bossów, motion warpingiem, hit-stopem, fizycznymi starciami broni, obsługą gamepada, sterowaniem dotykowym i deterministyczną symulacją.
To jest najważniejszy wniosek. Nie są to już po prostu małe gry, które przypadkiem renderują się na stronie internetowej. Część z nich rozwiązuje te same problemy inżynieryjne co klasyczne gry akcji, ale są dystrybuowane jako URL i można zacząć w nie grać od razu.
Dla mnie, jako programisty webowego, właśnie to jest najbardziej fascynujące. Stary sposób myślenia o grach był zdominowany przez instalatory, duże pliki do pobrania, patchery, launchery i opóźnienie między odkryciem gry a faktycznym wejściem z nią w interakcję. Przeglądarka radykalnie skraca tę drogę: otwierasz link, wczytujesz zasoby i zaczynasz grać.
W tych badaniach skupiłem się na projektach z grywalną wersją przeglądarkową i publicznie dostępnym kodem źródłowym. Eksporty Unity WebGL celowo wykluczyłem, ponieważ chciałem badać gry zbudowane wokół technologii webowych, a nie gry jedynie wyeksportowane do sieci.
Najmocniejsze projekty, które znalazłem
Najbardziej użyteczne znaleziska nie były mocne z tego samego powodu. Jedne miały najbardziej rozbudowane systemy kombinacji. Inne oferowały lepszą architekturę gry z perspektywy trzeciej osoby, czystszą symulację walki albo bardziej przekonujące fizyczne trafienia.
| Projekt | Najmocniejsza strona | Co warto przeanalizować | Demo | Źródło |
|---|---|---|---|---|
| Long Wind | Nowoczesna walka z perspektywy trzeciej osoby | Namierzanie celu, parowanie, postawa, dobicia, reakcje na trafienia | Uruchom demo | GitHub |
| Voxel Musou | Architektura kombinacji | Rozgałęzione ruchy, ataki w powietrzu, zestawy umiejętności postaci, tłumy | Uruchom demo | GitHub |
| Rotten Souls | Fundament gry z perspektywy trzeciej osoby | Namierzanie celu, uniki, walka z bossami, struktura animacji i kamery | Uruchom demo | GitHub |
| Samurai Third-Person Template | Motion warping | Pozycjonowanie ataku, namierzanie, strategia root motion | Uruchom demo | GitHub |
| Stick & Steel | Walka wręcz oparta na fizyce | Kontakt broni, kierunek gardy, walidacja uderzenia, powalenia | Uruchom demo | GitHub |
| Jelly Colosseum | Kompaktowa pętla walki wręcz | Lekkie i ciężkie ataki, parowanie, wytrzymałość, przełamanie gardy, charakter broni | Uruchom demo | GitHub |
| Hollowmere | Architektura walki | Deterministyczna symulacja, scentralizowane rozstrzyganie obrony, testowanie | Uruchom demo | GitHub |
| Fabled Revolutions | Odczucia z gry | Hit-stop, wstrząsy kamery, smugi, cząsteczki, odrzut, informacja zwrotna o uderzeniu | Uruchom demo | GitHub |
Dlaczego wyniki mnie zaskoczyły
Zaskoczeniem nie było po prostu to, że grafika wyglądała dobrze. Wyrenderowanie dopracowanej sceny to tylko jedna część tworzenia gry. Wyróżniające się projekty implementowały systemy, które trudno przekonująco udawać: buforowanie wejścia, przejścia między stanami walki, wybór celu, ruch podczas ataku, synchronizację animacji, wykrywanie trafień, reakcje przeciwników, okna obrony, zachowanie kamery i informację zwrotną o sile uderzenia.
Prowadzi to do kilku użytecznych rozróżnień:
- timing animacji to nie timing walki;
- częstotliwość renderowania klatek to nie częstotliwość symulacji;
- kolizja nie oznacza automatycznie prawidłowego trafienia;
- animacja nie musi być źródłem prawdy o ruchu;
- wizualny kontakt to nie to samo co odczuwalna siła uderzenia.
Te rozróżnienia powtarzały się w najlepszych projektach i są ważniejsze niż logo renderera w README.
Voxel Musou: walka w przeglądarce może mieć prawdziwą gramatykę ruchów
Voxel Musou było jednym z najczytelniejszych przykładów pokazujących, że walka w przeglądarce nie musi już oznaczać jednej animacji ataku przypisanej do jednego przycisku. Kod źródłowy jest dostępny w repozytorium mike007jd/voxel-musou.
Projekt wykorzystuje długie łańcuchy zwykłych ataków i rozgałęzienia ataków ładowanych zamiast całkowicie liniowego combo. Ma to znaczenie architektoniczne, ponieważ system można opisać jako:
current move + buffered input + combat state -> next moveTo znacznie lepsza podstawa dla gry character-action niż stale rosnący zbiór warunków obsługujących szczególne przypadki. Projekt pokazuje też ataki w powietrzu, sekwencje specjalne, różne zestawy umiejętności postaci, zachowania bossów, hit-stop i walkę z dużymi grupami przeciwników.
Szersza lekcja inżynieryjna brzmi: ruchy powinny stać się danymi, a przejścia powinny być jawne. Gdy tak się stanie, dodanie kolejnej postaci nie wymaga już przepisywania całego kontrolera walki.
Long Wind: najbliżej współczesnej przeglądarkowej gry akcji
Long Wind było jednym z najmocniejszych kompleksowych punktów odniesienia, ponieważ łączy ruch z perspektywy trzeciej osoby z lekkimi i ciężkimi atakami, namierzaniem celu, gardą, perfekcyjnym parowaniem, niewrażliwością podczas uniku, presją na postawę, dobiciami, reakcjami na wyrzucenie w powietrze i powalenie, pociskami, bossami oraz wieloma archetypami przeciwników. Kod źródłowy jest dostępny w repozytorium jbang2004/long-wind.
Projekt jest wartościowy nie dlatego, że każda z tych funkcji osobno jest czymś bezprecedensowym, lecz dlatego, że wszystkie współistnieją w jednym prototypie gry akcji natywnej dla przeglądarki. Dzięki temu można prześledzić całą drogę od wejścia przez wybór celu, stan ataku, animację, kontakt, reakcję i hit-stop aż po informację zwrotną z kamery.
Motion warping rozwiązuje problem często pomijany w webowych demach
Samurai Third-Person Template ThreeJS jest szczególnie interesujący, ponieważ mierzy się z klasycznym problemem walki wręcz z perspektywy trzeciej osoby. Kod źródłowy jest dostępny w repozytorium achrefelouafi/SamuraiThirdPersonTemplateThreeJS.
Przygotowana wcześniej animacja ataku zakłada, że cel znajdzie się w określonej odległości, gdy cios osiągnie klatkę kontaktu. W prawdziwej grze cel niemal nigdy nie znajduje się idealnie w tym miejscu. Jeśli postać po prostu odtworzy animację w miejscu, miecz może widocznie chybić, mimo że gra naliczy obrażenia. Jeśli postać zostanie teleportowana na właściwą pozycję, atak wygląda sztucznie.
Motion warping daje lepsze rozwiązanie: dostosować obrót i przesunięcie podczas ataku tak, aby postać znalazła się w oczekiwanej pozycji kontaktu w odpowiednim momencie.
Kluczowe rozróżnienie wygląda tak:
animation intent != movement authorityPostać może zachować wizualny zamiar przygotowanej animacji, a jednocześnie kontroler rozgrywki pozostaje autorytatywnym źródłem informacji o tym, dokąd postać faktycznie się przemieszcza.
Wykrywanie kolizji i walidacja trafienia to dwa różne problemy
Stick & Steel bada zupełnie inny model walki. Kod źródłowy jest dostępny w repozytorium Rabneba/stick-steel.
Zamiast traktować miecz przede wszystkim jako animację z obszarem zadawania obrażeń, projekt nadaje broni fizyczną obecność. Znaczenie mają prędkość kontaktu, orientacja broni, część ciała, gardy, starcia broni, powalenia i rozbrojenie.
Najbardziej uniwersalna lekcja nie polega na tym, że każda gra akcji powinna korzystać z w pełni fizycznej broni. Chodzi o to:
Kolizja mówi, że dwa obiekty się zetknęły. Nie mówi, czy doszło do znaczącego trafienia.
Przekonujący system walki często potrzebuje drugiej warstwy, która rozstrzyga, czy kontakt miał wystarczającą prędkość, właściwy kierunek, właściwy obszar broni, właściwy moment i prawidłowy stan celu, aby zaliczyć go jako obrażenia.
Scentralizowane rozstrzyganie walki ułatwia analizowanie złożonej obrony
Hollowmere, którego kod źródłowy znajduje się w repozytorium euuuuuuan/hollowmere-public, wyróżniało się mniej oprawą wizualną, a bardziej architekturą oprogramowania.
Symulacja walki jest oddzielona od renderowania, a rozstrzyganie obrony scentralizowane. Pozwala to uniknąć częstego problemu w grach akcji, w którym system uniku, system parowania, system reakcji na trafienie i warstwa animacji mogą niezależnie dojść do różnych wniosków co do tego, czy ten sam atak trafił.
Czystszy model mentalny to:
incoming attack -> evade | parry | hitMechanizm renderujący powinien wyświetlać wynik, a nie tworzyć drugą wersję prawdy o walce.
To rozróżnienie staje się coraz ważniejsze wraz ze wzrostem złożoności walki. Deterministyczna symulacja i jawne przejścia stanów nie są efektownymi funkcjami, ale ułatwiają testowanie, debugowanie i rozbudowę złożonego systemu walki.
Odczucia z gry to system inżynieryjny, nie dekoracja
Fabled Revolutions, z kodem źródłowym w repozytorium ericrius1/FabledRevolutions, jest użyteczne właśnie dlatego, że izoluje efekty sprawiające, iż trafienia wydają się mocne.
Logicznie poprawny system walki nadal może sprawiać wrażenie słabego. Kolizja może być dokładna, obrażenia mogą zostać zadane we właściwej klatce, a mimo to całość może wyglądać jak dwa modele przenikające przez siebie.
Odczuwalna siła uderzenia często wynika z nałożenia na siebie krótkotrwałych efektów:
- hit-stop;
- wstrząs lub szarpnięcie kamery;
- smugi broni;
- cząsteczki uderzenia;
- błysk po otrzymaniu obrażeń;
- odrzut;
- reakcja animacji;
- dobrze zsynchronizowany dźwięk.
Prowadzi to do kolejnego użytecznego rozróżnienia: poprawność systemu walki to nie to samo co odczucie walki. Gra przeglądarkowa potrzebuje obu.
Mechanizm renderujący nie był głównym wyznacznikiem jakości walki
Jedną z ciekawszych prawidłowości w tych badaniach było to, że jakość najlepszych systemów walki nie zależała od tego, czy projekt używał najnowszego API renderowania.
Three.js pojawiało się wielokrotnie. Część projektów korzystała z technologii renderowania związanych z WebGPU, inne z konwencjonalnych stosów opartych na WebGL. W badanych projektach pojawiały się silniki fizyczne, TypeScript, JavaScript, Vite, WebAssembly oraz różne podejścia do renderowania.
Zaawansowana walka znacznie częściej zależała jednak od architektury: symulacji ze stałym krokiem, jawnych stanów, niezawodnego namierzania, sensownego podziału odpowiedzialności za animację, ruchów sterowanych danymi, scentralizowanego rozstrzygania obrażeń i dobrej informacji zwrotnej o uderzeniach.
To dobra wiadomość dla programistów webowych. Nie trzeba czekać, aż każdy użytkownik będzie miał najnowszy stos graficzny, aby eksperymentować z poważnym projektowaniem systemów walki.
Dlaczego dystrybucja przez przeglądarkę zmienia układ sił
Przeglądarka ma przewagę, która niewiele ma wspólnego z grafiką: wyjątkowo mało barier dystrybucyjnych.
Tradycyjne gry często stawiają kilka kroków między odkryciem a interakcją: znaleźć stronę w sklepie, pobrać duży pakiet, zainstalować go, uruchomić, poczekać na aktualizacje, a czasem jeszcze utworzyć konto, zanim dotrze się do właściwej rozgrywki.
Gra przeglądarkowa może skrócić tę drogę do jednego linku.
Zmienia to sposób udostępniania i testowania prototypów. Developer może opublikować kompilację, wysłać URL, natychmiast uruchomić tę samą wersję u innej osoby, zebrać opinię i wdrożyć kolejną iterację bez proszenia testera o ręczną instalację nowego pakietu.
Ta przewaga jest szczególnie ważna dla gier eksperymentalnych i niezależnego tworzenia gier. Przeglądarka to nie tylko środowisko uruchomieniowe; to również system dystrybucji.
Gdzie przeglądarka nadal przegrywa
Te badania nie przekonały mnie, że przeglądarki zastąpiły natywne platformy do gier. Nie zastąpiły.
Nadal istotnych jest kilka ograniczeń:
- Duże pakiety zasobów. Natychmiastowy dostęp przestaje być natychmiastowy, gdy gra wymaga bardzo dużego początkowego pobrania.
- Presja na pamięć. Przeglądarki muszą współistnieć z innymi kartami i systemem operacyjnym, a zachowanie pamięci jest mniej przewidywalne niż w dedykowanym procesie natywnym.
- Limity termiczne urządzeń mobilnych. Technicznie działająca gra 3D nadal może mocno ograniczać wydajność podczas dłuższej sesji.
- Różnice między przeglądarkami. Grafika, dźwięk, blokada wskaźnika, tryb pełnoekranowy, kontrolery i charakterystyka wydajności nie są całkowicie jednolite.
- Przygotowanie shaderów i zasobów. Kompilacja lub przesyłanie nadal może powodować widoczne przycięcia, jeśli potok przetwarzania nie został starannie zaprojektowany.
- Ograniczenia pracy offline i lokalnego zapisu. Aplikacje natywne zachowują bardziej bezpośrednią kontrolę nad dużymi lokalnymi instalacjami i plikami.
- Bezpieczeństwo w rywalizacji. Poważny anti-cheat i założenie wrogiego klienta stają się znacznie trudniejsze, gdy klient jest aplikacją webową.
Te ograniczenia są ważne, ponieważ wyznaczają obszary, w których gry przeglądarkowe są dziś najmocniejsze: gry korzystające z natychmiastowego dostępu, szybkiej iteracji, dostarczania międzyplatformowego oraz możliwych do opanowania budżetów zasobów i środowiska uruchomieniowego.
AI znacznie skraca pętlę od prototypu do URL-a
AI ma tu znaczenie, ale nie dlatego, że magicznie zamienia jedno zdanie w gotową grę wysokiej jakości. Bardziej realistyczną korzyścią jest szybkość iteracji.
Współczesne tworzenie gier obejmuje wiele drobnych zadań, które łącznie są kosztowne: konfigurowanie maszyn stanów, tworzenie widoków debugowania, pisanie testów, eksperymentowanie z zachowaniami przeciwników, tworzenie formatów danych dla ruchów, refaktoryzację kodu wejścia, prototypowanie shaderów, analizowanie błędów fizyki i podpinanie tymczasowej zawartości.
AI może skrócić wiele z tych pętli. W połączeniu z dystrybucją webową przepływ pracy staje się wyjątkowo bezpośredni:
idea -> prototype -> deploy -> open URL -> test -> iteratePrzeglądarka już przyspiesza wdrażanie. AI może przyspieszyć również implementacyjną stronę tej samej pętli.
Ważnym zastrzeżeniem jest to, że szybkie generowanie nie zastępuje wyczucia ani walidacji. Wygenerowany kontroler walki może być strukturalnie błędny. Timing animacji nadal wymaga ludzkiego osądu. Fizyka nadal wymaga debugowania. Wydajność nadal trzeba mierzyć. AI obniża koszt sprawdzania pomysłów; nie usuwa potrzeby decydowania, które pomysły są dobre.
Co to oznacza dla programistów webowych
Granica między tworzeniem aplikacji webowych a tworzeniem gier staje się coraz mniej sztywna.
Poważna gra przeglądarkowa może dziś korzystać ze znanych narzędzi webowych, a jednocześnie wymagać klasycznych koncepcji inżynierii gier:
- stałe kroki symulacji;
- maszyny stanów;
- buforowanie wejścia;
- grafy animacji;
- zapytania przestrzenne;
- fizyka;
- budżety klatek;
- zarządzanie zasobami GPU;
- timing dźwięku;
- systemy deterministyczne.
Jednocześnie twórcy gier celujący w przeglądarkę zyskują rzeczy, w których web od dawna jest wyjątkowo dobry: URL-e, natychmiastowe wdrożenia, dostarczanie przez CDN, szybkie aktualizacje, telemetrię, systemy kont, responsywne interfejsy i bezproblemowe udostępnianie.
Te badania zmieniły mój własny sposób myślenia. Nie postrzegam już gier przeglądarkowych przede wszystkim jako uproszczonych wersji gier natywnych. Widzę przeglądarkę jako coraz bardziej zdolną platformę do gier o innym zestawie mocnych stron: natychmiastowej dystrybucji, szybkiej iteracji, coraz poważniejszych możliwościach 3D i ogromnym istniejącym ekosystemie programistycznym.
Web nie tylko coraz lepiej wyświetla gry zbudowane gdzie indziej. Coraz częściej staje się miejscem, w którym poważne systemy gier można projektować, implementować, testować, dystrybuować i bezpośrednio w nie grać.