最新文章
Cocos2d-x游戏开发实例详解7:对象释放时机
03-25 13:59
Cocos2d-x游戏开发实例详解6:自动释放池
03-25 13:55
Cocos2d-x游戏开发实例详解5:神奇的自动释放
03-25 13:49
Cocos2d-x游戏开发实例详解4:游戏主循环
03-25 13:44
Cocos2d-x游戏开发实例详解3:无限滚动地图
03-25 13:37
Cocos2d-x游戏开发实例详解2:开始菜单续
03-25 13:32
unity3d ui图片集动态加载
在Unity3D开发中,UI图片的加载和管理是一个重要的环节。NGUI(Next-Gen UI)为我们提供了方便的UIAtlas功能,其主要作用是优化DrawCall,它将众多图片整合在一张贴图上。由于Unity3D使用原生GUI简单易用,开发者很容易忽视DrawCall的问题,而NGUI的UIAtlas正是为改进这一问题而设计的。当然,NGUI还做了很多其他方面的优化。
本文主要介绍如何利用UISprite来动态加载图片,将详细阐述两种不同的方法。
动态加载图片的方法
方法1:在代码中创建和设置UIAtlas并显示UISprite
这种方法可以对任何零散的贴图进行加载,但缺点是会浪费DrawCall,主要适用于处理特别零散的贴图资源。以下是实现该方法的代码:
public class ImageLoader : MonoBehaviour {
// 需要加载动态图片的对象
public UISprite m_img;
// 自用的Atlas
private UIAtlas m_uiAtlas;
/// <summary>
/// 加载贴图
/// </summary>
/// <param name="tex">要加载的贴图</param>
public void ImageLoad(Texture2D tex) {
if (tex == null) {
return;
}
if (tex.name == m_img.spriteName) {
return;
}
// 准备对象和材质球
if (m_uiAtlas == null) {
Material mat;
Shader shader = Shader.Find("Unlit/Transparent Colored");
mat = new Material(shader);
m_uiAtlas = this.gameObject.AddComponent<UIAtlas>();
m_uiAtlas.spriteMaterial = mat;
}
// 设定贴图
m_uiAtlas.spriteMaterial.mainTexture = tex;
m_uiAtlas.coordinates = UIAtlas.Coordinates.Pixels;
// 为对应UISprite接口,给Atlas添加对象
UIAtlas.Sprite sprite = new UIAtlas.Sprite();
sprite.name = tex.name;
sprite.outer = sprite.inner = new Rect(0f, 0f, tex.width, tex.height);
m_uiAtlas.spriteList.Clear();
m_uiAtlas.spriteList.Add(sprite);
// 设置完成
m_img.atlas = m_uiAtlas;
m_img.spriteName = tex.name;
}
}
方法2:打包整个UIAtlas及其贴图形成资源并驻留内存
将整个UIAtlas及其贴图打包,形成资源并驻留在内存中(实际上只是指向资源的指针),Unity3D会根据引用来确定贴图是否直接放入实际内存。这种方法更适合处理ICON之类有规律、可以配置整合的资源,但缺点是需要进行维护。以下是实现该方法的代码:
// 从资源文件夹加载打包成assetBundle的ICON资源文件
private IEnumerator LoadResIcon() {
// 准备好资源路径格式
string strFormat = ResourcePath.GetPath() + "UI/{0}";
string strFilePath = "";
for (int i = 0, nMax = GameConfig.Instance.IconSet.strIcons.Length; i < nMax; i++) {
string strAssetName = GameConfig.Instance.IconSet.strIcons[i];
strFilePath = string.Format(strFormat, strAssetName);
WWW tmp_www = null;
try {
tmp_www = new WWW(strFilePath);
} catch {
tmp_www = null;
}
if (tmp_www == null) {
continue;
}
yield return tmp_www;
if (tmp_www.error != null) {
tmp_www.Dispose();
tmp_www = null;
yield break;
}
AssetBundle tmp_assetBundle = tmp_www.assetBundle;
tmp_www.Dispose();
tmp_www = null;
UIAtlas atlas = tmp_assetBundle.Load(strAssetName, typeof(UIAtlas)) as UIAtlas;
tmp_assetBundle.Unload(false);
GameConfig.Instance.IconSet.SaveUIAtlas(i, atlas);
}
yield return null;
}
UIAtlas的管理
为了更好地管理UIAtlas,我们可以创建一个IconSet类,该类负责保存和查找UIAtlas信息。以下是IconSet类的实现代码:
public class IconSet {
public string[] strIcons = {
"A1_Atlas",
"A2_Atlas",
"A3_Atlas"
};
public UIAtlas[] m_AtlasData;
Dictionary<string, int> m_dicIcon;
public IconSet() {
m_AtlasData = new UIAtlas[strIcons.Length];
m_dicIcon = new Dictionary<string, int>();
}
// 保存Atlas的完整信息
public void SaveUIAtlas(int nIndex, UIAtlas UIvalue) {
m_AtlasData[nIndex] = UIvalue;
foreach (string iconNames in UIvalue.GetListOfSprites()) {
m_dicIcon[(string)iconNames.Clone()] = nIndex; // 将所有的ICONNAME信息记录并且绑定成索引,以便查找
}
}
// 根据ICONNAME找出对应UIATLAS
public UIAtlas FindAtlasBySpriteName(string name) {
int nAtlasIndex = 0;
if (m_dicIcon.TryGetValue(name, out nAtlasIndex)) {
return m_AtlasData[nAtlasIndex];
}
return null;
}
}
实际使用范例
以下是一个实际使用的范例,展示了如何通过IconSet类来设置UISprite的显示:
// 设置显示对象
UISprite sprite = this.GetComponent<UISprite>();
sprite.atlas = GameConfig.Instance.IconSet.FindAtlasBySpriteName("Icon001");
sprite.spriteName = "Icon001";
总结
以上两种方法基本能够应对大部分UI的显示问题。由于ImageLoader本身传入的是Texture2D类型,所以即便是RenderTexture也能正常使用,都能与NGUI和谐相处。如果加以扩展,还可以让另一个摄像机导出的内容和当前NGUI摆放的UI进行结合。