Na czym polega port z Unity do Defolda
Z punktu widzenia gracza gra zostaje ta sama. Zasady, poziomy, balans, grafika i dźwięk przechodzą do nowej wersji. Zmienia się wszystko pod spodem. C# zamieniamy na Lua, prefaby i sceny na obiekty gry i kolekcje Defolda, a każde zewnętrzne SDK na rozszerzenie Defolda albo krótki własny kod.
Najczęściej port zaczyna się od problemu z wersją webową. Build z Unity ładuje się za długo jak na wymagania Poki czy CrazyGames albo gra przycina na tanich telefonach z Androidem. Czasem zespół chce mieć jeden mały projekt na web i mobile. Sam silnik Defold dokłada do buildu kilka megabajtów. Pliki projektu są tekstowe, więc dobrze widać zmiany w Gicie, a po sklonowaniu repozytorium nie trzeba czekać na odbudowę folderu Library.
Port najlepiej traktować jak pisanie gry od nowa według bardzo dokładnej specyfikacji. Tą specyfikacją jest projekt w Unity. W każdej chwili możesz go otworzyć i sprawdzić, jak działa skok albo co robi dany power-up. Dzięki temu port da się zaplanować dużo pewniej niż nową grę.
Unity a Defold: odpowiedniki najważniejszych elementów
Defold ma oficjalny poradnik dla osób przechodzących z Unity. Poniżej opisujemy różnice, które w praktyce zabierają najwięcej czasu.
GameObject, MonoBehaviour i komponenty
W Unity GameObject ma Transform i dowolną liczbę skryptów MonoBehaviour. Obiekt gry w Defoldzie ma wbudowaną pozycję, rotację i skalę oraz komponenty: sprite’y, etykiety, dźwięki, obiekty kolizji, fabryki i skrypty. Komponent skryptu to plik .script z funkcjami cyklu życia.
Awake,StartiOnEnableodpowiadają funkcjiinit(self).Updatetoupdate(self, dt),FixedUpdatetofixed_update(self, dt), aLateUpdatetolate_update(self, dt)w nowszych wersjach Defolda.OnDisableiOnDestroyodpowiadają funkcjifinal(self).- Wejście trafia do
on_input, kiedy skrypt wyśle do siebieacquire_input_focus. Wiadomości od innych skryptów odbieraon_message.
Pola z atrybutem SerializeField mają prosty odpowiednik. Linijka go.property("speed", 200) na początku skryptu pokazuje wartość w edytorze, a każda instancja może ją nadpisać.
Najwcześniej warto porzucić nawyk jednego skryptu na każdy obiekt. Scena z Unity z trzystoma MonoBehaviourami nie powinna zamienić się w trzysta skryptów Defolda, które wysyłają do siebie wiadomości. Projekt w Defoldzie jest czytelniejszy, kiedy skryptów jest mniej. Jeden skrypt sterujący wszystkimi przeciwnikami, z logiką w zwykłych modułach Lua, często zastępuje kilkadziesiąt małych komponentów. Doświadczeni użytkownicy na forum Defolda regularnie radzą to osobom, które przychodzą z Unity.
Defold nie gwarantuje też kolejności, w jakiej komponenty wywołują init czy update. Kod oparty na ustawieniach Script Execution Order trzeba przebudować. Zwykle robimy to tak, że jeden skrypt zarządzający wywołuje moduły w ustalonej kolejności.
Prefaby a fabryki i fabryki kolekcji
Prefab z jednym obiektem odpowiada plikowi obiektu gry, który tworzy komponent fabryki. Zamiast Instantiate piszesz factory.create("#enemy_factory", position) i dostajesz identyfikator nowego obiektu. Prefab z dziećmi odpowiada kolekcji tworzonej przez fabrykę kolekcji. Ta zwraca tabelę z identyfikatorami całej hierarchii.
Hierarchia działa inaczej niż w Unity. W prefabie możesz zagnieżdżać obiekty dowolnie głęboko, a plik obiektu gry w Defoldzie nie może zawierać innych obiektów. Relacje rodzic i dziecko ustawia się w kolekcji albo w trakcie gry przez go.set_parent. Warianty prefabów nie mają bezpośredniego odpowiednika. My zastępujemy je jednym prototypem i właściwościami skryptu przekazywanymi do factory.create.
Po zaznaczeniu opcji Load Dynamically fabryka wczytuje zasoby dopiero przy pierwszym użyciu. Rzadko używane obiekty nie zajmują wtedy pamięci przez całą grę.
Sceny a kolekcje i proxy kolekcji
Pierwszą sceną jest kolekcja startowa ustawiona w game.project. Kolejne sceny to kolekcje wczytywane przez proxy kolekcji. Wysyłasz do proxy async_load, czekasz na proxy_loaded i wysyłasz enable. Każde proxy wczytuje osobny świat gry z własną fizyką. Dane przekazywane między poziomami idą więc przez moduł Lua albo wiadomość.
Proxy mają jedną rzecz, której brakuje scenom w Unity. Wiadomością set_time_step spowolnisz albo zatrzymasz cały świat, więc pauza poziomu przy animowanym menu pauzy to jedna linijka kodu.
Obiekty z DontDestroyOnLoad zwykle trafiają do głównej kolekcji, która jest wczytana przez cały czas i podmienia poziomy przez proxy. Addytywne wczytywanie scen odpowiada kilku proxy włączonym jednocześnie.
Z C# na Lua
Przepisanie kodu z C# na Lua to największa część pracy, ale idzie szybciej, niż zakłada większość zespołów. Tej części Lua, której potrzebuje kod rozgrywki, można się nauczyć w jedno popołudnie. Większość błędów w świeżym porcie bierze się z kilku różnic:
- Indeksy w tabelach zaczynają się od 1, a
#listaprzestaje liczyć na pierwszym nil. - Lua 5.1 nie ma dzielenia całkowitego.
7 / 2daje 3.5, więc kod, który polegał na dzieleniu intów w C#, potrzebujemath.floor. - W Lua nie ma klas. Buduje się je z tabel i metatabel albo z małej biblioteki pomocniczej. Interfejsy i typy generyczne znikają i w kodzie rozgrywki rzadko ich brakuje.
- Wartości
vmath.vector3przekazywane są przez referencję. Jeśli dwie zmienne wskazują ten sam wektor, zmianav.xzmienia oba. W C# Vector3 jest strukturą, więc kod przepisany linijka po linijce potrafi się tu wyłożyć bez żadnego komunikatu o błędzie. - Literówka w nazwie zmiennej tworzy zmienną globalną albo zwraca nil, a kompilator Cię nie zatrzyma. Luacheck albo Lua language server wyłapią większość takich pomyłek. Jeśli zespół chce wrócić do typowania, Teal kompiluje kod z typami do Lua.
W buildzie HTML5 silnik używa standardowego Lua 5.1 zamiast LuaJIT. Ciężkie pętle profiluj więc także w przeglądarce.
Korutyny i kod asynchroniczny
W Unity korutynami zarządza silnik przez StartCoroutine i yield return. Lua ma korutyny wbudowane w język, ale Defold sam ich nie wznawia. Większość wywołań WaitForSeconds zamienia się w timer.delay(seconds, false, callback). Tweeny z callbackiem na końcu zastępuje go.animate albo gui.animate.
Przy dłuższych sekwencjach, jak tutorial, przerywnik filmowy czy łańcuch zapytań HTTP, kod zostaje czytelny dzięki prostej nakładce na korutyny. Wewnątrz korutyny robisz yield, a wznawiasz ją z timera albo callbacka. Napisz taki pomocnik w pierwszym tygodniu portu i używaj go wszędzie. Inaczej w projekcie szybko pojawią się trzy różne style kodu asynchronicznego.
Eventy a przesyłanie wiadomości
Eventy z C#, UnityEvents i bezpośrednie wywołania metod innych komponentów zamieniają się w wiadomości. msg.post("/player#script", "take_damage", { amount = 10 }) wysyła tabelę Lua do innego skryptu, który obsługuje ją w on_message. Adresy mają postać socket:/ścieżka#komponent. Wiadomość dociera później w tej samej klatce, więc odpowiedzi nie dostaniesz w następnej linijce kodu.
Nie ma GetComponent. Do odczytu i zmiany wartości na innym obiekcie służą go.get i go.set na właściwościach skryptu. Wspólny stan może siedzieć w module Lua, z którego korzysta kilka skryptów. Statyczne eventy z C# najprościej zastąpić małym modułem z funkcjami subscribe i publish. Słuchacze nie muszą wtedy znać swoich adresów.
uGUI a sceny GUI
Interfejs w Defoldzie budujesz w komponentach GUI, oddzielonych od świata gry. Plik .gui zawiera węzły (prostokąty, teksty, węzły pie, szablony, efekty cząsteczkowe), a gui_script steruje nimi przez API gui. GUI rysuje się w przestrzeni ekranu i ma własne warstwy oraz kolejność rysowania.
Ustawieniom Canvas Scaler odpowiada tryb dopasowania (adjust mode) każdego węzła i layouty dla profili ekranu. Pozwalają one ułożyć ekran inaczej w pionie i w poziomie. Layout Group i Content Size Fitter nie mają odpowiedników, więc listy i siatki ustawia się w kodzie. Wiele zespołów korzysta z Druida, biblioteki społeczności z przyciskami, przewijanymi obszarami, siatkami i polami tekstowymi.
Każdy ekran najlepiej odtworzyć ze zrzutów z Unity i oryginalnych sprite’ów. Przenoszenie hierarchii uGUI węzeł po węźle trwa dłużej niż ułożenie ekranu od nowa w edytorze GUI.
Animator a flipbooki, Spine i Rive
Animacje poklatkowe trafiają do atlasu albo tile source jako animacje flipbook i odtwarza się je przez sprite.play_flipbook. Animacje właściwości, czyli to, co zwykle robi się w DOTween albo w prostych klipach Animatora, przechodzą na go.animate z easingiem i trybami odtwarzania. Animację szkieletową 2D obsługują oficjalne rozszerzenia Spine i Rive, a modele 3D ze skinningiem importuje się jako glTF.
Defold nie ma maszyny stanów Animatora. Tę samą pracę wykona krótka maszyna stanów w Lua, która wybiera odpowiedni flipbook albo animację Spine. W większości gier 2D wychodzi krócej niż oryginalny graf w Animatorze.
Fizyka
Defold używa Box2D do fizyki 2D i Bullet do 3D. Rigidbody i Collider łączą się w jeden obiekt kolizji typu dynamic, kinematic, static albo trigger. Grupy i maski kolizji ustawia się po nazwach. Kolizje przychodzą jako wiadomości, na przykład contact_point_response i trigger_response.
Dwie rzeczy sprawdź na samym początku. Defold liczy w pikselach, więc ustaw skalę fizyki w game.project tak, żeby ciała w Box2D miały rozsądne rozmiary w metrach. Obiekty kinematic nie są same wypychane ze ścian. Kontroler postaci oparty w Unity na CharacterController albo Rigidbody2D.MovePosition potrzebuje własnego kodu, który rozsuwa obiekty na podstawie punktów kontaktu.
Shadery i materiały
Materiał w Defoldzie łączy program wierzchołków i program fragmentów w GLSL ze stałymi, samplerami i tagami. W skrypcie renderowania ustalasz, które tagi rysują się w którym przebiegu, z jaką kamerą i jakim trybem mieszania.
Grafy z Shader Graph i Amplify trzeba przepisać ręcznie na GLSL. Tint, mignięcie po trafieniu, dissolve albo przesuwanie UV to kwestia minut. Postprocessing, na przykład bloom czy korekcja kolorów, buduje się w skrypcie renderowania z użyciem render targetów. Na słabych GPU każdy taki efekt kosztuje czas klatki, więc zostaw te, które naprawdę budują wygląd gry. Duża liczba materiałów z różnymi tagami psuje też batching, co widać w profilerze jako więcej draw calli.
Sorting layers i order in layer zamieniają się w pozycję Z sprite’ów. W domyślnym skrypcie renderowania sprite’y z wyższym Z rysują się na wierzchu, w zakresie od -1 do 1.
ScriptableObject a moduły Lua i JSON
Dane gry ze ScriptableObjectów, takie jak statystyki przedmiotów, listy poziomów czy fale przeciwników, mają w Defoldzie dwa dobre miejsca. Moduł Lua zwracający tabelę sprawdza się przy danych, którymi zajmują się programiści. Pliki JSON dodane jako custom resources w game.project i czytane przez sys.load_resource oraz json.decode pasują do danych, które projektanci edytują w arkuszach.
Dane z Unity wyeksportuj małym skryptem edytora zamiast przepisywać je ręcznie. Będzie szybciej i bez pomyłek w wartościach balansu. W ten sam sposób wyciągniesz poziomy zbudowane z prefabów: jako listę obiektów z pozycjami w JSON, którą w Defoldzie odtwarzają fabryki. Tilemapy z Unity przenosi się do tile map w Defoldzie.
Natywne pluginy a natywne rozszerzenia
Natywnym pluginom z Unity (.aar, .framework, .jslib) odpowiadają natywne rozszerzenia Defolda. Rozszerzenie może zawierać kod w C, C++, Objective-C, Javie albo JavaScripcie i gotowe biblioteki. Serwer buildów Defolda kompiluje je razem z silnikiem, więc w większości projektów nie trzeba lokalnie instalować narzędzi Androida ani iOS.
Zanim zaczniesz pisać nowe rozszerzenie, przejrzyj portal z assetami Defolda. Reklamy, zakupy, analityka, powiadomienia push, obsługa safe area, prośby o ocenę w sklepie i większość SDK portali webowych mają już gotowe rozszerzenia.
Przenoszenie assetów
Assety przechodzą najłatwiej, a port to dobry moment, żeby je uporządkować.
- Atlasy. Każdy sprite, obrazek w GUI i tekstura cząsteczek w Defoldzie pochodzi z atlasu albo tile source. Grupuj grafiki według ekranu albo poziomu, na którym się pojawiają. Pierwszy poziom nie będzie wtedy ciągnął grafiki z całej gry. Eksportuj obrazy w rozmiarze, w jakim gra je pokazuje. Projekty w Unity często trzymają źródła 2048 px i zmniejszają je dopiero w trakcie działania.
- Kompresja tekstur. Profile tekstur ustawiają kompresję według wzorców ścieżek. Basis Universal jest w trakcie działania gry transkodowany do formatu, który obsługuje GPU, na przykład ASTC, ETC2 albo BC. Jeden build działa więc na wielu telefonach. Profil może też ograniczyć maksymalny rozmiar tekstury. Kompresja wydłuża budowanie, dlatego wiele zespołów włącza ją przy buildach wydaniowych, a w codziennej pracy ją pomija.
- Dźwięk. Defold odtwarza WAV i Ogg Vorbis. Muzykę przekonwertuj do Ogg, krótkie efekty zapisz w mono, a do osobnej głośności muzyki i efektów użyj grup dźwięków. Dźwięk w Defoldzie domyślnie nie jest przestrzenny. Audio 3D z Unity wymaga prostych obliczeń odległości w Lua albo rozszerzenia FMOD.
- Fonty. Fonty z TextMeshPro się nie przeniosą. Pliki .font w Defoldzie tworzysz z oryginalnych plików TTF albo OTF. Fonty distance field nadają się do skalowanego tekstu, a fonty bitmapowe do małego tekstu w stylu pixel art. Nowsze wersje Defolda potrafią też generować glify w trakcie gry, co pomaga przy językach z dużą liczbą znaków.
- Spine i modele 3D. Eksporty ze Spine działają z rozszerzeniem Spine, jeśli zgadzają się wersje runtime’u. Defold czyta glTF i Collada, więc pliki FBX trzeba przekonwertować, najczęściej w Blenderze.
Wymiana SDK: reklamy, analityka, zakupy i portale
Spisz każde SDK z projektu w Unity razem z wersją i funkcjami, które gra naprawdę wywołuje. Potem znajdź odpowiednik po stronie Defolda:
- Reklamy. Są rozszerzenia do AdMob, AppLovin MAX i Unity LevelPlay. Reklamy z nagrodą i pełnoekranowe przenosi się prawie jeden do jednego. Bannery często wymagają zmian w układzie ekranu.
- Zakupy w aplikacji. extension-iap obsługuje Google Play i App Store. Weryfikacja paragonów na serwerze może zostać bez zmian.
- Analityka i crashe. Firebase Analytics i Crashlytics mają rozszerzenia do Defolda, a GameAnalytics udostępnia własne SDK. Zachowaj nazwy eventów z wersji Unity, żeby dashboardy i lejki działały dalej bez przerwy w danych.
- Portale webowe. Rozszerzenie Poki SDK, rozszerzenie CrazyGames oraz Playgama Bridge albo GamePush, kiedy jedna integracja ma obsłużyć wiele portali. Mobilne SDK reklamowe nie działają w przeglądarce, więc wersja webowa korzysta z funkcji reklamowych portalu.
Niektóre SDK nie mają rozszerzenia do Defolda, na przykład mniejsza sieć reklamowa albo wewnętrzna analityka studia. Dla nich zaplanuj natywne rozszerzenie, a w wersji webowej krótki most w JavaScripcie. Każde takie SDK wydłuża port, dlatego podczas audytu listę SDK czytamy jako pierwszą.
Zapisy graczy i migracja postępów
Jeśli wersja w Defoldzie zastępuje grę z Unity, która już ma graczy, ci gracze oczekują, że ich postęp przetrwa aktualizację. Na urządzeniach mobilnych nowy build ma tę samą nazwę pakietu albo bundle id. Małe natywne rozszerzenie może przy pierwszym uruchomieniu odczytać stare PlayerPrefs (SharedPreferences na Androidzie, NSUserDefaults na iOS) i zapisać je w pliku zapisu Defolda.
W przeglądarce Unity trzyma PlayerPrefs w IndexedDB. Most w JavaScripcie odczyta je pod warunkiem, że build z Defolda działa w tej samej domenie. Najprościej jest z zapisami w chmurze przypisanymi do konta gracza, o ile Defold czyta i zapisuje dane w tym samym formacie. O migracji zdecyduj już przy audycie, bo od niej zależy, jak od pierwszego dnia zbudujesz system zapisu.
Audyt: lista kontrolna przed pierwszą linijką Lua
- Wersja Unity, render pipeline (Built-in, URP albo HDRP) i docelowe platformy.
- Rozmiar obecnych buildów i czas ładowania na średniej klasy Androidzie oraz w Safari na iPhonie.
- Każdy pakiet z Asset Store i każdy plugin, razem z funkcjami, z których gra korzysta.
- Każde SDK i jego wersja.
- Własne shadery i postprocessing.
- Sceny, prefaby i skrypty, a wśród nich te, w których siedzi większość logiki.
- Gdzie są dane gry: w ScriptableObjectach, JSON-ach, arkuszach czy na sztywno w kodzie C#.
- Lokalizacja: języki, fonty i sposób, w jaki teksty trafiają do gry.
- System zapisu i to, czy postęp graczy trzeba przenieść.
- Kto akceptuje „feel” gry i jak porównacie obie wersje.
Plan portu krok po kroku
- Audyt i decyzje. Przejdź przez listę kontrolną. Zapisz, co zostaje bez zmian, co upraszczacie, a z czego rezygnujecie.
- Szkielet projektu. Przygotuj game.project, kolekcję startową, skrypt renderowania, mapowanie wejścia, moduł zapisu i wczytywanie poziomów przez proxy. Ustal teraz strukturę folderów i nazewnictwo, póki nic to nie kosztuje.
- Eksport danych. Napisz w Unity skrypty edytora, które wyeksportują poziomy, przedmioty i balans do JSON albo Lua.
- Vertical slice. Przenieś główną pętlę rozgrywki i jeden pełny poziom z docelową grafiką i dźwiękiem. Zmierz rozmiar buildu, czas ładowania i liczbę klatek na najsłabszym docelowym telefonie. Zagraj w niego obok wersji z Unity.
- Treść i interfejs. Przenieś pozostałe poziomy, menu, sklep i funkcje meta w kamieniach milowych. Każdy kończy się grywalnym buildem.
- SDK. Zintegruj reklamy, zakupy, analitykę i SDK portali. Każde z nich przetestuj na prawdziwych urządzeniach.
- Optymalizacja. Dopracuj profile tekstur i podział atlasów, skompresuj dźwięk, przenieś do archiwów Live Update treści, które mogą poczekać, i wyłącz w app manifeście nieużywane moduły silnika.
- QA i porównanie z oryginałem. Porównaj grę z wersją z Unity poziom po poziomie i popraw różnice w odczuciu: łuk skoku, opóźnienie sterowania, płynność kamery.
- Premiera i migracja. Wydaj grę, obserwuj raporty crashy i analitykę, a projekt w Unity zarchiwizuj jako punkt odniesienia.
Najbardziej pilnuj kroku 4. Jeśli vertical slice osiąga zakładany rozmiar i liczbę klatek na tanim telefonie, reszta portu to głównie kwestia ilości pracy. Jeśli nie osiąga, dowiadujesz się o tym wtedy, kiedy zmiana kierunku jeszcze niewiele kosztuje.
Testy na słabych telefonach i w przeglądarce
Od vertical slice’a testuj na sprzęcie, który mają Twoi gracze. Komputer z mocną kartą graficzną ukrywa prawie każdy problem.
- Telefon z Androidem z 2 albo 3 GB RAM i starszym GPU oraz iPhone sprzed kilku generacji.
- Chrome na Androidzie i Safari na iOS dla buildów webowych. Safari ma najostrzejsze limity pamięci i przeładowuje kartę, kiedy gra zużywa jej za dużo.
- Ograniczenie prędkości sieci w narzędziach deweloperskich przeglądarki, żeby zobaczyć pierwsze ładowanie na danych mobilnych.
- Profiler Defolda w buildzie debug: czas klatki, draw calle i pamięć.
- Sesje po 30 minut i dłużej. Wycieki z obiektów, które powstają i nigdy nie są usuwane, wychodzą dopiero po czasie.
- Dźwięk, który rusza po pierwszym dotknięciu, pauza po przełączeniu karty i poprawny powrót po zablokowaniu telefonu.
Więcej wskazówek dla przeglądarki znajdziesz w naszym poradniku optymalizacji gier HTML5.
Najczęstsze błędy
- Skrypt na każdym obiekcie. Setki skryptów, które wysyłają do siebie wiadomości, trudno debugować i działają wolniej niż kilka skryptów zarządzających.
- Tłumaczenie linijka po linijce. Do kodu trafiają wzorce, których Lua nie potrzebuje: gettery, interfejsy, głębokie dziedziczenie. Przenoś zachowanie, sprawdzaj je z buildem z Unity i pisz prosty kod w Lua.
- Założona kolejność wykonania. Kod, który polegał na Script Execution Order albo na tym, że Awake wykona się przed Start, psuje się w sposób wyglądający na losowy.
- Fizyka, która „czuje się” inaczej. Ustawienia Box2D, skala fizyki i stały krok czasu zmieniają odczucie skoków i zderzeń. Dostrój je w trakcie vertical slice’a, póki jest na to czas.
- Jeden ogromny atlas. Cała grafika w jednym atlasie powiększa pierwsze pobranie i zużycie pamięci.
- Zapominanie o przeglądarce. Mobilne SDK reklamowe, dostęp do plików i wątki w buildzie HTML5 działają inaczej albo nie działają wcale. Sprawdź każde z nich w wersji webowej na wczesnym etapie.
- Zapisy odłożone na koniec. Przeniesienie postępów graczy po premierze jest dużo trudniejsze niż zaplanowanie go na starcie.
Port, przepisanie od nowa czy zostanie przy Unity
Po audycie zwykle wybiera się jedną z trzech dróg.
- Port ma sens, kiedy gra jest w 2D albo lekkim 3D, celem jest web albo słabsze telefony, a kod C# jest na tyle czytelny, że może służyć za specyfikację.
- Przepisanie od nowa wybierz, jeśli projekt gry i tak się zmienia albo kod w Unity jest tak splątany, że jego czytanie kosztuje więcej niż budowa według dokumentacji projektowej. Build z Unity dalej przyda się jako wzorzec odczucia i treści.
- Zostań przy Unity, jeśli gra opiera się na oświetleniu z URP albo HDRP, terenie, rozbudowanych shaderach z Shader Graph albo dużym zestawie narzędzi z Asset Store. Tak samo jest, gdy build webowy już mieści się w limitach portali i dobrze działa. Wtedy lepiej poświęcić czas na optymalizację obecnej wersji.
Defold nie ma wbudowanego terenu, komponentów światła, line i trail rendererów ani symulacji tkanin. Każdą z tych rzeczy da się zbudować, a dla części z nich społeczność ma gotowe rozwiązania. Jeśli jednak gra opiera się na kilku takich funkcjach naraz, może lepiej jej będzie w Unity.
Jak pracujemy przy portach z Unity
Porty z Unity to stała część naszej pracy w Codeward, najczęściej na web. Wśród nich były mobilne tytuły znanych marek gier mobilnych, zrobione w Unity i przeniesione do Defolda, żeby działały w przeglądarce.
Kilka osób w naszym zespole pracowało w Unity przez lata i bardzo dobrze zna C#. Zanim napiszemy pierwszą linijkę w Lua, czytamy oryginalny kod i szukamy miejsc, z których bierze się charakter rozgrywki. Często to kilka linijek w skrypcie kontrolera albo jedna krzywa animacji, i właśnie one muszą przetrwać port w niezmienionej formie.
Jeśli masz grę w Unity i zastanawiasz się, czy port do Defolda ma sens, wyślij nam build i krótki opis przez formularz kontaktowy albo na biuro@paweljarosz.pl. Napiszemy, co byśmy przenieśli, co zmienili i gdzie widzimy ryzyko. O produktowej stronie przenoszenia gry mobilnej do przeglądarki piszemy w poradniku o portowaniu gry mobilnej na web, a o innych silnikach w tekście o portowaniu gier z Unity, Godota i Construct na przeglądarkę.