您当前的位置: 首页 >  unity

鱼儿-1226

暂无认证

  • 2浏览

    0关注

    1100博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

基于Unity~UGUI的简单UI框架(附UIFramework源码)

鱼儿-1226 发布时间:2022-03-18 14:50:09 ,浏览量:2

文章目录 不使用UI框架存在的一些问题 UI框架总揽: 创建测试面板(非框架部分) 创建json文件和UIPanelType类来保存所有的面板信息 开发UIManger来解析面板信息json文件(框架核心:UIManager) 开发BasePanel抽象类(各个UIPanel的基类) 对UI面板Prefab实例化的创建与管理 开发界面存储栈,并进行出栈和入栈操作 控制Panel之间的跳转(非框架部分) UI框架(完结) 赞赏与支持

框架源码地址: UIFramework litjson.dll下载地址: litjson 不使用UI框架存在的一些问题 1.随着游戏系统的复杂,UI控件越来越多,各个UI直接的通讯,以及UI与GameObject之间的通讯形成一张复杂的蜘蛛网, 拖着拖着,有时候我都忘了哪个对象跟哪个对象关联了。如果是别人要看我的程序,我估计他找半天都找不到UI逻辑的入口。 2.耦合性非常严重,如果要改变需求,更改某个UI或者更改某个游戏对象,那么你需要再手动全部与该对象关联的物件重新更改一次。 3.作为强迫症的程序员,最受不了程序代码的混乱。这种组织方式十分“不优雅”,看着很乱。 鉴于以上各种情况,我们需要寻找一种新的,科学的,高效的UI管理方式

UI框架总揽:

创建测试面板(非框架部分) 将面板以Prefab形式放入Resources文件夹下面,便于框架加载面板

创建json文件和UIPanelType类来保存所有的面板信息 UIPanelType.json:

{     "panelInfoList":     [         {"panelType":"MainMenu","path":"UIPanel/MainMenuPanel"},         {"panelType":"ItemMessage","path":"UIPanel/ItemMessagePanel"},         {"panelType":"Knapsack","path":"UIPanel/KnapsackPanel"},         {"panelType":"Shop","path":"UIPanel/ShopPanel"},         {"panelType":"Skill","path":"UIPanel/SkillPanel"},         {"panelType":"System","path":"UIPanel/SystemPanel"},         {"panelType":"Task","path":"UIPanel/TaskPanel"}     ] } 1 2 3 4 5 6 7 8 9 10 11 12 UIPanelType.cs:

public class UIPanelType {     public const string MainMenu = "MainMenu";     public const string Knapsack = "Knapsack";     public const string ItemMessage = "ItemMessage";     public const string Shop = "Shop";     public const string Skill = "Skill";     public const string System = "System";     public const string Task = "Task"; }

1 2 3 4 5 6 7 8 9 10 开发UIManger来解析面板信息json文件(框架核心:UIManager) UIManager为框架的核心,全局只有一个UIManager,因此UIManager要使用单例模式 现阶段的完整的UIManager.cs(后续还会继续完善):

using System.Collections.Generic; using System.Collections; using System; using UnityEngine; using LitJson; public class UIPanelManager {     private static UIPanelManager _instance;

    public static UIPanelManager Instance     {         get         {             if (_instance == null)             {                 _instance = new UIPanelManager();             }             return _instance;         }     }

    private Dictionary panelPathDict;     //private Dictionary     //private Stack

    private UIPanelManager()     {         ParseUIPanelTypeJson();     }

    private void ParseUIPanelTypeJson()     {         panelPathDict = new Dictionary();         TextAsset textUIPanelType = Resources.Load("UIPanelTypeJson");         UIPanelInfoList panelInfoList = JsonMapper.ToObject(textUIPanelType.text);

        foreach (UIPanelInfo panelInfo in panelInfoList.panelInfoList)         {             panelPathDict.Add(panelInfo.panelType, panelInfo.path);             Debug.Log(panelInfo.panelType + ":" + panelInfo.path);         }     } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 开发BasePanel抽象类(各个UIPanel的基类) BasePanel给每个Panel定义了四个事件: OnEnter:面板进入时调用 OnPause:面板停止时调用(鼠标与面板的交互停止) OnResume:面板恢复使用时调用(鼠标与面板的交互恢复) OnExit:面板退出时调用

using UnityEngine;

public abstract class BasePanel : MonoBehaviour {     public abstract void OnEnter();

    public abstract void OnPause();

    public abstract void OnResume();

    public abstract void OnExit();

} 1 2 3 4 5 6 7 8 9 10 11 12 13 给各个面板添加UIPanel类(非框架部分)

using UnityEngine;

public class MainMenuPanel : BasePanel {

    public override void OnEnter()     {     }

    public override void OnPause()     {     }

    public override void OnResume()     {     }

    public override void OnExit()     {     } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 对UI面板Prefab实例化的创建与管理 获取Panel(如果panel没有被实例化,进行实例化,并且存储到已经实例化好的panel字典中)

private BasePanel GetPanel(string panelType)     {         BasePanel panel = panelDict.GetValue(panelType);

        //如果没有实例化面板,寻找路径进行实例化,并且存储到已经实例化好的字典面板中         if (panel == null)         {             string path = panelPathDict.GetValue(panelType);             Transform panelTransform = GameObject.Instantiate(Resources.Load(path), canvasTransform).transform;             panel = panelTransform.GetComponent();             panelDict.Add(panelType, panel);         }         return panel;     } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 字典的扩展:

using System.Collections.Generic;

public static class DictTool {     public static Tvalue GetValue(this Dictionary dict, Tkey key)     {         Tvalue value = default(Tvalue);         dict.TryGetValue(key, out value);         return value;     } }

1 2 3 4 5 6 7 8 9 10 11 12 现阶段的完整的UIManager.cs(后续还会继续完善):

using System.Collections.Generic; using System.Collections; using System; using UnityEngine; using LitJson; public class UIPanelManager {     private static UIPanelManager _instance;     private Transform canvasTransform;     private Transform CanvasTransform     {         get         {             if (canvasTransform == null)             {                 canvasTransform = GameObject.Find("Canvas").transform;             }             return canvasTransform;         }     }     public static UIPanelManager Instance     {         get         {             if (_instance == null)             {                 _instance = new UIPanelManager();             }

            return _instance;         }     }

    private Dictionary panelPathDict;     private Dictionary panelDict;     //private Stack

    private UIPanelManager()     {         ParseUIPanelTypeJson();     }

    private BasePanel GetPanel(string panelType)     {

        if (panelDict == null)         {             panelDict = new Dictionary();         }

        BasePanel panel = panelDict.GetValue(panelType);

        //如果没有实例化面板,寻找路径进行实例化,并且存储到已经实例化好的字典面板中         if (panel == null)         {             string path = panelPathDict.GetValue(panelType);             GameObject panelGo = GameObject.Instantiate(Resources.Load(path), CanvasTransform, false);             panel = panelGo.GetComponent();             panelDict.Add(panelType, panel);         }         return panel;     }

    //解析json文件     private void ParseUIPanelTypeJson()     {         panelPathDict = new Dictionary();         TextAsset textUIPanelType = Resources.Load("UIPanelTypeJson");         UIPanelInfoList panelInfoList = JsonMapper.ToObject(textUIPanelType.text);

        foreach (UIPanelInfo panelInfo in panelInfoList.panelInfoList)         {             panelPathDict.Add(panelInfo.panelType, panelInfo.path);             //Debug.Log(panelInfo.panelType + ":" + panelInfo.path);         }     } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 开发界面存储栈,并进行出栈和入栈操作 【设计理念】 1.鼠标只允许和一个界面进行交互,当一个界面显示后,上一个界面要停止和鼠标的交互 2.界面显示,进行入栈操作(Push,OnEnter),停止上一个界面(OnPause) 3.界面隐藏,进行出栈操作(Pop,OnExit),恢复上一个界面(OnResume)

 private Stack panelStack;     public void PushPanel(string panelType)     {         if (panelStack == null)         {             panelStack = new Stack();         }

        //停止上一个界面         if (panelStack.Count > 0)         {             BasePanel topPanel = panelStack.Peek();             topPanel.OnPause();         }

        BasePanel panel = GetPanel(panelType);         panelStack.Push(panel);         panel.OnEnter();     }

    public void PopPanel()     {         if (panelStack == null)         {             panelStack = new Stack();         }         if (panelStack.Count 0)         {             BasePanel panel = panelStack.Peek();             panel.OnResume();         }

    } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 控制Panel之间的跳转(非框架部分) 完善面板中的一些操作,实现面板之间的跳转,此部分不是框架部分,省略! MainMenuPanel.cs:

using UnityEngine; using UnityEngine.UI;

public class MainMenuPanel : BasePanel {     private Button TaskButton;     private Button KnapsackButton;     private Button SkillButton;     private Button ShopButton;     private Button SystemButton;     private CanvasGroup canvasGroup;     void Awake()     {         TaskButton = transform.Find("IconPanel/TaskButton").GetComponent();         KnapsackButton = transform.Find("IconPanel/KnapsackButton").GetComponent();         SkillButton = transform.Find("IconPanel/SkillButton").GetComponent();         ShopButton = transform.Find("IconPanel/ShopButton").GetComponent();         SystemButton = transform.Find("IconPanel/SystemButton").GetComponent();         canvasGroup = transform.GetComponent();

        TaskButton.onClick.AddListener(OnTaskButtonClick);         KnapsackButton.onClick.AddListener(OnKnapsackButtonClick);         SkillButton.onClick.AddListener(OnSkillButtonClick);         ShopButton.onClick.AddListener(OnShopButtonClick);         SystemButton.onClick.AddListener(OnSystemButtonClick);     }

    void OnDestory()     {         TaskButton.onClick.RemoveListener(OnTaskButtonClick);         KnapsackButton.onClick.RemoveListener(OnKnapsackButtonClick);         SkillButton.onClick.RemoveListener(OnSkillButtonClick);         ShopButton.onClick.RemoveListener(OnShopButtonClick);         SystemButton.onClick.RemoveListener(OnSystemButtonClick);     }     public override void OnEnter()     {     }

    public override void OnPause()     {         canvasGroup.blocksRaycasts = false;     }

    public override void OnResume()     {         canvasGroup.blocksRaycasts = true;     }

    public override void OnExit()     {     }

    private void OnTaskButtonClick()     {         UIPanelManager.Instance.PushPanel(UIPanelType.Task);     }     private void OnKnapsackButtonClick()     {         UIPanelManager.Instance.PushPanel(UIPanelType.Knapsack);     }     private void OnSkillButtonClick()     {         UIPanelManager.Instance.PushPanel(UIPanelType.Skill);     }     private void OnShopButtonClick()     {         UIPanelManager.Instance.PushPanel(UIPanelType.Shop);     }     private void OnSystemButtonClick()     {         UIPanelManager.Instance.PushPanel(UIPanelType.System);     } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 UI框架(完结)

【BasePanel(基类):所有面板继承自BasePanel】 定义了四个事件: OnEnter:面板进入时调用 OnPause:面板停止时调用(鼠标与面板的交互停止) OnResume:面板恢复使用时调用(鼠标与面板的交互恢复) OnExit:面板退出时调用

using UnityEngine;

public abstract class BasePanel : MonoBehaviour {     public abstract void OnEnter();     public abstract void OnPause();     public abstract void OnResume();     public abstract void OnExit();

}

1 2 3 4 5 6 7 8 9 10 11 【GameRoot】 实例化游戏中的主面板

using System.Collections; using System.Collections.Generic; using UnityEngine; using System;

public class GameRoot : MonoBehaviour {     void Start () {         UIPanelManager panelManager = UIPanelManager.Instance;         panelManager.PushPanel(UIPanelType.MainMenu);     } }

1 2 3 4 5 6 7 8 9 10 11 12 【UIPanelManager(框架的核心,单例)】 进行解析面板信息json文件,实例化面板Prefab,面板的入栈和出栈等等一系列操作

using System.Collections.Generic; using System.Collections; using System; using UnityEngine; using LitJson; public class UIPanelManager {     private static UIPanelManager _instance;     private Transform canvasTransform;     private Transform CanvasTransform     {         get         {             if (canvasTransform == null)             {                 canvasTransform = GameObject.Find("Canvas").transform;             }             return canvasTransform;         }     }     public static UIPanelManager Instance     {         get         {             if (_instance == null)             {                 _instance = new UIPanelManager();             }

            return _instance;         }     }

    private Dictionary panelPathDict;     private Dictionary panelDict;     private Stack panelStack;

    private UIPanelManager()     {         ParseUIPanelTypeJson();     }

    public void PushPanel(string panelType)     {         if (panelStack == null)         {             panelStack = new Stack();         }

        //停止上一个界面         if (panelStack.Count > 0)         {             BasePanel topPanel = panelStack.Peek();             topPanel.OnPause();         }

        BasePanel panel = GetPanel(panelType);         panelStack.Push(panel);         panel.OnEnter();     }

    public void PopPanel()     {         if (panelStack == null)         {             panelStack = new Stack();         }         if (panelStack.Count 0)         {             BasePanel panel = panelStack.Peek();             panel.OnResume();         }

    }

    private BasePanel GetPanel(string panelType)     {

        if (panelDict == null)         {             panelDict = new Dictionary();         }

        BasePanel panel = panelDict.GetValue(panelType);

        //如果没有实例化面板,寻找路径进行实例化,并且存储到已经实例化好的字典面板中         if (panel == null)         {             string path = panelPathDict.GetValue(panelType);             GameObject panelGo = GameObject.Instantiate(Resources.Load(path), CanvasTransform, false);             panel = panelGo.GetComponent();             panelDict.Add(panelType, panel);         }         return panel;     }

    //解析json文件     private void ParseUIPanelTypeJson()     {         panelPathDict = new Dictionary();         TextAsset textUIPanelType = Resources.Load("UIPanelTypeJson");         UIPanelInfoList panelInfoList = JsonMapper.ToObject(textUIPanelType.text);

        foreach (UIPanelInfo panelInfo in panelInfoList.panelInfoList)         {             panelPathDict.Add(panelInfo.panelType, panelInfo.path);             //Debug.Log(panelInfo.panelType + ":" + panelInfo.path);         }     } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 【litjson】 json文件解析的工具

【UIPanelTypeJson(保存面板信息的json文件)】 1.此文件需要加载,保存到Resources文件下 2.保存了面板的类型(相当于名称)和面板Prefab的路径(实例化面板时要用到) 3.每添加一个面板,都要在此文件添加该面板对应的信息

{     "panelInfoList":     [         {"panelType":"MainMenu","path":"UIPanel/MainMenuPanel"},         {"panelType":"ItemMessage","path":"UIPanel/ItemMessagePanel"},         {"panelType":"Knapsack","path":"UIPanel/KnapsackPanel"},         {"panelType":"Shop","path":"UIPanel/ShopPanel"},         {"panelType":"Skill","path":"UIPanel/SkillPanel"},         {"panelType":"System","path":"UIPanel/SystemPanel"},         {"panelType":"Task","path":"UIPanel/TaskPanel"}     ] } 1 2 3 4 5 6 7 8 9 10 11 12 【DictTool】 Dictionnary的拓展工具类

using System.Collections.Generic;

public static class DictTool {     public static Tvalue GetValue(this Dictionary dict, Tkey key)     {         Tvalue value = default(Tvalue);         dict.TryGetValue(key, out value);         return value;     } }

1 2 3 4 5 6 7 8 9 10 11 12 【UIPanelInfo(面板的信息类)】 包括面板的名称和面板Prefab的路径 用于和json文件进行映射

using System; [Serializable] public class UIPanelInfo {     public string panelType;     public string path;

    public UIPanelInfo()     {

    } }

1 2 3 4 5 6 7 8 9 10 11 12 13 【UIPanelInfoList(面板信息集合类)】 用于和json文件进行映射

using System; using System.Collections.Generic;

[Serializable] public class UIPanelInfoList {     public List panelInfoList;

    public UIPanelInfoList() { } }

1 2 3 4 5 6 7 8 9 10 11 【UIPanelType(面板的类型)】 用来记录面板的类型(名称) 每添加一个面板都要在此类里面添加对应面板的类型

public class UIPanelType {     public const string MainMenu = "MainMenu";     public const string Knapsack = "Knapsack";     public const string ItemMessage = "ItemMessage";     public const string Shop = "Shop";     public const string Skill = "Skill";     public const string System = "System";     public const string Task = "Task"; }

1 2 3 4 5 6 7 8 9 10

———————————————— 版权声明:本文为CSDN博主「cchoop」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_34937637/article/details/80374387

关注
打赏
1604459285
查看更多评论
立即登录/注册

微信扫码登录

0.6160s