Найти в Дзене
Андрей в Геймдеве

Уменьшаем вес игры на Unity

Оглавление

Всегда приятно, когда игра весит немного. Особенно, это актуально для HTML5 игр, где игрокам надо скачать вашу игру прямо в браузере. Лишнее время ожидания может оттолкнуть игроков и они закроют вкладку. Чтобы этого не произошло, надо уменьшить вес игры и свести его к необходимому минимуму. Ну что, погнали.

Определяем, что сколько весит

Самый надёждный подход в нашем деле - найти то, что нам надо оптимизировать в первую очередь. В Unity есть всё необходимое для этого. Делаем билд игры и смотрим в окно Console. В правом верхнем углу открываем меню и выбираем Open Editor Log.

Открываем лог едитора, чтобы узнать какие ассеты весят больше всего
Открываем лог едитора, чтобы узнать какие ассеты весят больше всего

В этом файле много текста и нам нужен лишь тот, который начинается со слов "Build Report". Ищем эту фразу по тексту в открытом файле. Находим примерно следующее:

Build Report
Uncompressed usage by category (Percentages based on user generated assets only):
Textures 15.4 mb 72.0%
Meshes 5.7 kb 0.0%
Animations 55.4 kb 0.3%
Sounds 4.1 mb 19.4%
Shaders 148.0 kb 0.7%
Other Assets 1.3 mb 6.3%
Levels 0.0 kb 0.0%
Scripts 186.2 kb 0.9%
Included DLLs 0.0 kb 0.0%
File headers 120.4 kb 0.6%
Total User Assets 21.4 mb 100.0%
Complete build size 12.7 mb

Как видно, большего всего места занимают текстуры и звуки. Это вполне ожидаемо и поэтому не так интересно, как то, что мы увидим ниже. Там будет список всех ассетов, отсортированных по их весу. То есть вверху будут самые жирные ассеты. С них и надо начать.

Приведу мои первые 5 строчек из этой секции Build Report.

1.7 mb 13.4% Assets/4_Audio/battle-music.ogg
1.4 mb 11.1% Assets/4_Audio/main-menu-theme.ogg
1.0 mb 8.1% Assets/TextMesh Pro/Resources/Fonts & Materials/LiberationSans SDF.asset
682.8 kb 5.3% Assets/eretichable Technologies/Cartoon explosion BOOM Weapons Gun VFX/Textures/1.png
675.6 kb 5.2% Assets/0_Pictures/UI/progressbar-gray2.png

Давайте пройдёмся по всем типам ассетов из этой пятёрки.

Музыка и звуки

Нужно ли стерео?

Если ваш звуковой файл является стерео (то есть хранит в себе две звуковые дорожки), то задумайтесь, а нужно ли это? Я заметил, что звуки стрельбы и способностей звучат хорошо даже в моно. Поэтому можно открыть ваши стерео-звуки в любом аудио-редакторе и превратить их в моно-звуки. Либо удаляйте вторую дорожку, либо накладывайте вторую на первую. Убедитесь, что звук не сильно исказился, и заменяйте файлы в Unity-проекте. Размер звуков уменьшается примерно раза в два. Такой трюк вряд ли прокатит с музыкой, так как она, обычно, сильно искажается.

Я использую бесплатный аудио-редактор Audacity.

Отрезаем хвосты

Нередко встречаются звуки, которые заканчиваются почти тишиной. Например, озвучка выстрелов зачастую имеет в конце утихающий эффект. В динамичной игре такие "хвосты" никто не услышит и поэтому их можно отрезать в аудио-редакторах, что ещё больше сократит вес файла.

Выбираем аудиоформат

Часто для игр используют .ogg аудио-формат, потому что он весит меньше популярных форматов типа mp3 или wav. Вы можете конвертировать звуки и музыку в этот формат и сэкономите немного памяти.

Понижаем качество звуков в Unity

Нажмите на звуковой файл в вашем Unity-проекте и найдите там Quality:

Понижаем качество звуков
Понижаем качество звуков

На моей картинке видно, что я открыл вкладку HTML5 и понижаю качество для этой платформы, так как я делал игру именно для HTML5. Этот приём можно использовать и для других платформ или сразу поменять качество для всех платформ во вкладке Default.

Обратите внимание на панельку ниже - там указано сколько памяти занимает выбранный звук. Затем меняйте Quality и нажимайте кнопку Apply. А теперь посмотрите на занятую память - она стала меньше. Поздравляю!

Чтобы выбрать подходящее значение Quality, можно потестировать как это звучит в игре. В боевиках одновременно слышно много звуков и поэтому качество не так важно. Лично я для себя решил использовать Quality=50 для музыки и 30-40 для звуков игры.

Можно выделить несколько звуковых файлов и поменять Quality сразу для них всех.

Текстуры

Главный принцип оптимизации размера текстур в Unity это POT - Power of Two. Это означает, что ширина и высота вашей картинки в пикселях должны быть кратны степени двойки (Power of Two).

Хорошие примеры разрешений текстур:

512х512

256х512

64х256

1024х1024

Плохие примеры разрешений текстур:

200х200

300х512

1000х117

На картинке ниже текстура с разрешением 200x200 занимает больше памяти, чем текстура с 256x256. Разница больше чем в 3 раза!

Размер текстуры 200х200 почти в 4 раза больше, чем размер текстуры 256x256
Размер текстуры 200х200 почти в 4 раза больше, чем размер текстуры 256x256

На текстуре 200x200 написано NPOT, что означет Non Power of Two - не является степенью двойки. Рассмотрим, что можно с этим делать.

Подогнать размер картинки под ближайший POT

Есть несколько вариантов.

1) Самым очевидным вариантом будет с начала разработки игры все текстуры подгонять под размеры POT. Если ваша картинка не укладывается под такие размеры, то можете добавлять прозрачные отступы:

Сверху и снизу есть пустое место, чтобы подогнать размер картинки под размеры POT
Сверху и снизу есть пустое место, чтобы подогнать размер картинки под размеры POT

2) Выставить Max Size в настройках текстуры.

Выставляем максимальный размер текстуры
Выставляем максимальный размер текстуры

Если картинка меньше Max Size, то ничего не изменится. Если картинка больше Max Size, то Unity подгонит вашу картинку под этот размер.

3) Атласы спрайтов. Если у вас уже много картинок NPOT, то можно их все собрать в одной текстуре размера POT прямо в Unity. Если на ваших картинках много свободного места, то спрайтовый атлас сэкономит памяти ещё больше.

Создать такой атлас можно через контексное меню Create. Нажмите правой кнопкой мыши в списке ассетов и выберите такой пункт в меню: Create -> 2D -> Sprite Atlas. Затем добавляйте ваши картинки в Object for Packing и нажимайте кнопку Pack Preview:

Sprite Atlas удачно скомпоновал все текстуры в одной размера POT
Sprite Atlas удачно скомпоновал все текстуры в одной размера POT

Я рекомендую в настройках Sprite Atlas убрать галочку Tight Packing. Иначе текстуры могут неудачно наложиться друг на друга.

Помимо экономии памяти, Sprite Atlas ещё используется для оптимизации загрузки ассетов, но это уже другая тема. Здесь я её затрагивать не стану, а просто дам ссылку для ознакомления: Optimizing Sprite Atlas usage and size for improved performance.

Задавать цвет для белых текстур

Если в вашей игре есть несколько картинок одинаковых по форме, но разных по цвету, то лучше сделать одну картинку с белой фигурой и задавать разные цвета в настройках Unity-компонентов Renderer. Помните картинку с белым куполом выше?

Белым текстурам можно менять цвет в Unity
Белым текстурам можно менять цвет в Unity

В моей игре белых куполов нет, но есть жёлтые, оранжевые и фиолетовые. Чтобы не импортировать 3 текстуры разных цветов, я сделал одну текстуру белого цвета и уже внутри Unity выставлял нужные цвета. Я сэкономил память на этой текстуре в 3 раза :)

Растягивающиеся текстуры

Многие элементы интерфейса (GUI) имеют области, которые просто залиты одним цветом или имеют градиент. Это кнопки, панели, прогрессбары, бэкграунды и так далее. На таких текстурах можно прилично сэкономить памяти. Я использовал 2 техники для 2 случаев:

1) Значительная область внутри текстуры просто залита одним цветом.

Приведу пример с кнопкой из моей игры:

Почти вся кнопка жёлтая - отличный повод для 9-slice
Почти вся кнопка жёлтая - отличный повод для 9-slice

Используем технику 9-slice. Идея в том, что мы убираем монотонные области и оставляем необходимый минимум, подогнанный под небольшой POT размер. Для этой кнопки вполне хватит жёлтого квадрата. Примерно вот такого:

Оптимизируем текстуру перед использованием 9-slice
Оптимизируем текстуру перед использованием 9-slice

Далее, в Unity настройках текстуры открываем Sprite Editor. Передвигаем зелёные точки с 4-х сторон таким образом, чтобы внутри остался монотонный прямоугольник:

Помещаем монотонный прямоугольник в центр
Помещаем монотонный прямоугольник в центр

Получилось 9 кусков текстуры - отсюда и название этого приёма 9-slice. Когда вы будете растягивать кнопку в вашем GUI, область внутри этого прямоугольника будет растягиваться по вертикали и горизонтали. Области выше и ниже прямоугольника растянутся только по горизонтали. Области слева и справа прямоугольника растянутся только по вертикали. Углы не будут растягиваться.

Таким образом, вы получаете такую же кнопку в GUI, но её текстура в несколько раз меньше оригинала.

С текстурами небольших размеров области вокруг прямоугольника могут как-то странно растягиваться, как будто теряют в качестве. Если такое происходит, надо поиграться со значением Pixel Per Unit в настройках текстуры. Как правило, увеличение этого значения спасает ситуацию.

2) Вам нужен градиент на большую область экрана.

Достаточно импортировать совсем небольшую картинку с градиентом шириной или высотой (в зависимости от направления вашего градиента) в 4 пикселя. Unity сама растянет текстуру и получится красивый градиент.

Crunch Compression

В настройках текстуры есть галочка Crunch Compression.

Crunch Compression заметно снижает вес текстуры
Crunch Compression заметно снижает вес текстуры

Этот вариант сжатия значительно уменьшает вес текстуры. Отрегулируйте качество сжатия через свойство Compressor Quality. Для простоты вы можете выставить хотя бы 40-50. Такое сжатие значительно уменьшит вес текстур в билде, но придётся заплатить качеством текстур. Однако, для большинства текстур в моей игре я практически не заметил потерь.

Текстуры из сторонних ассетов

Не забудьте о том, что все эти техники вы можете применить и для текстур из скачанных ассетов.

Шрифты

TextMeshPro импортирует дефолтный LiberationSans SDF.asset шрифт, который занимает целый мегабайт. Вы можете его удалить, если не используете этот шрифт. Однако, стоит учесть несколько подводных камней:

1) Unity будет использовать этот шрифт в качестве Fallback. То есть, если для какого-то текстового элемента в вашей игре не задан шрифт, то Unity попытается подставить LiberationSans SDF. Убедитесь, что этот шрифт нигде больше не используется.

2) Ё. Некоторые шрифты, которые вы будете использовать, могут не иметь букву Ё. Поэтому именно эту букву Unity попытается найти в том же LiberationSans SDF. Придётся заменить все Ё на Е. Ну или же выбрать другой шрифт, где эта буква есть.

Заключение

Надеюсь, мой сборник советов поможет вам значительно снизить вес билда в ваших играх. Если вы знаете ещё и другие приёмы, можете написать в коменты, чтобы обменяться опытом с другими разработчиками.