Як перенести проєкт з Unity 4 на Unity 6

Як перенести проєкт з Unity 4 на Unity 6 без втрати сцен: конвертація в текст через Unity 2019.4, порт UnityScript на C# зі збереженням GUID і відновлення HUD.

Споруда з блоків у рівні Onager на підлозі з матового скла

Не відкривайте проєкт з Unity 4 одразу в Unity 6 і тим паче нічого в ньому не зберігайте. Unity 6 завантажує старі бінарні сцени лише частково, а збереження робить втрату остаточною; безпечний шлях лежить через Unity 2019.4, яка вміє і прочитати старий формат, і записати його як текст, і лише потім на Unity 6.

Це стосується проєктів, у яких сцени й префаби збережено в бінарному форматі, а скрипти написано на UnityScript, схожій на JavaScript мові, яку Unity колись підтримувала поряд із C#. Як приклад візьмемо Onager, фізичну гру з катапультою, написану в Unity 4.1.2 на UnityScript. У проєкті було 126 скриптів, 75 сцен і 78 префабів. Після перенесення гра працює на Unity 6000.5 з URP (Universal Render Pipeline) і безкоштовно доступна в App Store і Google Play.

Що станеться, якщо відкрити проєкт в Unity 6

Найпростіший підхід: відкрити проєкт в Unity 6 і перемкнути серіалізацію на Force Text, тобто на збереження асетів як читабельного YAML. Але це не переклад файлів. Unity завантажує кожен асет через свій імпортер і записує назад як YAML, тож усе проходить через завантажувач Unity 6. На кожній сцені він повідомляє про Transform без GameObject і видаляє «завислий» компонент. Збереження робить це остаточним.

Втрату можна виміряти інструментом binary2text, який постачається з редактором і читає серіалізований файл без імпортера. В Onager ми порівняли його результат з отриманим YAML і рахували лише компоненти, що зникли з GameObject, які вціліли:

Компонент Втрачено
Camera 130
ParticleSystem 132
Transform 167
BoxCollider 104
Rigidbody 100
GUITexture / GUIText 303 / 179

Жодна з 75 сцен не пройшла без втрат. Зникли цілі камери для HUD, а головна камера отримала нову, стандартну. Головне: шкода виникає вже під час завантаження, а не під час збереження. Поки проєкт не конвертовано, Unity 6 не повинна його зберігати: жодної сцени, жодного префаба.

Крок 1: Зафіксуйте початковий стан

Перш ніж щось змінювати, зробіть знімок екрана кожної сцени й збережіть для кожного оригінального файлу сцени дамп через binary2text. За цими дампами ви перевірятимете камери в кроці 3 і відновлюватимете HUD у кроці 5. Оригінальні бінарні файли залиште в історії git, не видаляйте їх.

Перший рівень в Unity 6 до ремастера
Перший рівень Onager в Unity 6, ще зі старим рендером і оригінальними матеріалами. Зафіксуйте так кожну сцену, перш ніж щось змінювати.

Крок 2: Конвертація в текст через Unity 2019.4

Unity 2019.4 є останнім редактором, що вміє і читати, і записувати формат Unity 4.1. Конвертуйте із закритим редактором в окремій копії репозиторію:

  • Версія проєкту. У файлі з версією проєкту вкажіть початкову версію (для Onager 4.1.2), щоб редактор пішов шляхом для старих проєктів. Unity перезапише її під час відкриття, вона має діяти лише для першого імпорту.
  • Порожні пакети. Очистіть список залежностей пакетів. Одна помилка компіляції означає, що не працюватиме жоден пункт меню з редакторських скриптів, і це виглядає так, ніби меню взагалі не з'явилося.
  • Імпорт з нуля. Видаліть теку Library і дайте проєкту імпортуватися.
  • Force Text і примусовий перезапис. Після перемикання на Force Text Unity 2019.4 сама не перезаписує наявні файли. Це треба викликати функцією ресеріалізації асетів, і лише для асетів, а не для їхніх meta-файлів. Перезапис усіх meta-файлів призводить до того, що Unity 6 потім імпортує без кінця.

Одна пастка в git. Якщо в атрибутах git позначити сцени як текст із закінченням рядка LF, git під час додавання до репозиторію викидає з бінарних сцен байти, схожі на закінчення рядка. В Onager це пошкодило вісім сцен. Не ставте на асети Unity атрибут закінчення рядків, Unity і так пише LF.

Крок 3: Перевіряйте результат у редакторі, а не читанням YAML

Читання конвертованих файлів веде до впевнених і хибних висновків. Скорочені записи екземплярів префабів виглядають як втрата, так само як камера, яка лише переїхала в префаб. Важливо те, що Unity будує в пам'яті. Відкрийте кожну конвертовану сцену й порівняйте її камери з дампом оригіналу з кроку 1.

В Onager після конвертації всі 75 сцен мали ті самі камери в тому самому порядку. Втратилося лише те, чого не знає жоден сучасний редактор: 569 GUITexture, 179 GUIText і старі системи частинок, які Unity прибрала у 2018 році.

Крок 4: UnityScript на C# з тим самим GUID

Unity поступово прибирала UnityScript починаючи з версії 2017.2, тож ручний порт на C# є єдиним шляхом. Сцени посилаються на скрипти через GUID, унікальний ідентифікатор, який Unity зберігає в meta-файлі кожного асета, а значення полів зберігають за назвою поля. Якщо дотриматися цього під час порту, усі посилання під'єднаються самі:

для кожного скрипту X на UnityScript:
  створи C#-скрипт із класом точно на ім'я X
  скопіюй GUID з meta-файлу старого скрипту до meta-файлу нового
  публічні поля: та сама назва, той самий тип, навіть з одруківками
  нічого не перейменовуй, поки проєкт не працює

В Onager так після порту всіх 126 скриптів під'єдналися 12 935 компонентів у 73 сценах, і всі значення, задані в Inspector, залишилися.

Текстовим пошуком у проєкті не з'ясувати, які скрипти використовуються. Бінарний префаб зберігає GUID як байти, а не як текст. В Onager так двадцять один скрипт здавався невикористаним, і всі вони були живі. Остерігайтеся й залишків попередніх спроб порту: один префаб дерев'яного блоку вказував на два скрипти з такої спроби, і лише через нього бракувало 1 140 компонентів. Якщо в бінарному файлі треба змінити GUID, замініть його прямо в байтах, шістнадцять на шістнадцять, щоб файл не зсунувся.

Крок 5: Відновіть HUD з оригінальних бінарних сцен

GUITexture і GUIText в Unity 6 немає, і разом з ними зникає весь HUD, побудований на них. Малювати його заново не потрібно. binary2text читає оригінальні бінарні сцени з історії git незалежно від того, чи існують ще класи. Витягніть з них кожне зображення й текст HUD з текстурою, кольором, позицією й вирівнюванням і скриптом поверніть їх на ті самі об'єкти в сценах. В Onager це було 577 зображень і 180 текстів.

Так рятуються й тексти, яких більше ніде немає. В Onager це було 111 текстів: усі підписи туторіалів і увесь екран з титрами. Пишучи HUD з нуля, ви мусили б їх вигадати. Переносячи кольори, врахуйте те, про що мовчить документація: старий GUITexture подвоював колір під час малювання. Усі 577 зображень мали колір рівно 0,5, тобто сірий означав білий.

Після конвертації: замініть старі обхідні рішення

Старі проєкти часто обходили обмеження тодішньої Unity, і ці обхідні рішення варто переробити після конвертації:

  • Відображення в підлозі. Onager мав блискучу підлогу без справжнього відображення. Під підлогою стояв другий, дзеркальний світ: копія кожного об'єкта, позицію якої скрипт кожен третій кадр копіював з оригіналу, в одному рівні від 50 до 70 клонів. Замінити це можна однією додатковою камерою, яка малює відображення з половинною роздільною здатністю. Тоді відбиваються також частинки й уламки, чого клонований світ не вмів.
  • Прицілювання. Якщо попередній перегляд траєкторії передбачає, куди пошле постріл сила, додана на першому фізичному кроці, постріл падає не там, де мітка. Надійніше обчислити швидкість один раз, намалювати перегляд саме з неї й призначити її пострілу напряму.
  • Продуктивність. Вимірюйте на слабкому телефоні. На Motorola G52 Onager падав з 20 до 6 fps лише через шейдер стін, більше, ніж роздільність, тіні й відображення разом. Тому на низькій і середній деталізації стіни мають простіший матеріал.
Гравітаційний постріл у перенесеному Onager: куля піднімає блоки, навколо неї вихор і синє світло.
Райдужний постріл: білі точки виходять просто з поверхні влученого блоку.

Якщо ви розв'язуєте фізику тисяч об'єктів у сучасній Unity, подивіться також на фейковий ragdoll для тисяч ворогів в Unity DOTS. Як після перенесення додати старій 2D-грі glow і 2D-світло в URP, описано в окремій інструкції.

Чого цей підхід не розв'язує

Компоненти, яких сучасна Unity не знає, не під'єднаються. GUITexture і GUIText треба відновити, як у кроці 5, старі системи частинок втрачаються. Назви класів і полів залишаться точно такими, як в оригінальному проєкті, з одруківками й тією мовою, якою їх колись хтось написав. Сцени прив'язуються до них за назвою, тож перейменовувати має сенс лише через редактор, який сам перепише посилання.

Якщо у вас є старий проєкт на Unity, який треба перенести на сучасну версію, напишіть нам.

← Більше в категорії Onager