Wybór między sercem i rozumem (a może nie?)
Tak jak wspominałem w poprzednim poście, ten będzie o środowisku tworzenia całej gry. Unity - bo tak nazywa się silnik 3D wykorzystywany w naszym symulatorze - został wybrany nie bez przyczyny.
Pierwszą i podstawową jest to, że autorzy symulatora posiadają duże doświadczenie w pracy z tym silnikiem.
Oczywiście rozważane były inne silniki takie jak Unreal Engine 5 czy Godot, lecz po głębszej analizie doszliśmy do wniosku, że uczenie się nowego środowiska i całkowicie innej filozofii tworzenia w nim gier jest bez sensu.
Czas pokazał, że był to dobry wybór, gdyż niedawno Epic Games zapowiedział premierę JESZCZE nowszej wersji UE - 6. Silnik ma zostać przebudowany od zera, a filozofia i technologia tworzenia gry będzie całkowicie inna niż dotychczas.
Drugą przyczyną, niejako nawiązującą do pierwszej jest to, że w Unreal Engine pewne rzeczy można zrobić TYLKO tak, jak założyli to twórcy tego silnika. Jeżeli ktoś potrzebuje mocno customowej funkcjonalności, to albo trzeba z niej zrezygnować i zastąpić innym rozwiązaniem, albo wypracowywać obejścia, których złożoność i stopień skomplikowania powoduje nieopłacalność w ich stworzeniu.
Po wyborze silnika przychodzi czas na decyzję, który pipeline lepiej będzie nadawał się do gry. Z racji, iż celujemy w jak najwierniejsze odwzorowanie rzeczywistości i jak najlepszą grafikę, to oczywistym wyborem był tutaj HDRP (High Definition Render Pipeline). Wymaga on jednak sporo optymalizacji, bo każdy podkład, szyna, drzewo czy krzak będą wydłużały czas renderowania pojedynczej klatki. Oczywiście postaramy się, aby symulator działał sprawnie na większości sprzętów, lecz aby działał on płynnie na najwyższych ustawieniach graficznych potrzebna będzie karta graficzna rzędu co najmniej RTX 3060.
Drezyna z poprzedniego posta trafiła nagle tutaj i nawet stoi na torach!
Ale jak to się stało?
Otóż najpierw trzeba zaimportować goły model.
Jak widać, jest on całkowicie bez tekstury, a do tego spakowany w jeden GameObject. Naprawmy to dodając materiał, który wcześniej przygotowaliśmy z 3 tekstur (Color, Mask oraz Normal - dajcie znać na discordzie, czy chcecie abym trochę głębiej wytłumaczył na jakiej zasadzie działają tekstury).
No i zrobione!
Prawda...?
No nie do końca.
Nasz obiekt ładnie wygląda w scenerii, ale jest kompletnie martwy. Nie posiada żadnych komponentów, które pozwalałyby na jakąkolwiek interakcję z użytkownikiem.
Jak widzieliście wcześniej, drezynka w scenie testowej stoi sobie na torach. Nie zaprzęgamy jednak do tego żadnej fizyki oferowanej przez Unity, bo byłoby to bardzo kosztowne obliczeniowo ze względu na ciągłą potrzebę przeliczania styku colliderów (60 razy na sekundę!), czy też manipulowania siłami działającymi na pojazd.
Zamiast tego używamy tzw. krzywych, po których pojazd podąża. Oczywiście fizyka została zaimplementowana (poniżej jej fragment - liczenie momentu obrotowego z twierdzenia cosinusów) i na jej podstawie wyliczana jest realna prędkość, siły oporu powietrza czy siła hamowania.
Teraz to już musi działać!
Ano nie będzie.
Jest jeszcze jedna ważna rzecz - pobieranie wejścia od użytkownika. Za to odpowiedzialny jest nowy Input System, który stosuje bardzo fajne rozwiązanie Eventów i Delegatów. Polega to na tym, że w specjalnym pliku konfiguracyjnym definiujemy akcje, które mają się dziać po dostaniu konkretnego wejścia. Elastyczność tego rozwiązania kryje się w tym, że jedną akcję (np. "Interakcja") możemy przypisać nie tylko do lewego przycisku myszki, ale również do dotknięcia palcem na ekranie, przycisku "X" na kontrolerze Xbox, czy triggera na kontrolerze do zestawu VR.
Gdy już mamy skonfigurowaną taką akcję, możemy ją zasubskrybować w naszym kodzie i za każdym razem gdy się wykona, dana funkcja zostanie wywołana.
Tak oto doszliśmy (bardzo upraszczając te parę tygodni pracy) do gotowego modelu, który stoi na torach, jeździ do przodu i do tyłu i hamuje.
Następna stacja - Testy i Problemy!