LiteralliJeff 发表于 2023-2-17 20:10

Unity3D 效率优化:2D PSD Importer 改为生成UGUI

一般我们做UI的时候会是这样的-----美术做张效果图,然后在切图给程序,程序在照着效果图来拼UI,可是明明美术以及拼好了啊,程序又需要在拼一次,下面我们来看看如何优化这一过程。
起因是这样的:
Unity3D提供了一种PSB资源文件直接转为Prefab的方案,通过这个可以方便的创建2d sprite 骨骼以及动画,有关2D PSD Importer的详细介绍可以查看官方的资料或者一位B站Up的视频
上面这一系列视频的开头介绍了PSD Importer的用法。
后来我就想能不能使用这个方法来处理UI呢?这样如果配合一些代码自动生成的方法,再加上PSD直接转为Prefab,这两者组合,将会为写UI的同学提供极大的便利,下面简单介绍一下如何修改官方的代码来实现我们的功能。

首先将2D PSDImporter添加到工程中
Window->Package Manager 中添加2D PSDImporter


然后我们在package中找到它


然后把它挪到我们的工程中去


放到当前工程中后,就可以在Package Manager中移除掉PSD Importer,但是PSDImporter 依赖了另外三个package,我们不能少了这几位。


下面我们来修改代码,首先找到PSDImporter.cs中的OnProducePrefab函数,这个函数就在读取PSB中的相关层的信息并创建物体,我们可以通过修改这个方法来实现我们的效果
GameObject OnProducePrefab(string assetname, Sprite[] sprites, SpriteLibraryAsset s)
{
            GameObject root = null;
            if (sprites != null && sprites.Length > 0)
            {
                var spriteImportData = GetSpriteImportData();
                root = new GameObject();
                root.name = assetname + "_GO";
                RectTransform rectTransform = root.AddComponent<RectTransform>();
                // /root.AddComponent<GraphicRaycaster>();

                var canvas = root.AddComponent<Canvas>();
                root.AddComponent<CanvasGroup>();

                rectTransform.sizeDelta = new Vector2(750, 1334);

                var psdLayers = GetPSDLayers();
                for (int i = 0; i < psdLayers.Count; ++i)
                {
                  BuildGroupGameObject(psdLayers, i, root.transform);
                }
                //var boneGOs = CreateBonesGO(root.transform);
                for (int i = 0; i < psdLayers.Count; ++i)
                {
                  var l = psdLayers;
                  GUID layerSpriteID = l.spriteID;
                  var sprite = sprites.FirstOrDefault(x => x.GetSpriteID() == layerSpriteID);
                  var spriteMetaData = spriteImportData.FirstOrDefault(x => x.spriteID == layerSpriteID);
                  if (sprite != null && spriteMetaData != null && l.gameObject != null)
                  {
                        //spriteRenderer.sortingOrder = psdLayers.Count - i;
                        var uvTransform = spriteMetaData.uvTransform;
                        var outlineOffset = new Vector2(spriteMetaData.rect.x - uvTransform.x + (spriteMetaData.pivot.x * spriteMetaData.rect.width),
                            spriteMetaData.rect.y - uvTransform.y + (spriteMetaData.pivot.y * spriteMetaData.rect.height)) * definitionScale / sprite.pixelsPerUnit;

                        Vector3 pos = new Vector3(outlineOffset.x, outlineOffset.y, 0);
                        pos = new Vector3(pos.x * sprite.pixelsPerUnit - rectTransform.sizeDelta.x / 2, pos.y * sprite.pixelsPerUnit - rectTransform.sizeDelta.y / 2, 0);

                        l.gameObject.transform.position = pos;

                        var spriteRenderer = l.gameObject.AddComponent<Image>();
                        //var spriteRenderer = l.gameObject.AddComponent<SpriteRenderer>();
                        spriteRenderer.sprite = sprite;
                        spriteRenderer.SetNativeSize();


                  }
                }

            }

            return root;
      }
rectTransform.sizeDelta =newVector2(750,1334);
这一行可以设置成你所想要的分辨率,或者各个项目框架的UI分辨率,whatever

pos =newVector3(pos.x * sprite.pixelsPerUnit - rectTransform.sizeDelta.x /2, pos.y * sprite.pixelsPerUnit - rectTransform.sizeDelta.y /2,0);
原来是在世界坐标中进行坐标计算,现在在UI坐标中需要进行坐标的转化放大处理
<hr/>下面让美术来个测试用的PSB文件试试看




所有的层都被放在了它改在的位置,可以看见美术的图层命名还是不太规范的,之后就可以通过图层的名字来自定义各种各样的规则,比如图层名字含有_Button,就自动添加Button组件等等,这些留给大家自行扩展。

总结
PSB文件可以直接生成Prefab,然后就可以根据Prefab自动化生成脚本,这样就大大加速了UI的开发速度,但是我们也需要对生成的UI进行一些其他的处理,比如锚点对其方式等等。

最后Github地址

IT圈老男孩1 发表于 2023-2-17 20:12

可以把PSD Importer从Library里面挪到和Assets同级的Packages目录里,这样Package Manager中还能识别到这个第三方包
页: [1]
查看完整版本: Unity3D 效率优化:2D PSD Importer 改为生成UGUI