Unity游戏框架设计之UI管理器

Unity游戏框架设计之UI管理器

简单介绍

在游戏开发过程中,我们通常需要管理 UI 游戏对象的加载、打开和销毁等操作,同时也需要管理游戏数据和游戏数据在 UI 上的显示,因此我们需要一个 UI 管理器来统一实现上述基础功能。

我们可以基于 MVC 模式编写 UI 管理器,此时 UI 管理器将分为模型管理器(Model)、视图管理器(View)和控制管理器(Controller)。

UI模型管理器

简单介绍

UI 模型管理器主要管理 UI 上数据的设置和读取。为了将数据显示到 UI 上,则必须选定一个 UI 组件作为载体。对于不同的 UI 组件,则有不同的设置和读取方法。因此引入 UIModelType 类来区分不同的 UI 组件。

下述代码以 UI 组件中的 TextMeshProUGUI 组件为例,分别编写对应的 UI 组件的模型管理器。然后编写 UI 模型管理器来统一管理所有 UI 组件中的模型,并以 UIModelType 作为区分不同 UI 的标识符。

代码设计

public enum UIModelType
{
    TextMeshProUGUI
}
public class UITextMeshProGUIModelManager : SingletonMono<UITextMeshProGUIModelManager>
{
    public string GetTextModel(string sceneAssetPath, string uiName, string gameObjectName)
    {
        return UIManager.Instance.FindUIComponentByName<TextMeshProUGUI>(sceneAssetPath, uiName, gameObjectName).text;
    }

    public void SetTextModel(string sceneAssetPath, string uiName, string gameObjectName, string text)
    {
        UIManager.Instance.FindUIComponentByName<TextMeshProUGUI>(sceneAssetPath, uiName, gameObjectName).text = text;
    }
}
public class UIModelManager : SingletonMono<UIModelManager>
{
    protected override void Awake()
    {
        base.Awake();
        gameObject.AddComponent<UITextMeshProGUIModelManager>();
    }

    public string GetModel(string sceneAssetPath, string uiName, string gameObjectName, UIModelType type)
    {
        switch (type)
        {
            case UIModelType.TextMeshProGUI:
                return UITextMeshProGUIModelManager.Instance.GetTextModel(sceneAssetPath, uiName, gameObjectName);
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    public void SetModel(string sceneAssetPath, string uiName, string gameObjectName, string value, UIModelType type)
    {
        switch (type)
        {
            case UIModelType.TextMeshProGUI:
                UITextMeshProGUIModelManager.Instance.SetTextModel(sceneAssetPath, uiName, gameObjectName, value);
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
    }
}

UI视图管理器

简单介绍

UI 视图管理器主要管理 UI 的资源加载、UI 的打开、UI 的关闭、UI 的销毁。UI 视图管理器依赖于场景管理器(不是 Unity 官方 API 而是自己实现的游戏框架中的场景管理器),因为 UI 视图管理器的操作与场景管理器的操作类似。UI 的资源加载,实际上就是将资源加载到场景中。UI 的打开,实际上就是场景中游戏对象的激活。UI 的关闭,实际上就是场景中游戏对象的禁用。UI 的销毁,实际上就是场景中游戏对象的销毁。

代码设计

public class UIViewManager : SingletonMono<UIViewManager>
{
    public GameObject LoadUI(string sceneAssetPath, string uiAssetPath, string uiName)
    {
        return SceneManager.Instance.LoadRootPrefab(sceneAssetPath, uiAssetPath, uiName);
    }

    public (GameObject, T) LoadUI<T>(string sceneAssetPath, string uiAssetPath, string uiName) where T : Component
    {
        GameObject prefab = SceneManager.Instance.LoadRootPrefab(sceneAssetPath, uiAssetPath, uiName);
        T component = AddUIComponent<T>(sceneAssetPath);
        return (prefab, component);
    }

    public GameObject OpenUI(string sceneAssetPath, string uiName)
    {
        return SceneManager.Instance.ActiveRootPrefab(sceneAssetPath, uiName);
    }

    public GameObject LoadAndOpenUI(string sceneAssetPath, string uiAssetPath, string uiName)
    {
        return SceneManager.Instance.LoadAndActiveRootPrefab(sceneAssetPath, uiAssetPath, uiName);
    }

    public (GameObject, T) LoadAndOpenUI<T>(string sceneAssetPath, string uiAssetPath, string uiName) where T : Component
    {
        GameObject prefab = LoadAndOpenUI(sceneAssetPath, uiAssetPath, uiName);
        T component = AddUIComponent<T>(sceneAssetPath);
        return (prefab, component);
    }

    public void CloseUI(string sceneAssetPath, string uiName)
    {
        SceneManager.Instance.InactiveRootPrefab(sceneAssetPath, uiName);
    }

    public void CloseAndDestroyUI(string sceneAssetPath, string uiName)
    {
        SceneManager.Instance.InactiveAndDestroyRootPrefab(sceneAssetPath, uiName);
    }

    private T AddUIComponent<T>(string sceneAssetPath) where T : Component
    {
        return SceneManager.Instance.AddRootGameObjectComponent<T>(sceneAssetPath);
    }
}

UI控制管理器

简单介绍

UI 控制管理器主要用于控制 UI 事件的处理。首先我们通过 UI 控制管理器向 UI 添加 UI 事件的监听器,然后当 UI 事件触发时,将自动执行监听器中的代码来完成对 UI 事件的处理。下面以 Button 组件的事件监听器的绑定作为例子,编写 UI 控制管理器。

代码设计

public class UIControllerManager : SingletonMono<UIControllerManager>
{
    public void AddListenerOnButtonClick(string sceneAssetPath, string uiName, string gameObjectName, Action onButtonClick)
    {
        UIManager.Instance.FindUIComponentByName<Button>(sceneAssetPath, uiName, gameObjectName).onClick.AddListener(() => onButtonClick());
    }
}

代码说明

(一)使用 UI 控制管理器时,必须在场景中添加 EventSystem 组件,否则 UI 事件将不会触发。

(二)允许重复添加事件监听器。

(三)向 UI 添加 UI 事件的监听器后,不需要主动在 UI 被禁用或者被销毁时删除 UI 事件的监听器,监听的删除操作由 Unity 自动完成。

代码设计

在 UI 管理器中,提供 UI 模型管理器、UI 视图管理器和 UI 控制管理器的方法入口,并提供一些公用方法。

public class UIManager : SingletonMono<UIManager>
{
    protected override void Awake()
    {
        base.Awake();
        // UIViewManager
        gameObject.AddComponent<UIViewManager>();
        // UIControllerManager
        gameObject.AddComponent<UIControllerManager>();
        // UIModelManager
        gameObject.AddComponent<UIModelManager>();
    }
    
    public void SetModel(string sceneAssetPath, string uiName, string gameObjectName, string value, UIModelType type)
    {
        UIModelManager.Instance.SetModel(sceneAssetPath, uiName, gameObjectName, value, type);
    }

    public string GetModel(string sceneAssetPath, string uiName, string gameObjectName, UIModelType type)
    {
        return UIModelManager.Instance.GetModel(sceneAssetPath, uiName, gameObjectName, type);
    }

    public GameObject LoadUI(string sceneAssetPath, string uiAssetPath, string uiName)
    {
        return UIViewManager.Instance.LoadUI(sceneAssetPath, uiAssetPath, uiName);
    }

    public (GameObject, T) LoadUI<T>(string sceneAssetPath, string uiAssetPath, string uiName) where T : Component
    {
        return UIViewManager.Instance.LoadUI<T>(sceneAssetPath, uiAssetPath, uiName);
    }

    public GameObject OpenUI(string sceneAssetPath, string uiName)
    {
        return UIViewManager.Instance.OpenUI(sceneAssetPath, uiName);
    }

    public GameObject LoadAndOpenUI(string sceneAssetPath, string uiAssetPath, string uiName)
    {
        return UIViewManager.Instance.LoadAndOpenUI(sceneAssetPath, uiAssetPath, uiName);
    }

    public (GameObject, T) LoadAndOpenUI<T>(string sceneAssetPath, string uiAssetPath, string uiName) where T : Component
    {
        return UIViewManager.Instance.LoadAndOpenUI<T>(sceneAssetPath, uiAssetPath, uiName);
    }

    public void CloseUI(string sceneAssetPath, string uiName)
    {
        UIViewManager.Instance.CloseUI(sceneAssetPath, uiName);
    }

    public void CloseAndDestroyUI(string sceneAssetPath, string uiName)
    {
        UIViewManager.Instance.CloseAndDestroyUI(sceneAssetPath, uiName);
    }

	public void AddListenerOnButtonClick(string sceneAssetPath, string uiName, string gameObjectName, Action onButtonClick)
    {
        UIControllerManager.Instance.AddListenerOnButtonClick(sceneAssetPath, uiName, gameObjectName, onButtonClick);
    }

    public T FindUIComponentByName<T>(string sceneAssetPath, string uiName, string gameObjectName) where T : Component
    {
        return SceneManager.Instance.FindRootPrefabDescendantComponent<T>(sceneAssetPath, uiName, gameObjectName);
    }

    public GameObject FindUIGameObjectByName(string sceneAssetPath, string rootGameObjectName, string gameObjectName)
    {
        return SceneManager.Instance.FindRootPrefabDescendant(sceneAssetPath, rootGameObjectName, gameObjectName);
    }

    public string GetDefaultUIName(string uiAssetPath)
    {
        return SceneManager.Instance.GetDefaultPrefabName(uiAssetPath);
    }
}

后记

由于个人能力有限,文中不免存在疏漏之处,恳求大家斧正,一起交流,共同进步。

posted @ 2024-05-01 15:54  珂霖  阅读(16)  评论(0编辑  收藏  举报