UI优化方案(4)——动态图集

动态图集存在的意义

举例:

选择技能或者头像的时候,如果有100个头像,分成两个图集,加载一个头像图的时候可能需要把两个图集都加载出来;

动态打图集的消耗放在loading条加载过程;动态打图集能很大的优化Drallcall;

动态图集算法

using DaVikingCode.RectanglePacking;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Events;

namespace DaVikingCode.AssetPacker {

	public class AssetPacker : MonoBehaviour {

		public UnityEvent OnProcessCompleted;
		public float pixelsPerUnit = 100.0f;

		public bool useCache = false;
		public string cacheName = "";
		public int cacheVersion = 1;
		public bool deletePreviousCacheVersion = true;

		protected Dictionary<string, Sprite> mSprites = new Dictionary<string, Sprite>();
		protected List<TextureToPack> itemsToRaster = new List<TextureToPack>();

		protected bool allow4096Textures = false;


        /// <summary>
        /// 设定图集参数
        /// </summary>
        /// <param name="file">图片的路径</param>
        /// <param name="customID"></param>
		public void AddTextureToPack(string file, string customID = null) {

			itemsToRaster.Add(new TextureToPack(file, customID != null ? customID : Path.GetFileNameWithoutExtension(file)));
		}

		public void AddTexturesToPack(string[] files) {

			foreach (string file in files)
				AddTextureToPack(file);
		}

        /// <summary>
        /// 调用执行方法
        /// </summary>
        /// <param name="allow4096Textures">是否允许创建一个4096的图集</param>
		public void Process(bool allow4096Textures = false) {

			this.allow4096Textures = allow4096Textures;

            //是否用缓存到本地
			if (useCache) {

				if (cacheName == "")
					throw new Exception("No cache name specified");

				string path = Application.persistentDataPath + "/AssetPacker/" + cacheName + "/" + cacheVersion + "/";

				bool cacheExist = Directory.Exists(path);

                //缓存不存在,创建一个新的图集,如果存在,直接去加载
				if (!cacheExist)
					StartCoroutine(createPack(path));
				else
					StartCoroutine(loadPack(path));
				
			} else
				StartCoroutine(createPack());
			
		}


        /// <summary>
        /// 创建一个新的图集
        /// </summary>
        /// <param name="savePath"></param>
        /// <returns></returns>
		protected IEnumerator createPack(string savePath = "") {

            //如果路径不为空,创建文件夹
			if (savePath != "") {
                //把之前的清理掉
				if (deletePreviousCacheVersion && Directory.Exists(Application.persistentDataPath + "/AssetPacker/" + cacheName + "/"))
					foreach (string dirPath in Directory.GetDirectories(Application.persistentDataPath + "/AssetPacker/" + cacheName + "/", "*", SearchOption.AllDirectories))
						Directory.Delete(dirPath, true);

				Directory.CreateDirectory(savePath);
			}

			List<Texture2D> textures = new List<Texture2D>();
			List<string> images = new List<string>();

            //通过数据加载到图片
			foreach (TextureToPack itemToRaster in itemsToRaster) {

				WWW loader = new WWW("file:///" + itemToRaster.file);

				yield return loader;
                //有时候会发现加载出来的图片是粉红色的图片带?,itemToRaster.file这个文件的后缀没有加上,例如.png,没加.png
                textures.Add(loader.texture);
				images.Add(itemToRaster.id);
			}

            //默认创建的是2048的图集
			int textureSize = allow4096Textures ? 4096 : 2048;

			List<Rect> rectangles = new List<Rect>();
			for (int i = 0; i < textures.Count; i++)
				if (textures[i].width > textureSize || textures[i].height > textureSize)
					throw new Exception("A texture size is bigger than the sprite sheet size!");
				else
					rectangles.Add(new Rect(0, 0, textures[i].width, textures[i].height));

			const int padding = 1;

			int numSpriteSheet = 0;
			while (rectangles.Count > 0) {

                //创建一个texture2D图片,图集对象
				Texture2D texture = new Texture2D(textureSize, textureSize, TextureFormat.ARGB32, false);
				Color32[] fillColor = texture.GetPixels32();
                //把像素全部清理了一下
				for (int i = 0; i < fillColor.Length; ++i)
					fillColor[i] = Color.clear;

				RectanglePacker packer = new RectanglePacker(texture.width, texture.height, padding);

				for (int i = 0; i < rectangles.Count; i++)
					packer.insertRectangle((int) rectangles[i].width, (int) rectangles[i].height, i);

				packer.packRectangles();

				if (packer.rectangleCount > 0) {

					texture.SetPixels32(fillColor);
					IntegerRectangle rect = new IntegerRectangle();
					List<TextureAsset> textureAssets = new List<TextureAsset>();

					List<Rect> garbageRect = new List<Rect>();
					List<Texture2D> garabeTextures = new List<Texture2D>();
					List<string> garbageImages = new List<string>();

                    //计算当前图片需要显示的位置
					for (int j = 0; j < packer.rectangleCount; j++) {

						rect = packer.getRectangle(j, rect);

						int index = packer.getRectangleId(j);
                        //把当前图片的像素渲染到当前图集上,调用当前方法是需要texture是可读可写的,不然会报错
                        texture.SetPixels32(rect.x, rect.y, rect.width, rect.height, textures[index].GetPixels32());

						TextureAsset textureAsset = new TextureAsset();
						textureAsset.x = rect.x;
						textureAsset.y = rect.y;
						textureAsset.width = rect.width;
						textureAsset.height = rect.height;
						textureAsset.name = images[index];

						textureAssets.Add(textureAsset);

						garbageRect.Add(rectangles[index]);
						garabeTextures.Add(textures[index]);
						garbageImages.Add(images[index]);
					}

					foreach (Rect garbage in garbageRect)
						rectangles.Remove(garbage);

					foreach (Texture2D garbage in garabeTextures)
						textures.Remove(garbage);

					foreach (string garbage in garbageImages)
						images.Remove(garbage);

					texture.Apply();

					if (savePath != "") {

						File.WriteAllBytes(savePath + "/data" + numSpriteSheet + ".png", texture.EncodeToPNG());
						File.WriteAllText(savePath + "/data" + numSpriteSheet + ".json", JsonUtility.ToJson(new TextureAssets(textureAssets.ToArray())));
						++numSpriteSheet;
					}

					foreach (TextureAsset textureAsset in textureAssets)
						mSprites.Add(textureAsset.name, Sprite.Create(texture, new Rect(textureAsset.x, textureAsset.y, textureAsset.width, textureAsset.height), Vector2.zero, pixelsPerUnit, 0, SpriteMeshType.FullRect));
				}

			}

			OnProcessCompleted.Invoke();
		}

		protected IEnumerator loadPack(string savePath) {
			
			int numFiles = Directory.GetFiles(savePath).Length;

			for (int i = 0; i < numFiles / 2; ++i) {

				WWW loaderTexture = new WWW("file:///" + savePath + "/data" + i + ".png");
				yield return loaderTexture;

				WWW loaderJSON = new WWW("file:///" + savePath + "/data" + i + ".json");
				yield return loaderJSON;

				TextureAssets textureAssets = JsonUtility.FromJson<TextureAssets> (loaderJSON.text);

				Texture2D t = loaderTexture.texture; // prevent creating a new Texture2D each time.
				foreach (TextureAsset textureAsset in textureAssets.assets)
					mSprites.Add(textureAsset.name, Sprite.Create(t, new Rect(textureAsset.x, textureAsset.y, textureAsset.width, textureAsset.height), Vector2.zero, pixelsPerUnit, 0, SpriteMeshType.FullRect));
			}

			yield return null;

			OnProcessCompleted.Invoke();
		}

		public void Dispose() {

			foreach (var asset in mSprites)
				Destroy(asset.Value.texture);

			mSprites.Clear();
		}

		void Destroy() {

			Dispose();
		}

        /// <summary>
        /// 获取当前图片的方法
        /// </summary>
        /// <param name="id">图片id</param>
        /// <returns></returns>
		public Sprite GetSprite(string id) {

			Sprite sprite = null;

			mSprites.TryGetValue (id, out sprite);

			return sprite;
		}

		public Sprite[] GetSprites(string prefix) {

			List<string> spriteNames = new List<string>();
			foreach (var asset in mSprites)
				if (asset.Key.StartsWith(prefix))
					spriteNames.Add(asset.Key);

			spriteNames.Sort(StringComparer.Ordinal);

			List<Sprite> sprites = new List<Sprite>();
			Sprite sprite;
			for (int i = 0; i < spriteNames.Count; ++i) {

				mSprites.TryGetValue(spriteNames[i], out sprite);

				sprites.Add(sprite);
			}

			return sprites.ToArray();
		}
	}
}

创建动态图集

 每个图片类

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

public class ShowItem : MonoBehaviour
{
    public ShowName ID { get; private set; }
    private Image _image;
    private RuntimeAltasItem _altasItem;

    public void Init(ShowName id)
    {
        ID = id;
        _image = GetComponent<Image>();
        _altasItem = GetComponent<RuntimeAltasItem>();
    }

    public void SetSprite(Sprite sprite)
    {
        _image.sprite = sprite;
    }

    public void AddListener(Action selected)
    {
        gameObject.GetComponent<Button>().onClick.AddListener(()=>selected());
    }

    public KeyValuePair<string, string> GetData()
    {
        return new KeyValuePair<string, string>(ID.ToString(),_altasItem.Path);
    }
}

public enum ShowName
{
    ICON_1,
    ICON_2,
    ICON_3,
}

using UnityEngine;

public class RuntimeAltasItem : MonoBehaviour
{
    public string Path;
}

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

public class SelectedComplete : MonoBehaviour
{
    // Start is called before the first frame update
    public void Init(Func<Dictionary<string,string>> getPaths,LoadingView loadingView)
    {
        GetComponent<Button>().onClick.AddListener(() =>
        {
            loadingView.SetActiveState(true);
            AssetPackerMgr.Instance.GentatorNewAltas("Test",getPaths(),()=>loadingView.SwitchScene(SceneName.Game.ToString()));
        });
    }
}

public enum SceneName
{
    SelectView,
    Game
}

下面是选中图片的类,缓存图片路径的类

using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 选择的三个图标的管理类,负责管理选中的三个图标
/// </summary>
public class SelectShowView : MonoBehaviour
{
    private ShowItem _selectedItem;
    private RuntimeAltasItem _altasItem;
    
    // Start is called before the first frame update
    void Start()
    {
        ShowName id = ShowName.ICON_1;
        foreach (Transform trans in transform)
        {
            RuntimeAltasItem altasItem = trans.gameObject.AddComponent<RuntimeAltasItem>();
            //选中的三个小图类
            ShowItem item =trans.gameObject.AddComponent<ShowItem>();
            
            item.Init(id);
            id++;
            
            item.AddListener(() =>
            {
                _selectedItem = item;
                _altasItem = altasItem;
            });
        }
    }

    public void SetShowItem(Sprite sprite,string path)
    {
        _selectedItem.SetSprite(sprite);
        _altasItem.Path = path;
    }
    
    public Dictionary<string,string> GetPaths()
    {
        Dictionary<string,string> temp = new Dictionary<string, string>();
        KeyValuePair<string, string> tempPair;
        foreach (ShowItem item in GetComponentsInChildren<ShowItem>())
        {
            tempPair = item.GetData();
            temp.Add(tempPair.Key,tempPair.Value);
        }

        return temp;
    }
}

下面是生成图集的方法调用

打图集的类

using System;
using System.Collections.Generic;
using DaVikingCode.AssetPacker;
using UnityEngine;

/// <summary>
/// 打图集的时机是在加载资源,读条的过程中
/// </summary>
public class AssetPackerMgr : MonoBehaviour
{
    public static AssetPackerMgr Instance { get; private set; }
    private Dictionary<string,AssetPacker> _packers = new Dictionary<string, AssetPacker>();

    private void Awake()
    {
        //切换场景有可能重复加载
        if (Instance == null)
        {
            Instance = this;
            GameObject.DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    /// <summary>
    /// 创建新图集
    /// </summary>
    /// <param name="altasName">图集名称</param>
    /// <param name="paths">图片id,图片路径</param>
    /// <param name="complete">完成的回调</param>
    public void GentatorNewAltas(string altasName,Dictionary<string,string> paths,Action complete = null)
    {
        if(paths == null)
            return;
        
        //打包类
        AssetPacker packer = new GameObject(altasName).AddComponent<AssetPacker>();
        packer.transform.SetParent(transform);
        packer.cacheName = altasName;
        foreach (KeyValuePair<string,string> path in paths)
        {
            //图片的路径和id
            packer.AddTextureToPack(path.Value,path.Key);
        }
        //执行打图集的方法
        packer.Process();
        
        packer.OnProcessCompleted.AddListener(() =>
        {
            if (complete != null)
                complete();
        });
        
        _packers.Add(altasName,packer);
    }

    /// <summary>
    /// 获取图集
    /// </summary>
    /// <param name="altasName"></param>
    /// <returns></returns>
    public AssetPacker GetAltas(string altasName)
    {
        if (_packers.ContainsKey(altasName))
        {
            return _packers[altasName];
        }
        else
        {
            Debug.LogError("can not find altas name is "+altasName);
            return null;
        }
    }

    /// <summary>
    /// 清空图集
    /// </summary>
    /// <param name="altasName"></param>
    public void ClearAltas(string altasName)
    {
        if (_packers.ContainsKey(altasName))
        {
            AssetPacker packer = _packers[altasName];
            _packers.Remove(altasName);
            Destroy(packer.gameObject);
        }
        else
        {
            Debug.LogError("can not remove altas,because it can not find,name is"+altasName);
            return;
        }
    }
}

图集的使用

图片的模式  Single单个,Multiple多个,Polygon多边形模式

精灵的多边形设置

带透明通道的,GPU渲染的时候,透明部分的像素点也需要处理,会增加overdrall,但是会造成顶点面数高,

开启面片查看

需要在图片使用的时候设置

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值