C# 切换/加载场景时如何使用单例?
在层次结构中,我有3个对象,我希望在开始新游戏时保留它们,而不是销毁它们。 但我想在切换回主菜单时销毁它们 对象包括:玩家、游戏管理员、场景加载器 在3个对象(玩家、游戏管理员、场景加载器)上,我为每个对象添加了一个脚本名PersistentManager:C# 切换/加载场景时如何使用单例?,c#,unity3d,C#,Unity3d,在层次结构中,我有3个对象,我希望在开始新游戏时保留它们,而不是销毁它们。 但我想在切换回主菜单时销毁它们 对象包括:玩家、游戏管理员、场景加载器 在3个对象(玩家、游戏管理员、场景加载器)上,我为每个对象添加了一个脚本名PersistentManager: using System.Collections; using System.Collections.Generic; using UnityEngine; public class PersistentManager : MonoBe
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PersistentManager : MonoBehaviour
{
public static PersistentManager Instance { get; private set; }
private void Awake()
{
if(Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
}
附加到场景加载器的场景加载器脚本:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class SceneLoader : MonoBehaviour
{
private bool loadScene = false;
[SerializeField]
private int scene;
[SerializeField]
private Text loadingText;
// Updates once per frame
void Update()
{
// If the player has pressed the space bar and a new scene is not loading yet...
if (Input.GetKeyUp(KeyCode.Space) && loadScene == false)
{
LoadScene(scene);
}
// If the new scene has started loading...
if (loadScene == true)
{
// ...then pulse the transparency of the loading text to let the player know that the computer is still working.
loadingText.color = new Color(loadingText.color.r, loadingText.color.g, loadingText.color.b, Mathf.PingPong(Time.time, 1));
}
}
// The coroutine runs on its own at the same time as Update() and takes an integer indicating which scene to load.
IEnumerator LoadNewScene()
{
// This line waits for 3 seconds before executing the next line in the coroutine.
// This line is only necessary for this demo. The scenes are so simple that they load too fast to read the "Loading..." text.
//yield return new WaitForSeconds(3);
// Start an asynchronous operation to load the scene that was passed to the LoadNewScene coroutine.
AsyncOperation async = SceneManager.LoadSceneAsync(scene);
// While the asynchronous operation to load the new scene is not yet complete, continue waiting until it's done.
while (!async.isDone)
{
yield return null;
}
}
public void LoadScene(int scene)
{
// ...set the loadScene boolean to true to prevent loading a new scene more than once...
loadScene = true;
// ...change the instruction text to read "Loading..."
loadingText.text = "Loading...";
this.scene = scene;
// ...and start a coroutine that will load the desired scene.
StartCoroutine(LoadNewScene());
}
}
以及附加到游戏管理器的游戏管理器脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public SceneLoader sceneLoader;
public PlayerController playerController;
public CamMouseLook camMouseLook;
public static bool backToMainMenu = false;
public static bool togglePauseGame;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
PauseGame();
}
if (Input.GetKeyDown(KeyCode.Escape))
{
BackToMainMenu();
}
}
public void PauseGame()
{
togglePauseGame = !togglePauseGame;
if (togglePauseGame == true)
{
playerController.enabled = false;
camMouseLook.enabled = false;
Time.timeScale = 0f;
}
else
{
playerController.enabled = true;
camMouseLook.enabled = true;
Time.timeScale = 1f;
}
}
private void BackToMainMenu()
{
sceneLoader.LoadScene(0);
playerController.enabled = false;
camMouseLook.enabled = false;
Cursor.lockState = CursorLockMode.None;
Time.timeScale = 0f;
backToMainMenu = true;
}
}
现在,当我运行游戏,然后按下空格键开始一个新游戏时,主菜单场景被删除,不知道为什么
在使用我在3个对象中的每个对象上使用的PersistentManager脚本之前,请使用另一个脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DontDestroy : MonoBehaviour
{
private void Awake()
{
if (GameManager.backToMainMenu == false)
{
DontDestroyOnLoad(transform);
}
}
}
当开始新游戏时,这3个对象保持活动状态,如果切换回主菜单,问题是切换回主菜单时,这3个对象也在主菜单中
所以我有6个对象的副本。3在主菜单场景中,3在DontDestroyOnLoad场景中。
这就是为什么我尝试使用singleton
我希望,当我切换回主菜单时,3对象不会仅在DontDestroyOnLoad上的层次结构中的主菜单场景中。问题是,您继承的类在父类中有它的实例
publicstaticpersistentmanager实例{get;private set;}
这意味着第一个对象将消失
#region Using
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
#endregion
/// <summary>
/// Generic singleton Class. Extend this class to make singleton component.
/// Example:
/// <code>
/// public class Foo : GenericSingleton<Foo>
/// </code>
/// . To get the instance of Foo class, use <code>Foo.instance</code>
/// Override <code>Init()</code> method instead of using <code>Awake()</code>
/// from this class.
/// </summary>
public abstract class GenericSingleton<T> : MonoBehaviour where T : GenericSingleton<T>
{
private static T _instance;
[SerializeField, Tooltip("If set to true, the gameobject will deactive on Awake")] private bool _deactivateOnLoad;
[SerializeField, Tooltip("If set to true, the singleton will be marked as \"don't destroy on load\"")] private bool _dontDestroyOnLoad;
private bool _isInitialized;
public static T instance
{
get
{
// Instance required for the first time, we look for it
if (_instance != null)
{
return _instance;
}
var instances = Resources.FindObjectsOfTypeAll<T>();
if (instances == null || instances.Length == 0)
{
return null;
}
_instance = instances.FirstOrDefault(i => i.gameObject.scene.buildIndex != -1);
if (Application.isPlaying)
{
_instance?.Init();
}
return _instance;
}
}
// If no other monobehaviour request the instance in an awake function
// executing before this one, no need to search the object.
protected virtual void Awake()
{
if (_instance == null || !_instance || !_instance.gameObject)
{
_instance = (T)this;
}
else if (_instance != this)
{
Debug.LogError($"Another instance of {GetType()} already exist! Destroying self...");
Destroy(this);
return;
}
_instance.Init();
}
/// <summary>
/// This function is called when the instance is used the first time
/// Put all the initializations you need here, as you would do in Awake
/// </summary>
public void Init()
{
if (_isInitialized)
{
return;
}
if (_dontDestroyOnLoad)
{
DontDestroyOnLoad(gameObject);
}
if (_deactivateOnLoad)
{
gameObject.SetActive(false);
}
SceneManager.activeSceneChanged += SceneManagerOnActiveSceneChanged;
InternalInit();
_isInitialized = true;
}
private void SceneManagerOnActiveSceneChanged(Scene arg0, Scene scene)
{
// Sanity
if (!instance || gameObject == null)
{
SceneManager.activeSceneChanged -= SceneManagerOnActiveSceneChanged;
_instance = null;
return;
}
if (_dontDestroyOnLoad)
{
return;
}
SceneManager.activeSceneChanged -= SceneManagerOnActiveSceneChanged;
_instance = null;
}
protected abstract void InternalInit();
/// Make sure the instance isn't referenced anymore when the user quit, just in case.
private void OnApplicationQuit()
{
_instance = null;
}
void OnDestroy()
{
// Clear static listener OnDestroy
SceneManager.activeSceneChanged -= SceneManagerOnActiveSceneChanged;
StopAllCoroutines();
InternalOnDestroy();
if (_instance != this)
{
return;
}
_instance = null;
_isInitialized = false;
}
protected abstract void InternalOnDestroy();
}
gameObject.IsNullOrDestroyed()IsNullOrDestroyed()方法不存在。'GameObject'不包含'IsNullOrDestroyed'的定义,并且找不到可访问的扩展方法'IsNullOrDestroyed'接受类型为'GameObject'的第一个参数(是否缺少using指令或程序集引用?)。很抱歉,它使用的扩展方法不包括在内。我已经修改了没有它的代码,请现在再试一次