TexturePacker图集报警告导致Sprite无法显示

参考文章升级Unity2021版本后新加图片打图集异常

TexturePacker导出的png报警告,一些图片在运行时无法显示。打开png.meta后发现一些spriteId和InternalId为0。

手动点击右上角的Reset后可以解决。那么问题就变成了怎么直接调用reset对应的方法。

1.如何调用Reset

在Untiy提供的CS代码中,把相关的Inspector,editorWindow,improter等相关的看完都没发现对用的内容。

换个思路,在Inspector面板上右键可以添加的方法时ContextMenu的特性。没搜到对应的menu,就自己猜, Assets/Reset Object/Reset,都无法正常执行。放弃,看来Reset比较特殊。

2.直接修改meta文件

通过解析yaml文件,修改个值再序列化回去。但是由于unity的非标准yaml格式,换了几个插件都无法正常保存修改。放弃,可以自己硬编码逐行读取???自己保存???

3.通过Unity自己的SerializedProperty修改

网上找到上面提到的文章,自己生成guid来解决。可以实现但是再点击Reset发现meta文件还是会变化。通过找Unity U2D的方法,找到了生成SpriteId和InternalId的方式。

Unity 版本 2022.3

具体实现

    var persistentTypeID = GetPersistentTypeID();
    var makeMethod = typeof(AssetImporter).GetMethod("MakeLocalFileIDWithHash", bindingFlags);
    var spriteIdGenerateMethod = GetSpriteIDGenerate();
    private static Dictionary<string, InternalSpriteInfo> keyValuePairs = new Dictionary<string, InternalSpriteInfo>();
    private static BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly;

    private const string EmptySpriteId = "00000000000000000800000000000000";

    public static void ModifyTexturePacker(string assetPath){
        keyValuePairs.Clear();
        AssetImporter importer = AssetImporter.GetAtPath(assetPath);
        SerializedObject serializedObject = new SerializedObject(importer);
        //这个不改也不影响,实际上呢?
        SerializedProperty idToNameTable = serializedObject.FindProperty("m_InternalIDToNameTable");
        SerializedProperty sprites = serializedObject.FindProperty("m_SpriteSheet.m_Sprites");
        SerializedProperty nameFiledTable = serializedObject.FindProperty("m_SpriteSheet.m_NameFileIdTable");
        if (sprites.isArray)
        {
            var arraySize = sprites.arraySize;
            for (int i = 0; i < arraySize; i++)
            {
                var sprite = sprites.GetArrayElementAtIndex(i);
                var spriteName = sprite.FindPropertyRelative("m_Name");
                var spriteId = sprite.FindPropertyRelative("m_SpriteID");
                var internalId = sprite.FindPropertyRelative("m_InternalID");
                if (spriteId.stringValue.Equals(EmptySpriteId))
                {
                    //internalId是唯一的,重复调用是相同的,不同图集下同名sprite猜测应该会得到同一个值
                    var newIntarnalId = (long)makeMethod?.Invoke(null, new object[] { persistentTypeID, spriteName.stringValue, 0 });
                    var obj = (GUID)spriteIdGenerateMethod?.Invoke(null, new object[] { newIntarnalId });
                    internalId.longValue = newIntarnalId;
                    spriteId.stringValue = obj.ToString();
                    keyValuePairs.Add(spriteName.stringValue, new InternalSpriteInfo { InternalID = newIntarnalId, SpriteID = spriteId.stringValue });
                    //Debug.Log($"{spriteName.stringValue} = {obj.ToString()}");
                }
            }
        }
        if (nameFiledTable.isArray)
        {
            for (int i = 0; i < nameFiledTable.arraySize; i++)
            {
                var nameField = nameFiledTable.GetArrayElementAtIndex(i);
                var first = nameField.FindPropertyRelative("first");
                var second = nameField.FindPropertyRelative("second");
                if (keyValuePairs.TryGetValue(first.stringValue, out InternalSpriteInfo id))
                {
                    second.longValue = id.InternalID;
                }
            }
        }
        serializedObject.ApplyModifiedProperties();
        AssetDatabase.ForceReserializeAssets(new[] { assetPath }, ForceReserializeAssetsOptions.ReserializeMetadata);
        AssetDatabase.SaveAssetIfDirty(AssetDatabase.GUIDFromAssetPath(assetPath));
    }

    private static int GetPersistentTypeID(){
        var unityType = typeof(Editor).Assembly.GetType("UnityEditor.UnityType");
        var propertyID = unityType.GetProperty("persistentTypeID");
        var method = unityType.GetMethod("FindTypeByName", BindingFlags.Public | BindingFlags.Static);
        var spriteProper = method.Invoke(null, new object[] { "Sprite" });
        var persistentTypeID = (int)propertyID.GetValue(spriteProper);
        return persistentTypeID;
    }

    public static MethodInfo GetSpriteIDGenerate()
    {
        MethodInfo methodInfo = typeof(GUID).GetMethod("CreateGUIDFromSInt64", bindingFlags);
        return methodInfo;
    }


测试生成的internalId和spriteId和点击Reset结果一致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值