Unity框架学习_DataManager,基于事件的信息管理驱动系统,简单快捷的实现信息改动后全局的刷新
目录
1、博文介绍
本篇博客介绍了基于事件的信息管理驱动系统,我们在写工程时经常会遇到一些依赖关系,如下图所示:
在背包中有个金币数据Coin,页面1需要显示金币的数量,页面2会根据金币的数量来开放某些物品的购买,页面3会根据金币的数量来修改一些等级变化,我们如果在某个地方修改了Coin的值,其他三个页面要随之改变,最直接的办法就是直接引用三个页面手动去修改,这样做的坏处就是造成了代码的耦合,相互引用,代码会变得越来越复杂,本篇博文目的就是简单快捷的实现信息改动后全局的刷新,在Coin变动后发一个通知,让有关联的地方自动去修改,没看过博主上一篇EventManger的可以跳转上一篇看一下,本篇基于上一篇。
2、内容
(1)数据的标记DataType
/// <summary>
/// 数据类型
/// </summary>
public enum DataType
{
UserInfo = 1001,
EnemyInfo = 1002,
}
我们可能会有很多的信息数据表,比如玩家的信息UsrInfo,敌人的信息EnemyInfo,我们首先写一个枚举类型DataType,该枚举作为不同数据的标记,用来区分和获取数据。
(2) 核心脚本DataBase
/// <summary>
/// time:2019/6/21 16:36
/// author:Sun
/// des:数据驱动基类
///
/// github:https://github.com/KingSun5
/// csdn:https://blog.csdn.net/Mr_Sun88
/// </summary>
public abstract class DataBase
{
/// <summary>
/// 数据类型
/// </summary>
public abstract DataType InDataType { get;}
/// <summary>
/// 初始化
/// </summary>
public abstract void OnInit();
/// <summary>
/// 广播自身
/// </summary>
public abstract void Notify();
/// <summary>
/// 构造函数内注册自己
/// </summary>
public DataBase()
{
OnInit();
DataManager.Instance.Register(InDataType,this);
}
}
InDataType | DataType枚举类型,作为不同数据的标记 |
OnInit() | 在构造中调用,作为初始化的方法,构造时执行 |
Notify() | 广播方法,在该数据变动时,手动触发,发出广播 |
DataBase() | 构造时将整个数据信息和标记注册进入DataManager,如此可通过DataManager和标记在任何地方获取该数据 |
(3) 核心脚本DataEvent
/// <summary>
/// time:2019/6/23 13:13
/// author:Sun
/// des:事件封装
///
/// github:https://github.com/KingSun5
/// csdn:https://blog.csdn.net/Mr_Sun88
/// </summary>
public class DataEvent
{
/// <summary>
/// 实例事件
/// </summary>
public EventMgr InstanceEvent;
/// <summary>
/// 绑定方法
/// </summary>
/// <param name="eventMgr"></param>
public void BindEvnt(EventMgr eventMgr)
{
InstanceEvent += eventMgr;
}
}
InstanceEvent | 实例了一个EventMgr,用该委托实例去绑定刷新方法 |
BindEvent() | 绑定方法 |
(3) 核心脚本DataManger
/// <summary>
/// 数据管理成员接口
/// </summary>
public interface IDataMgr
{
Dictionary<DataType, DataBase> EventListerDict { get; set; }//存储注册的信息
Dictionary<DataType, DataEvent> EventMgrDict { get; set; }//存储绑定事件信息
void AddDataWatch(DataType dataType,EventMgr eventMgr);//绑定更新方法
void Register(DataType dataType, DataBase dataBase);//注册数据信息
DataBase Get(DataType dataType);//获取数据
}
/// <summary>
/// time:2019/6/21 16:37
/// author:Sun
/// des:数据驱动管理
///
/// github:https://github.com/KingSun5
/// csdn:https://blog.csdn.net/Mr_Sun88
/// </summary>
public class DataManager:IDataMgr
{
private static DataManager _instance;
public static DataManager Instance
{
get
{
if (_instance==null)
{
_instance = new DataManager();
}
return _instance;
}
}
public Dictionary<DataType, DataBase> EventListerDict { get; set; }
public Dictionary<DataType,DataEvent> EventMgrDict { get; set; }
/// <summary>
/// 绑定数据类监听
/// </summary>
/// <param name="dataType"></param>
/// <param name="eventMgr"></param>
public void AddDataWatch(DataType dataType, EventMgr eventMgr)
{
if (EventMgrDict==null)
{
EventMgrDict = new Dictionary<DataType, DataEvent>();
}
if (EventMgrDict.ContainsKey(dataType))
{
//已存在该信息的刷新方法 先移除监听 绑定方法后重新监听
EventManager.Instance.UnRegister((int)dataType);
EventMgrDict[dataType].BindEvnt(eventMgr);
EventManager.Instance.Register((int)dataType,EventMgrDict[dataType].InstanceEvent);
}
else
{
//不存在该信息的刷新方法,需注册
var dataEvent = new DataEvent();
dataEvent.BindEvnt(eventMgr);
EventMgrDict.Add(dataType,dataEvent);
EventManager.Instance.Register((int)dataType,dataEvent.InstanceEvent);
}
}
/// <summary>
/// 注册数据类
/// </summary>
/// <param name="dataType"></param>
/// <param name="dataBase"></param>
public void Register(DataType dataType, DataBase dataBase)
{
if (EventListerDict==null)
{
EventListerDict = new Dictionary<DataType, DataBase>();
}
if (EventListerDict.ContainsKey(dataType))
{
Debug.LogError("Key:"+dataType+"已经被注册!");
return;
}
EventListerDict.Add(dataType,dataBase);
}
/// <summary>
/// 获取数据类
/// </summary>
/// <param name="dataType"></param>
/// <returns></returns>
public DataBase Get(DataType dataType)
{
if (EventListerDict.ContainsKey(dataType))
{
return EventListerDict[dataType];
}
Debug.LogError("Key:"+dataType+"不存在,获取失败!");
return null;
}
}
EventListerDict | 字典内储存了所有数据信息,数据构造的时候加进来的 |
EventMgrDict | 字典内储存了数据标记和标记对应的绑定了刷新方法的委托 |
AddDataWatch() | 当前脚本为某个数据的标记添加监听方法,如果该标记的数据广播了,自动调用该方法 |
Register() | 将标记和数据作为键值对存储在EventListerDict内 |
Get() | 通过标记从EventListerDict内获取对应数据 |
(4)演示Demo
我们模拟一个情景来演示具体的用法,人物信息脚本UserInfo内有金币数据100,页面OnePanel用来显示金币数量,页面TwoPanel可以增减金币,并有一张图片,在金币达到500时会变色。
添加标记:
/// <summary>
/// 数据类型
/// </summary>
public enum DataType
{
UserInfo = 1001,
}
信息脚本:UserInfo
public class UserInfo : DataBase
{
/// <summary>
/// 背包内金币数量
/// </summary>
public int CoinTotal;
public override DataType InDataType
{
get { return DataType.UserInfo; }
}
public override void OnInit()
{
CoinTotal = 100;
}
public override void Notify()
{
EventManager.Instance.Invoke((int)InDataType,this);
}
}
页面1脚本:OnePanel
using UnityEngine;
using UnityEngine.UI;
public class OnePanel : MonoBehaviour {
/// <summary>
/// 页面1
/// </summary>
public Transform Panel1;
/// <summary>
/// 页面2
/// </summary>
public Transform Panel2;
/// <summary>
/// 金币显示
/// </summary>
public Text TxtCoin;
/// <summary>
/// 页面跳转
/// </summary>
public Button BtnGo;
/// <summary>
/// 背包数据
/// </summary>
private UserInfo _userInfo;
// Use this for initialization
void Start () {
BtnGo.onClick.AddListener(OnClickGo);
//初始化一下背包数据
new UserInfo();
//获取背包数据
_userInfo = DataManager.Instance.Get(DataType.UserInfo) as UserInfo;
//初始化金币显示
TxtCoin.text = _userInfo.CoinTotal.ToString();
//绑定方法,数据变动后刷新
DataManager.Instance.AddDataWatch(DataType.UserInfo,OnRefresh);
}
/// <summary>
/// 数据变动后的刷新方法
/// </summary>
/// <param name="param"></param>
private void OnRefresh(params object[] param)
{
//获取广播的数据
var user = param[0] as UserInfo;
//更新数据显示
TxtCoin.text = user.CoinTotal.ToString();
}
/// <summary>
/// 跳转页面
/// </summary>
private void OnClickGo()
{
Panel1.gameObject.SetActive(false);
Panel2.gameObject.SetActive(true);
}
}
页面2脚本:TwoPanel
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TwoPanel : MonoBehaviour {
/// <summary>
/// 页面1
/// </summary>
public Transform Panel1;
/// <summary>
/// 页面2
/// </summary>
public Transform Panel2;
/// <summary>
/// 金币增加
/// </summary>
public Button BtnAdd;
/// <summary>
/// 金币减少
/// </summary>
public Button BtnReduce;
/// <summary>
/// 返回
/// </summary>
public Button BtnReturn;
/// <summary>
/// 触发图
/// </summary>
public Image ImgChange;
/// <summary>
/// 背包数据
/// </summary>
private UserInfo _userInfo;
// Use this for initialization
void Start () {
//获取背包数据
_userInfo = DataManager.Instance.Get(DataType.UserInfo) as UserInfo;
BtnAdd.onClick.AddListener(OnClickAdd);
BtnReduce.onClick.AddListener(OnClickReduce);
BtnReturn.onClick.AddListener(OnClickReturn);
//绑定方法,数据变动后刷新
DataManager.Instance.AddDataWatch(DataType.UserInfo,OnRefresh);
}
/// <summary>
/// 添加金币
/// </summary>
private void OnClickAdd()
{
_userInfo.CoinTotal += 100;
//每次变动广播一下数据
_userInfo.Notify();
}
/// <summary>
/// 减少金币
/// </summary>
private void OnClickReduce()
{
_userInfo.CoinTotal -= 200;
//每次变动广播一下数据
_userInfo.Notify();
}
/// <summary>
/// 返回页面
/// </summary>
private void OnClickReturn()
{
Panel1.gameObject.SetActive(true);
Panel2.gameObject.SetActive(false);
}
/// <summary>
/// 数据变动后的刷新方法
/// </summary>
/// <param name="param"></param>
private void OnRefresh(params object[] param)
{
//获取广播的数据
var user = param[0] as UserInfo;
if (user.CoinTotal>=500)
{
Debug.Log("2222");
ImgChange.color = Color.black;
}
}
}
3、推送
工程演示:https://github.com/KingSun5/Study_DataManager
4、结语
写了很多,其实没多少东西,很简单的逻辑,若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。
QQ交流群:806091680(Chinar)
该群为CSDN博主Chinar所创,推荐一下!我也在群里!
本文属于原创文章,转载请著名作者出处并置顶!!!!