Одним из ключевых элементов, которым любой новичок в разработке игр может управлять в своем коде C #, является автоматическая сборка мусора, выполняемая, когда новый объект, строка или массив больше не нужны, а память, которую он использовал, может быть очищена, чтобы освободить место для чего-то. новый. Часто на ранних этапах обучения нас учат задавать направление элементов управления плеером и т. Д., Создавая экземпляр нового Vector3, или ссылаться на объект в методе с помощью вызова new Transform , и особенно, как только мы перейдем к сопрограммам, чтобы использовать yield return new WaitForSeconds.

Я здесь, чтобы научить вас очень простой привычке, которая поможет вам писать более качественный и производительный код на Unity. Большое спасибо GameDevHQ и пройденному мной курсу под названием Unity Optimization & Big O Notation за то, что научили меня использовать Unity Profiler для поиска проблем с производительностью и поиска кода, который можно оптимизировать.

Во-первых, что такое сборка мусора в Unity? Сборка мусора - это функция многих современных языков программирования, которая имеет дело с автоматическим управлением памятью. Такие языки, как C ++, не имеют этой функции и предназначены для того, чтобы программист определял управление памятью, специфичное для своего приложения и платформы, для которой он его пишет. Однако C # - это современный компонентный язык, основанный на C ++, который позволяет программисту сосредоточиться на логике, и наш код C # в Unity, к счастью, занимается сборкой мусора за нас. Когда создается объект, строка или массив, ему предоставляется блок памяти, в котором он будет храниться, пока он используется. Когда он больше не нужен, сборщик мусора уничтожает его в памяти, чтобы освободить место для хранения новых данных. Следует отметить один ключевой момент: Unity использует сборщик мусора Боэма – Демерса – Вайзера, который останавливает выполнение вашего кода до тех пор, пока сборщик мусора не завершит работу. Это может задержать выполнение вашей игры от менее одной миллисекунды до сотен миллисекунд, в зависимости от того, сколько памяти нужно обработать сборщику мусора и на какой платформе он работает.

Итак, как нам написать более производительный код в Unity? В начале статьи я упоминал, что одним из ключевых элементов, над которыми мы можем управлять, является автоматическая сборка мусора с использованием ключевого слова new.

Давайте посмотрим на обычную сопрограмму для начинающих в Unity. В этом случае эта сопрограмма заставляет игрока моргать, пока он не может получить урон, что часто бывает в ретро-играх:

IEnumerator Blink()
{
  while(_invincible)
  {
    _spriteRenderer.enabled = false;
    yield return new WaitForSeconds(0.5f);
    _spriteRenderer.enabled = true;
    yield return new WaitForSeconds(0.5f);
  }
}

Эта сопрограмма может просуществовать некоторое время. Это означает, что каждые полсекунды Unity создает новый экземпляр WaitForSeconds, который затем должен уничтожить. Этот пример сам по себе не создает слишком много проблем, но что, если бы сотни подобных сопрограмм работали одновременно и выполнялись с большей скоростью, чем каждые полсекунды? Кроме того, полсекунды - это довольно медленно для моргания. На самом деле нам бы хотелось, чтобы это было больше 0,15 секунды.

Итак, какое решение?

Это просто: кешируйте новые объекты, особенно если вы планируете использовать их снова и снова. Вместо того, чтобы делать что-то вроде предыдущего примера, объявите свой WaitForSeconds в верхней части скрипта и назначьте его в методе Start:

private WaitForSeconds _blinkYield;
void Start()
{
  _blinkYield = new WaitForSeconds(0.5f);
}

Теперь наша ссылка на _blinkYield кэшируется в памяти как один WaitForSeconds, и каждый раз, когда наша сопрограмма запускается, вместо того, чтобы создавать новый экземпляр WaitForSeconds, а затем отбрасывать его, оставляя его для очистки сборки мусора, наш сценарий будет ссылаться на тот же экземпляр в памяти, сохраненный для использования нами. Наш метод становится:

IEnumerator Blink()
{
   while(_invincible)
   {
       _spriteRenderer.enabled = false;
       yield return _blinkYield;
       _spriteRenderer.enabled = true;
       yield return _blinkYield;
   }
}

Вот и все! Это всего лишь один пример, но имейте в виду, что этот пример применим ко всему, где используется ключевое слово новое. Если вы используете метод, который будет запускаться регулярно (особенно Update и FixedUpdate, которые могут выполняться сотни раз в секунду!), Используйте вместо этого кешированную ссылку. Это поможет значительно повысить производительность вашего приложения!

Спасибо за прочтение. Я работаю инженером-программистом в Бостоне, и в настоящее время применяю свой опыт веб-разработки для создания корпоративных приложений и игр в Unity. Если вы 2D- или 3D-художник, работающий в цифровом формате, и ищете программиста для работы над созданием игры, или если вы работодатель и ищете программиста на Unity, чтобы присоединиться к вашей команде, напишите мне по адресу [email protected] и давайте подключимся!