Streamingassets что за папка
Работа с внешними ресурсами в Unity3D
Введение
Здравствуйте уважаемые читатели, сегодня речь пойдет о работе с внешними ресурсами в среде Unity 3d.
По традиции, для начала определимся, что это и зачем нам это надо. Итак, что же такое эти внешние ресурсы. В рамках разработки игр, такими ресурсами может быть все, что требуется для функционирования приложения и не должно храниться в конечном билде проекта. Внешние ресурсы могут находится как на жестком диска компьютера пользователя, так и на внешнем веб-сервере. В общем случае такие ресурсы — это любой файл или набор данных, который мы загружаем в наше, уже запущенное приложение. Если говорить в рамках Unity 3d, то ими могут быть:
Примечание: далее в статье используется код с использованием C# 7+ и рассчитан на компилятор Roslyn используемый в Unity3d в версиях 2018.3+.
Возможности Unity 3d
До версии Unity 2017 года для работы с серверными данными и внешними ресурсами использовался один механизм (исключая самописные), который был включен в движок – это класс WWW. Данный класс позволял использовать различные http команды (get, post, put и т.п.) в синхронном или асинхронном виде (через Coroutine). Работа с данным классом была достаточно проста и незамысловата.
Аналогичным образом можно получать не только текстовые данные, но и другие:
Работа с UWR в целом схожа с WWW в своей основе, однако есть и отличия, речь о которых пойдет дальше. Ниже приведен аналогичный пример загрузки текста.
Основные изменения, которые привнесла новая система UWR (помимо изменений принципа работы внутри) — это возможность назначать самому обработчиков для загрузки и скачивания данных с сервера, подробнее можно почитать здесь. По умолчанию это классы UploadHandler и DownloadHandler. Сам Unity предоставляет набор расширений этих классов для работы с различными данными, такими как аудио, текстуры, ассеты и т.п. Рассмотрим подробнее работу с ними.
Работа с ресурсами
Текст
Работа с текстом является одним из самых простых вариантов. Выше уже был описан способ его загрузки. Перепишем его немного с использование создания прямого http запроса Get.
Как видно из кода, здесь используется DownloadHandler по умолчанию. Свойство text это геттер, который преобразует byte массив в текст в кодировке UTF8. Основное применение загрузки текста с сервера — это получение json-файла (сериализованное представление данных в текстовом виде). Получить такие данные можно с использованием класса Unity JsonUtility.
Аудио
Для работы с аудио необходимо использовать специальный метод создания запроса UnityWebRequestMultimedia.GetAudioClip, а также для получения представления данных в нужном для работы в Unity виде, необходимо использовать DownloadHandlerAudioClip. Помимо этого, при создании запроса необходимо указать тип аудиоданных, представленный перечислением AudioType, который задает формат (wav, aiff, oggvorbis и т.д.).
Текстура
Загрузка текстур схожа с таковой для аудио файлов. Запрос создается с помощью UnityWebRequestTexture.GetTexture. Для получения данных в нужном для Unity виде используется DownloadHandlerTexture.
AssetBundle
Как было сказано ранее бандл – это, по сути, архив с ресурсами Unity, которые можно использовать в уже работающей игре. Этими ресурсами могут быть любые ассеты проекта, включая сцены. Исключение составляют C# скрипты, их нельзя передать. Для загрузки AssetBundle используется запрос, который создается с помощью UnityWebRequestAssetBundle.GetAssetBundle. Для получения данных в нужном для Unity виде используется DownloadHandlerAssetBundle.
Основные проблемы и решения при работе с веб-сервером и внешними данными
Выше были описаны простые способы взаимодействия приложения с сервером по части загрузки различных ресурсов. Однако на практике все обстоит гораздо сложнее. Рассмотрим основные проблемы, которые сопровождают разработчиков и остановимся на путях их решения.
Не хватает свободного места
Одной из первых проблем при загрузке данных с сервера является возможная нехватка свободного места на устройстве. Часто бывает, что пользователь использует для игр (особенно на Android) старые устройства, а также и сам размер скачиваемых файлов может быть достаточно большим (привет PC). В любом случае, эту ситуацию необходимо корректно обработать и заранее сообщить игроку, что места не хватает и сколько. Как это сделать? Первым дело необходимо узнать размер скачиваемого файла, это делается по средствам запроса UnityWebRequest.Head(). Ниже представлен код для получения размера.
Здесь важно отметить одну вещь, для правильной работы запроса, сервер должен уметь возвращать размер контента, в противном случае (как, собственно, и для отображения прогресса) будет возвращаться неверное значение.
После того, как мы получили размер скачиваемых данных, мы можем сравнить его с размером свободного места на диске. Для получения последнего, я использую бесплатный плагин из Asset Store.
Примечание: можно воcпользоваться классом Cache в Unity3d, он может показывать свободное и занятое место в кэше. Однако здесь стоит учесть момент, что эти данные являются относительными. Они рассчитываются исходя из размера самого кэша, по умолчанию он равен 4GB. Если у пользователя свободного места больше, чем размер кэша, то проблем никаких не будет, однако если это не так, то значения могут принимать неверные относительно реального положения дел значения.
Проверка доступа в интернет
Очень часто, перед тем, как что-либо скачивать с сервера необходимо обработать ситуацию отсутствия доступа в интернет. Существует несколько способов это сделать: от пингования адреса, до GET запроса к google.ru. Однако, на мой взгляд, наиболее правильный и дающий быстрый и стабильный результат — это скачивание со своего же сервера (того же, откуда будут качаться файлы) небольшого файла. Как это сделать, описано выше в разделе работы с текстом.
Помимо проверки самого факта наличия доступа в интернет, необходимо также определить его тип (mobile или WiFi), ведь вряд ли игроку захочется качать несколько сот мегабайт на мобильном траффике. Это можно сделать через свойство Application.internetReachability.
Кэширование
Следующей, и одной из самых важных проблем, является кэширование скачиваемых файлов. Для чего же нужно это кэширование:
Аналогично, получение данных из кэша.
Примечание: почему для загрузки текстур не используется тот же самый UWR с url вида file://. На данный момент наблюдается проблемы с этим, файл просто напросто не загружается, поэтому пришлось найти обходной путь.
Примечание: я не использую прямую загрузку AudioClip в проектах, все такие данные я храню в AssetBundle. Однако если необходимо, то это легко сделать используя функции класса AudioClip GetData и SetData.
В отличие от простых ресурсов для AssetBundle в Unity присутствует встроенный механизм кэширования. Рассмотрим его подробнее.
В своей основе этот механизм может использовать два подхода:
Итак, каким образом осуществляется кэширование:
В приведенном примере, Unity при запросе на сервер, сначала смотрит, есть ли в кэше файл с указанным hash128 значением, если есть, то будет возвращен он, если нет, то будет загружен обновленный файл. Для управления всеми файлами кэша в Unity присутствует класс Caching, с помощью которого мы можем узнать, есть ли файл в кэше, получить все кэшированные версии, а также удалить ненужные, либо полностью его очистить.
Примечание: почему такой странный способ получения hash значения? Это связано с тем, что получение hash128 способом, описанным в документации, требует загрузки всего бандла целиком, а затем получения из него AssetBundleManifest ассета и оттуда уже hash значения. Минус такого подхода в том, что качается весь AssetBundle, а нам как раз нужно, чтобы этого не было. Поэтому мы сначала скачиваем с сервера только файл манифеста, забираем из него hash128 и только потом, если надо скачаем файл бандла, при этом выдергивать значение hash128 придется через интерпретацию строк.
Работа с ресурсами в режиме редактора
Последней проблемой, а точнее вопросом удобства отладки и разработки является работа с загружаемыми ресурсами в режиме редактора, если с обычными файлами проблем нет, то с бандлами не все так просто. Можно, конечно, каждый раз делать их билд, заливать на сервер и запускать приложение в редакторе Unity и смотреть как всё работает, но это даже по описанию звучит как “костыль”. С этим надо что-то делать и для этого нам поможет класс AssetDatabase.
Для того, чтобы унифицировать работу с бандлами я сделал специальную обертку:
Теперь нам необходимо добавить два режима работы с ассетами в зависимости от того в редакторе мы или же в билде. Для билда мы используем обертки над функциями класса AssetBundle, а для редактора используем упомянутый выше класс AssetDatabase.
Примечание: в коде используется класс TaskManager, о нем пойдет речь ниже, если кратко, то это обертка для работы с Coroutine.
Помимо описанного выше, также в ходе разработки полезно смотреть, что именно мы загрузили и что находится сейчас в кэше. С этой целью можно воспользоваться возможностью установки своей папки, которая будет использоваться для кэширования (в эту же папки можно записывать и скачанные текстовые и другие файлы):
Пишем менеджер сетевых запросов или работа с веб-сервером
Выше мы рассмотрели основные аспекты работы с внешними ресурсами в Unity, теперь бы мне хотелось остановиться на реализации API, которая обобщает и унифицирует все выше сказанное. И для начала остановимся на менеджере сетевых запросов.
Примечание: здесь и далее используется обертка над Coroutine в виде класса TaskManager. Об этой обертке я писал в другой статье.
Заведем соответствующий класс:
Статическое поле NetworkType требуется для того, чтобы приложение могло получать сведения о типе интернет-соединения. В принципе это значение можно хранить, где угодно, я решил, что в классе Network ей самое место.
Как видно из кода, способ обработки завершения запроса изменен, по сравнению с кодом в предыдущих разделах. Это сделано с целью отображения прогресса загрузки данных. Также, все посылаемые запросы сохраняются в списке, с тем чтобы, если это необходимо, их можно было отменить.
Аналогичным образом создаются функции для текстуры, аудио, текста, байт-массива.
Теперь необходимо обеспечить отправку данных сервер через команду Post. Часто нужно, что-то передать серверу, и в зависимости от того, что именно, получить ответ. Добавим соответствующие функции.
Аналогично добавляются методы для текстуры, аудио-файла, текста и т.д.
На этом наш менеджер для работы с сетевыми запроса завершен. По необходимости, каждая подсистема игры, которая требует работы с сервером может создавать свои экземпляры класса.
Пишем менеджер загрузки внешних ресурсов
Помимо описанного выше класса, для полноценной работы с внешними данными, нам нужен отдельный менеджер, который будет не просто скачивать данные, но и уведомлять приложение о начале загрузке, завершении, прогрессе, отсутствии свободного места, а также заниматься вопросами кэширования.
Как видно, в конструкторе задается папка для кэширования в зависимости от того в редакторе мы находимся или нет. Также, мы завели приватное поле для экземпляра класса Network, который мы описали ранее.
Теперь добавим вспомогательные функции для работы с кэшем, а также определения размера скачиваемого файла и проверки свободного места для него. Далее и ниже код приводится на примере работы с AssetBundle, для остальных ресурсов все делается по аналогии.
Итак, что происходит в данной функции:
Аналогично описанному выше методу в менеджере можно/нужно завести и другие функции работы с данными: GetJson, GetTexture, GetText, GetAudio и т.д.
Здесь стоить понимать особенность работы TaskManager, который используется в менеджере сетевых запросов, по умолчанию он работает, выполняя все задачи по очереди. Поэтому загрузка файлов будет происходить соответственно.
Примечание: для тех, кто не любит Coroutine, все можно достаточно легко перевести на async/await, но в данном случае, в статье я решил использовать более понятный для новичков вариант (как мне кажется).
Заключение
В данной статье я постарался как можно более компактно описать работу с внешними ресурсами игровых приложений. Этот подход и код используется в проектах, которые были выпущены и разрабатываются при моем участии. Он достаточно прост и применим в несложных играх, где нет постоянного общения с сервером (ММО и другие сложные f2p игры), однако он сильно облегчает работу, в случае если нам надо скачать дополнительные материалы, языки, осуществить серверную валидацию покупок и другие данные, которые единовременно или не слишком часто используются в приложении.
Русские Блоги
Unity StreamingAssets, заполняющий заметки ямы
Сначала перейдите на официальный API, версия:2018.2
The location of this folder varies per platform. Please note that these are case-sensitive:
On a desktop computer (Mac OS or Windows) the location of the files can be obtained with the following code:
После фактического теста (тестовая среда win10 + Huawei mate8, unity5.6.6): если вы используете www для чтения, получить StreamingAssets в корневом каталоге Asset может использовать следующую запись:
Каталог на стороне ПК: «file: //» + Application.streamingAssetsPath
Каталог для Android: Application.streamingAssetsPath
Это в основном для проверки разницы в написании на стороне Android. После фактического тестирования конечный каталог Android пишется не так, как официальный. По этой причине в настоящее время неясно, и вы можете указать это.
Интеллектуальная рекомендация
Tree Дерево отрезков линии】 COGS 2632
Ссылочный блогАвтор:dreaming__ldxИсточник: CSDN Портал последовательности операций 【Название описания】 Последовательность длины n, вес порядкового номера в начале равен 0, есть m операций Поддерживают.
PAT-A-1046 кратчайшее расстояние [префикс и]
The task is really simple: given N exits on a highway which forms a simple cycle, you are supposed to tell the shortest distance between any pair of exits. Input Specification: Each input fi.
Как нарисовать несколько линий ROC на одном графике?
Класс коллекции JAVA
Резюме JAVA-коллекции Один, коллекция 1. Характеристики коллекций: коллекции используются только для хранения объектов, длина коллекции является переменной, и в коллекции могут храниться объекты разны.
MySQL репликация главный-подчиненный + переключатель главный-подчиненный
MySQL репликация главный-подчиненный + переключатель главный-подчиненный 05 января 2018 10:46:35Протрите протирать прыжок Количество просмотров: 5183Более Персональная категория:база данныхЭксплуатаци.
Streaming Assets
Unity combines most Assets into a Project when it builds the Project. However, it is sometimes useful to place files into the normal filesystem on the target machine to make them accessible via a pathname. An example of this is the deployment of a movie file on iOS devices; the original movie file must be available from a location in the filesystem to be played by the PlayMovie function.
Unity copies any files placed in the folder called StreamingAssets (case-sensitive) in a Unity Project verbatim to a particular folder on the target machine. To retrieve the folder, use the Application.streamingAssetsPath property. It’s always best to use Application.streamingAssetsPath to get the location of the StreamingAssets folder, as it always points to the correct location on the platform where the application is running.
The location returned by Application.streamingAssetsPath varies per platform:
To read streaming Assets on platforms like Android and WebGL, where you cannot access streaming Asset files directly, use UnityWebRequest. For an example, see Application.streamingAssetsPath.
On many platforms, the streaming assets folder location is read-only; you can not modify or write new files there at runtime. Use Application.persistentDataPath for a folder location that is writable.
Asset Bundles or Addressables are alternative ways of accessing content that is not part of regular game build data, and in many cases are preferred over Streaming Assets folder.
Специальные папки.
Содержание
Специальные папки.
Standard Assets
Скрипты в этой папке всегда компилируются первыми. Из скриптов в этой папке создаются сборки с именами или Assembly-CSharp-firstpass, или Assembly-UnityScript-firstpass или Assembly-Boo-firstpass, в зависимости от языка на котором они написаны. Смотри [http:// http://docs.unity3d.com/Documentation/Manual/ScriptCompileOrderFolders.html ScriptCompileOrderFolders]
Pro Standard Assets
То же самое, что Standard Assets, только файлы тут относятся к Pro версии. Это означает, что ассеты размещенные тут используют Pro фичи, такие как рендер в текстуру и полноэкранные эффекты.
Снова, скрипты размещенные тут компилируется ранее других, позволяя осуществить доступ из скрипта на другом языке, размещенного вне папки Pro Standard Assets.
Editor
Скрипты находящиеся в этой директории не будут включены в скомпилированный проект вашей игры. Все скрипты в этой директории предназначены только для редактора Unity.
У вас может быть несколько директорий с наименованием Editor и они могут находится на любой глубине вложенности иерархии директорий.
The Editor folder name is a special name which allows your scripts access to the Unity Editor Scripting API. If your script uses any classes or functionality from the UnityEditor namespace, it has to be placed in a folder called Editor.
Scripts inside an Editor folder will not be included in your game’s build. They are only used in the Unity Editor.
You can have multiple Editor folders throughout your project.
Plugins
Директория «Plugins» предназначена для размещения скомпилированных плагинов. Все плагины находящиеся в данной категории будут доступны для доступа в ваших скриптах, а так-же будут помещены в сборку игры. Обратите внимание, что директория «Plugins» имеет ограничения по размещению относительно корня проекта. Она должна находится в самом верхнем уровне иерархии каталогов проекта.
Обратите внимание, что все плагины находящиеся в этой директории обрабатываются при выполнении в первую очередь, поэтому будут доступны во всех скриптах, находящихся в других директориях.
The «Plugins» folder is where you must put any native plugins, which you want to be accessible by your scripts. They will also be automatically included in your build. Take note that this folder may not be in any subfolder (it has to reside within the top-level Assets folder).
Like the Standard Assets folder, any scripts in here are compiled earlier, allowing them to be accessed by other scripts (of any language) that are outside the Plugins folder.
Plugins/x86
If you are building for 32-bit or a universal (both 32 and 64 bit) platform, and if this subfolder exists, any native plugin files in this folder will automatically be included in your build. If this folder does not exist, Unity will look for native plugins inside the parent Plugins folder instead.
Plugins/x86_64
If you are building for 64-bit or a universal (both 32 and 64 bit) platform, and if this subfolder exists, any native plugin files in this folder will automatically be included in your build. If this folder does not exist, Unity will look for native plugins inside the parent Plugins folder instead.
If you are making a universal build, it’s recommended you make both the x86 and x86_64 subfolders. Then have the 32-bit and 64-bit versions of your native plugins in the proper subfolder correspondingly.
Plugins/Android
Plugins/iOS
If you need more control how to automatically add files to the Xcode project, you should make use of the PostprocessBuildPlayer feature. Doing so does not require you to place such files in the Plugins/iOS folder. See http://docs.unity3d.com/Documentation/Manual/BuildPlayerPipeline.html
Resources
По этой причине рекомендуется соблюдать осторожность при его использовании. Все ресурсы, которые вы помещаете в папку «Ресурсы», всегда включаются в вашу сборку (даже неиспользуемые), потому что Unity не может определить, какие из ресурсов используются или нет.
Одно из отличий заключается в том, что при доступе к активам в качестве переменных сценариев MonoBehaviour эти ресурсы загружаются в память после создания экземпляра сценария MonoBehaviour (т. Е. Его игровой объект или префаб теперь находятся на сцене). Если вам нужен больший контроль над тем, когда загружать его в память (возможно, для устройств с низкой спецификацией), рассмотрите возможность помещения их в папку ресурсов и загрузки через Resources.Load.
В вашем проекте может быть несколько папок ресурсов, поэтому не рекомендуется размещать ресурс в одной папке ресурсов, а другой ресурс с тем же именем в другой папке ресурсов.
Как только ваша игра построена, все ресурсы во всех папках ресурсов упаковываются в архив игры для ресурсов. Это означает, что папка «Ресурсы» технически больше не существует в вашей окончательной сборке, даже если ваш код по-прежнему будет обращаться к ним по тем путям, которые существовали в то время, когда он находился в вашем проекте.
Gizmos
Папка gizmos содержит все ресурсы текстур / значков для использования с Gizmos.DrawIcon (). Ресурсы текстур, размещенные внутри этой папки, могут называться по имени и выводиться на экран в виде гизмо в редакторе.
WebPlayerTemplates
Used to replace the default web page used for web builds. Any scripts placed here will not be compiled at all. This folder has to be in your top-level Assets folder (it should not be in any subfolder in your Assets directory).
Using Streaming Assets in Unity
Learn how to make a moddable game in Unity by utilizing streaming assets to dynamically load custom game assets at run-time.
How does a game gain traction and become a hit? There’s no secret recipe, but letting players take full control of the game and customize it to their liking with streaming assets is a powerful selling feature for sure.
In this tutorial, you’ll use the streaming assets directory under Unity to let your users customize the game’s UI, soundtrack, player model, and even create their own levels!
Along the way, you’ll learn:
Note: You’ll need to be familiar with some basic C# and know how to work within the Unity 2017.1 development environment. If you need some assistance getting up to speed, check out the Unity tutorials on this site.
Getting Started
Download the starter project here, and unzip and open the TankArena_Starter project in Unity. Another folder called TankArenaAllAssets is included with some sample assets you can use later on in this tutorial.
Note: Credit goes to Eric, our venerable Unity Team Leader for the tank model. I’ve been dying for find a use for that tank! The royalty-free music later in the tutorial is from the excellent Bensound. Finally, thanks to my kids who helped create some of the custom content!
Hit play and you’ll find yourself in a little tank in a little arena. Your goal is to proceed to the glimmering tower of light that constitutes the target tile. But be warned — there are a number of obstacles you need to avoid or destroy in order to reach your goal.
The game as it stands is a little “meh”, so you’ll add some on-demand assets to let the player customize the game and create some exciting levels.
Loading Resources at Runtime
There are several ways to serve up resources to Unity at runtime, and each method has its place in game development: asset bundles, resource folders, and streaming assets. Let’s look at each one in turn.
Asset Bundles
Asset bundles let you deliver content to your application outside of your Unity build. Generally, you’d host these files on a remote web server for users to access dynamically.
Why use asset bundles? When developing cross-platform games, you may need to create more than one texture or model to respect the limitations of the target platform. Asset bundles let you deliver the appropriate asset on a per-platform basis while keeping the initial game install size to a minimum.
Asset bundles can contain anything from individual assets to entire scenes, which also makes them ideal for delivering downloadable content (DLC) for your game.
Resource Folders
Unlike Asset bundles, resource folders are baked into the Unity Player as part of the game. You can do this by adding the required assets to a folder named Resources in your assets directory.
Resource folders are useful for loading assets at runtime that would not normally be part of the scene or associated with a GameObject. For example, an extremely rare event or hidden object that’s not seen often is not something you’d want to load 100% of the time.
Streaming Assets
Like Resource Folders, a Streaming Assets directory can be created by intuitively creating a folder named StreamingAssets in your project’s assets directory. Unlike Resource folders, this directory remains intact and accessible in the Unity player. This creates a unique access point for users to add their own files to the game.
Adding Streaming Assets
In the assets window, click on Create and add a new folder to your project. Rename the folder StreamingAssets.
Now click on File\Build Settings and ensure the Target Platform is correctly assigned to the platform you are working on. Click Build to build the player. Navigate to where you output the Unity player.
Any file or folder you drop into there will be accessible to your game. Feel free to drop files directly into the StreamingAssets folder in your Project view so you can quickly test in the Editor as you go.
Adding your First Image
Who is going to step up the plate and take on TankArena? Is it you? Your pet? Your favorite soft toy when you were a kid? Grab a saved photo of them and drag it into the StreamingAssets directory you created in the Project Window. I chose my fearless cat Nando.
If you want to forgo collecting and/or creating a bunch of assets to import, feel free use the assets included in the starter project download under the TankArenaAllAssets folder. I’m sure Nando will not let you down either.
You need to rename your image asset for two reasons:
Most of the files you add will have a similar format. They’ll have a tag to help identify them to the game, and subsequent text will enable you to add additional parameters to play with.
Loading your First Resource
In the Project Window, navigate to Assets\Scripts and double click on the Game Manager Script to open it in the IDE of your choice.
Under the class declaration, add these public variables to reference the UI Game Objects you will customize:
Before you add any code to find and access the files in your streaming assets directory, you will need to add the following to the top of your GameManager script:
This adds support for files and directories and allows the reading and writing of files.
Add the following to Start() under playerTank = GameObject.FindGameObjectWithTag(«Player»); :
The streaming assets directory resides in different locations depending on the platform. However, Application.streamingAssetsPath will always return the correct path. The entirely optional print statement will show you to see where your streamingAssetsPath points.
The final line creates an array containing all the files in the streaming assets directory. You will create a series of conditionals as you work through this tutorial to handle the files found.
To send the player’s image to be processed, add the following under the code you just added:
The foreach loop iterates through the files, and the conditional checks to see if the file name contains the key word “player1”. Once found, the file is passed to a Coroutine LoadPlayerUI() which you’ll add next:
Why a Coroutine? Although loading this image will happen very quickly, you will soon be loading and manipulating many more files. A Coroutine runs off the main thread and will not interrupt the game loop.
Before you hit that play button to see the fruits of your labor, remember to connect the playerAvatar and playerName to their respective Game Objects in Unity.
In the Unity Editor, select the Game Manager from the Hierarchy Window to expose the public variables in the inspector. Hold Alt and click on the disclosure triangle next to UICanvas in the Hierarchy Window. This should expand UICanvas and all of its children’s children.
Under the GameUIPanel drag PlayerAvatar and PlayerName to their identically named public variables on the Game Manager in the Inspector:
Press the play button and check out your new avatar and name label. Nice!
But wait! There is no way your awesome new avatar would jump into their tank without their own custom soundtrack, right? On to that next.
Beat the game to your own Beats!
There’s a soundtrack.ogg bundled with the resources for your use, but if you think you can find something even more epic, use that instead.
Drag your audio file into the Project Window StreamingAssets folder and rename the file soundtrack.
Note: There are many different audio file types out there. If you have trouble, convert the file to .ogg as it is a well supported format in Unity. Have a look here for free online conversion tools, but be warned: DRM-protected files will not convert.
Add a new public variable to the GameManager:
With the GameManager selected in the Hierarchy Window, connect this new variable to the AudioSource on the scene’s Main Camera by dragging the whole Main Camera over the variable in the Inspector.
The Main Camera is a child of your Player’s Tank model, so it obediently follows you around. Remember, you can use the hierarchy’s search box to find any Game Object quickly in the scene.
Head back to the GameManager Start() function and add a new conditional underneath the other one to pass the soundtrack file to a new Coroutine:
This code should look pretty familiar. Loading an audio file is very similar to loading a texture. You use the URL to load the file and then apply audio to musicPlayer’s clip property.
Finally, you call Play() on musicPlayer to get the soundtrack thumping.
Click play and hit that first level even harder than would have been possible before!
Player Model Customization
Now to customize the tank model. You’ll be walked through two different approaches for customizing the tank model. The first will use simple color swatches to let the user apply their favorite colors to the tank. The second will be a complete re-skin, similar to Minecraft skin mods.
Find the small 20 x 10 pixel playercolor image in the TankArenaAllAssets resources folder that came with the starter project download.
Drag the file into the Project Window StreamingAssets folder as you’ve done before.
You thought this was going to be hard?
Add the following new variables to the Game Manager, all under the new Header tag Tank Customisation:
The Game Manager will need to reference the tank models’ textures and the renderers so that changes can be made and the model reassembled. Additionally, you save the military green primary and red accent secondary color values as integers in a Vector3 for the upcoming conditional statements. You’re using Vector3 as opposed to Color, since comparing one Color to another is very unreliable.
This is the tanks Texture file as output by the 3D modeling program.
Jump back into Start() and add another conditional:
Under the LoadBackgroundMusic() Coroutine, add the following;
Add the following method under the one you just created:
ApplyTextureToTank() takes two arguments: the tank Renderer and the new Texture2D that you want to apply. You use GetComponentsInChildren to fetch all of the renderers in the tank model and apply the new modified texture.
With the primary and secondary colors replaced. The texture is applied to the tank.
You also place this part of the tank customization in it’s own public method as you’ll need identical functionality to this later.
The final step is to connect up the new public Game Manager variables in the Inspector.
Ensure Game Manager is selected in the Hierarchy Window. In the Project Window, look in the Assets\Tank Model directory. You will find the two default texture files used to skin the tank model. Drag the LowPolyTank to the Tank Texture and NewThreads to the Tank Treads variable. Back in the Hierarchy Window, drag Player\Tank to Tank Renderer.
Click play and check out your sharp new Tank:
Here are a few other examples I created earlier.
More than One Way to Skin a Tank
The other way to customize tanks is to let the user add new skins to streaming assets and let them select and apply them at runtime.
There’s a ScrollView and a Skin Object prefab situated in the Pause menu that you can use for the UI.
The SkinObject prefab is customised using the texture and filename.
Each skin will be showcased by a tank, and a button will enable you to add it.
Some tank «skin» textures were included in the TankArenaAllAssets folder that you got along with the starter project download. Place them in the Project Window StreamingAssets folder now.
Head back to the Game Manager script to get this new feature working.
The skins and their names will be stored in Lists. Therefore, add the Generic namespace at the top of the Game Manager script;
Add the following variables under your other tank customization variables;
As before, add another conditional to the start function:
Create a new coroutine to process the skin files:
Note: For this tutorial, you simply throw up a loading screen for one second before gameplay starts as this is sufficient for demonstration purposes. For a real game, you may want to add a cool little cut scene if you expect a more involved loading stage, and perhaps a callback of some sort when loading is finally complete.
For this tutorial, you’ll assume that when the loading screen dismisses, all of the streaming assets have been processed.
Add the following to the end of RemoveLoadingScreen() :
Create a new Coroutine and add the following code:
Navigate to the Scripts folder in the Project Window and double click on SkinManager script to open it in your IDE.
ConfigureSkin() saves the index it was passed in a private variable and the button label is customized using the skin name.
When the player presses the button to apply a skin, ApplySkinTapped() sends the saved index back to ApplySkin() in the GameManager.
Finish off ApplySkin() at the bottom of the GameManager Script by adding the following code:
This extracts the relevant texture from the list and applies it to the players tank. You also remove the pause menu and resume gameplay.
Time to get this all hooked up!
Tap on the Game Manager in the Hierarchy to reveal the Game Manager script in the Inspector. Drag the Skin Object prefab from the Project Window Prefabs folder to the public skinObject variable in the Inspector.
Type content in the Hierarchy search field to find the ScrollView’s content object without losing the Game Manager in the inspector (or tap the lock icon at the top right in the inspector view). Finally, drag the content object into the skinContainer variable.
Tap the play button and press Escape to pause the game. Tap a button and select a new skin for the tank:
Level Design, Now you are Playing with Power!
Okay, it’s time to move on to custom level design and creation. Interestingly, you won’t need more skills than you’ve already learned.
First, have a look at the anatomy of an arena so you can get a feel of how it will be constructed.
In the Hierarchy View, double-tap on the Default Arena Game Object to select it and bring it into view in the Scene View. The Arena is constructed from hundreds of tiles, and each tile type is a prefab from the Prefab folder in the Project View. You will use these prefabs to assemble a level in any combination or permutation you can imagine.
The other day I was sitting down with my kids and I asked them if they wanted to design a level for my upcoming tutorial. It went something like this:
Suffice to say I got the kids on the computer and they created two levels from their designs.
You can find these custom levels in the included starter download TankArenaAllAssets folder.
Have a look at the files, by using any image editor a fairly complex level can be constructed.
Now you will create your own custom level and write the code to load any of these levels up.
Open the image editor of your choice and create a new document/canvas 100 px X 100 px square.
Use a hard 1 px pencil tool or line tool to create objects using the following color scheme.
A 100 x 100 level created with any image editing package.
Use the cursor tool to get the x and y coordinates of where you would like the player to start and where the target tile should be.
Save the file as a png when you are finished using the following naming scheme.
Once you are happy with your design, add the file to the Project Window StreamingAssets folder.
Head back to the Game Manager. Above the class declaration, add the following code:
This creates an Arena class, containing all of the variables necessary to accommodate the data extracted from an arena file. The Serializable property allows this class to be displayed in the inspector.
Add a new list to the GameManager that will hold all of the instances of the Arena class you create:
Add the following additional public variables to the GameManager under the arenaList :
These variables comprise all of the building blocks for the level and serve as references to the player and the target object so you can customize their position. You also reference the defaultArena so we can remove it, and arenaTiles so that you have a container for new instantiated tiles.
Just like you did previously, add a new conditional statement to the start function:
Create a new coroutine named LoadArena() :
Add this final Coroutine to load an arena:
You’re almost there! Find the empty function StartNextLevel and add the following code:
Now that StartNextLevel() is fleshed out a little, type «Next» into the Hierachy Window Searchbar in Unity. This should filter down to a single Game Object named Next Level Button. Click to select it, and in the inspector tick interactable under the Button component.
You now need to make a few code amendments to accommodate the fact that you can now have multiple levels (and not just the original starter level).
Replace SceneManager.LoadScene(«MainScene»); in RestartLevel() with the following:
This code ensures that instead of just loading the game scene with the default starter level on level restart, the LoadLevel() coroutine is called instead, which destroys the default arena, and replaces it with the content of the custom level that was loaded from streaming assets.
Also replace timerText.text = arenaName + » » + formattedTime; in UpdateTimerUI() with the following line:
This bit of code will ensure that the level name text label in the game UI is updated with the custom level name.
Before you get excited and press Play, don’t forget to connect up the prefab outlets in the inspector.
Select the Prefabs folder in the Project Window, and select the Game Manager in the Hierarchy Window. This should expose everything you need.
In the Inspector, you will find the variables for the prefab arena tiles under the Arena Prefabs heading. Each of these has an identically named prefab in the Prefabs folder in the Project Window. Drag each one from the Prefab folder to their respective variable.
Next, take a look at the Arena Objects header in the Inspector. These three GameObject variables are found in the Hierarchy Window. Drag the Target, Default Arena and ArenaTiles from the Hierarchy Window to their respective variables in the Inspector.
Click play and see your designs come to life!
Adding Custom Assets to a Real Build
To wrap this tutorial up, you’ll add some custom assets to a real build. After all, that’s what your users will be doing!
Remove all of the custom assets from the Project Window StreamingAssets folder and click on File\Build Settings. Ensure the Target Platform is correctly assigned to the platform you are working on and click Build and Run.
You’re back to square one! However, the code is still in place to handle any customizations you many want to add.
Navigate to the StreamingAssets folder in the Player Build. On a PC, have a look in the accompanying folder named _Data. On the Mac, right-click the player and click Show Package Contents. From the popup Finder window, navigate to Contents\Resources\Data.
Drop in any or all of the custom assets you’ve used from the starter project download (under the TankArenaAllAssets folder).
Launch the player again; the customizations should be correctly applied and custom levels loaded. Perfect. :]
Where to Go From Here?
Here’s a link to the completed project from this tutorial.
In this tutorial, you learned how to use the streaming assets to customize an existing game in a number of ways. Now you can open that door to your users!
I hope you found this tutorial useful! I’d love to know how it helped you develop something cool. Questions, thoughts or improvements are most welcome in the comments below!
One last thing. If you’re interested in learning more about creating killer games with Unity, check out our book, Unity Games By Tutorials.
In this book, you create four complete games from scratch:
By the end of this book, you’ll be ready to make your own games for Windows, macOS, iOS, and more!
This book is for complete beginners to Unity, as well as for those who’d like to bring their Unity skills to a professional level. The book assumes you have some prior programming experience (in a language of your choice).