Level scripting w My Memory of Us: Game Actions

By:
Posted: 09/07/2018

W dzisiejszym wpisie chcemy opowiedzieć ogólnie, o tym jak tworzymy naszą grę i silnik, który napędza większość interakcji - Game Action System. Tak, tak... wiemy, że moglibyśmy być nieco bardziej kreatywni przy wyborze nazwy, najważniejsza jest jednak dla nas praktyczna strona tego rozwiązania.

Tworzymy My Memory of Us (MMoU) w Unity, używając C# jako naszego języka skryptowego. Jest to dość standardowe narzędzie i oferuje mnóstwo kontroli nad tworzonym materiałem. Najważniejsze jednak dla nas w fazie prototypu było jak najszybsze uruchamianie poziomów. My Memory of Us to gra napędzana treścią - wiedzieliśmy, że pod względem rozgrywki nie musimy zajmować się typowymi mechanizmami, takimi jak skoki, strzelanie (które pojawiło się później) lub upewnianie się, że power-upy działają poprawnie. Musieliśmy zacząć uzupełniać poziomy, głównie w celu sprawdzenia, jakie niebezpieczeństwa mogą kryć się w naszej historii oraz jak wiele pomysłów będziemy musieli zmodyfikować.

Aby umożliwić szybkie tworzenie prototypowej zawartości, postanowiliśmy prawie w całości oddzielić funkcję programisty i projektanta poziomów od pozostałych obowiązków. W celu umożliwienia wykonania prototypu poziomu roboczego w ciągu kilku dni używaliśmy dużych klocków LEGO, które okazały się idealne do tego zadania. Ze względu na charakter naszej gry nie mamy do czynienia z wieloma powtarzalnymi interakcjami, dlatego też większość z nich jest ręcznie dostosowywana dla najlepszego efektu. Te prymitywne prototypy pozwalają na szybkie testowanie pomysłów i, co ważniejsze, na znalezienie właściwych proporcji, kompozycji i tempa dla naszych poziomów. Jak wiecie, jesteśmy dość poważni, jeśli chodzi o to, jak wygląda My Memory of Us, więc posiadanie pomysłu na to, jak wszystko działa w stosunku do siebie było niezwykle użyteczne.

Jeśli zastanawiacie się, jak to wygląda przed dodaniem grafiki do miksu - oto migawka nieużywanego etapu prototypu jednego z naszych poziomów:



 

 

Dla przejrzystości zaznaczyliśmy miejsca, w których dochodzi do interakcji. Jak zostało już wspomniane, są one obsługiwane przez Game Actions, które mogą tworzyć długie łańcuchy interakcji. Mamy ich nieco ponad 200, ale wiele z nich jest używanych tylko w kilku miejscach i robią dość specyficzne rzeczy. Do codziennego podnoszenia największych ciężarów wykorzystujemy natomiast GA_Move_Object.

Ten zły chłopiec widział wszystko. Dodany przy pierwotnym zatwierdzeniu systemu, jest naszą najstarszą Game Action. Robi dosłownie to, co mówi. Obiera Unity GameObject jako cel i przenosi go z punktu A do punktu B. To powinno być na tyle, czyż nie?

Nie spodziewaliśmy się, że tak już pozostanie - oczywiście, był to tylko "prototyp prototypu" i GA_Move_Object przeszedł wiele zmian zanim stał się tym, czym jest dla nas dzisiaj. Niektóre z usprawnień zawierają całkiem przydatne funkcje jak rysowanie gadżetów, wybór punktu odniesienia (świat/lokalny do Game Action obiekt/lokalny do celu), stałe odświeżanie dla kolejnych elementów, przerwy i wreszcie - integracja iTween z wszystkimi tymi rzeczami ładnie wygląda. Dzięki temu możliwe stało się przybliżanie i oddalanie kamery, gdy prowadzimy nasze postacie między sceneriami. Wszystko to ma swoją cenę - wiele godzin spędzonych przez programistów na przerabianiu skryptu zgodnie z nowymi potrzebami projektowymi. Wiele z tych problemów można rozwiązać po stronie projektowej za pomocą systemu skryptów niższego poziomu, takiego jak Blueprints dla UE4 lub Bolt dla Unity. Nie zapewni to jednak tak pięknego wyglądu jak teraz:



Podsumowując, najważniejszą zaletą budowania Game Action System jest szybkość tworzenia treści. Ma to duże znaczenie, gdyż pozwoliło nam na kolejne iteracje i więcej godzin spędzonych na szlifowaniu grafiki, animacji i innych rzeczy. Po drugie, dość łatwo jest teraz debugować silnik - istnieje skończona ilość rzeczy, które mogą pójść nie tak z takim blokiem. W większości przypadków akcje w grze zdarzają się jedna po drugiej, więc szukamy tej, która charakteryzuje się dziwnym zachowaniem. Naprawienie tego jest zwykle kwestią zmiany konfiguracji, bez potrzeby wchodzenia w kod, co jest bardzo przydatne. Z drugiej strony, doszliśmy do tego momentu po ponad roku tworzenia bloków i upewnienia się, że nie wchodzą w interakcje ze sobą w nieprzewidziany sposób (w rzeczywistości nadal to robią, ale to już inna historia ;) ). Nasi programiści wkładają ogromną pracę w to, aby to wszystko było możliwe. Dzięki nim dysponujemy solidną bazą kodową, na której możemy budować w przyszłości...

 

Radosław Smyk