Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Реализация системы динамически загружаемого контента (DLC) для мобильной игры в Unity 3D

Anna | 18.06.2014 | нет комментариев

Недавно, для одной игры на Unity 3D, которую мы разрабатывали, появилась надобность добавить DLC систему. Правда это оказалось вдалеке не так легко, как казалось в начале, мы удачно совладали с возникшими задачами и игра ушла в gold. В этой статье я хочу высказать наш вариант реализации DLC, рассказать о возникших загвоздках и как мы их решили.

Постановка задачи

В игре есть магазин, где игрок приобретает вещи за игровую либо реальную валюту. В магазине – больше 200 пророческой. Когда игрок заходит в игру, ему доступно 20 пророческой в магазине. Если есть интернет, игра без ведома юзера опрашивает сервер на предмет наличия DLC и, если таковое имеется, скачивает в бэкграунде. Когда игрок вторично зайдет в магазин, он увидит все новые вещи из DLC.
Еще есть комплект локаций. Всякая локация имеет комплект текстур и .asset файлов. Новые локации также обязаны добавляться через DLC.
Загрузка источников из DLC должна быть синхронной.
Платформа: iOS (iPhone 3GS и выше.) и Android (Samsung Galaxy S и выше).

Содержимое DLC и работа с ним в игре

В игре вещи всецело определяются файлом itemdata.txt, в котором содержится информация о вещах и их текстурах. Значит, в всяком DLC будет находиться файл itemdata.txt с комплектом тех пророческой, которые есть в DLC тестуры для этих пророческой. А когда магазин запросит базу данных пророческой, мы склеим все текстовые файлы со всех DLC и дадим ему данный файл.
Подобно для локаций есть файл locationdata.txt со списком и колляциями локаций текстуры и asset файлы для них.
Соответствующий код на C# для загрузки источников в игровой логике будет выглядеть так:

public String GetItemDataBase() {
  if(DLCManager.isDLCLoaded() == true) {
    //склеить все файлы itemdata.txt во всех загруженных DLC и воротить как один string
    String itemListStr = DLCManager.GetTextFileFromAllDLCs(“itemdata”); 
    return itemListStr;
  }
  else {
    //загружаем файл по умолчанию
    TextAsset  itemTextFile = Resources.Load(“itemdata”) as TextAsset;
    return itemTextFile.text;
  }

  return String.Empty;
}

Подобно при запросе текстуры, мы проверяем её присутствие в DLC. Если она там есть, загружаем, напротив загружаем из игровых источников. Если и там нет, то загружаем что то дефолтное.

public Texture GetTexture(string txname) {
  Texture tx = null;
  if(DLCManager.isDLCLoaded() == true) {
    tx = DLCManager.GetTextureFromDLC(txname);
  }
  if(tx == null) {
    tx = Resources.Load(txname) as Texture;
  }
  if(tx == null) {
    Assert(tx, “Texture not find: ”   txname);
    tx = Resources.Load(kDefaultItemTexturePath) as Texture;
  }
  return tx;
}

Подобно для файлов .asset будет функция GetAsset(string assetName). Её реализация будет аналогичной, следственно пропустим её.

Файл DLC

Мы определились, что у нас должно быть в DLC. Осталось определиться, в виде чего это все беречь.

1-й вариант – беречь DLC в виде зип архива. В всяком архиве – текстовой файл N текстур. Текстуры обязаны быть в формате PVRTC для экономии видео памяти. Но здесь мы имеем первую загвоздку – Unity поддерживает загрузку текстур из файловой системы только в формате PNG либо JPG [link]. После этого текстуру дозволено записать в PVRTC текстуру [link]. Это неторопливый процесс, т.к. требует переконвертации в PVR в риалтайме. К тому же т.к. в DLC планируется беречь файлы типа .asset, а допустимо и игровые ярусы (.scene), такой способ и совсем непригоден.

2-й вариант – применять AssetBundle. Это решение безупречно подходит для DLC в играх.
Судя по документации, он владеет массой плюсов:

  • Может беречь всякие источники Unity, включая сжатые в необходимый формат текстуры (то что нам необходимо).
  • Это архив с отличным сжатием.
  • Легко и комфортно применять.
  • Поддерживает параметр version и хеш сумму (при загрузке функцией LoadFromCacheOrDownload), что комфортно для контроля версий DLC

Из минусов только касательно маленьких AssetBaundle-ов, т.к. потребляет дюже много оперативной памяти.

Работа над ошибками (Вариант 2)

Испробуем учесть все предыдущие задачи и обнаружить решения для них.

Задача с загрузкой крупных assetBundle-ов дозволено решить двумя методами.
1-й – применять класс WebClient. Впрочем с ним у нас появились задачи на iOS. WebClient ничего не мог скачать, впрочем на десктопе работал отменно.
2-й вариант – применять нативные функции ОС. Скажем, NSURLConnection для iOS и URLConnection для Android соответственно, которые поддерживаю буферизированную загрузку прямо в файл на диске.
Но это не такая уж и огромная задача, т.к. нам в любом случае нужно сокращать размер AssetBaundle для синхронной загрузки. Следственно пока мы оставили нынешний метод загрузки бандлов с сервера.

Гораздо больше серьезная задача – синхронная загрузка AssetBaundle. Т.к. он должен быть не только несжатым, но и занимать немного места в памяти, мы так либо напротив обязаны разбивать наш один огромный файл DLC на много маленьких файлов. Впрочем, если мы разобьем на слишком маленькие файлы, их будет много и это крепко увеличит время загрузки, т.к. придется для всякого файла устанавливать соединение снова. Значит, нам таки придется беречь их сжатыми для лучшей экономии времени загрузки и трафика.

Для решения этой задачи было решено применять свой личный архиватор. Была выбрана открытая библиотека архиватора для C#, которую без специальных усилий получилось завести под Mono в Unity.

Дальше алгорифм действий был дальнейшим:

  1. При создании бандла указывалась опция BuildOptions.UncompressedAssetBundle, Дабы получить несжатый бандл.
  2. После этого бандл архивировался и шифровался архиватором и заливался на сервер.
  3. Во время работы приложения создавался обособленный поток, тот, что в бэкграунде выкачивал бандлы, распаковывал их и складывал в особую папку.

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

Для системы контроля версий DLC было выбрано следующее решение. На сервере в папке, где лежали фалы DLC завели текстовой файл dlcversion. Он содержал список DLC в папке и md5 хеши для них. Эти хеши считались на этапе аплода DLC на сервер. На заказчике имелся такой же верно файл, и при старте приложения заказчик сопоставлял свой файл с файлом на сервере. Если какой-то DLC файл имел хорошие хеши либо хеша совсем не было, считалось, что файл на заказчике устарел и заказчик подтягивал с сервера новейший файл DLC.

Позже того, как новейший файл DLC был скачан и распакован, его хеш еще раз сверялся с серверным, и только позже этого устаревший файл заменялся на новейший и в файле dlcversion заказчика делалась соответствующая запись.

Описанная система была удачно имплементирована и отменно работает. Исключительный минус, тот, что мы имели, это небольшие просадки по fps (лаги) при закачке и распаковке DLC в бэкграунде. А также немножко усилились пиковые значения потребления памяти приложения.

Спасибо за внимание. Буду рад ответить на ваши вопросы.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB