【发布时间】:2018-03-08 15:19:00
【问题描述】:
我正在尝试在我的游戏中开发一个功能,该功能加载一个随机场景,总共 8 个填充在一个列表中,然后在加载场景后从列表 forestSceneIndexes = new List<int>(); 中删除。这样,当加载下一个随机场景时,它会从列表中的现有场景中进行选择,依此类推。
我做的第一件事是用函数填充我的列表:
private IEnumerator DoInitSceneIndexList()
{
// Initialize scene name list
for (int i = 0; i < numberOfForestScenes; i++)
{
forestSceneIndexes.Add(firstForestSceneIndexNumber + i);
Debug.Log("Scene index " + forestSceneIndexes[i].ToString() + " added to int list.");
}
yield return new WaitForEndOfFrame();
initSceneList = false;
}
之后我在函数 DoGetRandomScene 中得到随机场景
private IEnumerator DoGetRandomScene()
{
// Get scene name from random pick
randomSceneIndex = Random.Range(firstForestSceneIndexNumber, (firstForestSceneIndexNumber + forestSceneIndexes.Count) - 1);
yield return new WaitForEndOfFrame();
StartCoroutine(DoRemoveRandomSceneFromList());
// Load selected scene
StartCoroutine(DoLoadScene(randomSceneIndex));
}
获得随机场景后,我会立即从列表中删除该索引:
private IEnumerator DoRemoveRandomSceneFromList()
{
// Remove selected scene from list
forestSceneIndexes.Remove(randomSceneIndex);
yield return new WaitForEndOfFrame();
}
然后我将 randomSceneIndex 传递给 DoLoadScene() 函数
private IEnumerator DoLoadScene(int sceneIndex)
{
yield return new WaitForEndOfFrame();
SceneManager.LoadScene(sceneIndex, LoadSceneMode.Single);
}
我的问题是它不能正常工作,前几个场景似乎开始没问题,但是一旦剩下大约 3 个场景,它就会继续重新加载相同的场景。我不确定我有什么问题,任何帮助将不胜感激!下面还添加了完整的脚本。谢谢!
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEngine.Networking;
public class ForestGameManager : NetworkBehaviour
{
public static ForestGameManager fgm = null; // create singleton
ForestSceneTimer forestSceneTimer;
[Header("Network Prefab")]
public GameObject serverNetworkManagerPrefab;
[Header("Forest Game Manager")]
private int fgmIndex;
private int firstForestSceneIndexNumber;
private int lastForestSceneIndexNumber;
private bool _isInitialized;
[Header("Forest Scenes")]
[TextArea(1, 1)]
public string forestSceneNotes = "Please place all Forest Scenes after Forest Loader scene";
public int numberOfForestScenes;
private float sceneCountdownLength = 15.0f;
private List<int> forestSceneIndexes;
private int randomSceneIndex;
private bool initSceneList = true;
private int currentSceneIndex;
[Header("Forest Animal Management")]
public int maxAnimalCount = 4;
public List<ForestAnimal> forestAnimals;
private void Awake()
{
//DontDestroyOnLoad(this.gameObject);
StartCoroutine(DoInitForestGameManager());
StartCoroutine(DoInitServerNetworking());
fgmIndex = SceneManager.GetActiveScene().buildIndex;
firstForestSceneIndexNumber = fgmIndex + 1;
//Debug.Log("firstForestSceneIndexNumber Index is : " + firstForestSceneIndexNumber);
forestSceneTimer = GetComponent<ForestSceneTimer>();
}
private void Start()
{
if (!this._isInitialized)
{
forestAnimals = new List<ForestAnimal>();
forestSceneIndexes = new List<int>();
lastForestSceneIndexNumber = ((firstForestSceneIndexNumber + numberOfForestScenes) - 1);
if (initSceneList)
{
StartCoroutine(DoInitSceneIndexList());
StartCoroutine(DoGetRandomScene());
}
Debug.Log("There are " + numberOfForestScenes + " forest scenes in MasterLoader.");
this._isInitialized = true;
}
else
{
this.forestAnimals.Clear(); //I assume you can clear the list on scene change
}
InvokeRepeating("CheckAnimalCount", 0, 1f);
InvokeRepeating("CheckRemainingScenes", 0, 10f);
}
private void CheckAnimalCount()
{
if (forestAnimals.Count >= maxAnimalCount)
{
GameObject toDestroy = forestAnimals[0].forestAnimalGO;
forestAnimals.RemoveAt(0);
StartCoroutine(ExplodedMesh(toDestroy));
//yield return new WaitForSeconds(1f);
}
Debug.Log("Checking animal count");
}
private void CheckRemainingScenes()
{
if (currentSceneIndex >= firstForestSceneIndexNumber && currentSceneIndex <= lastForestSceneIndexNumber)
{
// If all forest scenes have been used, re-initialize scene name list and pick the next random scene
if (forestSceneIndexes.Count == 0)
{
StartCoroutine(DoInitSceneIndexList());
StartCoroutine(DoGetRandomScene());
Debug.Log("Out of scenes, re-initializing scene list.");
}
//yield return new WaitForSeconds(1f);
Debug.Log("Checking remaining scenes");
}
}
private IEnumerator ExplodedMesh(GameObject toDestroy)
{
MeshExploder meshExploder = toDestroy.transform.GetChild(0).gameObject.AddComponent<MeshExploder>();
yield return new WaitForEndOfFrame();
toDestroy.transform.GetChild(0).gameObject.GetComponent<MeshExploder>().Explode();
yield return new WaitForEndOfFrame();
Destroy(toDestroy);
yield return new WaitForEndOfFrame();
}
private void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
currentSceneIndex = SceneManager.GetActiveScene().buildIndex;
//Debug.Log("Current scene index is : " + currentSceneIndex);
if (currentSceneIndex >= firstForestSceneIndexNumber && currentSceneIndex <= lastForestSceneIndexNumber)
{
// Start scene change countdown timer
forestSceneTimer.StartSceneCountTimer(sceneCountdownLength);
}
}
private IEnumerator DoInitSceneIndexList()
{
// Initialize scene name list
for (int i = 0; i < numberOfForestScenes; i++)
{
forestSceneIndexes.Add(firstForestSceneIndexNumber + i);
Debug.Log("Scene index " + forestSceneIndexes[i].ToString() + " added to int list.");
}
yield return new WaitForEndOfFrame();
initSceneList = false;
}
private IEnumerator DoInitForestGameManager()
{
if (fgm == null)
fgm = this;
else if (fgm != null)
Destroy(gameObject);
DontDestroyOnLoad(gameObject);
yield return new WaitForEndOfFrame();
}
private IEnumerator DoInitServerNetworking()
{
Instantiate(serverNetworkManagerPrefab);
yield return new WaitForEndOfFrame();
}
public void GetRandomScene()
{
Debug.Log("Get Random Scene");
StartCoroutine(DoGetRandomScene());
}
private IEnumerator DoGetRandomScene()
{
//Debug.Log("First forest scene index : " + firstForestSceneIndexNumber);
//Debug.Log("Last forest scene index : " + lastForestSceneIndexNumber);
// Get scene name from random pick
randomSceneIndex = Random.Range(firstForestSceneIndexNumber, (firstForestSceneIndexNumber + forestSceneIndexes.Count) - 1);
Debug.Log("First scene in list is " + firstForestSceneIndexNumber + " , the last one is " + ((firstForestSceneIndexNumber + forestSceneIndexes.Count) - 1));
yield return new WaitForEndOfFrame();
StartCoroutine(DoRemoveRandomSceneFromList());
// Load selected scene
StartCoroutine(DoLoadScene(randomSceneIndex));
Debug.Log("randomSceneIndex is " + randomSceneIndex);
for (int i = 0; i < forestSceneIndexes.Count; i++)
{
// Debug.Log("Scene " + forestSceneIndexes[i].ToString() + " is still left in the list");
Debug.Log(forestSceneIndexes.Count.ToString() + " scenes are still left in the list");
}
}
private IEnumerator DoRemoveRandomSceneFromList()
{
// Remove selected scene from list
forestSceneIndexes.Remove(randomSceneIndex);
Debug.Log("Scene " + randomSceneIndex + " has been removed from the list.");
yield return new WaitForEndOfFrame();
}
private IEnumerator DoLoadScene(int sceneIndex)
{
yield return new WaitForEndOfFrame();
SceneManager.LoadScene(sceneIndex, LoadSceneMode.Single);
foreach (ForestAnimal animal in forestAnimals) // Spawn Animal Stored in the forestAnimals List
{
// print("Animal " + animal.forestAnimalName + "is still in the list");
//GameObject animalGO = (GameObject)Instantiate(animal.forestAnimalGO);
//NetworkServer.Spawn(animalGO);
Debug.Log(animal.forestAnimalName + " re-instantiated in new scene");
}
}
}
【问题讨论】:
-
不要从列表中随机选择项目,而是随机排列列表然后对其进行迭代。
-
我本来打算在你的一个问题中警告你有这个问题,但我认为这个问题被删除了,或者我放弃了,因为错误太多了。我建议你创建一个新项目,找到关于协程的 Unity 教程并尝试示例。这将教你协程是如何工作的。 了解当你让和不让协程时会发生什么。一旦你理解了协程,你就可以回到这段代码并解决你所有的问题。
-
你有一个屈服问题(认为一个函数已经完成并返回而它还没有完成)并且你的其他代码依赖于这个函数。即使您让某人修复此代码并将其作为答案,您的其他代码中也可能会遇到许多类似的问题。正确的解决方案是像我在第一条评论中所说的那样理解协程。
-
看看那里了解协程是如何工作的:stackoverflow.com/questions/48199790/…。你也经常使用
yield return new WaitForEndOfFrame();。您几乎不必使用它。如果需要它,那通常是你的代码过于依赖统一方法的执行顺序的味道。 -
我想补充一下,你真的不需要协程来处理几乎所有的事情,比如由少于 10 个循环组成的
for循环和List.Addin每个周期。这确实是对协程的滥用,最终使代码的可读性降低并且更容易出错。
标签: c# list unity3d random scene