文章目录

  • 11.1 山岗的星光
  • 11.2 Unity猫咪救济管理系统
  • 11.3 设置UI摄像机
  • 11.4 设置Canvas
  • 11.5 制作登录界面预设
  • 11.6 制作大厅界面预设
  • 11.7 制作信息界面预设
  • 11.8 UI界面管理器:UIManager
  • 11.9 封装猫信息的类:CatInfo
  • 11.10 猫信息管理器:CatManager
  • 11.11 数据存储:CatDataBase
  • 11.12 Json库:LitJson
  • 11.13 观察者模式
  • 11.14 登录界面代码:LoginPanel
  • 11.15 大厅界面代码:PlazaPanel
  • 11.16 信息界面代码:InfoPanel

简介:我是一名Unity游戏开发工程师,皮皮是我养的猫,会讲人话,它接到了喵星的特殊任务:学习编程,学习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 ModeScreen Space -Camera,设置Render CameraUICamera,再把Canvas Scaler组件的UI Scale Mode设置为Scale With Screen Size

11.5 制作登录界面预设

LoginPanel.prefab


两个Input Field组件,用来输入账号和密码(accountpassword),一个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;}/// <summary>/// 显示界面/// </summary>/// <param name="panelName">界面名称</param>/// <returns></returns>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;/// <summary>/// 界面资源缓存/// </summary>private Dictionary<string, GameObject> m_panelRes = new Dictionary<string, GameObject>();/// <summary>/// 单例模式/// </summary>private static UIManager s_instance;public static UIManager Instance{get{if (null == s_instance)s_instance = new UIManager();return s_instance;}}
}/// <summary>
/// 界面名称,对应预设文件名称
/// </summary>
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是猫星人的编号,由喵星人手动输入。

/// <summary>
/// 猫咪信息
/// </summary>
public class CatInfo
{public CatInfo(){uuid = System.Guid.NewGuid().ToString("N");}/// <summary>/// 系统唯一标识符/// </summary>public string uuid;/// <summary>/// 喵星身份编号/// </summary>public string id;/// <summary>/// 昵称/// </summary>public string nickname;/// <summary>/// 品种/// </summary>public string kind;/// <summary>/// 毛色/// </summary>public string color;/// <summary>/// 性别,0:母,1:公/// </summary>public int gender;/// <summary>/// 出生/// </summary>public string birth;/// <summary>/// 流浪原因/// </summary>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();}/// <summary>/// 新增或修改猫信息/// </summary>/// <param name="info"></param>public void AddOrModify(CatInfo info){CatDataBase.AddOrModify(info);// 抛出事件,更新界面EventDispatcher.instance.DispatchEvent(EventNameDef.EVENT_ADD_OR_MODIFY_CAT, info);}/// <summary>/// 删除猫信息/// </summary>/// <param name="uuid"></param>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; }}/// <summary>/// 猫信息数据缓存/// </summary>private Dictionary<string, CatInfo> m_datas = null;/// <summary>/// 单例模式/// </summary>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;/// <summary>
/// 猫数据库
/// </summary>
public class CatDataBase
{/// <summary>/// 新增或修改数据/// </summary>/// <param name="info"></param>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();}/// <summary>/// 删数据/// </summary>/// <param name="uuid"></param>public static void Del(string uuid){if (!s_datas.ContainsKey(uuid)) return;s_datas.Remove(uuid);SaveData();}/// <summary>/// 查询所有猫信息/// </summary>/// <returns></returns>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;}/// <summary>/// 使用PlayerPrefs将数据写入本地/// </summary>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);

写入数据接口

public static void SetString(string key, string value);

11.12 Json库:LitJson

需要将数据序列号到本地文件中,采用Json的格式,所以需要导入一个Json库,从GitHub下载LitJson源码:
https://github.com/LitJSON/litjson/releases/tag/0.15.0

下载后将源码导入到工程中。

使用时引入命名空间。

using LitJson;

主要用到JsonMapper的两个接口。
objectjson字符串接口

public static string ToJson (object obj)

json字符串转object接口

public static T ToObject<T> (string json)

11.13 观察者模式

数据更新的时候要更新ui的显示,这里采用观察者模式,ui界面的代码监听事件,数据变化时抛出事件,从而实现ui的显示刷新。
封装一个事件订阅和发送的类:EventDispatcher

using UnityEngine;
using System.Collections.Generic;public delegate void MyEventHandler(params object[] objs);public class EventDispatcher
{/// <summary>/// 注册事件的响应函数/// </summary>/// <param name="type"></param>/// <param name="handler"></param>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);}/// <summary>/// 注销事件的响应函数/// </summary>/// <param name="type"></param>/// <param name="handler"></param>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);}}}/// <summary>/// 抛出事件,触发之前注册过的响应函数/// </summary>/// <param name="evt"></param>/// <param name="objs"></param>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);}}}}}/// <summary>/// 清理事件/// </summary>/// <param name="key"></param>public void ClearEvents(string key){if (listeners.ContainsKey(key)){listeners.Remove(key);}}/// <summary>/// 事件监听缓存/// </summary>private Dictionary<string, Dictionary<int, MyEventHandler>> listeners = new Dictionary<string, Dictionary<int, MyEventHandler>>();private readonly string szErrorMessage = "DispatchEvent Error, Event:{0}, Error:{1}, {2}";/// <summary>/// 单例模式/// </summary>private static EventDispatcher s_instance;public static EventDispatcher instance{get{if (null == s_instance)s_instance = new EventDispatcher();return s_instance;}}
}

定义事件

public class EventNameDef
{/// <summary>/// 新增或修改一只猫的信息/// </summary>public const string EVENT_ADD_OR_MODIFY_CAT  = "EVENT_ADD_OR_MODIFY_CAT";/// <summary>/// 删除一只猫的信息/// </summary>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);}}/// <summary>/// 创建信息列表的一行ui/// </summary>/// <param name="info"></param>void CreateItem(CatInfo info){var obj = Instantiate(catItemObj);obj.SetActive(true);obj.transform.SetParent(listRoot, false);var itemUi = obj.GetComponent<CatListItem>();// 使用数据更新uiitemUi.UpdateUi(info);// 缓存,方便后面更新uim_catUiList[info.uuid] = itemUi;}/// <summary>/// 数据发生变化,更新ui/// </summary>/// <param name="args"></param>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);}}/// <summary>/// 信息被删除,删除对应的ui/// </summary>/// <param name="args"></param>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);}}/// <summary>/// 界面被销毁/// </summary>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;/// <summary>
/// 列表的一行ui
/// </summary>
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);});}/// <summary>/// 更新ui/// </summary>/// <param name="info"></param>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;
}

绑定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的猫》——第十二章:使用Unity制作背包,皮皮的梦想背包

《学Unity的猫》——第十一章:Unity猫咪救济管理系统,山岗的星光相关推荐

  1. 第三十一章 Unity骨骼动画

    关于骨骼动画的原理,我们这里不再详细介绍,有不清楚的可以回去看DirectX课程和3dsMAX课程.接下来,我们来讲解一下Unity的骨骼动画系统.Unity 的动画系统基于动画剪辑(Animatio ...

  2. 【Aries - Unity入门】第四章 Unity菜单栏介绍(上)

    目录 -------- [Aries - Unity入门] -------- 第四章 菜单栏介绍 4.1 File [文件] 4.1.1 New Scene [新建场景] 4.1.2 Open Sce ...

  3. 《学Unity的猫》——第一章:故事开始

    文章目录 1.1 关于我 1.2 关于我的猫--皮皮 1.3 hello,喵 1.1 关于我 大家好,我是一名程序员,职业是Unity游戏开发工程师,每天上班下班,偶尔画画,弹弹吉他,写写博客.日子就 ...

  4. Ruby‘s Adventrue游戏制作笔记(十一)Unity角色攻击——发射子弹

    Ruby's Adventrue游戏制作笔记(十一)Unity角色攻击--发射子弹 前言 一.编辑子弹 二.创建脚本 三.修改玩家攻击脚本 四.将子弹拖入玩家脚本 五.让子弹碰撞到该碰撞的东西 六.编 ...

  5. Unity网络多玩家游戏开发教程第1章Unity自带网络功能

    Unity网络多玩家游戏开发教程第1章Unity自带网络功能 Unity拥有大量的第三方插件,专门提供了对网络功能的支持.但是,大部分开发者第一次接触到的还是Unity自带的网络功能,也就是大家经常说 ...

  6. Unity4.x 2D游戏开发基础教程第1章Unity及其组成的介绍

    Unity4.x 2D游戏开发基础教程第1章Unity及其组成的介绍 本书主要讲解的是,如何使用Unity开发2D游戏.但在开始讲解之前,最好先熟悉一下Unity这个工具.本章会首先介绍Unity的下 ...

  7. unity入门精要之第6 章 Unity 中的基础光照概述-1

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 6.1 我们是如何看到这个世界的 6.2 标准光照模型 参考 前言 渲染总是围绕着一个基础问题:我们如何决定一个像素的颜色?从宏观上来说 ...

  8. unity入门精要之第6 章 Unity 中的基础光照--环境光和自发光

    Unity系列文章目录 文章目录 Unity系列文章目录 前言 一.Unity 中的环境光和自发光 二.在Unity Shader 中实现漫反射光照模型 参考 前言 但这种模型有很多局限性.首先,有很 ...

  9. Unity 游戏黑暗之光笔记第一章 完善场景

    Unity 游戏黑暗之光笔记 第一章 完善场景 1. 导入资地形.地貌资源,新建场景,导入地形.地貌prefab 2. 设置相机与视野匹配 选中主摄像机,点选菜单栏中GameObject > A ...

最新文章

  1. 苏区振兴下的赣州发展状况分析
  2. 模拟人生4修身拉德兰连衣裙MOD下载
  3. java线程池(ThreadPool)
  4. Allegro改动shape网络节点
  5. 如何去掉DataTable中的重复行(新增.net 2.0中最新解决方法---简便)
  6. 备份自己常用的VS2010设置
  7. yshon对讲机如何调频率_窄带宽、窄脉宽、高重复频率,主动调Q光纤激光器是如何实现的?...
  8. [转载]:C# 中结构与类的区别
  9. postgre 表被加锁无法解锁问题
  10. Spring与Struts2的整合
  11. 无线路由器关掉dhcp服务器,无线路由器关闭dhcp会好不好
  12. 程序员要实现财富自由,“出海”这条路该怎么走?
  13. VEMD11940FX01光学传感器
  14. 微信账号和系统账号绑定
  15. 图解ArcGIS数据三维显示
  16. 允许在CAD中操作超链接!Aspose.CAD最新版v19.9新功能你都了解吗?
  17. Plants vs. Zombies 解题报告
  18. 对技术的态度(酷壳)
  19. 行式数据库评测:Oracle 11g R2企业版
  20. Cannot convert value of type ‘java.lang.String‘ to required type ‘java.util.Map‘ for property ‘param

热门文章

  1. redis5.0 主从配置
  2. 为什么我用Ipad Pro做电子笔记和看PDF电子书
  3. (附源码)springboot游戏道具在线交易平台 毕业设计171956
  4. 机器学习之基础知识(从数据处理到模型评估)
  5. iOS 调用手机浏览器打开网页
  6. War Thunder for Mac(战争雷霆)中文版
  7. 获得三星(Samsung) Galaxy Note 10.1的root权限--(3)
  8. springboot项目多租户实现
  9. java从小白到工程师--基础篇(三)
  10. 【论文写作助手】综述论文行书的思路