文章目录
简介:我是一名Unity
游戏开发工程师,皮皮是我养的猫,会讲人话,它接到了喵星的特殊任务:学习编程,学习Unity
游戏开发。
于是,发生了一系列有趣的故事。
12.1 皮皮的梦想背包
皮皮:“太阳天空照,花儿对我笑,小鸟说早早早,你为什么背着小书包?”
我:“我去上ang班,天天不迟到,爱学习爱工作,要不哪里有钱买猫粮。”
皮皮:“包里都装什么东西呀?有吃的吗?”
我打开我的双肩包:“没有吃的,有雨伞、水杯、工牌、纸巾、移动电源、充电器、笔、本子、各种卡,还有水电煤的单子。”
皮皮:“我也想要一个背包,不过我想要里面装满了我的玩具和爱吃的食物。”
我:“现在就给你做一个吧。”
模块设计如下
本工程使用的Unity
版本为2020.1.14f1c1 (64-bit)
,工程已上传到GitHub
,感兴趣的同学可以下载下来学习。
GitHub
地址:https://github.com/linxinfa/Unity-BackpackDemo
12.2 准备道具图片
皮皮:“你这道具图片也太没诚意了。”
我:“不要在意这些细节。”
我们需要把图片放到Unity
工程中,如下,放在Assets/Atlas/Bag
文件夹中。
皮皮:“为什么不放在Resources
文件夹中呢,这样可以直接通过Resources.Load
加载图片。”
我:“因为后面我要将这些图片打成一个图集,放在Resources
中的图片是不会被打进图集中的。”
12.3 UGUI打图集
UGUI
中,我们可以使用Image
或RawImage
组件来显示图片。
皮皮:“RawImage
和Image
有什么区别呢?”
RawImage
和Image
都继承MaskableGraphic
,但Image
比RawImage
的封装重一些。
RawImage
只为我们提供了修改UV
的方法,主要用来显示未加工的图片,比如背景图;而Image
提供了四种ImageType
:Simple
(普通)、Sliced
(切割)、Tiled
(平铺)、Filled
(填充),显示图片的方式丰富;另外,Image
支持精灵图的图集合批,可以减少DrawCall
。
道具种类繁多,道具图片可以打在一个图集中,这样显示多个道具图片可以合成一个批次显示,提升性能。
皮皮:“问题来了,怎么打图集呢?”
12.3.1 设置图集模式:Always Enabled(Legacy Sprite Packer)
点击菜单Edit - Project Settings...
,打开Project Settings
窗口。
点击Editor
标签页,将Sprite Packer
的Mode
选为Always Enabled(Legacy Sprite Packer)
。
12.3.2 设置图片为Sprite(2D and UI)类型
将图片的Texture Type
设置为为Sprite(2D and UI)
。
设置成功后,会有个小箭头,点开可以看到对应的Sprite
。
12.3.3 设置Packing Tag
想要把多张图片打在一个图集中,需要将这些图片的Packing Tag
设置为相同的值。
比如都设置成Bag
。
不过这样每次都手动设置有点麻烦,写个Editor
工具监听图片导入,自动修改图片格式,并设置Packing Tag
为所在文件夹名字。
代码如下,将其保存为PostTexture.cs
放在Editor
文件夹中。
using UnityEngine;
using UnityEditor;
using System.IO;
public class PostTexture : AssetPostprocessor
{
/// <summary>
/// 监听图片导入,自动修改图片格式,并设置Packing Tag为所在文件夹名字
/// </summary>
/// <param name="texture"></param>
void OnPostprocessTexture(Texture2D texture)
{
var dirName = Path.GetDirectoryName(assetPath);
// 文件夹名字作为图集名字
string atlasName = new DirectoryInfo(dirName).Name;
TextureImporter textureImporter = assetImporter as TextureImporter;
// 设置为Sprite(2D and UI)
textureImporter.textureType = TextureImporterType.Sprite;
// 设置设置Packing Tag为图集名字
textureImporter.spritePackingTag = atlasName;
// 不使用mipmap,否则图片可能会变模糊
textureImporter.mipmapEnabled = false;
}
}
12.3.4 使用Sprite Packer打图集
点击菜单Window - 2D - Sprite Packer
。
点击Pack
按钮,即可将多张图片打成一个图集了。
打图集成,即可看到对应的图集了。
如果有多张图集,可以在View Atlas
下拉菜单中切换显示。
12.4 制作精灵预设,通过预设加载精灵
使用过NGUI
的同学应该知道,在NGUI
中图集会有一个对应的图集预设,要加载某个精灵图,需要先加载对应的图集。UGUI
则不同,直接加载对应的精灵即可。但是上面我们的精灵并不是放在Resources
文件夹中,是不会被打进包体中的。如果将精灵图拷贝到Resources
文件夹中,则会产生双份资源,造成资源冗余。
解决办法就是将精灵图包装成预设,把预设放在Resources
文件夹中,这样就可以通过Resources.Load
接口加载精灵图了。
预设中使用Sprite Renderer
组件,设置它的Sprite
属性为具体的精灵图。
这样挨个制作精灵预设很麻烦,所以写个Editor
工具批量执行。
将下面的代码保存为MakeSpritePrefabs.cs
放在Editor
文件夹中。
using UnityEngine;
using UnityEditor;
using System.IO;
public class MakeSpritePrefabs
{
[MenuItem("Tools/MakeSpritePrefabs")]
private static void Make()
{
// 创建 Assets/Resources/Sprite 文件夹,用来存放生成的精灵预设
var prefabRootDir = Path.Combine(Application.dataPath, "Resources/Sprite");
if (!Directory.Exists(prefabRootDir))
{
Directory.CreateDirectory(prefabRootDir);
}
// 遍历 Assets/Atlas 文件夹中的 png 图片
var pngRootDir = Path.Combine(Application.dataPath, "Atlas");
var pngFils = Directory.GetFiles(pngRootDir, "*.png", SearchOption.AllDirectories);
foreach (string filePath in pngFils)
{
string assetPath = filePath.Substring(filePath.IndexOf("Assets"));
Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(assetPath);
GameObject go = new GameObject(sprite.name);
go.AddComponent<SpriteRenderer>().sprite = sprite;
var prefabPath = Path.Combine(prefabRootDir, sprite.name + ".prefab");
prefabPath = prefabPath.Substring(prefabPath.IndexOf("Assets"));
// 将 gameObject 保存为预设
PrefabUtility.SaveAsPrefabAsset(go, prefabPath);
GameObject.DestroyImmediate(go);
}
// 刷新目录
AssetDatabase.Refresh();
}
}
点击菜单Tools - MakeSpritePrefabs
即可自动将精灵图制作成预设了。
接着,我们就可以通过Resources.Load
接口加载精灵图了。
var obj = Resources.Load<GameObject>("Sprite/bj");
var sprite = .GetComponent<SpriteRenderer>().sprite;
12.5 json配置表
我们将道具以json
格式弄成配置表,如下
[
{
"id":1,
"name":"逗猫棒",
"sprite":"dmb",
"desc":"逗猫棒是一种深受猫咪喜爱的玩具"
},
{
"id":2,
"name":"猫布丁",
"sprite":"mbd",
"desc":"猫布丁是以香滑布丁粉为主要材料制作而成的一道甜品"
},
{
"id":3,
"name":"猫薄荷",
"sprite":"mbh",
"desc":"猫薄荷是指能让家猫等猫科动物产生幻觉的一类多年生草本植物"
},
{
"id":4,
"name":"鸡胸肉",
"sprite":"jxr",
"desc":"鸡胸肉,是鸡身上最大的两块肉,富含丰富的蛋白质"
},
{
"id":5,
"name":"猫麦草",
"sprite":"mmc",
"desc":"猫麦草可以刺激猫的肠胃蠕动,帮助猫吐出在胃中结成团的毛球"
},
{
"id":6,
"name":"猫罐头",
"sprite":"mgt",
"desc":"猫罐头是根据猫咪的特殊身体因素研制而成的食物,营养丰富"
},
{
"id":7,
"name":"猫条",
"sprite":"mt",
"desc":"猫条是一种猫的零食,口味多种多样"
}
]
12.6 配置表读取
将上面的配置表保存为PropCfg.json
放在Resources
目录中。
接着我们就可以通过Resources.load
加载配置文件,再通过LitJson
解析。
关于
LitJson
,第十一章已讲过,可以查阅第十一章:《学Unity的猫》——第十一章:Unity猫咪救济管理系统,山岗的星光
using System.Collections.Generic;
using UnityEngine;
using LitJson;
public class PropCfg
{
/// <summary>
/// 读取配置表
/// </summary>
public void LoadCfg()
{
var cfgJson = Resources.Load<TextAsset>("PropCfg");
var cfg = JsonMapper.ToObject<List<PropCfgItem>>(cfgJson.text);
foreach(var cfgItem in cfg)
{
m_cfgDic[cfgItem.id] = cfgItem;
}
}
/// <summary>
/// 通过道具id获取道具配置
/// </summary>
/// <param name="id">道具id</param>
/// <returns></returns>
public PropCfgItem GetCfg(int id)
{
if (m_cfgDic.ContainsKey(id))
return m_cfgDic[id];
return null;
}
/// <summary>
/// 配置表
/// </summary>
private Dictionary<int, PropCfgItem> m_cfgDic = new Dictionary<int, PropCfgItem>();
/// <summary>
/// 单例模式
/// </summary>
private static PropCfg s_instance;
public static PropCfg Instance
{
get
{
if (null == s_instance)
s_instance = new PropCfg();
return s_instance;
}
}
}
/// <summary>
/// 道具配置数据结构
/// </summary>
public class PropCfgItem
{
public int id;
public string name;
public string sprite;
public string desc;
}
12.7 制作界面预设
大厅界面:PlazaPanel.prefab
。
背包界面:BackpackPanel.prefab
提示语预设:TipsUi.prefab
12.8 资源管理器
编写一个资源管理器ResourceMgr
,用于加载资源,缓存资源。
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 资源管理器
/// </summary>
public class ResourceMgr
{
/// <summary>
/// 加载精灵图
/// </summary>
/// <param name="name">精灵名</param>
/// <returns></returns>
public Sprite LoadSprite(string name)
{
if (m_spritesDic.ContainsKey(name))
return m_spritesDic[name];
var obj = Resources.Load<GameObject>("Sprite/" + name);
var sprite = obj.GetComponent<SpriteRenderer>().sprite;
m_spritesDic[name] = sprite;
return sprite;
}
/// <summary>
/// 加载界面预设
/// </summary>
/// <param name="name">界面名</param>
/// <returns></returns>
public GameObject LoadPanel(string name)
{
GameObject prefab = null;
if (m_panelsDic.ContainsKey(name))
prefab = m_panelsDic[name];
else
{
prefab = Resources.Load<GameObject>("Panel/" + name);
m_panelsDic[name] = prefab;
}
return prefab;
}
/// <summary>
/// 精灵资源
/// </summary>
private Dictionary<string, Sprite> m_spritesDic = new Dictionary<string, Sprite>();
/// <summary>
/// 界面资源
/// </summary>
private Dictionary<string, GameObject> m_panelsDic = new Dictionary<string, GameObject>();
/// <summary>
/// 单例模式
/// </summary>
private static ResourceMgr s_instance;
public static ResourceMgr Instance
{
get
{
if (null == s_instance)
s_instance = new ResourceMgr();
return s_instance;
}
}
}
例:加载精灵图
// 加载猫麦草精灵图
var sprite = ResourceMgr.Instance.LoadSprite("mmc");
12.9 界面管理器
编写一个界面管理器PanelMgr
,用于显示界面。
using UnityEngine;
/// <summary>
/// 界面管理器
/// </summary>
public class PanelMgr
{
/// <summary>
/// 初始化
/// </summary>
/// <param name="canvas"></param>
public void Init(Canvas canvas)
{
m_canvasTrans = canvas.transform;
}
/// <summary>
/// 显示界面
/// </summary>
/// <param name="panelName"></param>
/// <returns></returns>
public GameObject ShowPanel(string panelName)
{
var prefab = ResourceMgr.Instance.LoadPanel(panelName);
var obj = Object.Instantiate(prefab);
obj.transform.SetParent(m_canvasTrans, false);
return obj;
}
/// <summary>
/// 缓存Canvas
/// </summary>
private Transform m_canvasTrans;
private static PanelMgr s_instance;
public static PanelMgr Instance
{
get
{
if (null == s_instance)
s_instance = new PanelMgr();
return s_instance;
}
}
}
/// <summary>
/// 界面名称
/// </summary>
public class PanelName
{
public const string PlazaPanel = "PlazaPanel";
public const string BackpackPanel = "BackpackPanel";
public const string TipsUi = "TipsUi";
}
例:显示背包界面
// 显示背包界面
var obj = PanelMgr.Instance.ShowPanel(PanelName.BackpackPanel);
12.10 背包数据读写
封装一个本地数据读写的类,模拟数据库,用到了PlayerPrefs
和LitJson
这两个类。
通过PlayerPrefs
可以方便地进行数据读写,通过LitJson
可以方便地进行json
数据格式转换。
using System.Collections.Generic;
using UnityEngine;
using LitJson;
/// <summary>
/// 道具数据库
/// </summary>
public class PropsDatabase
{
/// <summary>
/// 从本地读取数据
/// </summary>
/// <returns></returns>
public static Dictionary<int, int> LoadData()
{
PlayerPrefs.SetString("props", "{}");
var jsonStr = PlayerPrefs.GetString("props", "{}");
Debug.Log("LoadData: \n" + jsonStr);
var result = JsonMapper.ToObject<Dictionary<string, int>>(jsonStr);
Dictionary<int, int> data = new Dictionary<int, int>();
foreach (var item in result)
{
data[int.Parse(item.Key)] = item.Value;
}
return data;
}
/// <summary>
/// 写入数据到本地
/// </summary>
/// <param name="data"></param>
public static void SaveData(Dictionary<int, int> data)
{
var jsonStr = JsonMapper.ToJson(data);
PlayerPrefs.SetString("props", jsonStr);
}
}
12.11 背包管理器
再封装一个背包管理器BackPackMgr
,提供读取道具数据和增减道具数量的方法。
using System.Collections.Generic;
/// <summary>
/// 背包管理器
/// </summary>
public class BackPackMgr
{
/// <summary>
/// 初始化
/// </summary>
public void Init()
{
// 从本地读取背包数据
m_propsDic = PropsDatabase.LoadData();
}
/// <summary>
/// 修改道具数量
/// </summary>
/// <param name="id">道具id</param>
/// <param name="deltaCnt">数量变化值</param>
public void ChangePropCnt(int id, int deltaCnt)
{
if (m_propsDic.ContainsKey(id))
{
m_propsDic[id] += deltaCnt;
}
else
{
m_propsDic[id] = deltaCnt;
}
if (m_propsDic[id] < 0)
{
m_propsDic[id] = 0;
}
// 写入数据到本地
PropsDatabase.SaveData(m_propsDic);
// 抛出事件
EventDispatcher.instance.DispatchEvent(EventNameDef.EVENT_UPDATE_PROP_CNT, id, m_propsDic[id]);
}
/// <summary>
/// 背包道具数据缓存,key: id, value: cnt
/// </summary>
private Dictionary<int, int> m_propsDic = new Dictionary<int, int>();
public Dictionary<int, int> propsDic
{
get { return m_propsDic; }
}
/// <summary>
/// 单例模式
/// </summary>
private static BackPackMgr s_instance;
public static BackPackMgr Instance
{
get
{
if (null == s_instance)
s_instance = new BackPackMgr();
return s_instance;
}
}
}
例:增加一个id
为1
的道具(逗猫棒)
// 增加一个逗猫棒道具
BackPackMgr.Instance.ChangePropCnt(1, 1);
12.12 事件管理器
上面背包管理器中用到了事件管理器,当道具数量发生改变的时候,要通知界面ui
更新显示。使用观察者模式,通过事件订阅的方式实现道具数量更新时同步更新ui
的显示。
事件管理器如下
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// 事件委托
/// </summary>
public delegate void MyEventHandler(params object[] objs);
/// <summary>
/// 事件管理器
/// </summary>
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;
}
}
}
例:事件订阅
// 事件订阅
EventDispatcher.Instance.Regist("EVENT_UPDATE_PROP_CNT", OnEventUpdatePropCnt);
// 注销事件订阅
EventDispatcher.Instance.UnRegist("EVENT_UPDATE_PROP_CNT", OnEventUpdatePropCnt);
抛出事件
EventDispatcher.Instance.DispatchEvent("EVENT_UPDATE_PROP_CNT", id, cnt);
响应函数
private void OnEventUpdatePropCnt(params object[] args)
{
int id = (int)args[0];
int cnt = (int)args[1];
}
12.13 界面代码
12.13.1 大厅界面
大厅界面主要是两个按钮,一个按钮点击了随机增加一个道具,另一个按钮点击了打开背包界面。
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 大厅界面
/// </summary>
public class PlazaPanel : MonoBehaviour
{
public Button packpackBtn;
public Button addPropBtn;
void Start()
{
// 背包按钮
packpackBtn.onClick.AddListener(() =>
{
PanelMgr.Instance.ShowPanel(PanelName.BackpackPanel);
});
// 加道具按钮
addPropBtn.onClick.AddListener(() => {
// 随机加一个道具
var propId = Random.Range(1, 8);
BackPackMgr.Instance.ChangePropCnt(propId, 1);
var cfg = PropCfg.Instance.GetCfg(propId);
TipsUi.Show("恭喜获得" + cfg.name + "x1");
});
}
}
12.13.2 背包界面
背包界面稍复杂一点点,界面左边用一个Scroll View
用来显示道具列表,选中某个道具,界面右边显示道具信息,点击使用按钮,扣除一个道具。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class BackpackPanel : MonoBehaviour
{
private void Awake()
{
// 订阅事件
EventDispatcher.Instance.Regist(EventNameDef.EVENT_UPDATE_PROP_CNT, OnEventUpdatePropCnt);
}
private void OnDestroy()
{
// 注销事件
EventDispatcher.Instance.UnRegist(EventNameDef.EVENT_UPDATE_PROP_CNT, OnEventUpdatePropCnt);
}
private void Start()
{
propItemUi.SetActive(false);
// 关闭按钮
closeBtn.onClick.AddListener(() =>
{
Destroy(gameObject);
});
// 使用道具按钮
usePropBtn.onClick.AddListener(() =>
{
if (-1 == m_selectPropId) return;
var cfg = PropCfg.Instance.GetCfg(m_selectPropId);
TipsUi.Show("使用了" + cfg.name);
BackPackMgr.Instance.ChangePropCnt(m_selectPropId, -1);
});
// 创建道具列表
CreatePropList();
}
/// <summary>
/// 道具数量发生变化
/// </summary>
/// <param name="args"></param>
private void OnEventUpdatePropCnt(params object[] args)
{
int id = (int)args[0];
int cnt = (int)args[1];
if (cnt <= 0)
{
if (m_propUiDic.ContainsKey(id))
{
Destroy(m_propUiDic[id].obj);
m_propUiDic.Remove(id);
if (id == m_selectPropId)
AutoSelectOneProp();
}
}
else
{
if (m_propUiDic.ContainsKey(id))
{
m_propUiDic[id].cnt.text = "x" + cnt;
}
else
{
CreatePropItem(id, cnt);
}
}
}
/// <summary>
/// 创建道具列表
/// </summary>
private void CreatePropList()
{
foreach (var item in BackPackMgr.Instance.propsDic)
{
CreatePropItem(item.Key, item.Value);
}
// 自动选择一个道具
AutoSelectOneProp();
}
/// <summary>
/// 自动选择一个道具
/// </summary>
private void AutoSelectOneProp()
{
var itor = m_propUiDic.GetEnumerator();
if (itor.MoveNext())
{
var item = itor.Current.Value;
item.tgl.isOn = true;
itor.Dispose();
OnPropItemSelected(item.propId);
}
else
{
OnPropItemSelected(-1);
}
}
/// <summary>
/// 创建一个道具item
/// </summary>
/// <param name="propId">道具id</param>
/// <param name="cnt">道具数量</param>
private void CreatePropItem(int propId, int cnt)
{
if (m_propUiDic.ContainsKey(propId)) return;
if (cnt <= 0) return;
PropItemUI ui = new PropItemUI();
var obj = Instantiate(propItemUi);
obj.SetActive(true);
obj.transform.SetParent(propItemUi.transform.parent, false);
ui.obj = obj;
ui.propId = propId;
ui.icon = obj.transform.Find("Button/Icon").GetComponent<Image>();
ui.cnt = obj.transform.Find("Button/Cnt").GetComponent<Text>();
ui.tgl = obj.transform.Find("Button").GetComponent<Toggle>();
ui.tgl.onValueChanged.AddListener((v) =>
{
if (ui.tgl.isOn) OnPropItemSelected(propId);
});
var cfg = PropCfg.Instance.GetCfg(propId);
if (null != cfg)
{
var sprite = ResourceMgr.Instance.LoadSprite(cfg.sprite);
ui.icon.sprite = sprite;
//ui.icon.SetNativeSize();
}
ui.cnt.text = "x" + cnt;
m_propUiDic[propId] = ui;
}
/// <summary>
/// 道具被选中
/// </summary>
/// <param name="propId"></param>
private void OnPropItemSelected(int propId)
{
m_selectPropId = propId;
if (-1 == m_selectPropId)
{
// 没有道具被选中
rightInfoRoot.SetActive(false);
}
else
{
rightInfoRoot.SetActive(true);
var cfg = PropCfg.Instance.GetCfg(propId);
nameText.text = cfg.name;
descText.text = cfg.desc;
icon.sprite = ResourceMgr.Instance.LoadSprite(cfg.sprite);
}
}
public Button closeBtn;
public GameObject propItemUi;
public GameObject rightInfoRoot;
public Text nameText;
public Text descText;
public Image icon;
public Button usePropBtn;
private int m_selectPropId;
/// <summary>
/// 道具列表ui缓存
/// </summary>
private Dictionary<int, PropItemUI> m_propUiDic = new Dictionary<int, PropItemUI>();
private class PropItemUI
{
public int propId;
public GameObject obj;
public Image icon;
public Toggle tgl;
public Text cnt;
}
}
12.13.3 提示语UI
制作一个提示语UI的动画,动画播放结束后通过帧事件调用OnAnimationEnd
方法销毁自己。
TipsUi
组件挂在TipsUi.prefab
上。
using UnityEngine;
using UnityEngine.UI;
public class TipsUi : MonoBehaviour
{
public Text tipsText;
/// <summary>
/// 显示提示语
/// </summary>
/// <param name="text"></param>
public static void Show(string text)
{
var obj = PanelMgr.Instance.ShowPanel(PanelName.TipsUi);
var bhv = obj.GetComponent<TipsUi>();
bhv.tipsText.text = text;
}
/// <summary>
/// 动画结束,销毁自己
/// </summary>
public void OnAnimationEnd()
{
Destroy(gameObject);
}
}
12.14 程序入口脚本
写一个程序入口脚本,挂到Canvas
上,并赋值Canvas
对象。
using UnityEngine;
public class UIMain : MonoBehaviour
{
public Canvas canvas;
// 执行初始化
private void Awake()
{
PropCfg.Instance.LoadCfg();
BackPackMgr.Instance.Init();
PanelMgr.Instance.Init(canvas);
}
void Start()
{
// 显示大厅界面
PanelMgr.Instance.ShowPanel(PanelName.PlazaPanel);
}
}
完成。
如果有什么疑问,欢迎留言或私信。