我正在开发一款游戏,从 JSON 文件加载关卡数据并根据该数据实例化对象和地形 (SpriteShape)。我正在使用 Unity 和 C#。我的问题是我的加载 UI 立即隐藏,无需等待关卡数据完成加载。这是加载逻辑脚本:
void Start()
{
StartCoroutine(LoadLevel());
}
private IEnumerator LoadLevel()
{
loadingLevelUI.SetActive(true);
GameObject ground = GameObject.Find("Ground");
playerSpawn = GameObject.Find("PlayerSpawn");
// Construct the full file path based on createdLevelsPath and currentLevel
string createdLevelsPath = Path.Combine(Application.persistentDataPath, "CreatedLevels");
string filePath = Path.Combine(createdLevelsPath, currentLevel);
// Check if the file exists
if (File.Exists(filePath))
{
// Read the file content
string fileContent = File.ReadAllText(filePath, Encoding.UTF8); // Specify UTF-8 encoding for JSON
try
{
// Deserialize the JSON data into a LevelData object
LevelData levelData = JsonUtility.FromJson<LevelData>(fileContent);
if (levelData.defaultSpawn != null && playerSpawn)
{
playerSpawn.transform.position = new Vector3(levelData.defaultSpawn.x, levelData.defaultSpawn.y, -5.4f);
}
// Access and process the levelContent array
if (levelData.levelContent != null)
{
foreach (LevelData.LevelObject levelObject in levelData.levelContent)
{
// Remove "(Clone)" from the object name, if present
string objectName = levelObject.objectName.Replace("(Clone)", "").Trim();
// Find the prefab based on the object name
GameObject prefab = GetPrefab(objectName);
// Check if prefab was found
if (prefab == null)
{
Debug.LogWarning("Prefab for object '" + objectName + "' not found.");
continue; // Skip to next level object
}
// Instantiate the prefab
GameObject newObject = Instantiate(prefab);
Quaternion objectRot = levelObject.rotation;
// Set object position based on levelObject position
newObject.transform.position = levelObject.position;
newObject.transform.rotation = objectRot;
newObject.transform.localScale = levelObject.size;
// Parent the instantiated object to the ground
if (ground != null)
newObject.transform.parent = ground.transform;
else
Debug.LogWarning("Ground object not found.");
}
foreach (LevelData.LevelTerrain levelTerrain in levelData.levelTerrains)
{
string objectName = levelTerrain.terrainName.Replace("(Clone)", "").Replace("_p", "").Trim();
// Find the prefab based on the object name
GameObject prefab = GetPrefab(objectName);
// Check if prefab was found
if (prefab == null)
{
Debug.LogWarning("Prefab for terrain '" + objectName + "' not found.");
continue; // Skip to the next level terrain
}
// Instantiate the terrain prefab
GameObject newObject = Instantiate(prefab);
Quaternion objectRot = levelTerrain.rotation;
Vector2 size = levelTerrain.size;
// Set object position based on levelTerrain position
newObject.transform.position = levelTerrain.position;
newObject.transform.rotation = objectRot;
newObject.transform.localScale = new Vector3(size.x, size.y, 1f); // Ensure size is correctly set
if (ground != null)
{
newObject.transform.parent = ground.transform;
}
else
{
Debug.LogWarning("Ground object not found.");
}
Debug.Log("Instantiated Terrain: " + objectName + " at position: " + levelTerrain.position);
Debug.Log("Terrain size: " + levelTerrain.size);
// Clear existing points before loading new ones
SpriteShapeController terrainController = newObject.GetComponent<SpriteShapeController>();
if (terrainController != null)
{
terrainController.spline.Clear(); // Clear all existing points
}
else
{
Debug.LogError("Terrain prefab '" + objectName + "' does not have a SpriteShapeController component.");
continue; // Skip to the next level terrain if component is missing
}
// Load new points from levelTerrain.points
foreach (Vector3 point in levelTerrain.points)
{
Vector3 localPosition = point; // Use the saved position directly
terrainController.spline.InsertPointAt(terrainController.spline.GetPointCount(), localPosition);
int pointIndex = levelTerrain.points.IndexOf(point);
if (pointIndex >= 0 && pointIndex < levelTerrain.tangentMode.Count) // Check for valid index
{
ShapeTangentMode tangentMode = levelTerrain.tangentMode[pointIndex];
terrainController.spline.SetTangentMode(terrainController.spline.GetPointCount() - 1, tangentMode);
// Check if left and right tangent data exists (assuming separate lists)
if (pointIndex >= 0 && pointIndex < levelTerrain.leftTangents.Count && pointIndex < levelTerrain.rightTangents.Count)
{
Vector3 leftTangent = levelTerrain.leftTangents[pointIndex];
Vector3 rightTangent = levelTerrain.rightTangents[pointIndex];
terrainController.spline.SetLeftTangent(terrainController.spline.GetPointCount() - 1, leftTangent);
terrainController.spline.SetRightTangent(terrainController.spline.GetPointCount() - 1, rightTangent);
}
else
{
Debug.LogWarning("Missing left/right tangent data for point " + pointIndex + " in terrain " + levelTerrain.terrainName);
}
}
else
{
Debug.LogError("Missing tangent mode data for point " + pointIndex + " in terrain " + levelTerrain.terrainName);
}
}
}
}
else
{
Debug.Log("Level has no objects in levelContent.");
}
// Set isLevelLoaded to true after loading is complete
isLevelLoaded = true;
}
catch (System.Exception e)
{
Debug.LogError("Error loading level data: " + e.Message);
}
}
else
{
Debug.LogWarning("Level file not found: " + filePath);
}
// Wait until isLevelLoaded is true
while (!isLevelLoaded)
{
yield return null;
}
// Once loaded, hide the loading UI
loadingLevelUI.SetActive(false);
}
它只是立即隐藏加载关卡 UI,导致大关卡加载时间更长,这意味着关卡在启动时将为空。
您可以通过在每个循环后使用
yield return null;
来解决它。这可确保在下一帧中处理每个对象和地形点。因此,它将保持加载 UI 可见,直到关卡完全加载。
所以它看起来就像这样:
foreach (LevelData.LevelObject levelObject in levelData.levelContent)
{
//your current code
yield return null; // add this at the end of the loop
}
foreach (LevelData.LevelTerrain levelTerrain in levelData.levelTerrains)
{
//your current code
yield return null; // same with this
}