Unity开发——UGUI框架搭建

本文档介绍了如何使用Unity 2021.1.14版本的UGUI进行UI框架的搭建,包括UIType、BasePanel、UIManager、PanelManager等核心类的实现,以及如何解决资源路径问题和MissingReferenceException。
摘要由CSDN通过智能技术生成

Unity:2021.1.14flc1
在B站跟着视频
[Unity编程]这大概是最好理解的UI框架了吧
搭建的一个UGUI的框架,处理了一些小问题,参考MissingReferenceException: The object of type ‘GameObject‘ has been destroye
整个框架分层比较乱,而且实际运行的话要根据你在unity工程里面具体的资源放置来修改代码里的资源路径,所以这里主要是给我自己做个记录

UIType.cs

/*
 存储单个UI的信息,包括名字和路径
 */
public class UIType
{
    public string Name { get; private set; }
    public string Path { get; private set; }

    public UIType(string path)
    {
        Path = path;
        Name = path.Substring(path.LastIndexOf('/') + 1);
    }
}

BasePanel.cs

/// <summary>
/// 所有UI面板的父类,包含UI面板的状态信息
/// </summary>
public class BasePanel
{
    /// <summary>
    /// UI信息
    /// </summary>
    public UIType UIType { get; private set; }
    /// <summary>
    /// UI管理工具
    /// </summary>
    public UITool UITool { get; private set; }
    /// <summary>
    /// 面板管理器
    /// </summary>
    public PanelManager PanelManager { get; private set; }
    /// <summary>
    /// UI管理器
    /// </summary>
    public UIManager UIManager { get; private set; }

    public BasePanel(UIType uiType)
    {
        UIType = uiType;
    }

    /// <summary>
    /// 初始化UITool
    /// </summary>
    /// <param name="tool"></param>
    public void Initialize(UITool tool)
    {
        UITool = tool;
    }

    /// <summary>
    /// 初始化面板管理器
    /// </summary>
    /// <param name="panelManager"></param>
    public void Initialize(PanelManager panelManager)
    {
        PanelManager = panelManager;
    }

    /// <summary>
    /// 初始化UI管理器
    /// </summary>
    /// <param name="uiManager"></param>
    public void Initialize(UIManager uiManager)
    {
        UIManager = uiManager;
    }
    /// <summary>
    /// UI进入操作
    /// </summary>
    public virtual void OnEnter() { }
    /// <summary>
    /// UI暂停操作
    /// </summary>
    public virtual void OnPause()
    {
        UITool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = false;
    }
    /// <summary>
    /// UI继续操作
    /// </summary>
    public virtual void OnResume()
    {
        UITool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = true;
    }
    /// <summary>
    /// UI退出操作
    /// </summary>
    public virtual void OnExit()
    {
        UIManager.DestroyUI(UIType);
    }
}

UIManager.cs

/// <summary>
/// //存储所有UI信息,并可以创建或者销毁UI
/// </summary>
public class UIManager
{

    /// <summary>
    /// 存储所有UI信息的字典,每一个UI信息都会对应一个GameObject
    /// </summary>
    private Dictionary<UIType, GameObject> dicUI;

    public UIManager()
    {
        dicUI = new Dictionary<UIType, GameObject>();
    }


    /// <summary>
    /// 获取一个UI对象
    /// </summary>
    /// <param name="type">UI信息</param>
    /// <returns></returns>
    public GameObject GetSingleUI(UIType type)
    {
        GameObject parent = GameObject.Find("Canvas");
        if (!parent)
        {
            Debug.LogError("Canvas不存在,请仔细查找有无这个对象!");
            return null;
        }
        if (dicUI.ContainsKey(type))
            return dicUI[type];
        GameObject ui = GameObject.Instantiate(Resources.Load<GameObject>(type.Path), parent.transform);
        ui.name = type.Name;
        dicUI.Add(type, ui);
        return ui;
    }

    /// <summary>
    /// 销毁一个对象
    /// </summary>
    /// <param name="type">UI信息</param>
    public void DestroyUI(UIType type)
    {
        if (dicUI.ContainsKey(type))
        {
            GameObject.Destroy(dicUI[type]);
            dicUI.Remove(type);
        }
    }
}

PanelManager.cs

/// <summary>
/// 面板管理器,用栈来存储UI
/// </summary>
public class PanelManager
{
    /// <summary>
    /// 存储UI面板的栈
    /// </summary>
    private Stack<BasePanel> stackPanel;

    /// <summary>
    /// UI管理器
    /// </summary>
    private UIManager uiManager;

    private BasePanel panel;

    public PanelManager()
    {
        stackPanel = new Stack<BasePanel>();
        uiManager = new UIManager();
    }

    /// <summary>
    /// UI的入栈操作,此操作会显示一个面板
    /// </summary>
    /// <param name="nextPanel">要显示的面板</param>
    public void Push(BasePanel nextPanel)
    {
        if (stackPanel.Count > 0)
        {
            stackPanel.Peek().OnPause();
        }
        stackPanel.Push(nextPanel);
        GameObject panelGo = uiManager.GetSingleUI(nextPanel.UIType);
        nextPanel.Initialize(new UITool(panelGo));
        nextPanel.Initialize(this);
        nextPanel.Initialize(uiManager);
        nextPanel.OnEnter();
    }

    /// <summary>
    /// UI的出栈操作
    /// </summary>
    public void Pop()
    {
        if (stackPanel.Count > 0)
            stackPanel.Pop().OnExit();
        if (stackPanel.Count > 0)
            stackPanel.Peek().OnResume();
    }

    /// <summary>
    /// 执行所有面板的OnExit()
    /// </summary>
    public void PopAll()
    {
        while (stackPanel.Count > 0)
        {
            stackPanel.Pop().OnExit();
        }
    }
}

MainPanel.cs

/// <summary>
/// Main场景的主面板
/// </summary>
public class MainPanel : BasePanel
{
    static readonly string path = "Prefabs/UI/Panel/MainPanel";

    public MainPanel() : base(new UIType(path)) { }

    public override void OnEnter()
    {
        UITool.GetOrAddComponentInChildren<Button>("Button").onClick.AddListener(() =>
        {
            GameRoot.Instance.SceneSystem.SetScene(new StartScene());
            PanelManager.Pop();
        });
    }
}

StartPanel.cs

/// <summary>
/// 开始主面板
/// </summary>
public class StartPanel : BasePanel
{
    static readonly string path = "Prefabs/UI/Panel/StartPanel 1";

    public StartPanel():base(new UIType(path)){ }

    public override void OnEnter()
    {
        UITool.GetOrAddComponentInChildren<Button>("Button").onClick.AddListener(() =>
        {
            //点击事件可以写在这里
            Debug.Log("按钮被点击了");
            PanelManager.Push(new SettingPanel());
        });
        UITool.GetOrAddComponentInChildren<Button>("Play Button").onClick.AddListener(() =>
        {
            //点击事件可以写在这里
            GameRoot.Instance.SceneSystem.SetScene(new MainScene());
/*            PanelManager.Pop();*/
        });
    }
}

UITool.cs

/// <summary>
/// UI管理工具,包括获取某个子对象组件的操作
/// </summary>
public class UITool
{
    /// <summary>
    /// 当前的活动面板
    /// </summary>
    GameObject activePanel;

    public UITool(GameObject gameObject)
    {
        activePanel = gameObject;
    }

    /// <summary>
    /// 给当前的活动面板获取或添加一个组件
    /// </summary>
    /// <typeparam name="T">组件类型</typeparam>
    /// <returns></returns>
    public T GetOrAddComponent<T>() where T : Component
    {
        if (activePanel.GetComponent<T>() == null)
            activePanel.AddComponent<T>();
        return activePanel.GetComponent<T>();
    }

    /// <summary>
    /// 根据名称查找一个子对象
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public GameObject FindChildGameObject(string name)
    {
        Transform[] trans = activePanel.GetComponentsInChildren<Transform>();

        foreach(Transform item in trans)
        {
            if (item.name == name)
            {
                return item.gameObject;
            }
        }

        Debug.LogWarning($"{activePanel.name}里找不到名为{name}的子对象");
        return null;
    }

    /// <summary>
    /// 根据名称获取一个子对象的组件
    /// </summary>
    /// <typeparam name="T">组件类型</typeparam>
    /// <param name="name">子对象的名称</param>
    /// <returns></returns>
    public T GetOrAddComponentInChildren<T>(string name) where T : Component
    {
        GameObject child = FindChildGameObject(name);
        if (child)
        {
            if (child.GetComponent<T>() == null)
                child.AddComponent<T>();

            return child.GetComponent<T>();
        }
        return null;
    }
}

SceneSystem.cs

/// <summary>
/// 场景的状态管理系统
/// </summary>
public class SceneSystem
{
    /// <summary>
    /// 场景状态类
    /// </summary>
    SceneState sceneState;

    /// <summary>
    /// 设置当前场景并进入当前场景
    /// </summary>
    /// <param name="state"></param>
    public void SetScene(SceneState state)
    {
        /*if (sceneState != null)
            sceneState.OnExit();
        sceneState = state;
        if (sceneState != null)
            sceneState.OnEnter();*/
        sceneState?.OnExit();
        Debug.Log("okOnExit" + state.ToString());
        sceneState = state;
        sceneState?.OnEnter();
        Debug.Log("okOnEnter" + state.ToString());
    }
}

SceneState.cs

public abstract class SceneState
{
    /// <summary>
    /// 场景进入时执行的操作
    /// </summary>
    public abstract void OnEnter();

    /// <summary>
    /// 场景退出时执行的操作
    /// </summary>
    public abstract void OnExit();
}

MainScene.cs

/// <summary>
/// Main场景
/// </summary>
public class MainScene : SceneState
{
    readonly string sceneName = "Main";
    PanelManager panelManager;

    public override void OnEnter()
    {
        Debug.Log("Main 的 OnEnter执行了");
        panelManager = new PanelManager();
        if (SceneManager.GetActiveScene().name != sceneName)
        {
            SceneManager.LoadScene(sceneName);
            SceneManager.sceneLoaded += SceneLoaded;
        }
        else
        {
            panelManager.Push(new StartPanel());
            GameRoot.Instance.SetActive(panelManager.Push);

        }
    }

    public override void OnExit()
    {
        SceneManager.sceneLoaded -= SceneLoaded;
        panelManager.PopAll();
    }

    /// <summary>
    /// 场景加载完毕之后执行的方法
    /// </summary>
    /// <param name="scene"></param>
    /// <param name="load"></param>
    private void SceneLoaded(Scene scene, LoadSceneMode load)
    {
        panelManager.Push(new MainPanel());
        GameRoot.Instance.SetActive(panelManager.Push);
        Debug.Log($"{sceneName}场景加载完毕!");
    }
}

StartScene.cs

/// <summary>
/// 开始场景
/// </summary>
public class StartScene : SceneState
{
    readonly string sceneName = "Start";
    PanelManager panelManager;

    public override void OnEnter()
    {
        panelManager = new PanelManager();
        if (SceneManager.GetActiveScene().name != sceneName)
        {
            SceneManager.LoadScene(sceneName);
            SceneManager.sceneLoaded += SceneLoaded;
        }
        else
        {
            panelManager.Push(new StartPanel());
            GameRoot.Instance.SetActive(panelManager.Push);
        }
    }

    public override void OnExit()
    {
        SceneManager.sceneLoaded -= SceneLoaded;
        panelManager.PopAll();
    }

    /// <summary>
    /// 场景加载完毕之后执行的方法
    /// </summary>
    /// <param name="scene"></param>
    /// <param name="load"></param>
    private void SceneLoaded(Scene scene,LoadSceneMode load)
    {
        panelManager.Push(new StartPanel());
        GameRoot.Instance.SetActive(panelManager.Push);
        Debug.Log($"{sceneName}场景加载完毕!");
    }
}

GameRoot.cs

/// <summary>
/// 管理全局的一些东西
/// </summary>
public class GameRoot : MonoBehaviour
{
    public static GameRoot Instance { get; private set; }
    /// <summary>
    /// 场景管理器
    /// </summary>
    public SceneSystem SceneSystem { get; private set; }

    /// <summary>
    /// 显示一个面板
    /// </summary>
    public UnityAction<BasePanel> Push { get; private set; }

    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(this.gameObject);
        }
        else
        {
            Instance = this;
        }
        SceneSystem = new SceneSystem();
        DontDestroyOnLoad(this.gameObject);
        /*if (Instance == null)
            Instance = this;
        else
            Destroy(gameObject);
        Instance = this;
        DontDestroyOnLoad(gameObject);*/
    }

    void Start()
    {
        SceneSystem.SetScene(new StartScene());
    }

    public void SetActive(UnityAction<BasePanel> push)
    {
        Push = push;
    }
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值