Динамическая загрузка спрайтов из файла JSON не работает - PullRequest
0 голосов
/ 18 февраля 2019

Проект Unity, который я создаю, нацелен на iOS, Android и Windows X64.

Проблема
В одной из моих сцен я использую файл JSON для динамической загрузки некоторых спрайтов, находящихся в папке Resources, во время выполнения.Проблема, с которой я столкнулся на данный момент, заключается в следующем: когда я запускаю игру в редакторе Unity, она ведет себя как ожидалось (спрайты динамически загружаются и отображаются на сцене).Но когда я запускаю его на любой из трех платформ (на реальном оборудовании), спрайты не загружаются / не отображаются в сцене.Однако загружаются статические спрайты.

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

enter image description here

В обратном вызове Start одного из игровых объектов я запускаю код, чтобы прочитать JSONdata:

var sceneSelectionInfoList = JsonHelper.GetSceneSelectionInfoForLanguage(GameLanguage.German);

Класс JSONHelper (использует JSON.NET для ресурса Unity из хранилища активов):

using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public static class JsonHelper
{
    private const string SceneDataIndexFilename = "Assets/Resources/SceneData/SceneDataIndex.json";

    // Start is called before the first frame update
    public static List<SceneSelectionInfo> GetSceneSelectionInfoForLanguage(GameLanguage language)
    {
        var sceneSelectionInfoList = new List<SceneSelectionInfo>();

        // Open scene selection index
        var sceneDataIndexEntries = GetSceneDataIndexEntries(SceneDataIndexFilename);

        foreach (var sceneDataIndexEntry in sceneDataIndexEntries)
        {
            Logger.LogInfo(sceneDataIndexEntry.Filename);
            using (var streamReader = new StreamReader(sceneDataIndexEntry.Filename))
            {
                var jsonData = streamReader.ReadToEnd();
                var jObject = JObject.Parse(jsonData);
                var id = jObject.SelectToken("id").ToString();
                var basePath = jObject.SelectToken("basePath").ToString();
                var sceneSelectionImage = basePath + jObject.SelectToken("dragAndDrop.sceneSelectionImage");
                string title = null;

                switch (language)
                {
                    case GameLanguage.English:
                        title = jObject.SelectToken("titleEN").ToString();
                        break;
                    case GameLanguage.French:
                        title = jObject.SelectToken("titleFR").ToString();
                        break;
                    case GameLanguage.SwissGerman:
                        title = jObject.SelectToken("titleSG").ToString();
                        break;
                    case GameLanguage.Spanish:
                        title = jObject.SelectToken("titleES").ToString();
                        break;
                    case GameLanguage.German:
                        title = jObject.SelectToken("titleDE").ToString();
                        break;
                    case GameLanguage.Italian:
                        title = jObject.SelectToken("titleIT").ToString();
                        break;
                }

                var sceneSelectionInfo = new SceneSelectionInfo();
                sceneSelectionInfo.SceneId = id;
                sceneSelectionInfo.SceneSelectionImage = sceneSelectionImage;
                sceneSelectionInfo.Title = title;
                sceneSelectionInfoList.Add(sceneSelectionInfo);
            }
        }

        return sceneSelectionInfoList;
    }

    private static List<SceneDataIndexEntry> GetSceneDataIndexEntries(string sceneDataIndexFilename)
    {
        using (var reader = new StreamReader(sceneDataIndexFilename))
        {
            var jsonData = reader.ReadToEnd();
            Logger.LogInfo(jsonData);
            return JsonConvert.DeserializeObject<List<SceneDataIndexEntry>>(jsonData);
        }
    }
}

Просто для полноты: класс SceneSelectionInfo простоконтейнер данных (DTO), содержащий некоторые значения для передачи:

public class SceneSelectionInfo
{
    public string SceneId;
    public string SceneSelectionImage;
    public string Title;
}

Вот пути к файлам и спрайтам JSON относительно папки проекта Unity:

SpriteПуть:
Assets/Resources/SceneData/AfternoonAtTheBeach/DragAndDrop/SceneSelection.png

Путь к файлу JSON:
Assets/Resources/SceneData/AfternoonAtTheBeach/SceneData.json

Вот фрагмент кода из файла JSON (basePath и sceneSelectionImage вместе создают путь к загружаемому спрайту):

{
  "id": "AfternoonAtTheBeach",
  "basePath": "SceneData/AfternoonAtTheBeach/",
  "titleEN": "Afternoon at the beach",
  "titleFR": "Après-midi sur la plage",
  "titleSG": "Namitag am Strand",
  "titleES": "Tarde en la playa",
  "titleDE": "Nachmittag am Strand",
  "titleIT": "Pomeriggio in spiaggia",
  "dragAndDrop": {
    "sceneSelectionImage": "DragAndDrop/SceneSelection",
    "levels": [
      {
        "backgroundImage": "DragAndDrop/Graphics/Level1/Background",
        "items": [
          {
            "image": "DragAndDrop/Graphics/Level1/Ball",
            "dropPosX": -623,

Код для загрузки спрайтов (после прочтения пути из файла JSON):

  var sprite = Resources.Load<Sprite>(sceneSelectionInfo.SceneSelectionImage);
  swiperItem.GetComponent<SpriteRenderer>().sprite = sprite;

То, что я проверял до сих пор

  • Я ссылаюсь на спрайты, используя относительные пути, начиная с каталога Assets / Resources, без расширений файлов (см. пример спрайтового пути выше).
  • Я отключил кэширование библиотеки в Unity Cloud Build, чтобы избежать проблем со старыми артефактами сборки (поэтому каждый раз, когда я собираю, я делаю правильную, чистую сборку)
  • Я могу локально собрать все три платформы (Unity сообщает об этом как "Успешная сборка")
  • Я использую LoadSceneMode.Single (по умолчанию)
  • Я использую ту же версию Unityлокально и в Unity Cloud Build: 2018.3.0f2

Спасибо за любые подсказки!

1 Ответ

0 голосов
/ 18 февраля 2019

Здесь есть две основные проблемы: 1) способ загрузки вашего JSON-файла и 2) способ разрушения самого объекта менеджера.


для файла JSON:

Вы используете StreamReader, который является инструментом C # для чтения из файловой системы.Это не совсем то, как работает система Unity «Ресурсы».Поскольку он существует в каталоге «Assets», ваш редактор может найти его просто отлично;это , где существует в файловой системе, в которой он работает.Когда вы делаете сборку устройства, все, что находится в каталоге «Resources», упаковывается в сборку, и должен быть доступным через Resources API.

У вас есть два варианта: Вы можетезамените использование StreamReader на вызов Resources.Load<TextAsset> и убедитесь, что вы используете " SceneData / SceneDataIndex " (примечание: без расширения файла) вместо версии с " Активы / Ресурсы ».Другой вариант - поместить ресурс JSON в свернутый файл с именем « Assets / StreamingAssets », а затем использовать Application.streamingAssetsPath, чтобы загрузить его с StreamReader.Путь потоковых ресурсов позволяет загружать его с обычными соглашениями о загрузке файлов C #, поскольку он будет помещен в читаемый путь файловой системы.

Некоторые примечания: Resources вызовы API MUST используйте косую черту (/) независимо от платформы.При использовании загрузчиков на основе файловой системы, таких как StreamReader, вы должны использовать Path.Combine или Path.PathSeparator, чтобы убедиться, что у вас правильные слэши.


Теперь для второй загрузки сцены А. Это сложночтобы быть уверенным, в чем ваша проблема, не зная точного расположения иерархии игровых объектов, но я предполагаю, что ваш GameManager сценарий находится на важном GameObject, и вы уничтожаете его с помощью:

else if (Instance != this)
{
    Destroy(gameObject);
}

Это уничтожит игровой объект, все скрипты на нем, и все его дочерние элементы и все скрипты на них.Если вы измените это значение на Destroy(this), он только удалит скрипт из объекта и оставит иерархию игровых объектов без изменений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...