Unity

Разработка вашей первой игры с помощью Unity и C#. Часть 4

Адам Тьюлипер

Продукты и технологии:

Unity, C#, Microsoft .NET, Mono

В статье рассматриваются:

  • разработка для Windows;
  • использование специфичного для платформы кода;
  • варианты сборки;
  • настройки игрока.

Добро пожаловать в последнюю статью цикла по разработке игр в Unity. Помните, когда впервые взорвался рынок приложений? На волне всеобщего увлечения создали колоссальное количество программ, и у нас появились приложения для всего. Но в этом море приложений людям стало сложно найти нужное приложение. Приложения, которые теряются на рынке, стали крупной проблемой для разработчиков. Windows Store/Windows Phone Store — далеко не доминирующая рыночная площадка на планете. Означает ли это, что вы не должны ничего разрабатывать для этого рынка? Абсолютно нет. У разработчиков есть реальные шансы на то, что здесь их приложения будут найдены своей аудиторией. Я часто слышал о разработчиках, приложения которых становились рекомендуемыми. Я знаю троих, с приложениями которых это произошло на других платформах, а я общаюсь со множеством разработчиков, использующих все платформы.

В этой статье я рассмотрю процесс переноса в Windows игры, созданной в Unity. Этот процесс довольно прямолинеен и позволяет весьма эффективно интегрировать платформу, что довольно легко реализовать в игре. В Unity 4.5 доступен превосходный инструментарий, который также поддерживает новые универсальные проекты (Universal Projects) (решения, генерирующие пакеты для Windows Phone и Windows Store с общим кодом).

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

Платформа

Если вы читаете этот журнал, то, вероятно, имеете представление об экосистеме Windows. Я лишь кратко расскажу, что поддерживает Unity в этой экосистеме. Вы можете вести разработку в расчете на Xbox 360, Xbox ONE, Windows Phone 8/8.1, Windows 8/8.1 (приложения Windows Store) и настольные компьютеры. В бесплатной версии Unity можно выбрать любую из этих платформ, кроме Xbox. Вы увидите, что Xbox перечисляется в вариантах сборки, но не сможете ничего скомпилировать под него, если только вы не являетесь участником программы ID для Xbox ONE. В случае Xbox 360 вы должны зарегистрироваться через уполномоченного издателя. Если вы работаете над чем-то сногсшибательным, пожалуйста, ознакомьтесь с программой ID по ссылке xbox.com/Developers/id. В Windows Phone и Windows Store процессы сборки очень похожи.

Помните, что Windows Phone и Windows Store предлагают следующие варианты сборки: Windows Phone 8 через Silverlight, Windows Phone 8.1 через Silverlight или Windows Runtime (WinRT), Windows 8, Windows 8.1, универсальные приложения, рассчитанные на Windows Phone 8.1 и Windows 8.1.

Разработка для Windows

Выполнить сборку из Unity на самом деле довольно легко. Для локального тестирования просто откройте диалог сборки (File | Build Settings), щелкните Build и выберите папку для вывода. Вариант Build and Run запустит вашу игру после компиляции либо на подключенном смартфоне, либо в вашей локальной системе — в зависимости от того, что именно вы выбрали. Это базовый уровень. После успешной сборки будет открыта выбранная вами папка либо с исполняемым файлом, либо с решением Visual Studio. Ошибки будут выводиться в консольном окне, поэтому всегда лучше заранее открывать его через меню. Если у вас не открыто консольное окно, вам придется все время посматривать на самую нижнюю строку состояния в окне Editor и обращать внимание на сообщения с красным текстом.

Для всех вариантов сборки Unity выполняет сборку с помощью так называемого игрока (player) и поддерживает игроков всех других платформ, упомянутых ранее. Создавая сборку своей игры, вам понадобится добавить в сборку каждую нужную вам сцену. Чтобы загрузить различные сцены в вашей игре (кроме первой, которая загружается по умолчанию), используйте Application.LoadLevel, который принимает либо имя сцены, например Application.LoadLevel("Level1"), либо индекс вида Application.LoadLevel(2). Я не любитель указывать индексы, потому что, как вы увидите, порядок сцен может запросто меняться.

Каждый уровень, который вы хотите загружать в коде, должен быть добавлен в сборку. В диалоге Build settings вы включаете любые сцены кнопкой Add Current или перетаскиванием файлов сцены на диалог сборки. Здесь вы можете переупорядочить их (что, опять же, делает загрузку сцен по индексу опасной). Вы можете разрешить или запретить использование этих сцен для любой сборки, помечая или снимая флажки рядом с ними. Как показано на рис. 1, нужно выполнить следующие операции.

  1. Добавить сцены в сборку.
  2. Убедиться, что нужные сцены отмечены. Я часто отмечаю тестовую сцену для включения в локальную сборку и сбрасываю ее флажок в финальной сборке.
  3. Выбрать платформу, под которую вы хотите скомпилировать игру.
  4. Щелкнуть Switch platform, чтобы Unity подготовила ваши ресурсы для выбранной платформы и включила специфичные для платформы константы препроцессора, такие как UNITY_METRO, UNITY_IPHONE, UNITY_WEBPLAYER и т. д.
  5. Скомпилировать свою игру в пакет, специфичный для платформы.

Добавление сцен в сборку

Рис. 1. Добавление сцен в сборку

Для настольной Windows Автономная (настольная) сборка предлагается по умолчанию при открытии Unity. При такой сборке Unity использует Mono для компиляции сборок (assemblies) и пакетов вашей игры вместе с ядром исполняющей среды. Вы получаете исполняемый файл и папку, в которую пакуется все. Эта сборка (build) предельно прямолинейна.

Для Windows Store и Windows Phone А здесь начинается самое интересное. При экспорте в Windows Store и Windows Phone можно добиться весьма впечатляющей интеграции с платформой. Вы можете использовать активную плитку (live tile), чтобы завлекать пользователей вернуться в вашу игру, отправлять текстовое сообщение, применять настройку геозон (geofencing) и др. Главное, что нужно отметить, — интегрировать функциональность, специфичную для платформы, в вашу игру сравнительно легко.

Процесс сборки слегка отличается от сборки для настольной системы, хотя вы по-прежнему можете воспользоваться Build and Run из диалога и довольно быстро получить рабочее приложение Windows Store или Windows Phone для тестирования.

Чтобы понять, где специфичный для платформы код важен для вашей Unity-игры, посмотрите, как Unity компилирует ваш код. Код, выполняемый в Unity Editor, компилируется лицензированной версией Mono. Это означает, что вы не можете обращаться к WinRT (Windows Store/Windows Phone 8.1) API, например использовать GeoLocation, пока игра выполняется в Editor, поскольку специфические WinRT-методы отсутствуют в Mono. Аналогично в Mono есть свои средства, которых нет в Windows Runtime, такие как Hashtable и доступ к файлам через System.IO в традиционной .NET. Многие виды функциональности в Mono и Windows Runtime перекрываются, но у них другие API.

Когда вы компилируете свой проект для Windows Store, Unity использует Microsoft .NET Framework для компиляции игровых сборок. По умолчанию для компиляции сборок применяется .NET Core, чем, по сути, и является WinRT .NET. Вам просто нужен способ сообщить Unity компилировать ваш код, специфичный для платформы, только при компиляции для этой конкретной платформы.

Есть два способа использования кода, специфичного для платформы. (Существует и третий, называемый мостовым [bridge], который связывает операции между кодом Unity и решения Visual Studio, но он применяется гораздо реже и поэтому здесь не рассматривается.) Первый способ — подключение плагина. Вы можете написать свой плагин, что весьма тривиально, или скачать подходящий из нескольких хороших источников. На момент написания этой статьи плагины от prime31.com для Windows Store и Windows Phone были бесплатными. Практически все основные издатели, применяющие Unity, используют плагины в своих игровых проектах. Скачивайте их, пока можно.

Использование специфичного для платформы кода

Через плагины Модель плагинов в Unity использует две версии библиотеки с одинаковыми сигнатурами методов. Одна из них является, по сути, заглушкой, компилируемой под .NET Framework 3.5 и помещаемой в Assets\Plugins\YourPlugin.dll. Эту версию Unity применяет, когда ваша игра выполняется в Editor. Другая компилируется под целевую платформу, скажем, Windows Store или Windows Phone и пакуется в вашу игру, когда вы осуществляете сборку из Unity (рис. 2).

Сборка с кодом, специфичным для платформы, через плагин

Рис. 2. Сборка с кодом, специфичным для платформы, через плагин

Специфичная для платформы библиотека помещается в Assets\Plugins\<Platform>\YourPlugin.dll (платформой может быть Windows 8.x, iOS, Windows Phone 8 и т. д.). Если у вас есть причина создать свою библиотеку вместо того, чтобы скачивать одну из множества доступных, загляните по ссылке bit.ly/1EuLV1N — там есть базовые инструкции на этот счет. Основное отличие в плагинах (помимо API платформы, конечно) заключается в том, куда вы помещаете специфичную для платформы DLL. Места размещения плагинов можно узнать по ссылке bit.ly/1v2ml1m.

Применение одного из плагинов с prime31 для установки активной плитки — дело простое: достаточно подключить код с рис. 3 к любому GameObject в вашей сцене. SettingsPane и класс Tiles — плагины, содержащие функциональность для реализации специфичного для платформы кода.

Рис. 3. Код плагина от prime31

public class WindowsStoreAppSettings : MonoBehaviour
{
  private void Start()
  {
#if UNITY_METRO // директива препроцессора, выполняемая, когда
               // в Unity выбирается сборка для Windows Store
  SettingsPane.registerSettingsCommand("Privacy Policy",
    "This is my privacy policy. Consider a url as well to bring you to the site.");
  // Задаем активную плитку. В качестве источника можно указать
  // URL из Интернета. Это не папка assets в Unity.
  // Вы должны убедиться, что это изображение появляется
  // в сгенерированном Visual Studio проекте, так как оно
  // никоим образом не передается из Unity.
  var images = new string[] { "ms-appx:///assets/WideLiveTile.png" };
  Tiles.updateTile(TileTemplateType.TileWideImage, null, images);
#endif
  }
}

Через директивы препроцессора Вы также можете использовать директивы препроцессора, чтобы включать или отключать компиляцию подставляемого кода. Это распространенный способ при разделении кода между платформами и разнообразными технологиями, и он тоже часто применяется в Unity-играх. С помощью этого способа вы просто указываете директиву в коде класса. Эти директивы можно использовать в разных целях. Помните важное правило: разделяйте свой код по платформам с помощью директив препроцессора, специфичных для платформы; одни директивы становятся активными в момент переключения платформ в настройках сборки в Unity (вроде UNITY_METRO), другие — только при компиляции вне Editor (NETFX_CORE), а третьи могут быть доступны постоянно (например, проверка версии Unity, UNITY_4_5 и другие директивы, определенные вами).

Я покажу пример использования кода, специфичного для платформы Windows. Если нужен доступ к GeoLocation в Windows Runtime, этот код можно включить прямо в класс, производный от MonoBehavior (рис. 4), и этот класс назначить любому GameObject. Поскольку этот код скомпилирован в Editor с помощью Mono, он потерпит неудачу без его обертывания в подходящую директиву препроцессора. Нам нужно сообщить Unity, что этот код компилируется только вне Editor. Возможно, вас интересует, в чем разница между NETFX_CORE и UNITY_METRO. Первая директива — это параметр компиляции, используемый, только когда сборки вашей игры компилируются для Windows Runtime. Вторая применяется при выборе Windows Store в качестве платформы в настройках сборки в Unity. Она может быть активна в вашем коде на C#, UnityScript или Boo. Лично я предпочитаю директиву NETFX_CORE для обертывания своего WinRT-кода, а не UNITY_METRO, так как NETFX_CORE доступна лишь при экспорте/сборке, а UNITY_METRO активна в Editor, как только вы переключаете платформы в Build Settings. То есть код может выполняться и в Editor, что вызовет проблему, если он содержит специфичный для платформы API. Вы можете добавить в ту же строку другие директивы, такие как && !UNITY_EDITOR, но я предпочитаю обходиться NETFX_CORE.

Рис. 4. Использование Geolocation

public class FindLandTarget : MonoBehaviour
{
// Если вы компилируете для Windows Runtime, используйте
// этот код для использования геопозиционирования
// при коллизии объектов
#if NETFX_CORE
  void OnCollisionEnter(Collision collision)
  {
    Debug.Log("Collided with " + collision.gameObject.name);
    GetGeoLocation();
  }
  async void GetGeoLocation()
  {
  // Геопозиционирование следует вызывать в UI-потоке,
 // так как здесь есть часть UI, которую надо показывать
    UnityEngine.WSA.Application.InvokeOnUIThread(
      async () =>
        {
        var locator = new Windows.Devices.Geolocation.Geolocator();
        var position = await locator.GetGeopositionAsync();
        Debug.Log(string.Format("{0}, {1}  Accuracy: {2}",
          position.Coordinate.Latitude, position.Coordinate.Longitude,
          position.Coordinate. Accuracy));
        }, false
            );
    /**/
  }
#else  // Если вы не используете Windows Runtime, тогда
          // применяйте этот код коллизии
  void OnCollisionEnter(Collision collision)
  {
         // Платформы, отличные от Windows Runtime,
       // никакого геопозиционирования

    Debug.Log("Collided with " + collision.gameObject.name);
  }
#endif
}

Сборки

Unity будет компилировать ваш код для Windows Store и Windows Phone 8.1, используя .NET Framework под Windows Runtime. Она не использует Silverlight for Windows Phone 8.1. Однако код для Windows Phone 8 компилируется как HH — Silverlight-пакет для Windows Phone, как и следовало бы ожидать.

Unity будет компилировать ваши игровые сборки (assemblies) и создаст решение Visual Studio, который вы в свою очередь будете использовать для определения финальной сборки (build). Иначе говоря, кроме случая сборки под настольную систему, вам понадобится выполняться финальную компиляцию в Visual Studio, прежде чем отправлять свою игру в Windows Store или Windows Phone Store. Решение, генерируемое Visual Studio, содержит двоичные файлы Unity, упакованные с вашими игровыми сборками и базовым хост-приложением на XAML/C# или C++. При каждой сборке из Unity единственное, что перезаписывается Unity, — ваша папка Data. Любой пользовательский код или другие изменения, внесенные в решение Visual Studio, не перезаписываются при последующих сборках из Unity.

Сборки для Windows Store и универсальных приложений

Я рассмотрю варианты сборки для Windows Store (рис. 5). Типы сборки для Windows Store в Unity включают Windows 8, Windows 8.1, Windows Phone 8.1 и универсальные решения, которые содержат проекты для Windows Phone 8.1 и Windows 8.1, а также общий проект, как показано на рис. 6. Кроме того, обратите внимание на флажок Unity C# Projects на рис. 5. Это невероятно полезная функция, и я настоятельно советую пользоваться ею. Она позволит создать решение Visual Studio с дополнительными проектами, содержащими ваш Unity-код (рис. 7). Вы можете изменять код в этих проектах до определенной степени, и при компиляции Visual Studio будет запрашивать Unity заново обработать ваши игровые сборки, не выполняя заново полной сборки из Unity. То есть вы можете редактировать свой Unity-код в конечном решении Visual Studio, что крайне важно для отладки кода, специфичного для конкретной платформы. Это означает, что вам не придется заново компилировать решение из Unity при каждом изменении в коде.

Сборка для Windows Store

Рис. 5. Сборка для Windows Store

Универсальное приложение с общим проектом

Рис. 6. Универсальное приложение с общим проектом

Дополнительные проекты

Рис. 7. Дополнительные проекты

Когда Unity генерирует ваше решение Visual Studio, стоит обратить внимание на несколько моментов. Прежде всего ваш проект Windows Store по умолчанию будет рассчитан на компиляцию под аппаратную платформу ARM, а не x86 (по крайней мере, на момент написания этой статьи). Это создает путаницу, когда пытаешься скомпилировать и запустить свой проект, и тут вдруг получаешь ошибку с сообщением, что система не относится к ARM. Хотя я советую создавать сборки как для ARM, так и для x86, в целях локального тестирования нужно выбрать x86, чтобы избежать этой ошибки с ARM. Кроме того, на момент написания статьи в Unity не было 64-разрядных игроков для Windows Store или Windows Phone. Если у вас есть одно из немногих ARM-устройств с Windows 8, такое как Surface 1 или Surface 2 (RT не относится к Pro; Pro является системой на базе x86), тогда выбирайте ARM и выполняйте удаленное развертывание и отладку. Однако большинство разработчиков использует для локального тестирования ПК на основе x86.

Далее вы заметите, что Build Configuration Type включает варианты Debug, Master и Release. Это контрастирует с типичными .NET-приложениями, где возможны лишь варианты Debug и Release. Сборка Debug самая медленная. Она содержит отладочную информацию и поддерживает Unity Profiler — средство профилирования в версии Pro, применяемое для оптимизации игр. Сборка Release полностью оптимизируется, но тоже поддерживает Unity Profiler. Сборка Master — это то, что вы передаете в каждый магазин. Это оптимизированная, готовая к работе версия, которая не поддерживает Unity Profiler. При первом тестировании игры я выбрал сборку Master, чтобы получить реальное представление о скорости работы игры на своем устройстве.

В случае Windows Phone два основных варианта: Windows Phone 8 или Windows Phone 8.1. Приложения Windows Phone 8 будут нормально работать на устройстве с Windows Phone 8.1, хотя в Windows Phone 8.1 стратегия совместного использования кода, специфичного для платформ, гораздо эффективнее, поскольку вы можете ориентироваться на универсальные приложения, которые делят около 90% API с приложениями Windows Store. Однако в случае типичной игры это совместное использование кода может оказаться не особо полезным, если только вы не пишете специфичный для платформ код.

Как только у вас будет решение в Visual Studio, запакуйте его и отправьте в магазин, как и любое другое приложение Windows Phone или Windows Store. У вас обязательно должна быть учетная запись разработчика для Windows Store; вы лишь раз платите за нее и потом пользуетесь всю жизнь. Процесс передачи неоднократно описывался в различных материалах, но краткие обзоры можно посмотреть в «Publish to the Windows Store» (bit.ly/Za0Jlx)), «Publish to the Windows Phone Store» (bit.ly/1rdDCwR) и «Why and How to Port Your Unity Game to Windows and Windows Phone» (bit.ly/1ElzrcL).

Параметры игрока Я обсуждал базовый процесс сборки из Unity для Windows, но не рассмотрел, как задать значки, начальные экраны (splash screens), имя приложения и другие необходимые элементы. Все это можно найти в Player Settings, которые загружаются с экрана Build Settings и позволяют конфигурировать все основные параметры для приложений Windows Store и Windows Phone, как показано на рис. 8. Вы можете указать здесь начальный экран, имя приложения, издателя, параметры компиляции, значки, возможности приложения, например сервисы позиционирования, и некоторые другие параметры. Эти параметры публикуются в вашем решении Visual Studio, как только вы впервые скомпилируете решение из Unity.

Параметры игрока для Windows Store

Рис. 8. Параметры игрока для Windows Store

Значки приложения Unity предоставляет вашему приложению некоторые значки по умолчанию, чтобы оно могло быть скомпилировано в Visual Studio. Но вы должны сменить эти значки по умолчанию, иначе вы рискуете не пройти сертификацию. Unity заметно упрощает просмотр того, какие изображения вы можете задать в проекте, но вы должны свериться с документами на сертификацию для каждой платформы, чтобы определить, какие именно изображения обязательны. Вы должны проверить Visual Assets в файле Package.appxmanifest в Visual Studio (для Windows Store и универсальных приложений), так как Unity могла установить некоторые изображения по умолчанию, которые вы не заменили своими, — их нужно удалить.

Как минимум, в приложении Windows Store должны быть эмблема магазина 50×50, квадратная эмблема 150×150, квадратная эмблема 30×30 и начальный экран 620×300, как описано в Windows Dev Center (bit.ly/1vIJsue). В приложениях Windows Phone 8 обязательны изображение списка приложения (app list image) и изображение для плиток по умолчанию малого и среднего размеров, используемых на экране Start, как описано в Windows Dev Center (bit.ly/1oKo8Ro). Приложения Windows Phone 8.1 требуют тех же изображений. Магазины (которые, по слухам, унифицируются с Windows 10) могут запросить некоторые другие изображения в процессе передачи, например экранные снимки.

Если вы намерены предоставить только одно изображение для плиток на экране Start, то должны передать изображение, масштабируемое до 240% в случае приложений Windows Phone Store и до 180% в случае приложений Windows Store, как поясняется в Windows Dev Center (bit.ly/1nzWber).

Кстати, некоторое время назад я написал простенькую утилиту, которая помогает генерировать изображения для приложений Windows Store. Вы найдете ее по ссылке bit.ly/ImageProcessor.

Перекомпиляция и перезапись Вспомните, что Unity перезаписывает только вашу папку Data в вашем проекте Visual Studio (рис. 9). Это обоюдоострый меч. Вы можете задать начальный экран, значки и прочее в любой момент в Unity (и я советую делать именно так), но, если вы уже сгенерировали свое решение Visual Studio, файл Package.appxmanifest, содержащий эти настройки, не будут перезаписан при следующей компиляции из Unity. Вам придется вручную задавать визуальные ресурсы, возможности и многое другое в своем решении Visual Studio в файле Package.appxmanifest или создавать новую папку и искать разницу в структуре папки с помощью утилит вроде BeyondCompare, или удалять решение Visual Studio, если в нем нет вашего кода, и давать возможность Unity заново сгенерировать его. Обычно я выбираю третий вариант, потому что я храню все свои сконфигурированные изображения значков и начального экрана в Unity. Мне остается лишь не забыть перенести собственные активные плитки в решение Visual Studio. Если вы разрабатываете под Windows Phone 8 (но не 8.1), значок в любом случае должен быть установлен в Visual Studio; этот случай один из немногих, которые не обрабатываются из Unity.

Папка Data в проекте Visual Studio

Рис. 9. Папка Data в проекте Visual Studio

Only thing Unity overwrites Unity перезаписывает только эту папку

Заключение

Процесс сборки чрезвычайно прост. Настройте параметры сборки, щелкните кнопку Build, откройте решение и разверните его. Я показал варианты оптимизации вашей сборки через плагины и директивы препроцессора. Поскольку вы можете вызывать специфичный для платформы код вне Mono, вы получаете кое-какие дополнительные возможности. Не забудьте проверить на prime31.com плагины для Unity, которые в настоящее время бесплатны для платформы Windows. Они позволяют легко интегрировать функционал платформы всего несколькими строками кода. Также заглядывайте на Channel 9 за новыми обучающими материалами по Unity (рассчитывайте на десятиминутные видеоролики) и в мой блог на Channel 9 за многими советами по компиляции игр для разных платформ.

Дополнительные ресурсы


Адам Тьюлипер (Adam Tuliper) — старший идеолог по технологиям в Microsoft; живет в солнечной Южной Калифорнии. Разработчик инди-игр, один из администраторов Orange County Unity Meetup и автор на pluralsight.com. Скоро в его семье появится третий ребенок, так что связывайтесь с ним, пока у него еще есть свободные минуты, по адресу adamt@microsoft.com или через twitter.com/AdamTuliper.

Выражаю благодарность за рецензирование статьи экспертам Unity Томасу Дирванаускасу (Tomas Dirvanauskas), Игнасу Зиберкасу (Ignas Ziberkas) и Тоутвидасу Цилису (Tautvydas Žilys).