学Unity的猫之猫咪救济管理系统(十一)
11.1 山岗的星光
稀疏的星光,清辉洒地,流浪猫小花凝望着窗外,它没有想到一个月前它还是一只无家可归的流浪小猫,此时已经有了一个温暖的家。 事情要回到一个月前的那个夜晚,秋风瑟瑟,小花在路边蜷缩着身子,有个人类经过它的身旁,那个人站住了,嘴里发出蹩脚的喵喵声,慢慢想要靠近,小花见状立刻躲进了斜坡中的草丛里,那人停留片刻后便离开了。
两天后,小花又看到了那个人,而且还带着一只猫一台电脑,那只猫朝着小花挥手:“喂,过来这边,不要怕,我们不是坏人。”
小花不敢靠前,那只猫又喊道:“我叫皮皮,这个是我的铲屎官,这里有吃的,快过来。” 后来,小花不仅饱饱的吃了一餐,还得知了他们正在做一个猫咪救济管理系统,皮皮是项目的策划猫,它希望可以为那些流浪猫提供基础的保障,实名登记流浪猫,统一管理,调度资源,在设定的救济点投放食物和过冬物资,并与人类铲屎官合作,希望可以给流浪猫寻找合适的家。 每一只来到地球的喵星人都有一个唯一的编号,只要登记了这个编号,就可以随时随地通过猫电波进行通信,小花成为了救济系统的第一只猫。 很快便有人类来领养了小花,以前,小花总是坐在小斜坡上望着星星,它不知道自己从哪里来的,那里还有很多和它一样的猫,有的从来没见过,有的离开了又回来了,有的离开了就再也没有回来,只有星星一直陪着它。现在它有了家,它也想和皮皮它们一起,帮助流离失所的猫寻找温暖的家。 山岗的星光,愿你不再流浪,被世界温柔以待。
11.2 Unity猫咪救济管理系统
猫咪救济管理系统,模块设计如下:运行效果如下:
本工程使用的Unity
版本为2020.1.14f1c1 (64-bit)
,工程已上传到GitHub
,感兴趣的同学可以下载下来学习。GitHub
地址:https://github.com/linxinfa/Unity-CatInfoSystem
11.3 设置UI摄像机
创建一个摄像机,重命名为UICamera
。设置
Culling Mask
只渲染UI
层。设置视口
Projection
为正交视口Orthographic
。设置
Main Camera
不渲染UI
层。
11.4 设置Canvas
创建Canvas
,并设置Render Mode
为Screen Space -Camera
,设置Render Camera
为UICamera
,再把Canvas Scaler
组件的UI Scale Mode
设置为Scale With Screen Size
。
11.5 制作登录界面预设
LoginPanel.prefab
两个
Input Field
组件,用来输入账号和密码(account
和password
),一个Button
组件作为登录按钮(LoginButton
)。
11.6 制作大厅界面预设
PlazaPanel.prefab
一个
Button
组件作为登记按钮(AddButton
),一个Scroll View
组件作为拖拉列表,一个Item
作为列表的项,一个Button
组件作为退出登录按钮(LogoutButton
)。其中,Item
中使用多个Text
组件作为信息显示。
11.7 制作信息界面预设
InfoPnel.prefab
使用三个
Button
组件作为确定、删除、关闭按钮,使用多个Input Field
组件和一个Drop Down
组件作为信息输入。
11.8 UI界面管理器:UIManager
UI
预设资源放在Resources
目录中。封装一个
UIManager
类,用来加载界面预设资源和显示界面。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIManager
{
public void Init(Canvas canvas)
{
m_canvasTrans = canvas.transform;
}
public GameObject ShowPanel(string panelName)
{
GameObject prefabObj = null;
if (m_panelRes.ContainsKey(panelName))
{
prefabObj = m_panelRes[panelName];
}
else
{
prefabObj = Resources.Load<GameObject>(panelName);
m_panelRes[panelName] = prefabObj;
}
GameObject panelObj = Object.Instantiate(prefabObj);
panelObj.transform.SetParent(m_canvasTrans, false);
return panelObj;
}
private Transform m_canvasTrans;
private Dictionary<string, GameObject> m_panelRes = new Dictionary<string, GameObject>();
private static UIManager s_instance;
public static UIManager Instance
{
get
{
if (null == s_instance)
s_instance = new UIManager();
return s_instance;
}
}
}
public class PanelName
{
public const string LOGIN_PANEL = "LoginPanel";
public const string PLAZA_PANEL = "PlazaPanel";
public const string INFO_PANEL = "InfoPanel";
}
11.9 封装猫信息的类:CatInfo
猫的信息中有个uuid
是系统生成的,id
是猫星人的编号,由喵星人手动输入。
public class CatInfo
{
public CatInfo()
{
uuid = System.Guid.NewGuid().ToString("N");
}
public string uuid;
public string id;
public string nickname;
public string kind;
public string color;
public int gender;
public string birth;
public string reason;
}
11.10 猫信息管理器:CatManager
封装一个猫信息的管理类,CatManager
,负责数据加载和增删改查。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CatManager
{
public void Init()
{
m_datas = CatDataBase.QueryDatas();
}
public void AddOrModify(CatInfo info)
{
CatDataBase.AddOrModify(info);
EventDispatcher.instance.DispatchEvent(EventNameDef.EVENT_ADD_OR_MODIFY_CAT, info);
}
public void Del(string uuid)
{
CatDataBase.Del(uuid);
EventDispatcher.instance.DispatchEvent(EventNameDef.EVENT_DEL_CAT, uuid);
}
public Dictionary<string, CatInfo> data
{
get { return m_datas; }
}
private Dictionary<string, CatInfo> m_datas = null;
private static CatManager s_instance;
public static CatManager Instance
{
get
{
if (null == s_instance)
s_instance = new CatManager();
return s_instance;
}
}
}
11.11 数据存储:CatDataBase
封装一个CatDataBase
类,负责数据的本地写入和读取。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LitJson;
using System.IO;
public class CatDataBase
{
public static void AddOrModify(CatInfo info)
{
if (s_datas.ContainsKey(info.uuid))
{
s_datas[info.uuid] = info;
}
else
{
s_datas.Add(info.uuid, info);
}
SaveData();
}
public static void Del(string uuid)
{
if (!s_datas.ContainsKey(uuid)) return;
s_datas.Remove(uuid);
SaveData();
}
public static Dictionary<string, CatInfo> QueryDatas()
{
string jsonStr = PlayerPrefs.GetString("cats", null);
if (string.IsNullOrEmpty(jsonStr))
{
s_datas = new Dictionary<string, CatInfo>();
}
else
{
s_datas = JsonMapper.ToObject<Dictionary<string, CatInfo>>(jsonStr);
}
return s_datas;
}
public static void SaveData()
{
string jsonStr = JsonMapper.ToJson(s_datas);
PlayerPrefs.SetString("cats", jsonStr);
}
private static Dictionary<string, CatInfo> s_datas = new Dictionary<string, CatInfo>();
}
其中写入本地数据用到了Unity
提供的PlayerPrefs
类。 读取数据接口
public static string GetString(string key, string defaultValue);
1
写入数据接口
public static void SetString(string key, string value);
1
11.12 Json库:LitJson
需要将数据序列号到本地文件中,采用Json
的格式,所以需要导入一个Json
库,从GitHub
下载LitJson
源码: https://github.com/LitJSON/litjson/releases/tag/0.15.0下载后将源码导入到工程中。
使用时引入命名空间。
using LitJson;
主要用到JsonMapper
的两个接口。object
转json
字符串接口
public static string ToJson (object obj)
json
字符串转object
接口
public static T ToObject<T> (string json)
11.13 观察者模式
数据更新的时候要更新ui
的显示,这里采用观察者模式,ui
界面的代码监听事件,数据变化时抛出事件,从而实现ui
的显示刷新。 封装一个事件订阅和发送的类:EventDispatcher
。
皮皮:“微信搜索公众号 [爱上游戏开发],回复 “资料”,免费领取 200G 学习资料!”
using UnityEngine;
using System.Collections.Generic;
public delegate void MyEventHandler(params object[] objs);
public class EventDispatcher
{
public void Regist(string type, MyEventHandler handler)
{
if (handler == null)
return;
if (!listeners.ContainsKey(type))
{
listeners.Add(type, new Dictionary<int, MyEventHandler>());
}
var handlerDic = listeners[type];
var handlerHash = handler.GetHashCode();
if (handlerDic.ContainsKey(handlerHash))
{
handlerDic.Remove(handlerHash);
}
listeners[type].Add(handler.GetHashCode(), handler);
}
public void UnRegist(string type, MyEventHandler handler)
{
if (handler == null)
return;
if (listeners.ContainsKey(type))
{
listeners[type].Remove(handler.GetHashCode());
if (null == listeners[type] || 0 == listeners[type].Count)
{
listeners.Remove(type);
}
}
}
public void DispatchEvent(string evt, params object[] objs)
{
if (listeners.ContainsKey(evt))
{
var handlerDic = listeners[evt];
if (handlerDic != null && 0 < handlerDic.Count)
{
var dic = new Dictionary<int, MyEventHandler>(handlerDic);
foreach (var f in dic.Values)
{
try
{
f(objs);
}
catch (System.Exception ex)
{
Debug.LogErrorFormat(szErrorMessage, evt, ex.Message, ex.StackTrace);
}
}
}
}
}
public void ClearEvents(string key)
{
if (listeners.ContainsKey(key))
{
listeners.Remove(key);
}
}
private Dictionary<string, Dictionary<int, MyEventHandler>> listeners = new Dictionary<string, Dictionary<int, MyEventHandler>>();
private readonly string szErrorMessage = "DispatchEvent Error, Event:{0}, Error:{1}, {2}";
private static EventDispatcher s_instance;
public static EventDispatcher instance
{
get
{
if (null == s_instance)
s_instance = new EventDispatcher();
return s_instance;
}
}
}
定义事件
public class EventNameDef
{
public const string EVENT_ADD_OR_MODIFY_CAT = "EVENT_ADD_OR_MODIFY_CAT";
public const string EVENT_DEL_CAT = "EVENT_DEL_CAT";
}
11.14 登录界面代码:LoginPanel
登录界面代码LoginPanel
,挂在LoginPanel.prefab
上。 简单判断下账号和密码,如果账号为admin
且密码为123456
则进入大厅界面。 (实际开发需要有账号注册,与服务器通信才能完成登录,这里只是演示效果)。
using UnityEngine;
using UnityEngine.UI;
public class LoginPanel : MonoBehaviour
{
public InputField nameInput;
public InputField pwdInput;
public Button loginBtn;
void Start()
{
loginBtn.onClick.AddListener(() =>
{
if ("admin" == nameInput.text && "123456" == pwdInput.text)
{
Destroy(gameObject);
UIManager.Instance.ShowPanel(PanelName.PLAZA_PANEL);
}
});
}
}
绑定ui
对象
11.15 大厅界面代码:PlazaPanel
大厅界面代码PlazaPanel
,挂在PlazaPanel.prefab
上。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlazaPanel : MonoBehaviour
{
public Button logoutBtn;
public Button signBtn;
public GameObject catItemObj;
private Transform listRoot;
void Awake()
{
EventDispatcher.instance.Regist(EventNameDef.EVENT_ADD_OR_MODIFY_CAT, OnEventAddOrModifyCat);
EventDispatcher.instance.Regist(EventNameDef.EVENT_DEL_CAT, OnEventDelCat);
CatManager.Instance.Init();
catItemObj.SetActive(false);
listRoot = catItemObj.transform.parent;
}
void Start()
{
logoutBtn.onClick.AddListener(() =>
{
Destroy(gameObject);
UIManager.Instance.ShowPanel(PanelName.LOGIN_PANEL);
});
signBtn.onClick.AddListener(() =>
{
UIManager.Instance.ShowPanel(PanelName.INFO_PANEL);
});
foreach (CatInfo catInfo in CatManager.Instance.data.Values)
{
CreateItem(catInfo);
}
}
void CreateItem(CatInfo info)
{
var obj = Instantiate(catItemObj);
obj.SetActive(true);
obj.transform.SetParent(listRoot, false);
var itemUi = obj.GetComponent<CatListItem>();
itemUi.UpdateUi(info);
m_catUiList[info.uuid] = itemUi;
}
void OnEventAddOrModifyCat(params object[] args)
{
var info = args[0] as CatInfo;
if (m_catUiList.ContainsKey(info.uuid))
{
m_catUiList[info.uuid].UpdateUi(info);
}
else
{
CreateItem(info);
}
}
void OnEventDelCat(params object[] args)
{
var uuid = (string)args[0];
if (m_catUiList.ContainsKey(uuid))
{
var ui = m_catUiList[uuid];
if(null != ui)
{
Destroy(ui.gameObject);
}
m_catUiList.Remove(uuid);
}
}
private void OnDestroy()
{
EventDispatcher.instance.UnRegist(EventNameDef.EVENT_ADD_OR_MODIFY_CAT, OnEventAddOrModifyCat);
EventDispatcher.instance.UnRegist(EventNameDef.EVENT_DEL_CAT, OnEventDelCat);
}
private Dictionary<string, CatListItem> m_catUiList = new Dictionary<string, CatListItem>();
}
绑定PlazaPanel
组件的ui
对象。其中,列表的行
ui
单独封装成一个组件CatListItem
,挂在Item
节点上。
using UnityEngine;
using UnityEngine.UI;
public class CatListItem : MonoBehaviour
{
public Text idText;
public Text nameText;
public Text kindText;
public Text colorText;
public Text genderText;
public Text birthText;
public Text resonText;
public Button itemBtn;
public void Start()
{
itemBtn.onClick.AddListener(() =>
{
var panelObj = UIManager.Instance.ShowPanel(PanelName.INFO_PANEL);
var infoPanel = panelObj.GetComponent<InfoPanel>();
infoPanel.Init(m_info);
});
}
public void UpdateUi(CatInfo info)
{
m_info = info;
idText.text = info.id;
nameText.text = info.nickname;
kindText.text = info.kind;
colorText.text = info.color;
genderText.text = 0 == info.gender ? "母" : "公";
birthText.text = info.birth;
resonText.text = info.reason;
}
private CatInfo m_info;
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
绑定CatListItem
组件的ui
对象。
11.16 信息界面代码:InfoPanel
信息界面代码InfoPanel
,挂在InfoPanel.prefab
上。
using UnityEngine;
using UnityEngine.UI;
public class InfoPanel : MonoBehaviour
{
public InputField idInput;
public InputField kindInput;
public InputField nameInput;
public InputField colorInput;
public Dropdown genderDropdown;
public InputField birthInput;
public InputField reasonInput;
public Button okBtn;
public Button delBtn;
public Button closeBtn;
public CatInfo m_catInfo;
public void Init(CatInfo info)
{
m_catInfo = info;
idInput.text = info.id;
kindInput.text = info.kind;
nameInput.text = info.nickname;
colorInput.text = info.color;
genderDropdown.value = info.gender;
birthInput.text = info.birth;
reasonInput.text = info.reason;
}
private CatInfo MakeCatInfo()
{
if (null == m_catInfo)
m_catInfo = new CatInfo();
m_catInfo.id = idInput.text;
m_catInfo.kind = kindInput.text;
m_catInfo.nickname = nameInput.text;
m_catInfo.color = colorInput.text;
m_catInfo.gender = genderDropdown.value;
m_catInfo.birth = birthInput.text;
m_catInfo.reason = reasonInput.text;
return m_catInfo;
}
void Start()
{
okBtn.onClick.AddListener(() =>
{
CatManager.Instance.AddOrModify(MakeCatInfo());
Destroy(gameObject);
});
delBtn.onClick.AddListener(() =>
{
if(null != m_catInfo)
{
CatManager.Instance.Del(m_catInfo.uuid);
}
Destroy(gameObject);
});
closeBtn.onClick.AddListener(() =>
{
Destroy(gameObject);
});
}
}
绑定ui
对象。完成。 如果有任何疑问欢迎留言或私信。
标题:学Unity的猫之猫咪救济管理系统(十一)
作者:shirlnGame
地址:https://mmzsblog.cn/articles/2021/01/11/1610372464440.html
-----------------------------
如未加特殊说明,此网站文章均为原创。
网站转载须在文章起始位置标注作者及原文连接,否则保留追究法律责任的权利。
公众号转载请联系网站首页的微信号申请白名单!
