UGUI新手引导开发
来源:互联网 发布:乔约翰逊生涯数据 编辑:程序博客网 时间:2024/05/18 00:46
转自:
http://blog.csdn.net/lyh916/article/details/50878799,请点击链接查看原文,尊重楼主版权。
效果图:
对于新手引导,主要分两种做法:需要使用shader的和不需要shader的,这里介绍的是后者
1.屏蔽点击
假如ImageA在ImageB前面,且ImageA完全覆盖ImageB,点击两者的重叠部分,ImageA会收到点击事件,而ImageB不会。对于UGUI来说,就是将一张灰色半透明图放到最前面了
2.目标UI高亮
这里有三种做法:
a.调整目标UI的Hierarchy层级
b.克隆目标UI,调整克隆UI的Hierarchy层级
c.使用Canvas + Graphic Raycaster
这里本人选择的是第三种,因为第一种会破坏原有的的层级,第二种的话,如果目标UI本身没有绑定Mono脚本,则需要复制事件,不太好
需要注意的是,上面三种做法都是会增加drawcall的。
案例为UGUI,Canvas画布下,有几个按钮,画布上挂着Canvas.cs脚本,MonoSingletionRoot下挂着GuideManager.cs脚本。
先看Canvas1.cs:
using UnityEngine;public class Canvas1 : MonoBehaviour { void Awake() { EventTriggerListener.GetListener(UIManager.Instance.Find("Button")).onPointerClick += (go) => { UIManager.Instance.Show("EquipPanel"); }; EventTriggerListener.GetListener(UIManager.Instance.Find("Button (1)")).onPointerClick += (go) => { UIManager.Instance.Show("BagPanel"); }; EventTriggerListener.GetListener(UIManager.Instance.Find("Button (2)")).onPointerClick += (go) => { GuideManager.Instance.Next(); }; EventTriggerListener.GetListener(UIManager.Instance.Find("Button (3)")).onPointerClick += (go) => { GuideManager.Instance.Next(); }; GuideManager.Instance.Init(); //初始化引导管理器 }}这个脚本在一开始给场景中几个物体赋予了点击事件,前两个按钮是显示两个界面,后两个是走引导步骤。
这里用到了GuideManager类,我们再来看看这个脚本写了啥:
using UnityEngine;using System.Collections;using UnityEngine.UI;using System;public class GuideManager : MonoSingletion<GuideManager> { //单例 private Transform maskTra;//半透黑遮罩UI private string fileDir = "GuideFile/";//Resource文件夹下引导配置文件夹 private string nowCsvFile;//目前进行的引导配置文件 private int nowIndex; //目前索引 private bool isFinish = false;//是否完成所有的新手引导 private string[] nameArray; //配置的引导组件路径 public void Init() { //读取进度 string content = Resources.Load<TextAsset>(fileDir + "GuideProgress").ToString(); //Guide1,0,FALSE string[] temp = content.Split(','); nowCsvFile = temp[0];//读取目前进行的引导配置文件名 nowIndex = int.Parse(temp[1]);//读取目前索引 isFinish = bool.Parse(temp[2]);//读取是否结束 //读取需要高亮的组件的Hierarchy路径 if (!isFinish) { string s = Resources.Load<TextAsset>(fileDir + nowCsvFile).ToString();//配置文件内容 nameArray = s.Split(new string[] { "\r\n" }, System.StringSplitOptions.RemoveEmptyEntries); } } void OnDestroy() { //退出游戏后的处理 Debug.Log("OnDestroy"); } /// <summary> /// 按步骤一个一个强引 /// </summary> public void Next() { if (nowIndex < nameArray.Length) { ShowHightLight(nameArray[nowIndex]);//高亮显示组件 nowIndex++; } else//加载下一个文件 { maskTra.gameObject.SetActive(false); int index = int.Parse(nowCsvFile.Substring(nowCsvFile.Length - 1)); index++; nowCsvFile = nowCsvFile.Substring(0, nowCsvFile.Length - 1) + index.ToString(); string path = fileDir + nowCsvFile; string content = null; try { content = Resources.Load<TextAsset>(path).ToString(); } catch (Exception e) { isFinish = true; Debug.Log("finish"); return; } nowIndex = 0; nameArray = content.Split(new string[] { "\r\n" }, System.StringSplitOptions.RemoveEmptyEntries); } } /// <summary> /// 高亮显示组建 /// </summary> void ShowHightLight(string name) { StartCoroutine(FindUI(name)); } /// <summary> /// 取消高亮显示组件 /// </summary> void CancelHightLight(GameObject go) { Destroy(go.GetComponent<GraphicRaycaster>()); Destroy(go.GetComponent<Canvas>()); Next(); EventTriggerListener.GetListener(go).onPointerClick -= CancelHightLight; } /// <summary> /// 在画布下寻找制定UI /// </summary> IEnumerator FindUI(string name) { //寻找目标 GameObject go = UIManager.Instance.Find(name); while(go == null) { yield return new WaitForSeconds(0.1f); Debug.Log("wait"); go = UIManager.Instance.Find(name); } //高亮 maskTra = UIManager.Instance.Show("Mask").transform; maskTra.SetAsLastSibling(); go.AddComponent<Canvas>().overrideSorting = true; go.AddComponent<GraphicRaycaster>(); //设置监听 EventTriggerListener.GetListener(go).onPointerClick += CancelHightLight; }}代码和注释都很清晰,总之就是把要引导的物体高亮显示(调整层级在遮罩前面)和点击引导高亮显示下一引导,走到下一步引导并移除上一按钮的引导事件。
还有,额外打开的界面上也有脚本设置了按钮的事件:
public class Panel1 : MonoBehaviour {void Start () { EventTriggerListener.GetListener(transform.Find("Button").gameObject).onPointerClick += (go) => { gameObject.SetActive(false); }; EventTriggerListener.GetListener(transform.Find("Button (1)").gameObject).onPointerClick += (go) => { Debug.Log("装上"); }; EventTriggerListener.GetListener(transform.Find("Button (2)").gameObject).onPointerClick += (go) => { Debug.Log("卸下"); }; EventTriggerListener.GetListener(transform.Find("Image/Button").gameObject).onPointerClick += (go) => { Debug.Log("查看属性"); };}}Guide1配置文件类似如下的配置方式:
ButtonEquipPanel/Button (1)EquipPanel/Button (2)EquipPanel/Image/ButtonEquipPanel/Button
下面讲解一下这个配置文件的生成方式:
首先是每组数据都要记录高亮的物体个在Canvas下路径:
所以我们写一个脚本并序列化:
[Serializable]public class GuideUI{ public GameObject go; public string hierarchyPath; public GuideUI(GameObject go, string hierarchyPath) { this.go = go; this.hierarchyPath = hierarchyPath; }}public class MakeGuide : MonoBehaviour { public List<GuideUI> guideList = new List<GuideUI>();//引导的组件数据}然后我们写个工具来生成配置文件:
using UnityEngine;using System.Collections;using UnityEditor;using System.Collections.Generic;using System.IO;[CustomEditor(typeof(MakeGuide))][ExecuteInEditMode] public class MakeGuideEditor : Editor { string filePath;//文件路径 public override void OnInspectorGUI() { base.OnInspectorGUI(); if (Event.current.type == EventType.DragExited) { UpdatePath(); } EditorGUILayout.LabelField("----------------------------------------------------------"); EditorGUILayout.LabelField("文件路径:"); EditorGUILayout.TextField(filePath); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("清空路径")) { filePath = ""; } if (GUILayout.Button("读取文件(.csv)")) { Load(); } if (GUILayout.Button("保存")) { Save(); } EditorGUILayout.EndHorizontal(); } string hierarchyPath;//场景中物体路径 string GetHierarchyPath(Transform t, bool initPath = true) //获取物体路径 { if (initPath) hierarchyPath = ""; hierarchyPath = t.name + hierarchyPath; if (t.parent.name != "Canvas") { Transform parent = t.parent; hierarchyPath = "/" + hierarchyPath; GetHierarchyPath(parent, false); } return hierarchyPath; } void UpdatePath()//拖拽一个物体到这里后更新物体的Hierarchy路径 { MakeGuide makeGuide = (MakeGuide)target; List<GuideUI> guideList = makeGuide.guideList; foreach (GuideUI guideUI in guideList) { if (guideUI.go != null) { guideUI.hierarchyPath = GetHierarchyPath(guideUI.go.transform); } } } void Load() { filePath = EditorUtility.OpenFilePanel("读取文件(.csv)", Application.dataPath, "csv"); string content = File.ReadAllText(filePath); string[] paths = content.Split(new string[] { "\r\n" }, System.StringSplitOptions.RemoveEmptyEntries); MakeGuide makeGuide = (MakeGuide)target; makeGuide.guideList = new List<GuideUI>(); Transform canvasTra = GameObject.Find("Canvas").transform; foreach(string path in paths) { GameObject go = canvasTra.Find(path).gameObject; makeGuide.guideList.Add(new GuideUI(go, path)); } } void Save() { if (string.IsNullOrEmpty(filePath))//创建一个新文件并保存 { string path = EditorUtility.SaveFilePanel("Save", Application.dataPath, "", "csv"); File.WriteAllText(path, GetInspectorInfo()); } else//直接保存在读取的文件 { File.WriteAllText(filePath, GetInspectorInfo()); } AssetDatabase.Refresh(); Debug.Log("保存成功"); } string GetInspectorInfo() { string content = ""; MakeGuide makeGuide = (MakeGuide)target; List<GuideUI> guideList = makeGuide.guideList; foreach (GuideUI guideUI in guideList) { if (guideUI.go != null) { content += guideUI.hierarchyPath + "\r\n"; } } return content; }}
得到这样的视图,然后把这个脚本MakeGuide脚本拖到场景物体上,我们就可以按照我们想要的引导的高亮顺序来显示UI了。
然后可以得到这样的文件,我们就可以根据配置文件在游戏运行时候设置引导了。
Button (2)EquipPanel/Button (1)EquipPanel/Button (2)EquipPanel/ImageGuideProgress文件为记录强引状态的文件,有服务器就可以在服务器记录了。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
另外补充本例用到的几个课外的脚本:
单例:
using UnityEngine;using System.Collections;public abstract class MonoSingletion<T> : MonoBehaviour where T : MonoBehaviour { private static string rootName = "MonoSingletionRoot"; private static GameObject monoSingletionRoot; private static T instance; public static T Instance { get { if (monoSingletionRoot == null) { monoSingletionRoot = GameObject.Find(rootName); if (monoSingletionRoot == null) Debug.Log("please create a gameobject named " + rootName); } if (instance == null) { instance = monoSingletionRoot.GetComponent<T>(); if (instance == null) instance = monoSingletionRoot.AddComponent<T>(); } return instance; } }}
public abstract class CSharpSingletion<T> where T : new() { private static T instance; public static T Instance { get { if (instance == null) { instance = new T(); } return instance; } }}UI管理器:
using UnityEngine;using System.Collections;using System.Collections.Generic;public class UIManager : MonoSingletion<UIManager> { public Transform canvasTra; private Dictionary<string, GameObject> nameGoDir = new Dictionary<string, GameObject>(); void Init() { if (canvasTra == null) canvasTra = GameObject.Find("Canvas").transform; } public void Clear() { nameGoDir.Clear(); } public GameObject Find(string name) { Init(); Transform t = canvasTra.Find(name); if(t == null) return null; else return t.gameObject; } public GameObject Show(string name) { if (!nameGoDir.ContainsKey(name)) { GameObject go = Instantiate<GameObject>(Resources.Load<GameObject>(name)); go.name = name; go.transform.SetParent(canvasTra, false); nameGoDir.Add(name, go); } else { nameGoDir[name].SetActive(true); } return nameGoDir[name]; }}
这是unitypackage:
http://pan.baidu.com/s/1bA4dQ2
- UGUI新手引导开发
- UGUI新手引导开发(二、引导用ScriptableObject配置)
- [UnityUI]UGUI新手引导
- UGUI新手引导
- UGUI新手引导系统
- [Unity3D]UGUI 新手引导遮罩控件
- UGUI强制新手引导制作方案
- [Unity3D]UGUI 新手引导遮罩控件
- UGUI之新手引导事件上下分离
- UGUI研究院之新手引导事件上下分离
- Unity3D新手引导开发手记
- Unity3D新手引导开发手记
- Unity3D新手引导开发手记
- 新手引导
- 新手引导
- 新手引导
- 新手引导
- UGUI 实现引导
- 斗鱼弹幕助手授权验证相关
- Rectangles
- 每日三题-Day6-A(FZU 2214 Knapsack problem 01背包)
- Hibernate对象关系映射-- 多对多关联关系映射
- hdfs文件操作命令
- UGUI新手引导开发
- 同余定理
- I am new to Maven so please excuse any of my ignorance
- 三角形数字路径最大值问题
- 静态链表的实现
- java类加载机制
- 绝对路径与相对路径
- bzoj1444: [Jsoi2009]有趣的游戏
- DFS 做背包问题