U3D遊戲開發框架(三)——UI管理器

一:目的
在製做遊戲過程當中,UI界面都是必不可少的,多則上百個少則幾個,若是這些UI界面都放在場景裏(以下圖所示),那麼運行的時候會佔用大量的內存
image.pngcanvas

通常都是將每個UI界面製做成一個Prefab動態的進行顯示隱藏,加載卸載
因此咱們須要一個管理器統一管理UI的相關操做ide

二:解決的問題及優勢ui

——不須要建立UI畫布和UI相機,動態建立並設置屬性
——管理每個UI界面的層級
——打開和關閉UI界面
——查找某一個UI界面spa

三:使用方法code

——將全部UI製做成預製體統一放在Resources—Prefabs—UI文件夾下
——全部的UI預製體都須要與掛載在身上的腳本名相同
——全部的UI預製體身上的腳本都須要繼承UIBase基類
——使用UIMgr.Ins.XXXorm

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;
    }
}

圖片來源:遊戲加盟圖片

相關文章
相關標籤/搜索