这两天详细的看了下U3D的新图集系统 SpriteAtlas ,目前为止觉得这个新系统用起来问题不大。但是在理解上有一些问题,我会在这里做一些记录。
在操作上,这个没什么问题。有问题的是SpriteAtlasManager这块,需要去理解一下调用机制。

操作

UNITY每次更新旧操作方式都会变得更加简单,这次亦是如此。

启用图集打包方式

1
2
3
4
5
Edit-> ProjectSettings -> Editor -> Sprite Packer -> Mode
-> Enable For Builds:在打包时使用图集
-> AlwaysEnabled:保持图集状态

制作图集

新建SpriteAtlas文件,将Sprite或者Sprite所在文件夹拖入Objects for Packing,按Pack Preview预览。

变体

使用变体方便的制作低清晰度图集给低性能设备使用

注意

SpriteAtlas -> Include in Build : 勾选的话作用于编辑器中。取消后需要在代码中监听SpriteAtlasManager.atlasRequested事件来在程序中加载贴图集。

如果你准备用AB加载图集 或者 直接从Resources加载图集 建议你将 Include in Build 的选中去掉。避免重复的资源出现在包体里。

机制

先加载后取值

如果现在要在运行时从资源目录或者AB里加载出Prefab,这个时候我们需要先加载这个Prefab的代码上先进行SpriteAtlas的加载工作 – 也就是需要保证这个Sprite所属SpriteAtlas已经被Load到运行时。

下面的代码是可以正常工作的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
using UnityEngine.UI;
public class TestSA : MonoBehaviour
{
public GameObject[] objs;
private SpriteAtlas at;
// Start is called before the first frame update
IEnumerator Start()
{
at = Resources.Load<SpriteAtlas>("NewSpriteAtlas2");
yield return new WaitForSeconds(3);
for (int i = 0; i < objs.Length; i++)
{
objs[i].SetActive(true);
}
objs[0].GetComponent<Image>().sprite = at.GetSprite("04");
objs[1].GetComponent<Image>().sprite = at.GetSprite("04");
objs[2].GetComponent<Image>().sprite = at.GetSprite("04");
}
}

因为没有对 SpriteAtlasManager 中的回调函数进行监听,我们收获了一个Warning , 但是不影响编辑器中的正常显示 。

1
⚠️ SpriteAtlasManager.atlasRequested wasn't listened to while NewSpriteAtlas2 requested.

如果你考虑上面的做法务必小心你在每次代码调用Sprite加载都已经Load过SpriteAtlas。这应该是需要写一个相应的模块去管理 SpriteAtlas - Sprite 的从属关系。

先注册后取值

第二种就简单一些了,这也是UNTIY推荐的方法。你不必每次都在代码前检测是否调用过图集加载之类或者其他加载图集相关代码。 你只需要在 SpriteAtlasManager 中注册 atlasRegistered . 在第一次加载相应图集的时候会自动调一次,这时候在该函数的回调中内你可以轻松的写一段加载图集的代码。

加载时机

哦对了,这个图集什么时候被加载 ? 如果你实例化物体关联到Sprite 就会执行 atlasRequested 回调,在UNITY内部做了一个检测,如果该关联到的图集是第一次被关联到,那么才会调用一次。

Trigger when any Sprite was bound to SpriteAtlas but couldn’t locate the atlas asset during runtime.
This usually means the sprite was packed to an atlas which is not included in build
This callback does not expect an immediate response from the user. Instead, it passes on a System.Action. The user can load the atlas object later and use this System.Action to pass back the loaded atlas.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using UnityEngine;
using UnityEngine.U2D;
public class AtlasLoader : MonoBehaviour
{
void OnEnable()
{
SpriteAtlasManager.atlasRequested += RequestAtlas;
}
void OnDisable()
{
SpriteAtlasManager.atlasRequested -= RequestAtlas;
}
void RequestAtlas(string tag, System.Action<SpriteAtlas> callback)
{
var sa = Resources.Load<SpriteAtlas>(tag);
callback(sa);
}
}

参考链接

Unity2017的新spriteAtlas
SpriteAtlasManager
About “Include in Build” behaviour