使用了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扩展界面如下:嗯,有点熟悉!这个就是我用来管理我自己的的图集的,只要我们把新建立的绑定有UIAtlas脚本的预设体拖到上面Atals的位置,再在资源文件夹里选中你要添加到里面去的Sprite就行,大概效果是这样
然后点击最底下 Add/Update 按钮就会生成包含上面两个Sprite的Prefab啦,如下:
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); } }到此打完收工!