Особенности разработки мобильной MMO RTS. Часть 3



    Содержание:


    1. Оптимизация производительности и целевые устройства
    2. Отрисовка текста и оптимизация Label
    3. Виртуальные списки и перемещение камеры

    Оптимизация производительности и целевые устройства


    Я знаю 3 вещи, которые никогда не заканчиваются: вселенная, ремонт BMW и оптимизация.
    Вы начинаете оптимизировать на стадии проектирования архитектуры. Кажется, что этот процесс прекратится после достижения требуемой производительности на целевых устройствах. Но это миф. После того как вы добавляете новый функционал или графический контент в билд, производительность ухудшается.

    Мы проанализировали статистику по всем устройствам и выделили те, на которых будем отслеживать производительность в ~30fps. Суть в том, чтобы определить самые слабые устройства, с которых совершаются множество покупок.



    Чтобы выявить проблемные места, используем нативный профилировщик Unity и xCode. Постоянно анализируем, чтобы выявить недостатки, оцениваем возможности их устранения и выгоду от этого. После приоритезируем задачи и работаем, пока не достигнем желаемой производительности.

    При профилировании обращаем внимание на 4 аспекта: выделение памяти в каждом кадре, пики производительности, частоту вызовов методов и самые времязатратные участки кода.

    Давайте рассмотрим примеры.

    Оптимизация Label и отрисовки текста


    Давайте разберем, как Unity работает с текстом. Все символы и глифы при запросе для отрисовки добавляются системой в специальную текстуру, которая находится в памяти. Затем с помощью точных текстурных координат символы отрисовываются из этой текстуры. Для батчинга желательно, чтобы все Label были в одном DrawCall. Следите за этим во время сборки UI.

    Мы переписали компонент работы с текстом в NGUI под наши потребности. В итоге получили ощутимое увеличение производительности. Вот список оптимизаций и переделок:

    • Разделили Label на несколько компонентов. Базовый – для отрисовки собственно текста. Компонент эффектов – для добавления BB-кода, теней, обводки и других надстроек над процессом построения текста. Если нужен текст без эффектов, базовый компонент выигрывает. В нем нет кода парсинга текста и дополнительных полей для хранения состояний. Также лейбл полностью пересчитывается только в случае изменения текста, размера шрифта и его собственного ректа.
    • Расширили список поддерживаемых BB-кодов.
    • Внедрили политику работы с размерами шрифтов. Проанализировали их использование в проекте и выбрали самые эффективные размеры: 28, 36, 40. Если разработчик выбирает 25-й размер, будет использоваться ближайший из списка – 28-й. Выбранный размер отскейлится до 25. Это позволило значительно сократить размер текстуры под шрифт.
    • Оптимизировали процесс обновления текстуры при увеличении ее размера. Раньше, если запрашивался символ, который не помещался в текстуру, она удалялась. После этого запрашивались все символы из активных лейблов в UI и строилась новая. Из текстуры просто удалялись неиспользуемые символы, и она могла не увеличиваться в размерах. На практике при открытии нового окна с другим набором символов текстура могла пересоздаваться. Мы добавили кэширование используемых символов и их размеров, чтобы гарантировать увеличение текстуры каждый раз до значения следующей степени двойки. Довольно быстро эта текстура заполнялась всеми используемыми символами и размерами. Это оказалось оптимальнее, чем постоянная перестройка с меньшей по размеру текстурой.

    Виртуальные списки и перемещение камеры


    В нашей игре очень много данных. Чтобы отображать их, мы реализовали виртуальные списки. В них есть определенное количество элементов, которые отображают контент. Это количество обусловлено размером видимой области списка и несколькими экстраэлементами для перестраховки. Когда элемент выходит за границы видимой области, ему определяются новые данные, и он переставляется в списке таким образом, чтобы пользователь, проскроллив дальше, увидел его следующим. Этот подход позволяет не создавать много объектов и отображать сколько угодно данных.



    Мы заметили, что при активном использовании списков данных у пользователей ощутимо проседал FPS. Дело в том, что в Unity изменение позиции объектов – относительно дорогая операция, учитывая, что UI сам по себе – большое количество GameObject. Чтоб избежать изменения позиций большого количества элементов, решили изменять позицию всего одного элемента – камеры. Грубо говоря, форма отображается двумя камерами. Одна для списка, другая для остального UI. На области скролла находится контроллер, который обрабатывает перемещения камеры и сообщает списку как ему нужно перестраиваться.



    Мы также можем создавать бесконечные списки, когда данные загружаются с сервера страницами и динамически добавляются в источник данных. Следующий запрос выполняется, когда пользователю остается просмотреть еще какое-то фиксированное количество объектов. Такое решение удобно использовать в рейтингах.

    Это не очень удобно при сборке UI: приходится постоянно контролировать слои объектов в рамках одного префаба, но после доработки инструментария проблем с этим не возникало. Кроме списков и прочих UI-элементов, мы используем такой подход с камерами для сектора, карты, превью персонажей, войск и зданий.



    Заканчиваю работу над четвертой статьей. Увидимся!

    Другие статьи из серии:


    Plarium
    134,73
    Разработчик мобильных и браузерных игр
    Поделиться публикацией

    Комментарии 22

      0
      Есть ли у uGUI те же проблемы что у NGUI с производительностью? И решаются ли они так же как описано в статье?
        +1
        C uGUI на самом деле всё ещё интересней. Советую обратиться к документу с Best Practices https://unity3d.com/learn/tutorials/topics/best-practices
        Товарищ с последнего юнайта так же достаточно много времени уделяет проблемам и оптимизации uGUI https://www.youtube.com/watch?v=n-oZa4Fb12U
        От себя скажу что хак с прокруткой листа в uGUI ещё больше в тему из-за особенностей построения батчей в канвасе
          +1
          Очень значительное улучшение производительности дает выключение PixelPerfect.
          Значительно — это 20 раз разница на больших списках:
          image
            0
            В данном случае я не имел в виду pixel perfect, я имел в виду сборку батча канвасом при изменении любых параметров (в данном случае положения) элементов внутри скролвьюшки. Для тех случаев, когда все pixel perfect и прочие вещи уже давно выключены, а производительность оставляет желать лучшего
              +2
              Ну я с вами не спорю, просто оставил как довольно важный пункт, о котором человек, зашедший в эту статью из гугла может не знать. Если не сложно напишите еще и остальные
              прочие вещи уже давно выключены

              которые важны, но столь очевидны что о них уже нигде не пишут.
          0
          В статье речь про оптимизацию производительности, а не о решении проблем с какой-то конкретной системой. Поэтому в примере — несколько обобщённых примеров, которые можно обыграть в любом фреймворке.
          +1
          Большое спасибо за статью, но хотелось бы отметить, то что не упомянуто в статье (во всяком случае я не заметил)

          1) Правильно ли я понял про списки? — данный подход можно использовать, только если на Canvas (на котором находится список) стоит Render mode — World Space:

          1.1) Если будет стоять Overlay — то там камера вообще ненужна, т.к рендер UI происходит и без нее
          1.2) Если Camera — то все UI элементы будут двигаться в 3D пространстве вместе с камерой (оставляя в кадре тот элемент который и был ранее) — получается прокрутку не осуществить двигая камеру…

          2) Для небольших списков есть лайфхак, во Viewport списка, замест компонента Mask, установить Rect Mask 2D. Повышает производительность на слабых девайсах примерно в 1.5-2 раза.

          image
            +2
            В статье речь об NGUI, в uGUI всё гораздо печальнее с производительностью.
              0
              Тогда в этом есть смысл) почему то перемкнуло что в пункте 2 про NGUI, в пункте 3 про UGUI (наверно сыграла ассоциация UI и Unity часто в контексте) — обычно данное словосочетание ассоциируется с UGUI (наверно у тех кто мало работал с NGUI и много с UGUI) — спасибо
                0
                Если рассматривать NGUI и UGUI «из коробки», то NGUI сильно проигрывает. Но, ввиду открытости последнего, в случае с NGUI у разработчика больше возможностей по оптимизации, всё упирается лишь в его скил. В то время как на стороне UGUI поддержка и гарантия развития.
                  0
                  По моим ощущениям, UGUI проигрывает, NGUI из коробки работает хорошо. С UGUI через какое-то время начинаются адовые тормоза, и не понятно почему так происходит. Потом ты набредаешь на статьи и видео где рассказывают что всё это время ты проектировал интерфейс неправильно. И что все те оптимизации которые по идее должны были срабатывать, не работали вовсе. Т.е. он сделан контринтуитивно в этом плане. Например все объекты на Canvas считаются будто-бы с прозрачностью, любое перемещение или изменение элемента на экране это практически всегда перестройка всего меша до Canvas (а он обычно один, никто не говорит что их надо делать побольше). Деактивированные объекты участвуют в создании меша (по крайней мере я об этом слышал из видео юнити разраба, может я его неправильно понял) и т.д. и т.п.

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

                  Ну и как бы оба движка, условно говоря, поставляются с исходниками. Но разобраться в логике работы UGUI весьма и весьма затруднительно. Всё это лишь, конечно же, мое мнение, основанное на довольно обширном опыте работы с обоими движками. Мой выбор NGUI.
                    0
                    Согласен, что разобраться в логике работы UGUI не всегда просто ввиду того, что открыт он лишь частично. Честно говоря, никогда не было ситуации вроде «UGUI через какое-то время начинаются адовые тормоза», выпустили достаточно крупный проект в котором примерно 90% 2d контента и крайне «тяжелый» UI — проблем с производительностью относительно UGUI не было в принципе. На NGUI были «собраны» два не менее крупных проекта, в итоге, попробовав UGUI, единогласно решили полностью перейти на него. К тому же тут большую роль играет наличие саппорта, когда можешь прямо в скайпе написать ответственному из Unity и попробовать разрулить проблему.
                0
                1) Да, только с таким Render mode канвас будет неподвижен относительно камеры.
                  0
                  Вы наверно спутали с типом Render mode — Camera… с типом World Space… можно и камеру смещать относительно Canvas и Canvas относительно камеры…

                  image
                +3
                данных. Чтобы отображать их, мы реализовали виртуальные списки. В них есть определенное количество элементов, которые отображают контент. Это количество обусловлено размером видимой области списка и несколькими экстраэлементами для перестраховки. Когда элемент выходит за границы видимой области, ему определяются новые данные, и он переставляется в списке таким образом, чтобы пользователь, проскроллив дальше, увидел его следующим. Этот подход позволяет не создавать много объектов и отображать сколько угодно данных.

                Выложили б ответственный код. Вполне себе библиотечная функция, на которую интересно посмотреть.
                  0
                  Ну скажем так, в функцию весь этот код не уместится, поэтому автор и попытался подробно описать подход, чтоб появилось понимание. А с пониманием, нам кажется, ни у кого не составит труда подробно расписать алгоритм, и тем более, реализовать.
                  0
                  И всё равно найдусь я, у которого будет лагать. От этого никуда не денешься.
                    0
                    Можете подробнее разобрать как работает GIF с отрисовкой карты?
                    Это inactive геймобъекты или же динамическая подрузка с последующей выгрузкой?
                      0
                      И то, и другое. Если вкратце, то там динамически подгружаемые из ресурсов при первом использовании объекты, которые по мере того, как выходят из области видимости, складываются в пулы, в inactive состоянии.
                      Тут важна сама идея, как и со списками, как и глобальным сulling'ом, не рендерить то, чего игрок не видит, а так же максимально-возможное переиспользование всего: один из первых заветов любого гейм-девелопера.
                      +1
                      Артём, раз уж вы первый начали про списки, хочу вас попросить от лица всех игроков. Доведите пожалуйста до ума списки в мобильных играх.

                      Суть проблемы. По любому событию (например, приход войск разведки обратно на базу, или завершение строительства) список, который находится на экране, даже не связанный с этим событием (например, список заметок на карте), пересоздается и изменением точки отрисовки, говоря повседневным языком — мгновенно скроллируется наверх. Ладно в заметках, поматерился, отмотал на 5 экранов вниз и по новой, а если событие настигает в момент выбора количества юнитов на списке войск? Список под движущимся пальцем перерисовывается и вот ты уже выбираешь других юнитов. Люди так много теряли по невнимательности.

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

                      Очень ждем.
                        0
                        К сожалению, случаются ситуации, когда команда разработки сосредоточена на решении более глобальных задач, а вот такие неполадки остаются долгое время в To do-листе.

                        Все подобные места чинятся отдельно, и то, что вы описали в своём сообщении, мы обязательно исправим в ближайших релизах.
                        0

                        Горизонтальную ориентацию экрана что мешает сделать для планшетов, кстати?
                        Платят мало? И не будут платить, играть неудобно.

                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                        Самое читаемое