UGUI -- 原生Sprite

使用了Unity5.0 之后的版本,做UI界面再也不想用第三方的UI插件了,毕竟支持比较好!但也有很多不足的地方,比如Sprite的使用,系统没有提供根据Sprite名称获取Sprite的方法,所以一开始我是直接把Sprite的路径保存在文件里面,使用的时候Resources.Load一下,这样做每次修改都要更新文件,很麻烦,而且当Sprite超多的时候就更加麻烦了,NGUI和2Dtoolkit里都有图集的概念来管理这些Sprite,但是原生的是没有的!一开始自己的想法是把每张Sprite保存到Prefab里面,百度一下,原来雨松MOMO大神也有这么介绍,他的文章地址点击打开链接;好,既然思路正确,虽然雨松MOMO也有给出了代码,不过还是要自己按照自己的风格写一遍,哈哈哈!

首先写一个UIAtlas类,直接盗用NGUI的名称,不要介哈,这个类主要提供根据名称获取Sprite的接口!主要代码如下:

public class UIAtlas : MonoBehaviour
{
   private Dictionary<string, Sprite> spriteDictionary = new Dictionary<string, Sprite>();
    private bool isInit = false;
    void Awake()
    {
        InitSprites();
    }


    void InitSprites()
    {
        if (!isInit)
        {
            SpriteRenderer[] renders = GetComponentsInChildren<SpriteRenderer>();
            foreach (var render in renders)
            {
                if (!spriteDictionary.ContainsKey(render.name))
                {
                    spriteDictionary.Add(render.sprite.name, render.sprite);
                }
            }
            isInit = true;
        }
    }


    public Sprite Load(string spriteName)
    {
        InitSprites();
        if (spriteDictionary.ContainsKey(spriteName))
        {
            return spriteDictionary[spriteName];
        }
        else
        {
            Debug.LogError("Sprite[" + spriteName + "] do not exist!");
        }
        return null;
    }


    public bool HasSprite(string spriteName)
    {
        InitSprites();
        return spriteDictionary.ContainsKey(spriteName);
    }
}   


那么我们在建立预设体的时候就要挂上这个脚本,然后把所有你要加入到这个图集的Sprite生成一个子物体,把Sprite引用到子物体上,好,是不是很简单!

不过如果我们都要自己手动来把所有的Sprite都建立一个子物体也会让人崩溃,所以下面我给出一个Editor下的不完善的小工具,

同时上面UIAtlas 类会增加以下在Editor下的接口

#if UNITY_EDITOR
    public void AddSprite(Sprite sprite)
    {
        GameObject go = new GameObject(sprite.name);
        SpriteRenderer sr = go.AddComponent<SpriteRenderer>();
        sr.sprite = sprite;
        go.transform.parent = transform;
        go.transform.ResetLocal();
    }



    public Dictionary<string, Sprite> GetSprites() {

        Dictionary<string, Sprite> ret = new Dictionary<string, Sprite>();

        SpriteRenderer[] renders = GetComponentsInChildren<SpriteRenderer>();
        foreach (var render in renders)
        {
            if (!ret.ContainsKey(render.name))
            {
                ret.Add(render.sprite.name, render.sprite);
            }
        }
        return ret;
    }

    public void RemoveSprite(string name)
    {
        SpriteRenderer[] renders = GetComponentsInChildren<SpriteRenderer>();
        foreach (var render in renders)
        {
            if(render.name == name)
            {
                DestroyImmediate(render.gameObject);
            }
        }
    }
#endif
扩展界面如下:

UGUI -- 原生Sprite_第1张图片

嗯,有点熟悉!这个就是我用来管理我自己的的图集的,只要我们把新建立的绑定有UIAtlas脚本的预设体拖到上面Atals的位置,再在资源文件夹里选中你要添加到里面去的Sprite就行,大概效果是这样

UGUI -- 原生Sprite_第2张图片

然后点击最底下 Add/Update 按钮就会生成包含上面两个Sprite的Prefab啦,如下:

UGUI -- 原生Sprite_第3张图片

OK,到这里就算完成了!

至于这个扩展怎么写的我就不多说了,我对Editor下编写扩展也不太熟悉,这也是我生搬硬套搞出来的!代码还是贴上来,如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;


public class CreateAtlasWindow : EditorWindow
{
    class SpriteData
    {
        public SpriteData(string name, Sprite sprite)
        {
            this.Sprite = sprite;
            this.SpriteName = name;
        }
        public string SpriteName;
        public Sprite Sprite;
        public bool IsChange = true;
    }

    [MenuItem("ExtensionTools/Open Atlas Window")]
    static void Init()
    {
        CreateAtlasWindow window = GetWindow<CreateAtlasWindow>();
    }

    public UIAtlas uiAtlas = null;
    private Dictionary<string,SpriteData> sprites = new Dictionary<string, SpriteData>();
    private Vector2 pos;
    void OnGUI()
    {
        if (Selection.activeObject)
        {         
            Sprite sprite = Selection.activeObject as Sprite;
            if(sprite)
            {
                if (!sprites.ContainsKey(sprite.name))
                {
                    sprites.Add(sprite.name, new SpriteData(sprite.name, sprite));
                }
                else
                {
                    if(sprites[sprite.name].Sprite != sprite)
                    {
                        sprites[sprite.name].Sprite = sprite;
                        sprites[sprite.name].IsChange = true;
                    }
                }
            }

        }

        EditorGUILayout.BeginVertical();

        float posX = 10;
        float posY = 10;

        Rect rect = new Rect(posX, posY, 500, 20);

        uiAtlas = EditorGUI.ObjectField(rect, new GUIContent("Atlas:"), uiAtlas, typeof(UIAtlas), false) as UIAtlas;

        if (uiAtlas)
        {
            foreach(var item in uiAtlas.GetSprites())
            {
                if (!sprites.ContainsKey(item.Key))
                {
                    sprites.Add(item.Key, new SpriteData(item.Key, item.Value));
                }
            }
        }
        else
        {
            sprites.Clear();
        }

        posY += 20;
        rect = new Rect(posX, posY, 100, 50);
        GUILayout.BeginArea(rect);
        using (var h = new EditorGUILayout.HorizontalScope("Button"))
        {
            if (GUI.Button(h.rect, GUIContent.none))
            {
                CreateNewAtlas();
            }
            GUIStyle style = new GUIStyle();
            style.alignment = TextAnchor.MiddleCenter;
            GUILayout.Label("New Atlas", style);
        }
        GUILayout.EndArea();

        posY += 50;

        pos = EditorGUILayout.BeginScrollView(new Vector2(posX, posY)); 

        GUILayout.BeginArea(new Rect(pos, new Vector2(600, 250)));
        
        EditorGUILayout.BeginVertical();

        List<string> curSprites = new List<string>(sprites.Keys);
        foreach (var sp in curSprites)
        {
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.TextField("Sprite:", sp, GUILayout.Width(500));
            
            if(GUILayout.Button(new GUIContent("Delete")))
            {
                sprites.Remove(sp);
                DeleteSprite(sp);
            }
            EditorGUILayout.EndHorizontal();
        }

        EditorGUILayout.EndVertical();

        GUILayout.EndArea();

        EditorGUILayout.EndScrollView();

        using (var h = new EditorGUILayout.HorizontalScope("Button"))
        {
            if (GUI.Button(h.rect, GUIContent.none))
            {
                if (uiAtlas)
                {
                    AddOrUpdateAtlas(uiAtlas.name);
                }
                else
                {
                    Debug.LogError("Atlas can't be null!");
                }
            }
            GUIStyle style = new GUIStyle();
            style.alignment = TextAnchor.MiddleCenter;
            GUILayout.Label("Add/Update", style);
        }

        EditorGUILayout.EndVertical();

        this.Repaint();
    }

    void AddOrUpdateAtlas(string name)
    {
        GameObject newPrefabs = new GameObject(name);
        UIAtlas atlas = newPrefabs.AddComponent<UIAtlas>();

        foreach(var sp in sprites)
        {
            atlas.AddSprite(sp.Value.Sprite);
        }

        GameObject go = PrefabUtility.ReplacePrefab(newPrefabs, uiAtlas, ReplacePrefabOptions.Default);

        uiAtlas = go.GetComponent<UIAtlas>();

        DestroyImmediate(newPrefabs);
    }

    void CreateNewAtlas()
    {
        GameObject go = new GameObject("New Atlas");
        UIAtlas uiAtlas = go.AddComponent<UIAtlas>();
        
        GameObject newGo = PrefabUtility.CreatePrefab("Assets/NewAtlas.prefab", go);
        DestroyImmediate(go);

        this.uiAtlas = newGo.GetComponent<UIAtlas>();
    }

    void DeleteSprite(string sprite)
    {
        Debug.Log("DeleteSprite");
        GameObject go = Instantiate(this.uiAtlas.gameObject);

        UIAtlas uia = go.GetComponent<UIAtlas>();
        if (uia.HasSprite(sprite))
        {
            uia.RemoveSprite(sprite);

            GameObject last = PrefabUtility.ReplacePrefab(go, uiAtlas, ReplacePrefabOptions.Default);

            this.uiAtlas = last.GetComponent<UIAtlas>();
        }

        DestroyImmediate(go);
    }
}

到此打完收工!

你可能感兴趣的:(C#,unity,UGUI)