随机场景加载器无法正常工作

Random scene loader not working correctly

我正在尝试开发我的游戏中的功能,该功能加载一个随机场景,该场景共有 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");
        }
    }
}

除了评论中提到的问题(您一定要仔细阅读)之外,问题在于您如何选择随机数。您没有从实际的索引列表中提取。它应该是这样的:

private IEnumerator DoGetRandomScene()
{
    // Get scene name from random pick
    int choice= Random.Range(0, forestSceneIndexes.Count - 1);
    //here's where you convert your random choice into an actual scene index
    int sceneIndex = forestSceneIndexes[choice]; 

    yield return new WaitForEndOfFrame();
    //If you want to remove the scene, just do it now
    forestSceneIndexes.RemoveAt(choice);
    // Load selected scene
    StartCoroutine(DoLoadScene(sceneIndex));
}

注意,我没有修改你对协程的大部分使用,但正如评论中所指出的,你肯定有很多需要清理的地方。