赞
踩
创建 Game Manager 脚本:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager : MonoBehaviour { // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } }
创建一个 Player,挂载同名脚本:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { private GameManager _gm; // Start is called before the first frame update void Start() { _gm = GameObject.Find("Game Manager").GetComponent<GameManager>(); // 传统方法找到对应的 GameManager 脚本,需要先找到对应的游戏对象,然后获取游戏对象下面挂载的脚本组件 } // Update is called once per frame void Update() { } }
改成设计成 singleton:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager : MonoBehaviour { private static GameManager _instance; // 生成一个静态实例,确保了仅有一个实例 public static GameManager Instance { get { if (_instance == null) { Debug.Log("Game Manager is null"); } return _instance; } } // 用于别的脚本与 GameManager 交互 // 这个 property 仅有一个 get 方法,确保了别的脚本只能对其只读 // 读取的就是 _instance 实例对象 // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } private void Awake() // 加载脚本实例的时候进行调用 { _instance = this; // 赋值为该游戏对象 } public void Test() { Debug.Log("Testing"); } }
在 Player 中调用:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { // private GameManager _gm; // Start is called before the first frame update void Start() { // _gm = GameObject.Find("Game Manager").GetComponent<GameManager>(); // 传统方法找到对应的 GameManager 脚本,需要先找到对应的游戏对象,然后获取游戏对象下面挂载的脚本组件 GameManager.Instance.Test(); // 使用了 singleton 后就可以直接调用了 } // Update is called once per frame void Update() { } }
使用 singleton 的时候,我们可以让所有的游戏对象(非静态)访问 Manager 的脚本进行交互,这也是仅有的和 Manager class 交互的方式,Manager classes 之间也可以交互,但是 Manager 脚本不会访问其他的游戏对象进行交互,所以这种交互是单向的。
创建一个空的游戏对象,命名为 UI Manager,挂载同名脚本:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; // 需要引入 UI 的库 public class UIManager : MonoBehaviour { private static UIManager _instance; // static 确保只有一个,所有游戏对象都访问这个 public static UIManager Instance // 这里的 property 也是 static { get { if (_instance == null) // 检测脚本有没有挂载到游戏对象上 { Debug.Log("The UIManager instance is null"); } return _instance; } // 这设定 property,外部脚本只读访问 _instance } private void Awake() { _instance = this; // 对实例进行赋值为该游戏对象 } public void ShowScore(int score) { Debug.Log("The score is: " + score); GameManager.Instance.Test(); // Manager classes 之间也可以相互访问 // 但是 Manager class 不访问别的游戏对象 // 仅由别的游戏对象访问 Manager class } }
UI Manager 脚本负责管理游戏中的所有 UI 游戏对象,整个游戏中只会有一个 UI Manager,所以可以使用 singleton 使得访问更简便。
还可以在 Manager classes 之间进行交互:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager : MonoBehaviour { private static GameManager _instance; // 生成一个静态实例,确保了仅有一个实例 public static GameManager Instance { get { if (_instance == null) { Debug.Log("Game Manager is null"); } return _instance; } } private void Awake() // 加载脚本实例的时候进行调用 { _instance = this; // 赋值为该游戏对象 } public void Test() { Debug.Log("Testing"); } }
Player 可以简便地访问 Manager class:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { // Start is called before the first frame update void Start() { UIManager.Instance.ShowScore(77); // 使用了 singleton 后就可以直接调用了 } // Update is called once per frame void Update() { } }
创建游戏对象 Spawn Manager 并挂载同名脚本:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SpawnManager : MonoBehaviour { private static SpawnManager _instance; public static SpawnManager Instance { get { if (_instance == null) { Debug.Log("The Spawn Manager instance is null"); } return _instance; } } // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } private void Awake() { _instance = this; } public void SpawnEnemy() { Debug.Log("Spawn one Enemy"); } }
在 Player 中调用:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { // Start is called before the first frame update void Start() { SpawnManager.Instance.SpawnEnemy(); // 使用了 singleton 后就可以直接调用了 } // Update is called once per frame void Update() { } }
但是我们也可以先不创建游戏对象,自然创建的脚本也不用挂载了:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; // 需要引入 UI 的库 public class UIManager : MonoBehaviour { private static UIManager _instance; // static 确保只有一个,所有游戏对象都访问这个 public static UIManager Instance // 这里的 property 也是 static { get { if (_instance == null) // 检测脚本有没有挂载到游戏对象上 { GameObject obj = new GameObject("UI Manager"); // 新建一个游戏对象叫做 UI Manager obj.AddComponent<UIManager>(); // 为该游戏对象增加组件:该脚本 } return _instance; } // 这设定 property,外部脚本只读访问 _instance } private void Awake() { _instance = this; // 对实例进行赋值为该游戏对象 } public void ShowScore(int score) { Debug.Log("The score is: " + score); } }
我们可以把原有的 UI Manager 删除,然后 Player 中照样可以调用:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { if (Input.GetKeyDown(KeyCode.Space)) { UIManager.Instance.ShowScore(88); } } }
运行以后会自动创建游戏对象 UI Manager,停止运行后该游戏对象会被删除。
使用 singleton 的两大优势:
之前我们制作 singleton 的时候,每一个 manager class 都需要进行初始化设定以及实例赋值,假设我们有 50 个,那就要进行 50 次类似的操作。
即然需要重复做,那我们就可以想办法进行模块化操作。
建立一个 singleton 的模版,脚本命名为 MonoSingleton:
using System.Collections; using System.Collections.Generic; using UnityEngine; public abstract class MonoSingleton<T> : MonoBehaviour where T: MonoSingleton<T> // 设定为抽象类,这样就不能挂载到游戏对象上,仅作为模版使用 // <T> 设定了一个 generic type,即不同的类型都可以使用该模版,多态性 // T 继承的应用模版的时候所输入的类型 // 这里这么做的原因在于,我们不但要继承 MonoSingleton,还需要知道具体的类型 { private static T _instance; public static T Instance { get { if (_instance == null) { Debug.LogError(typeof(T).ToString()+ " has no instance"); // 显示该类没有实例化,即没有赋值游戏对象(游戏对象挂载脚本) } return _instance; } } private void Awake() { _instance = this as T; // 或者 _instance = (T)this; Int(); // 一旦加载实例,即进指定的行初始化 // 如果没有被重写,那不执行任何操作 } public virtual void Int() // 设定一个初始化方法 { // 虚方法,可以选择重写,也可以不重写 } // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } }
我们尝试把 Player 的脚本来使用一下这个模版:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoSingleton<Player> // 继承自模版,类型为 Player { public override void Int() { base.Int(); // 调用默认的初始化方法,可去除 Debug.Log("Player initialized!"); } // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } }
另外尝试创建一个 Level Manager,挂载同名脚本:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class LevelManager : MonoSingleton<LevelManager> { public override void Int() { Debug.Log("Level Manager initialized"); } public void SetLevel() { Debug.Log("Set a level"); } }
通过 Player 尝试直接调用:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoSingleton<Player> { public override void Int() { Debug.Log("Player initialized!"); LevelManager.Instance.SetLevel(); // 可以直接调用 } // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。