UGUI自適應工具

遊戲開發中UI自適應是個非常重要的環節,自適應方式不僅影響遊戲的美觀,也影響在不同機型上的交互。實際遊戲開發中美觀方面一般交給美術或策劃調整,然聞道有先後,術業有專攻。需要一個簡單易用的工具來輔助他們調整,通過代碼修改  Scene 下的分辨率。下面是具體工具的代碼實現,遊戲中使用1334 * 750作爲標準分辨率。


 
//*****************************************************************************
//  文件要述:  UI Resolution Tool
//  文件描述:  分辨率適應工具
//  參與編寫人 :  Mars
//  參考鏈接 : https://answers.unity.com/questions/956123/add-and-select-game-view-resolution.html
//*****************************************************************************
using UnityEngine;
using UnityEditor;
using System;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Reflection;

public class ResolutionConfig
{
    public int width = 0;    // 寬
    public int height = 0;   // 高

    public string desc = ""; // 描述

    public ResolutionConfig(int iWidth, int iHeight, string strDesc)
    {
        width = iWidth;
        height = iHeight;
        desc = strDesc;
    }
}
public enum GameViewSizeType
{
    AspectRatio, FixedResolution
}

public class UIResolutionTool : EditorWindow
{
    [MenuItem("工具/自適應工具")]
    private static void Open()
    {
        UIResolutionTool window = (UIResolutionTool)EditorWindow.GetWindow(typeof(UIResolutionTool));
        _Init();
        window.Show();
    }

    private List<ResolutionConfig> _listResolution = new List<ResolutionConfig>() 
    {
        new ResolutionConfig(750, 1334, "iphone6(標準)"),
        new ResolutionConfig(960, 1280, "3:4"),
        new ResolutionConfig(1080, 1920, "9:16"),
        new ResolutionConfig(1125, 2436, "iphoneX"),
    };

    private int _iWidth = 0;
    private int _iHeight = 0;
    private static MethodInfo _getGroup;
    private static object _gameViewSizesInstance;

    private static void _Init()
    {
        var sizesType = typeof(Editor).Assembly.GetType("UnityEditor.GameViewSizes");
        var singleType = typeof(ScriptableSingleton<>).MakeGenericType(sizesType);
        var instanceProp = singleType.GetProperty("instance");
        _getGroup = sizesType.GetMethod("GetGroup");
        _gameViewSizesInstance = instanceProp.GetValue(null, null);
    }

    void OnGUI()
    {
        int len = _listResolution.Count;
        for (int i = 0; i < len; i++)
        {
            ResolutionConfig item = _listResolution[i];
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("應用", GUILayout.Width(100), GUILayout.Height(20)))
            {
                _SetResolution(item);
            }

            GUILayout.Label(string.Format("{0}x{1}", item.width, item.height), GUILayout.MaxWidth(80));
            GUILayout.Label(item.desc, GUILayout.MaxWidth(200));

            EditorGUILayout.EndHorizontal();
        }



        EditorGUILayout.BeginHorizontal();
        if (GUILayout.Button("應用", GUILayout.Width(100), GUILayout.Height(20)))
        {
            _SetResolution(_iWidth, _iHeight);
        }

        string strWidth = GUILayout.TextField(_iWidth.ToString(), GUILayout.Width(50));
        GUILayout.Label("x", GUILayout.MaxWidth(20));
        string strHeight = GUILayout.TextField(_iHeight.ToString(), GUILayout.Width(50));

        int width = 0;
        if (int.TryParse(strWidth, out width))
        {
            _iWidth = width;
        }

        int height = 0;
        if (int.TryParse(strHeight, out height))
        {
            _iHeight = height;
        }

        GUILayout.Label("自定義分辨率", GUILayout.MaxWidth(80));

        EditorGUILayout.EndHorizontal();
    }


    private static void _SetResolution(ResolutionConfig conf)
    {
        _SetResolution(conf.width, conf.height);
    }

    private static void _SetResolution(int width, int height)
    {
        CanvasScaler canScaler = GameObject.FindObjectOfType<CanvasScaler>();

        //CanvasScaler canScaler = resMgr.UIParent.transform.parent.GetComponent<CanvasScaler>();
        // 適配方案 1334 * 750 iphone6 分辨率 1.7787  16:9 = 1.7778 4:3 = 1.3333  
        if (null != canScaler)
        {
            if (width > height)
            {
                // 高適配
                //canScaler.scaleFactor = ((float)Screen.width) / 1334.0f;
                // 寬適配
                //canScaler.scaleFactor = ((float)Screen.height) / 750.0f;
                float scaleWidth = ((float)height) / 750.0f;
                float scaleHeight = ((float)width) / 1334.0f;
                canScaler.scaleFactor = Mathf.Min(scaleWidth, scaleHeight);
            }
            else
            {
                // 高適配
                //canScaler.scaleFactor = ((float)Screen.height) / 1334.0f;
                // 寬適配
                //canScaler.scaleFactor = ((float)Screen.width) / 750.0f;
                float scaleWidth = ((float)width) / 750.0f;
                float scaleHeight = ((float)height) / 1334.0f;
                canScaler.scaleFactor = Mathf.Min(scaleWidth, scaleHeight);
            }
        }

        int index = FindSize(GameViewSizeGroupType.Standalone, string.Format("{0}x{1}", width, height));
        //Debug.LogError("----------------------------- index " + index);
        if (-1 != index)
        {
            SetSize(index);
        }
        else
        {
            AddCustomSize(GameViewSizeType.FixedResolution, GameViewSizeGroupType.Standalone, width, height, "");
            index = FindSize(GameViewSizeGroupType.Standalone, string.Format("{0}x{1}", width, height));
            if (-1 != index)
            {
                SetSize(index);
            }
        }

        Camera camera = GameObject.FindObjectOfType<Camera>();
        if (null != camera)
        {
            camera.enabled = false;
            camera.enabled = true;
        }
    }

    public static void AddCustomSize(GameViewSizeType viewSizeType, GameViewSizeGroupType sizeGroupType, int width, int height, string text)
    {
        // goal:
        // var group = ScriptableSingleton<GameViewSizes>.instance.GetGroup(sizeGroupType);
        // group.AddCustomSize(new GameViewSize(viewSizeType, width, height, text);

        var asm = typeof(Editor).Assembly;
        var sizesType = asm.GetType("UnityEditor.GameViewSizes");
        var singleType = typeof(ScriptableSingleton<>).MakeGenericType(sizesType);
        var instanceProp = singleType.GetProperty("instance");
        var getGroup = sizesType.GetMethod("GetGroup");
        var instance = instanceProp.GetValue(null, null);
        var group = getGroup.Invoke(instance, new object[] { (int)sizeGroupType });
        var addCustomSize = getGroup.ReturnType.GetMethod("AddCustomSize"); // or group.GetType().
        var gvsType = asm.GetType("UnityEditor.GameViewSize");
        var ctor = gvsType.GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(string) });
        var newSize = ctor.Invoke(new object[] { (int)viewSizeType, width, height, text });
        addCustomSize.Invoke(group, new object[] { newSize });
    }

    public static void SetSize(int index)
    {
        var gvWndType = typeof(Editor).Assembly.GetType("UnityEditor.GameView");
        var selectedSizeIndexProp = gvWndType.GetProperty("selectedSizeIndex",
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        var gvWnd = EditorWindow.GetWindow(gvWndType);
        selectedSizeIndexProp.SetValue(gvWnd, index, null);
    }

    public static int FindSize(GameViewSizeGroupType sizeGroupType, string text)
    {
        // GameViewSizes group = gameViewSizesInstance.GetGroup(sizeGroupType);
        // string[] texts = group.GetDisplayTexts();
        // for loop...

        var group = GetGroup(sizeGroupType);
        var getDisplayTexts = group.GetType().GetMethod("GetDisplayTexts");
        var displayTexts = getDisplayTexts.Invoke(group, null) as string[];
        for (int i = 0; i < displayTexts.Length; i++)
        {
            string display = displayTexts[i];
            //Debug.LogError("---------------- display " + display);

            // the text we get is "Name (W:H)" if the size has a name, or just "W:H" e.g. 16:9
            // so if we're querying a custom size text we substring to only get the name
            // You could see the outputs by just logging
            // Debug.Log(display);
            int pren = display.IndexOf('(');
            if (pren != -1)
            {
                display = display.Substring(0, pren - 1); // -1 to remove the space that's before the prens. This is very implementation-depdenent
            }

            if (display == text)
            {
                return i;
            }
        }
        return -1;
    }

    static object GetGroup(GameViewSizeGroupType type)
    {
        return _getGroup.Invoke(_gameViewSizesInstance, new object[] { (int)type });
    }
}



 

編譯完成後在菜單欄  “工具/自適應工具” 即可打開,效果圖如下:

UGUI自適應工具 - Mars - MarsZhan

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章