我目前正在 Unity 中开发游戏,但遇到了一个小问题。我正在开发一个重新启动功能,当玩家死亡并再次加载第一个场景时会自动调用它。但是由于某种原因,当重新加载场景时,游戏对象会被复制,死亡时处于活动状态的游戏对象版本处于非活动状态,并且每次玩家死亡时加载的版本应该被加载设置为活动等等将相同游戏对象的新副本添加到层次结构中。我试图以多种方式解决这个问题。首先,通过附加一个脚本来检查每个被复制的游戏对象是否已经运行了一个实例,该脚本在每次场景发生变化时检查它们是否已经是存在的游戏对象的实例:
public static GameObject Instance;
void Awake()
{
if(Instance){
DestroyImmediate(gameObject);
}else
{
DontDestroyOnLoad(gameObject);
Instance = this;
}
}
起初这似乎解决了问题,但到最后变得很麻烦,因为脚本使我所有的其他场景对象表现不佳或根本没有,所以我选择寻找另一种解决方案。
其次,我尝试在开始加载第一个场景之前销毁每个单独的游戏对象。起初这似乎也有效,但现在我的对象池只是重新创建游戏对象的新实例,它也添加了层次结构,基本上将相同的问题转移到其他游戏对象。
最后,为了解决这个问题,我试图让我的 objectpooler 在需要加载它的场景被调用时只运行一次,但这似乎也不起作用。有谁知道我如何解决这个问题。这是负责在玩家死亡时加载原始场景的脚本的一部分:
void Restart()
{
GameObject[] allObjects = UnityEngine.Object.FindObjectsOfType<GameObject>();
foreach (GameObject gos in allObjects)
{
if (gos.activeInHierarchy)
{
if (gos != GameObject.Find("GameManager") && gos != GameObject.Find("ScreenBound"))
{
gos.SetActive(false);
}
}
}
MySceneManager.LoadScene(0, this);
}
我该如何更改它以便能够重新加载原始场景而不会GameObject
复制任何先前加载的内容并根据它在最初加载的场景中的行为方式进行操作?
负责加载和卸载场景的类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public static class MySceneManager
{
private static int lastLoadedScene = 0;
public static void LoadScene(int index, MonoBehaviour caller)
{
ObjectPooler objP = new ObjectPooler();
objP.ReleaseAll();
caller.StartCoroutine(loadNextScene(index));
}
private static IEnumerator loadNextScene(int index)
{
var _async = SceneManager.LoadSceneAsync(index, LoadSceneMode.Additive);
_async.allowSceneActivation = false;
while (_async.progress < 0.9f)
{
yield return null;
}
_async.allowSceneActivation = true;
while (!_async.isDone)
{
yield return null;
}
var newScene = SceneManager.GetSceneByBuildIndex(index);
if (!newScene.IsValid()) yield break;
SceneManager.SetActiveScene(newScene);
if (lastLoadedScene >= 0) SceneManager.UnloadSceneAsync(lastLoadedScene);
lastLoadedScene = index;
}
}
这是我的对象池:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPooler : MonoBehaviour
{
[System.Serializable]
public class Pool
{
public string tag;
public GameObject prefab;
public int size;
}
#region Singleton
public static ObjectPooler Instance;
private void Awake()
{
if (Instance)
{
Destroy(this.gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(this.gameObject);
}
#endregion
public List<Pool> pools;
public Dictionary<string, Queue<GameObject>> poolDictionary;
private Dictionary<string, Pool> prefabPools;
void Start()
{
poolDictionary = new Dictionary<string, Queue<GameObject>>();
foreach (Pool pool in pools)
{
Queue<GameObject> objectPool = new Queue<GameObject>();
for (int i = 0; i < pool.size; i++)
{
GameObject obj = Instantiate(pool.prefab);
DontDestroyOnLoad(obj);
obj.SetActive(false);
objectPool.Enqueue(obj);
}
poolDictionary.Add(pool.tag, objectPool);
}
}
private List<GameObject> currentlySpawnedObjects = new List<GameObject>();
public void Release(GameObject obj)
{
currentlySpawnedObjects.Remove(obj);
obj.SetActive(false);
obj.transform.SetParent(transform);
poolDictionary[obj.tag].Enqueue(obj);
DontDestroyOnLoad(obj);
}
public void ReleaseAll()
{
foreach (var child in currentlySpawnedObjects)
{
Release(child);
}
}
public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation)
{
if (!poolDictionary.ContainsKey(tag))
{
Debug.LogWarning("Pool with tag" + tag + " doesn't exist.");
return null;
}
GameObject objectToSpawn = poolDictionary[tag].Dequeue();
objectToSpawn.SetActive(true);
objectToSpawn.transform.position = position;
objectToSpawn.transform.rotation = rotation;
IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();
if (pooledObj != null)
{
pooledObj.OnObjectSpawn();
}
poolDictionary[tag].Enqueue(objectToSpawn);
return objectToSpawn;
currentlySpawnedObjects.Add(objectToSpawn);
return objectToSpawn;
}
}