在游戏中,个模块间数据交互更新甚为常见。比如我们购买了一件装备,我们在背包里穿上这件装备,
对应的游戏场景中需要替换上新的服装模型或者特效等等。为了实现这种功能,我们需要一个通知的机制,
告诉对应的模块取改变状态。新建一个脚本命名为 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;
}
}
}
}
运行结果