一:目的

在制作游戏过程中,UI界面都是必不可少的,多则上百个少则几个,如果这些UI界面都放在场景里(如下图所示),那么运行的时候会占用大量的内存
U3D游戏开发框架(三)——UI管理器_游戏开发
一般都是将每一个UI界面制作成一个Prefab动态的进行显示隐藏,加载卸载
所以我们需要一个管理器统一管理UI的相关操作

二:解决的问题及优点

——不需要创建UI画布和UI相机,动态创建并设置属性
——管理每一个UI界面的层级
——打开和关闭UI界面
——查找某一个UI界面

三:使用方法

——将所有UI制作成预制体统一放在Resources—Prefabs—UI文件夹下
——所有的UI预制体都需要与挂载在身上的脚本名相同
——所有的UI预制体身上的脚本都需要继承UIBase基类
——使用UIMgr.Ins.XXX

UIMgr.Ins.OpenUI<UI_Main>();
UIMgr.Ins.CloseUI<UI_Main>();
UIMgr.Ins.TopUI;

——根据不同项目需求设置UI画布的缩放:UIMgr.Ins.SetCanvasScaler()

四:代码实现

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine.EventSystems;
 
/// <summary>
/// UI基类
/// </summary>
public class UIBase : MonoBehaviour
{
    /// <summary>
    /// 打开UI时
    /// </summary>
    public virtual void OnView()
    {
        transform.SetAsLastSibling();
        gameObject.SetActive(true);
    }
 
    /// <summary>
    /// 关闭UI时
    /// </summary>
    public virtual void OnDisView()
    {
        gameObject.SetActive(false);
    }
}
 
/// <summary>
/// UI管理器
/// </summary>
public class UIMgr : Singleton<UIMgr>
{
    public const string UIDir = "Prefabs/UI/";//UI目录
 
    //渲染UI的画布
    private Canvas uiCanvas;
    public Canvas UICanvas { get { return uiCanvas; } }
 
    //渲染UI的相机
    private Camera uiCamera;
    public Camera UICamera { get { return uiCamera; } }
 
    //显示在最顶部的UI
    private UIBase topUI;
    public UIBase TopUI { get { return topUI; } }
 
    private Dictionary<string, UIBase> uiDict = new Dictionary<string, UIBase>();//场景中的UI
 
    protected override void Init()
    {
        base.Init();
 
        if (uiCamera == null)
        {
            uiCamera = CreateUICamera();
        }
        if (uiCanvas == null)
        {
            uiCanvas = CreateUICanvas();
        }
 
        //设置Canvas缩放
        SetCanvasScaler(new Vector2(750, 1334), false);
    }
 
    /// <summary>
    /// 打开UI
    /// </summary>
    public T OpenUI<T>(string uiRoot = "")
        where T : UIBase
    {
        string uiName = typeof(T).Name;
        if (!uiDict.ContainsKey(uiName))
        {
            CreateUI(uiName, uiRoot);
        }
 
        UIBase ui = uiDict[uiName];
        ui.OnView();
        FindTopUI();
 
        return ui as T;
    }
 
    /// <summary>
    /// 关闭UI
    /// </summary>
    public void CloseUI(string uiName, bool destroy = false)
    {
        if (!uiDict.ContainsKey(uiName))
        {
            Debug.LogError("场景中没有此UI:" + uiName);
            return;
        }
 
        if (destroy)
        {
            GameObject.Destroy(uiDict[uiName].gameObject);
            uiDict.Remove(uiName);
        }
        else
        {
            uiDict[uiName].OnDisView();
        }
 
        FindTopUI();
    }
 
    /// <summary>
    /// 关闭UI
    /// </summary>
    public void CloseUI<T>(bool destroy = false)
    {
        string uiName = typeof(T).Name;
        if (!uiDict.ContainsKey(uiName))
        {
            Debug.LogError("场景中没有此UI:" + uiName);
            return;
        }
 
        if (destroy)
        {
            GameObject.Destroy(uiDict[uiName].gameObject);
            uiDict.Remove(uiName);
        }
        else
        {
            uiDict[uiName].OnDisView();
        }
 
        FindTopUI();
    }
 
    /// <summary>
    /// 查找UI
    /// </summary>
    public T FindUI<T>()
        where T : UIBase
    {
        string uiName = typeof(T).Name;
        if (!uiDict.ContainsKey(uiName))
        {
            Debug.LogError("场景中没有此UI:" + uiName);
            return default;
        }
        return uiDict[uiName] as T;
    }
 
    /// <summary>
    /// 查找最顶部的UI
    /// </summary>
    private void FindTopUI()
    {
        for (int i = uiCanvas.transform.childCount - 1; i >= 0; i--)
        {
            if (uiCanvas.transform.GetChild(i).GetComponent<UIBase>() != null
                && uiCanvas.transform.GetChild(i).gameObject.activeSelf)
            {
                topUI = uiCanvas.transform.GetChild(i).GetComponent<UIBase>();
                break;
            }
        }
    }
 
    /// <summary>
    /// 设置Canvas缩放
    /// </summary>
    /// <param name="referResolution">参考的分辨率</param>
    /// <param name="isLandscape">是否为横屏</param>
    public void SetCanvasScaler(Vector2 referResolution, bool isLandscape)
    {
        CanvasScaler canvasScaler = uiCanvas.GetComponent<CanvasScaler>();
        canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
        canvasScaler.matchWidthOrHeight = isLandscape ? 1 : 0;
        canvasScaler.referenceResolution = referResolution;
    }
 
    /// <summary>
    /// 创建UI
    /// </summary>
    private void CreateUI(string uiName, string uiRoot)
    {
        string path = UIDir + uiName;
        GameObject uiPrefab = Resources.Load<GameObject>(path);
        if (uiPrefab == null)
        {
            Debug.LogError("UI不存在:" + path);
            return;
        }
        UIBase uiBase = GameObject.Instantiate(uiPrefab, uiRoot == "" ? uiCanvas.transform : GameObject.Find(uiRoot).transform).GetComponent<UIBase>();
        uiBase.gameObject.name = uiName;
        uiDict.Add(uiName, uiBase);
    }
 
    /// <summary>
    /// 创建UI画布
    /// </summary>
    private Canvas CreateUICanvas()
    {
        GameObject uiCanvas = new GameObject("UICanvas");
        uiCanvas.layer = 5;
        Canvas canvas = uiCanvas.AddComponent<Canvas>();
        canvas.renderMode = RenderMode.ScreenSpaceCamera;
        canvas.worldCamera = uiCamera;
        uiCanvas.AddComponent<CanvasScaler>();
        uiCanvas.AddComponent<GraphicRaycaster>();
 
        GameObject eventSystem = new GameObject("EventSystem");
        eventSystem.AddComponent<EventSystem>();
        eventSystem.AddComponent<StandaloneInputModule>();
        eventSystem.transform.SetParent(uiCanvas.transform);
 
        GameObject.DontDestroyOnLoad(uiCanvas);
        return uiCanvas.GetComponent<Canvas>();
    }
 
    /// <summary>
    /// 创建UI相机
    /// </summary>
    private Camera CreateUICamera()
    {
        GameObject uiCamera = new GameObject("UICamera");
        Camera camera = uiCamera.AddComponent<Camera>();
        camera.clearFlags = CameraClearFlags.Depth;
        camera.cullingMask = 1 << 5;
        camera.orthographic = true;
        camera.depth = 0;
 
        GameObject.DontDestroyOnLoad(uiCamera);
        return camera;
    }
}

图片来源:http://www.lyouxi.com/  手游