Любая игра в Unity состоит из данных и методов их обработки. Кол-во этих данных может быть любое, к тому же они могут быть любого типа – изображение или текстовый файл. Раньше все эти данные хранились вместе в архиве с игрой, но с рассветом сети и ростом скорости подключения к ней появилась возможность хранить второстепенные данные удаленно. В связи с этим, при разработке не только игр, но и других приложений, появилась целая новая область по работе с этими данными.
В этой статье мы рассмотрим разные способы по работе с внешними ресурсами в Unity. Как работать с внешними типами данных, какие они бывают и чем отличаются разные инструменты по обработке этих самых данных.
Самыми часто используемыми типами внешних данных являются:
- Текстовый файл. В этом файле могут находится настройки, либо описания других объектов. Самый простой тип данных, который хранится в виде строк.
- Изображение. Это может быть текстура или просто картинка.
- Аудио файл. Музыкальный трек, либо звук спецэффекта.
- Видео файл.
- Байт массив. Самый универсальный тип данных, который можно преобразовать в любой другой тип данных(включая выше перечисленные). Изначально, любые загружаемые данные представляют из себя поток массива байтов.
Для Unity есть еще один специальный тип данных AssetBundle, который представляет из себя контейнер, где можно хранить сразу несколько ресурсов, включая сложные объекты вроде GameObject’ов и сцен.
Возможности unity
Для работы с внешними ресурсами в Unity существует целый специальный раздел Networking, который хранит все необходимые инструменты для работы в сети.
В этой части статьи мы начнем с самого важного элемента всей системы, который называется UnityWebRequest.
Этот элемент является основой для любых коммуникаций с сетевыми сервисами.
Объект UnityWebRequest можно представить в виде посредника, который связывается с сетевым сервисом по указанному адресу и проводит операции по передаче данных между приложением и указанным сервисом. Общение между приложением и сервисом происходит в виде Запроса (Request) и Ответа (Response), которые посылает и принимает UnityWebRequest. Также этот объект отвечает за загрузку и отправку любых типов данных.
Обычно все действия по загрузке или отправке данных в UnityWebRequest, выполняются асинхронно, и чтобы отследить результат работы через время, пользуются корутинами, либо разного рода Update’ами, где проверяют процесс выполнения работы.
Загрузка изображения
Теперь попробуем разобрать работу UnityWebRequest’а по порядку. Для примера, загрузим простое изображение и выведем его на экран.
Создаем новый скрипт SimpleRequest наследуемый от MonoBehaviour.
- public class SimpleRequest : MonoBehaviour {
- }
Далее добавляем новую строковую переменную url.
- public class SimpleRequest : MonoBehaviour {
- public string url;
- }
В этой переменной url будет храниться ссылка на изображение.
Теперь объявим еще одну переменную tex типа Texture2D, куда мы поместим загруженное изображение.
- public class SimpleRequest : MonoBehaviour {
- public string url;
- private Texture2D tex = null;
- }
Чтобы вывести изображение на экран воспользуемся старой системой GUI, для этого добавим в класс SimpleRequest метод OnGUI.
- public class SimpleRequest : MonoBehaviour {
- public string url;
- private Texture2D tex = null;
- private void OnGUI() {
- }
- }
В этом методе OnGUI, добавим проверку – если текстура загрузилась, то попробуем вывести ее на экран. Вот как это выглядит.
- public class SimpleRequest : MonoBehaviour {
- public string url;
- private Texture2D tex = null;
- private void OnGUI() {
- if (tex) {
- Rect r = new Rect(0, 0, tex.width, tex.height);
- GUI.DrawTexture(r, tex);
- }
- }
- }
Для отрисовки изображения определяем область Rect с размерами текстуры, и с помощью метода GUI.DrawTexture выводим ее на экран.
Теперь осталось только написать метод по загрузке самого изображения из сети. Для этого воспользуемся методом Start, представленного в виде корутины.
- public class SimpleRequest : MonoBehaviour {
- public string url;
- private Texture2D tex = null;
- private IEnumerator Start() {
- }
- private void OnGUI() {
- if (tex) {
- Rect r = new Rect(0, 0, tex.width, tex.height);
- GUI.DrawTexture(r, tex);
- }
- }
- }
Чтобы создать новый экземпляр класса UnityWebRequest для загрузки изображения, воспользуемся специально-предназначенным для этого классом UnityWebRequestTexture, который автоматически настроит новый экземпляр UnityWebRequest для загрузки изображения.
- public class SimpleRequest : MonoBehaviour {
- public string url;
- private Texture2D tex = null;
- private IEnumerator Start() {
- UnityWebRequest req = UnityWebRequestTexture.GetTexture(url);
- }
- private void OnGUI() {
- if (tex) {
- Rect r = new Rect(0, 0, tex.width, tex.height);
- GUI.DrawTexture(r, tex);
- }
- }
- }
Передаем в статический метод GetTexture класса UnityWebRequestTexture ссылку на изображение, которое храниться в переменной url и получаем на выходе готовый для работы UnityWebRequest.
Далее, чтобы запустить процесс загрузки изображения воспользуемся методом SendWebRequest.
- public class SimpleRequest : MonoBehaviour {
- public string url;
- private Texture2D tex = null;
- private IEnumerator Start() {
- UnityWebRequest req = UnityWebRequestTexture.GetTexture(url);
- req.SendWebRequest();
- }
- private void OnGUI() {
- if (tex) {
- Rect r = new Rect(0, 0, tex.width, tex.height);
- GUI.DrawTexture(r, tex);
- }
- }
- }
Для проверки выполнения работы, у класса UnityWebRequest существует специальное свойство isDone, которое возвращает boolean значение.
- public class SimpleRequest : MonoBehaviour {
- public string url;
- private Texture2D tex = null;
- private IEnumerator Start() {
- UnityWebRequest req = UnityWebRequestTexture.GetTexture(url);
- req.SendWebRequest();
- while(req.isDone == false) {
- yield return new WaitForEndOfFrame();
- }
- }
- private void OnGUI() {
- if (tex) {
- Rect r = new Rect(0, 0, tex.width, tex.height);
- GUI.DrawTexture(r, tex);
- }
- }
- }
В нашем случае, пока свойство isDone не вернет значение true, мы будем ожидать выполнения процесса загрузки.
После завершения загрузки воспользуемся специальным классом DownloadHandlerTexture, который преобразует загруженные ранее данные в готовое изображение.
- public class SimpleRequest : MonoBehaviour {
- public string url;
- private Texture2D tex = null;
- private IEnumerator Start() {
- UnityWebRequest req = UnityWebRequestTexture.GetTexture(url);
- req.SendWebRequest();
- while(req.isDone == false) {
- yield return new WaitForEndOfFrame();
- }
- tex = DownloadHandlerTexture.GetContent(req);
- }
- private void OnGUI() {
- if (tex) {
- Rect r = new Rect(0, 0, tex.width, tex.height);
- GUI.DrawTexture(r, tex);
- }
- }
- }
Для получение изображения достаточно передать в статический метод GetContent экземпляр класса UnityWebRequest’а, который храниться в переменной req.
Теперь можно поместить скрипт SimpleRequest на камеру, что на сцене, задать url адрес изображения в инспекторе и ожидать выполнения загрузки.
Важно! Чтобы UnityWebRequest мог правильно выполнить подключение к любому сетевому сервису, при этом неважно, выполняем мы при этом загрузку или отправку данных, ссылка должна быть “статической”. Часто сетевые сервисы, делают ссылки на свои ресурсы “динамическими”, то есть ссылки на эти самые ресурсы время от времени меняются, либо к ним не подключиться без прохождения дополнительных проверок, это делается для безопасности самого сервиса.
Для примера, можно воспользоваться любым бесплатным хостинг-сервисом для изображений, который выдает статические ссылки. В браузере Google Chrome, достаточно просто открыть изображение, кликнув по нему правой кнопкой мыши, и выбрать Копировать URL картинки.
Заключение
Все действия, которые были выполнены выше, описывают лишь часть всех возможностей по загрузке простых типов данных из сети, без их обработки.
В область работ по обработке данных входят:
- Доступность. В первую очередь, проверка возможностей подключения к указанному сервису в сети.
- Сохранение. Кэширование данных является первостепенной задачей после их загрузки.
- Актуальность. Наличие более новых версий данных.
В следующей части, мы рассмотрим какие инструменты используются для загрузки данных, как и где эти данные хранятся на устройстве.