Unity3D学习笔记 - C# 和 Unity 的单例模式

在我们做开发时,一般都会专门写一个 GameManager 来管理游戏的数据,但 GameManager 存在也会遇到一个问题。在我们进入下一个场景时,上一个场景的所有 GameObject 都会被销毁,所以就有了单例模式(Singleton)。

下面是最简单的实现:

1
2
3
4
5
6
7
8
9
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }

private void Awake()
{
Instance = this;
}
}

这里要注意,把 GameManager 的 Instance 属性里的 set 设置为 private,是为了保证外部只能读取。

但是这么写以后还是没解决会被销毁的问题,于是需要使用 DontDestroyOnLoad() 方法:

1
2
3
4
5
6
7
8
9
10
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }

private void Awake()
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
}

这么完成以后会发现一个问题,假设我们从场景一到场景二,然后从场景二回到场景一,这时候就会出现两个 GameManager ,所以我们要通过判断,保证场景里永远只存在一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }

private void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
}

这样就完成了一个完整的单例模式。

但实际使用中,我们可能大量内容需要使用单例,这时候每个文件都这么写就很麻烦了,所以可以使用一个简单的办法,通过继承一个类来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
public static T Instance { get; private set; }

protected void Awake()
{
if (Instance == null)
{
Instance = (T) this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
}

每次使用的时候就非常方便了:

1
2
3
4
public class GameManager : Singleton<GameManager>
{

}