Unity框架学习_DataManager,基于事件的信息管理驱动系统,简单快捷的实现信息改动后全局的刷新

              Unity框架学习_DataManager,基于事件的信息管理驱动系统,简单快捷的实现信息改动后全局的刷新


目录

1、博文介绍

2、内容

(1)数据的标记DataType

  (2) 核心脚本DataBase

  (3) 核心脚本DataManger

(4)演示Demo

3、推送

4、结语


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所创,推荐一下!我也在群里!

       本文属于原创文章,转载请著名作者出处并置顶!!!!

猜你喜欢

转载自blog.csdn.net/Mr_Sun88/article/details/93372075