Я сейчас разрабатываю игру в 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;
}
}
Это мой ObjectPooler:
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;
}
}