关于这次的文章,主要需要涉及到以下内容:
1.U3D中用代码动态生成片并设置UV坐标显示图片;
如果这方面还不知道,可以看看另篇文章:http://blog.csdn.net/midashao/article/details/8139109
2.C#版本的LitJson库的简单使用;
LitJson官方地址:http://litjson.sourceforge.net/ ,本人也是刚使用这条内裤,如果不知道Json是神马东西,问下谷哥和度娘吧~
什么是TexturePacker?
用过cocos2d的同学应该对这个比较了解吧(了解到可以直接无视下面的解释了~),不了解也没关系,TexturePacker可以说是个可以把很 多张小图集合成一张大图,并把图片的位置信息保存成文件,然后你需要做的就是解析这个图片位置信息的文件,并结合大图集合显示其中的一张小切图,这也是我 们下面需要做的。
这样合成大图的好处我觉得是可以减少程序加载使用资源的内存,因 为OpenGL ES中每张贴图都需要设置成2的n次方才能使用。比如你有一张宽高为100x100和一张宽高为10x10的图片,如果不合成大贴图,那么需要使用 128x128和16x16的两张图片(分别是2的7次方和2的4次方),但如果使用一张大图的话,可以把100x100和10x10的图片放到 128x128的大图中,这样就用一张图片。
类似这样的一张大贴图就是很多小图片合成的,实际在使用时会只显示其中的一张贴图。
TexturePacker的官网:http://www.codeandweb.com/texturepacker 可以下载免费使用,只不过没付费版本最终导出图片时会随机一张图片加了个水印。
关于TexturePacker的使用,这里简单说下:
软件打开后大概界面就是如上图那样,再把你需要合成的图片拖放到右边的Sprites面板中就会自动排序并显示效果在中间了.
这里简单说明下上图左边用红色圈圈圈出来的属性说明下吧。
Data Format 这里是需要导出的数据格式,下拉框下有cocos2d、libgdx、Unity3d等等..,
本文章选择的是JSON-ARRAY;
Data file 这是导出图片集合信息文件存放的目录,后面就是需要解析这个文件,在这个选项右边的按钮可以选择存放的目录,设置好目录后Texture file选项也会自动填充对应的目录文件。
Image format 这个是设置导出大贴图图片集合的编码格式,这个看自己的具体需求设置;
第二个红色框
Border padding 是设置图片之间的间距,这个挺有用的,如果为0的话也可以,不过可能会出现切出来的图片边边有可能会切到其他图片,所以一般都要设置个值。
Allow rotation 复选框是设置你的贴图在大贴图集合里是否可以旋转的存放,一般都勾上吧,这样可以利用一些空间;
Trim 复选框是是否自动去掉小图中的多余部分。如下图,如果勾上了的话就是左图到右图的效果,把边边透明部分去掉了,这样也是可以大大的节省资源的。
设置好了后按工具栏的Publish按钮就可以导出了,导出的目录就是设置Data file的目录;如果是免费版本导出的大图里面是有水印的,这是正常的。
导出成功后会在对应的目录下找到大贴图集合和一个文件格式;本文导出的格式就如下:
因为打算用LitJson这个库来解析,所以理所当然导出Json的数据结构.
其他的一些属性也是设置大图的导出一些属性,喜欢折腾的可以玩玩;
这里还有篇翻译老外的文章,更详细的介绍TexturePacker的使用,有兴趣可以阅读
http://www.cnblogs.com/andyque/articles/1988097.html~
看看导出的Json结构吧~
{"frames": [ { "filename": "op_01.png", "frame": {"x":2,"y":304,"w":300,"h":429}, "rotated": true, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":300,"h":429}, "sourceSize": {"w":300,"h":429} }, { "filename": "op_02.png", "frame": {"x":433,"y":2,"w":300,"h":429}, "rotated": true, "trimmed": false, "spriteSourceSize": {"x":0,"y":0,"w":300,"h":429}, "sourceSize": {"w":300,"h":429} }] }
这里推荐个文本的编辑器~个人感觉比记事本和UltraEdit都好用,而且还是免费的~
Notepad++
为了节省空间,其他部分就不贴出来了。看结构不难看出,文件保存着文件的名字,文件在大图中贴图的偏移量和大小.
这里大概解释下代表的信息:
filename: 原文件名;
frame: 图片在大图中的偏移位置(左上角为原点)和大小(未旋转前) 需要注意这里的图片大小是图片未旋转前的大小;
rotated: 是否旋转(顺时针方向);
trimmed: 是否有去掉周围多余的透明部分;
spriteSourceSize: x,y表示图片未去掉周围透明部分的偏移量,这是如果需要还原图片原先的大小要用的;
sourceSize: 图片的原始大小,包含透明部分;
用LitJson解析导出的Json结构
~有LitJson库,解析起来很简单,大概步骤如下:
1.将下载下来的LitJson库源码,并将几个源码文件放到U3D项目Assets/Plugins文件夹下
我这边是在Plugins文件夹下加个LitJson文件夹,放到里面,这样看起来清晰些~
下面直接上代码吧~,有了内裤,解析起来很简单而且比.net自带的解析xml还简单~
PS:如果引用不到LitJson的命名空间,在MonoDevelop编辑器中,右键项目Editor References..选项,在弹出来的选择对话框中选择类似xxxx-xxx-firstpass的项目名,因为放在Plugins文件夹下的代码是在另外的项目中的,还有Ediotr文件夹的,这不属于本文的范围了
如下图:
代码如下:
using UnityEngine; using System.Collections; using System.Collections.Generic; using LitJson; /// <summary> /// 帧的信息,包括偏移xy和宽高 /// </summary> public class EFrame { //在大图中的偏移量// public int x, y; //图片占用的宽高// public int width, height; public EFrame(JsonData jsonData) { x = (int)jsonData["x"]; y = (int)jsonData["y"]; width = (int)jsonData["w"]; height = (int)jsonData["h"]; } } public class ESpriteFrameInfo { //文件源文件名// public string filename; //帧贴图的信息// public EFrame frame; //图片是否旋转// public bool isRotate; } public class ESpriteUtility { public static List<ESpriteFrameInfo> analysisTexturePacker(TextAsset txtAsset){ List<ESpriteFrameInfo> readResult = new List<ESpriteFrameInfo>(); JsonData rootJsonData = JsonMapper.ToObject(txtAsset.text); JsonData framesData = rootJsonData["frames"]; int framesCount = framesData.Count; for(int i = 0 ; i < framesCount; i++){ JsonData frame = framesData[i]; ESpriteFrameInfo frameInfo = new ESpriteFrameInfo(); frameInfo.filename = (string)frame["filename"]; frameInfo.isRotate = (bool)frame["rotated"]; frameInfo.frame = new EFrame(frame["frame"]); readResult.Add(frameInfo); } Debug.Log("analysis Done!"); return readResult; } }
这只是个工具类,具体使用还需要写个脚本,拖上TexturePacker导出的数据格式,然后传到analysisTexturePacker方法中使用,最后看到控制台打印analysis Done! 说明解析搞定~这里只是用到了将图片显示的部分显示出来,关于图片周边透明度的实现,本片文章就没做处理了~
这是调用的代码,很简单~
using UnityEngine; using System.Collections; public class TestScript : MonoBehaviour { public TextAsset spriteData; // Use this for initialization void Start () { ESpriteUtility.analysisTexturePacker(spriteData); } // Update is called once per frame void Update () { } }
直接把这个脚本随便拖到一个GameObject上,再把TexturePacker导出的数据格式,拖到spriteData上就可以;记得需要把TexturePacker导出的数据格式的扩展名改成.txt结尾的哦~