我正在构建的Unity项目针对iOS,Android和Windows X64。
问题
在我的一个场景中,我使用JSON文件在运行时动态加载位于Resources文件夹中的某些精灵。我目前遇到的问题是:当我在Unity编辑器中运行游戏时,它的行为符合预期(精灵会动态加载并显示在场景中)。但是,当我在三个平台中的任何一个上(在实际硬件上)运行精灵时,它们不会在场景中加载/显示。不过会加载静态精灵。
设置
该场景是一种级别选择屏幕。对于每个级别,都会显示一个精灵。精灵和显示的精灵数量基于场景开始时读取的JSON文件。这是一个截图,可以给您更好的印象:
在游戏对象的Start
回调之一中,我运行代码以读取JSON数据:
var sceneSelectionInfoList = JsonHelper.GetSceneSelectionInfoForLanguage(GameLanguage.German);
到目前为止的JSONHelper类(将JSON.NET用于Asset Store中的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;
}
以下是相对于Unity项目文件夹的JSON文件和精灵的路径:
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;
我到目前为止检查的内容
感谢任何提示!
答案 0 :(得分:1)
这里的两个主要问题是:1)JSON文件的加载方式; 2)管理器对象销毁自身的方式。
对于JSON文件:
您正在使用StreamReader
,它是一种C#工具,用于从文件系统读取。这并不是Unity的“资源”系统的工作方式。由于它存在于“资产”目录下,因此您的编辑器可以找到它。这是它运行所在的文件系统中的 where 。进行设备构建时,“资源”目录下的所有内容都会打包到构建中,并且必须必须通过Resources
API进行访问。
您在这里有两个选择:您可以将StreamReader
的用法替换为Resources.Load<TextAsset>
的调用,并确保使用“ SceneData / SceneDataIndex ”(注意:没有文件扩展名),而不是带有“ 资产/资源”的版本。您还可以选择将JSON资产放置在名为“ Assets / StreamingAssets ”的折叠后,然后使用Application.streamingAssetsPath
将StreamReader
加载到该资产。流媒体资源路径允许将其与常规C#文件加载约定一起加载,因为它将被放置在可读的文件系统路径中。
一些注意事项:无论平台如何,Resources
API调用必须都使用正斜杠(/)。使用StreamReader
之类的基于文件系统的加载程序时,应使用Path.Combine
或Path.PathSeparator
来确保斜杠正确。
现在是场景A的第二次加载。在不知道游戏对象层次结构的确切布局的情况下,很难确定问题出在哪里,但我的假设是您的GameManager
脚本位于重要的{ {1}},而您正在使用以下方法销毁它:
GameObject
这将破坏游戏对象,该对象上的所有脚本,及其所有子对象以及它们上的所有脚本。如果将其更改为else if (Instance != this)
{
Destroy(gameObject);
}
,它只会从对象中删除脚本,并保持游戏对象层次结构不变。