在游戏中,个模块间数据交互更新甚为常见。比如我们购买了一件装备,我们在背包里穿上这件装备,
对应的游戏场景中需要替换上新的服装模型或者特效等等。为了实现这种功能,我们需要一个通知的机制,
告诉对应的模块取改变状态。新建一个脚本命名为 NotificationCenter
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace SSGame { public static class TypeDefinition { public static string NOTICE_COLOR_CHANGE = "notice_color_change"; } public delegate void NotificationDelegate(params object[] param); //广播委托也就是广播需要做的事情// public class NotificationObserver { public string name; //每种广播都有自己的名字// public object target; //这个就代表的谁的广播// public NotificationDelegate selector; //这个呢就是广播要做的事情了// public NotificationObserver(string _name, object _target, NotificationDelegate _selector) { SetAttr(_name, _target, _selector); } public void SetAttr(string _name, object _target, NotificationDelegate _selector) { this.name = _name; this.target = _target; this.selector = _selector; } //广播唤醒// public void PerformSelector(params object[] param) { if(target != null) { selector.Invoke(param); } } } //调度中心需要能随时注册新的广播,删除废弃广播,唤醒需要执行的广播 public class NotificationCenter { //在一个系统中只需要一个广播调度// private static NotificationCenter instance; //同一个名称,同一个目标只会有一个广播// //比如每个村子只有一个通知开会的广播,但是还会有其他功能的广播// private Dictionary<string, List<NotificationObserver>> dict; public NotificationCenter() { dict = new Dictionary<string, List<NotificationObserver>>(); } public static NotificationCenter Share() { if(instance == null) { instance = new NotificationCenter(); } return instance; } //新增的广播必须要在广播中心来注册// public void RigistObsever(string name, object target, NotificationDelegate selector) { List<NotificationObserver> delegateList; if(!dict.TryGetValue(name, out delegateList)) { delegateList = new List<NotificationObserver>(); NotificationObserver observer = new NotificationObserver(name, target, selector); delegateList.Add(observer); dict.Add(name, delegateList); } else { for(int i = delegateList.Count - 1; i >= 0; i--) { if(delegateList[i].name == name && delegateList[i].target == target) { //已经存在了// return; } } NotificationObserver observer = new NotificationObserver(name, target, selector); observer.SetAttr(name, target, selector); delegateList.Add(observer); } } //既然有注册必然需要消除,为内存优化考虑// public void UnRigistObsever(string name, object target) { List<NotificationObserver> delegateList; if(!dict.TryGetValue(name, out delegateList)) { return; } for(int i = delegateList.Count - 1; i >= 0; i--) { if(delegateList[i].name == name && delegateList[i].target == target) { delegateList.RemoveAt(i); break; } } } //还需要一个广播播放的机制// public void PostNotification(string name, params object[] obj) { List<NotificationObserver> delegateList; if(!dict.TryGetValue(name, out delegateList)) { return; } for(int i = delegateList.Count - 1; i >= 0; i--) { delegateList[i].PerformSelector(obj); } } } }以下是一个简单的粒子,我们通过点击按钮来随机一个颜色来模拟换装。我们建立一个UI 上面一个按钮用来点击随机颜色。场景中放两个模型,模型上附着同一个材质球。然后在UI上挂载脚本UINoticeForm模型的控制节点上增加脚本SceneNotice
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace SSGame { public class UINoticeForm : MonoBehaviour { public Button RandomBtn; void Start() { RandomBtn.onClick.AddListener(() => { RandomColor(); }); } private void RandomColor() { float r, g, b; r = Random.Range(0f, 1f); g = Random.Range(0f, 1f); b = Random.Range(0f, 1f); Color color = new Color(r, g, b); NotificationCenter.Share().PostNotification(TypeDefinition.NOTICE_COLOR_CHANGE, color); } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace SSGame { public class SceneNotice : MonoBehaviour { public GameObject[] objects; void OnEnable() { NotificationCenter.Share().RigistObsever(TypeDefinition.NOTICE_COLOR_CHANGE, this, ColorChange); } void OnDisable() { NotificationCenter.Share().UnRigistObsever(TypeDefinition.NOTICE_COLOR_CHANGE, this); } private void ColorChange(object[] objs) { if(objs.Length < 1) return; Color color = (Color)objs[0]; for(int i = 0; i < objects.Length; i++) { objects[i].transform.GetComponent<MeshRenderer>().material.color = color; } } } }
运行结果