UIPrefabChecker

本文介绍了一个用于Unity游戏开发的UI Prefab检查工具,该工具能够检查UI预制体中图集的使用情况、不在图集中的图片、大尺寸图像资源以及引用丢失等问题,有助于提高UI资源管理和性能优化的效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.U2D;
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.UI;

/// <summary>
/// UI预制体检查
/// 
/// 1.使用图集的数量
/// 2.不在图集中的图片
/// 3.使用的大图资源
/// 4.引用丢失
/// 
/// </summary>
public class UIPrefabChecker 
{
    enum CheckType
    {
        UsingAtlas,
        ImageNotInAtals,
        LargeImge,
        MissRef,
    }

    private static Dictionary<CheckType, string> m_checkDesDict = new Dictionary<CheckType, string>()
    {
        { CheckType.UsingAtlas,"using atlas count is"},
        { CheckType.ImageNotInAtals,"these image not in atlas"},
        { CheckType.LargeImge,"consider change to texture or scale image"},
        { CheckType.MissRef,"miss ref"},
    };


    [MenuItem(ToolDes.UI_CheckUIPrefab)]
    public static void DeepCheck()
    {
        var objs = CollectResUtility.SelectObjs();

        if (objs.Length > 0)
        {
            CollectAtlasSprite();
        }

        int index = 0;
        List<string> report = new List<string>();
        foreach (var obj in objs)
        {
            index++;
            var path = AssetDatabase.GetAssetPath(obj);
            if (path.Contains(".prefab"))
            {
                var log = DeepCheck(obj);
                if (log != null)
                    report.Add(log);
                EditorUtility.DisplayProgressBar("ui prefab checking", "current is " + path, (float)index / (float)objs.Length);
            }
        }

        if (report.Count > 0)
        {
            FileUtil.Export(Application.dataPath + "/UIPrefabCheckReport.txt", report);
            AssetDatabase.Refresh();
        }
        
        EditorUtility.ClearProgressBar();
    }

    private static string DeepCheck(Object obj)
    {
        var go = obj as GameObject;
        if (go == null)
            return null;

        string path = AssetDatabase.GetAssetPath(obj);
        List<string> usingAtlas = new List<string>();
        List<string> imageNotInAtlas = new List<string>();
        List<string> largeImage = new List<string>();
        CheckImage(go, usingAtlas, imageNotInAtlas, largeImage);

        List<string> missRef = new List<string>();
        CheckObj(go, missRef);

        return ToLog(path, usingAtlas, imageNotInAtlas, largeImage, missRef);
    }


    private static void CheckImage(GameObject go, List<string> usingAtlas, List<string> imageNotInAtlas, List<string> largeImage)
    {
        Image[] images = go.transform.GetComponentsInChildren<Image>(true);
        for (int i = 0; i < images.Length; i++)
        {
            var img = images[i];
            var imgPath = GetComponentPath(img);

            var mat = img.material;
            var sprite = img.sprite;

            //排除特效所用的资源
            if (sprite != null && mat.name == "Default UI Material")
            {
                var asset_path = AssetDatabase.GetAssetPath(sprite);

                var atlasPath = GetAtalsPathByImage(asset_path);

                if (atlasPath == null)
                {
                    var guid = AssetDatabase.AssetPathToGUID(asset_path);
                    if (guid != "0000000000000000f000000000000000")
                    {
                        imageNotInAtlas.Add("path:" + imgPath + "   res:" + asset_path);
                    }
                }
                else
                {
                    if (!usingAtlas.Contains(atlasPath))
                        usingAtlas.Add(atlasPath);
                }

                if (sprite.rect.width >= 512 || sprite.rect.height >= 512)
                {
                    largeImage.Add("path:" + imgPath + "    res:" + asset_path);
                }
            }
        }
    }


    private static void CheckObj(GameObject go, List<string> componentPaths)
    {
        if (go.transform.childCount <= 0)
        {
            return;
        }
        else
        {
            for (int i = 0; i < go.transform.childCount; i++)
            {
                var trans = go.transform.GetChild(i);
                var paths = CheckTrans(trans);
                componentPaths.AddRange(paths);

                CheckObj(trans.gameObject, componentPaths);
            }
        }
    }

    private static List<string> CheckTrans(Transform trans)
    {
        List<string> componentPaths = new List<string>();
        var components = trans.GetComponentsInChildren<Component>(true);
        foreach (var component in components)
        {
            var path = CheckRef(trans, component);
            if (path != null)
            {
                componentPaths.Add(path);
            }
        }

        return componentPaths;
    }


    private static string CheckRef(Transform trans, Component component)
    {
        if (component != null)
        {
            SerializedObject so = new SerializedObject(component);
            var iter = so.GetIterator();
            while (iter.NextVisible(true))
            {
                if (iter.propertyType == SerializedPropertyType.ObjectReference)
                {
                    if (iter.objectReferenceValue == null && iter.objectReferenceInstanceIDValue != 0)
                    {
                       return GetComponentPath(trans);
                    }
                }
            }
        }
        else
        {
            return GetComponentPath(trans);
        }

        return null;
    }


    private static string ToLog(string path, List<string> usingAtlas, List<string> imageNotInAtlas, List<string> largeImage, List<string> missRef)
    {
        string logFormat = "[" + path + "]" + "\r\n";

        string usingAtlasFormat = GetLogByCheckType(CheckType.UsingAtlas, usingAtlas);
        if (usingAtlasFormat != null)
            logFormat += usingAtlasFormat;

        string imageNotInAtlasFormat = GetLogByCheckType(CheckType.ImageNotInAtals, imageNotInAtlas);
        if (imageNotInAtlasFormat != null)
            logFormat += imageNotInAtlasFormat;

        string largeImageFormat = GetLogByCheckType(CheckType.LargeImge, largeImage);
        if (largeImageFormat != null)
            logFormat += largeImageFormat;

        string missRefFormat = GetLogByCheckType(CheckType.MissRef, missRef);
        if (missRefFormat != null)
            logFormat += missRefFormat;

        return logFormat;
    }

    private static string GetLogByCheckType(CheckType type, List<string> checkResult)
    {
        if (checkResult.Count == 0)
            return null;

        var des = m_checkDesDict[type];

        if (type == CheckType.UsingAtlas)
            des += "  " + checkResult.Count + "\r\n";
        else
            des += "  " + "\r\n";

        foreach (var item in checkResult)
        {
            des += "  " + item + "\r\n";
        }

        return des;
    }

    private static string GetComponentPath(Component component)
    {
        string str = component.name + ":" + component.GetType().Name;
        var trans = component.transform;
        while (trans.parent != null)
        {
            var name = trans.parent.name;
            str = name + "/" + str;

            trans = trans.parent;
        }

        return str;
    }


    #region CollectAtlasInfo

    private static Dictionary<string, string> m_spriteDicts = new Dictionary<string, string>();

    public static void CollectAtlasSprite()
    {
        var atalsGuid = AssetDatabase.FindAssets("t:" + typeof(SpriteAtlas).Name);
        foreach (var guid in atalsGuid)
        {
            var atlasPath = AssetDatabase.GUIDToAssetPath(guid);
            SpriteAtlas atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasPath) as SpriteAtlas;
            if (atlas != null)
            {
                var assets = GetSpritesInAtlas(atlas);
                foreach (var asset in assets)
                {
                    if (!m_spriteDicts.ContainsKey(asset))
                    {
                        m_spriteDicts.Add(asset, atlasPath);
                    }
                }
            }
        }
    }

    private static List<string> GetSpritesInAtlas(SpriteAtlas atlas)
    {
        List<string> spirtes_path = new List<string>();
        UnityEngine.Object[] sprites = SpriteAtlasExtensions.GetPackables(atlas);
        foreach (var sprite in sprites)
        {
            var path = AssetDatabase.GetAssetPath(sprite);

            var sprite_guids = AssetDatabase.FindAssets("t:" + typeof(Sprite).Name, new string[] { path });

            foreach (var guid in sprite_guids)
            {
                var certain_path = AssetDatabase.GUIDToAssetPath(guid);
                if (!spirtes_path.Contains(certain_path))
                {
                    spirtes_path.Add(certain_path);
                }
            }
        }
        return spirtes_path;
    }

    private static string GetAtalsPathByImage(string iamgePath)
    {
        string path = null;
        if (m_spriteDicts.TryGetValue(iamgePath, out path))
        {
            return path;
        }

        return null;
    }

    #endregion
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值