Unity杂谈(一)图集制作与图集分割

1、图集制作

1.1、NGUI下的图集制作

首先将需要制作成图集的小图放到Unity工程下的某个目录下,再通过NGUI->Open->Atlas Maker。如下图

将会打开图集制作界面,如下图。在选择好需要制作成图集的小图后,点击Craete,将生成NGUI生成好的图集。

NGUI将生成三个文件,分别是png文件(图集);material文件(材质);prefab文件(实际用到的Atlas)。

 

1.2 UGUI制作图集

UGUI打包图集的设置在Project Seting >>Editor>>Sprite Packer的Mode。

其中,Disabled表示不启用图集打包,Enabled For Builds 表示仅在发布时启用。Always Enabled表示一直启用,方便我们开发人员在开发阶段就查看图集打包的情况。我们选择这种方式。

在开启图集打包后,我们选中需要打包成图集的小图(不能放在Resources目录下),将Packing Tag填入指定的值。如下

此时,UGUI将会把Packing Tag值相同的图片打包到同一个图集中,可在Window->Sprite Packer中查看。(如果未出现图集,点击Pack)。实际生成的图集在默认放在Libary/AtlasCache里面。

1.3 使用TexurePacker

TexturePacker官网链接

下载TexturePacker并安装后,打开TexturePacker,如下图

将需要合成图集的小图拖拽到左侧空白处,并在右侧的Data Format 选择 JSON Data(当然可以选择其他格式的文件,这边只是其中的一种方法)。

然后点击publish sprite sheet。生成所需要的图集。

在Unity中,可以通过json文件保存的信息进行图集的再次slice。我在网上找到一些代码,可以对图集进行分割。

TexturePacker.cs

/*
Copyright (c) 2013 Mitch Thompson
Extended by Harald Lurger (2013) (Process to Sprites)

Standard MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

public static class TexturePackerExtensions{
	public static Rect TPHashtableToRect(this Hashtable table){
		return new Rect((float)table["x"], (float)table["y"], (float)table["w"], (float)table["h"]);
	}
	
	public static Vector2 TPHashtableToVector2(this Hashtable table){
		if(table.ContainsKey("x") && table.ContainsKey("y")){
			return new Vector2((float)table["x"], (float)table["y"]);
		}
		else{
			return new Vector2((float)table["w"], (float)table["h"]);
		}
	}
	
	public static Vector2 TPVector3toVector2(this Vector3 vec){
		return new Vector2(vec.x, vec.y);
	}
	
	public static bool IsTexturePackerTable(this Hashtable table){
		if(table == null) return false;
		
		if(table.ContainsKey("meta")){
			Hashtable metaTable = (Hashtable)table["meta"];
			if(metaTable.ContainsKey("app")){
				return true;
//				if((string)metaTable["app"] == "http://www.texturepacker.com"){
//					return true;	
//				}
			}
		}
		
		return false;
	}
}

public class TexturePacker{

	public class PackedFrame{
		public string name;
		public Rect frame;
		public Rect spriteSourceSize;
		public Vector2 sourceSize;
		public bool rotated;
		public bool trimmed;
		Vector2 atlasSize;
		
		public PackedFrame(string name, Vector2 atlasSize, Hashtable table){
			this.name = name;
			this.atlasSize = atlasSize;
			
			frame = ((Hashtable)table["frame"]).TPHashtableToRect();
			spriteSourceSize = ((Hashtable)table["spriteSourceSize"]).TPHashtableToRect();
			sourceSize = ((Hashtable)table["sourceSize"]).TPHashtableToVector2();
			rotated = (bool)table["rotated"];
			trimmed = (bool)table["trimmed"];
		}
		
		public Mesh BuildBasicMesh(float scale, Color32 defaultColor){
			return BuildBasicMesh(scale, defaultColor, Quaternion.identity);
		}
		
		public Mesh BuildBasicMesh(float scale, Color32 defaultColor, Quaternion rotation){
			Mesh m = new Mesh();
			Vector3[] verts = new Vector3[4];
			Vector2[] uvs = new Vector2[4];
			Color32[] colors = new Color32[4];
		
			
			if(!rotated){
				verts[0] = new Vector3(frame.x,frame.y,0);
				verts[1] = new Vector3(frame.x,frame.y+frame.height,0);
				verts[2] = new Vector3(frame.x+frame.width,frame.y+frame.height,0);
				verts[3] = new Vector3(frame.x+frame.width,frame.y,0);
			}
			else{
				verts[0] = new Vector3(frame.x,frame.y,0);
				verts[1] = new Vector3(frame.x,frame.y+frame.width,0);
				verts[2] = new Vector3(frame.x+frame.height,frame.y+frame.width,0);
				verts[3] = new Vector3(frame.x+frame.height,frame.y,0);
			}
			
			

			
			uvs[0] = verts[0].TPVector3toVector2();
			uvs[1] = verts[1].TPVector3toVector2();
			uvs[2] = verts[2].TPVector3toVector2();
			uvs[3] = verts[3].TPVector3toVector2();
			
			for(int i = 0; i < uvs.Length; i++){
				uvs[i].x /= atlasSize.x;
				uvs[i].y /= atlasSize.y;
				uvs[i].y = 1.0f - uvs[i].y;
			}
			
			if(rotated){
				verts[3] = new Vector3(frame.x,frame.y,0);
				verts[0] = new Vector3(frame.x,frame.y+frame.height,0);
				verts[1] = new Vector3(frame.x+frame.width,frame.y+frame.height,0);
				verts[2] = new Vector3(frame.x+frame.width,frame.y,0);
			}
			
			
			//v-flip
			for(int i = 0; i < verts.Length; i++){
				verts[i].y = atlasSize.y - verts[i].y;
			}
			
			//original origin
			for(int i = 0; i < verts.Length; i++){
				verts[i].x -= frame.x - spriteSourceSize.x + (sourceSize.x/2.0f);
				verts[i].y -= (atlasSize.y - frame.y) - (sourceSize.y - spriteSourceSize.y) + (sourceSize.y/2.0f);
			}
			
			//scaler
			for(int i = 0; i < verts.Length; i++){
				verts[i] *= scale;
			}
			
			//rotator
			if(rotation != Quaternion.identity){
				for(int i = 0; i < verts.Length; i++){
					verts[i] = rotation * verts[i];
				}
			}
		
			for(int i = 0; i < colors.Length; i++){
				colors[i] = defaultColor;
			}
			
			
			m.vertices = verts;
			m.uv = uvs;
			m.colors32 = colors;
			m.triangles = new int[6]{0,3,1,1,3,2};
			
			m.RecalculateNormals();
			m.RecalculateBounds();
			m.name = name;
			
			return m;
		}

		public SpriteMetaData BuildBasicSprite(float scale, Color32 defaultColor){
			SpriteMetaData smd = new SpriteMetaData();
			Rect rect;

			if(!rotated){
				rect = this.frame;
			}
			else
			{
				rect = new Rect(frame.x,frame.y,frame.height,frame.width);
			}


			/* Look if frame is outside from texture */ 

			if( (frame.x + frame.width) > atlasSize.x || (frame.y + frame.height) > atlasSize.y ||
			    (frame.x < 0 || frame.y < 0)) 
			{
				Debug.Log(this.name + " is outside from texture! Sprite is ignored!");
				smd.name = "IGNORE_SPRITE";
				return smd;

			}
			//calculate Height 
		 	/* Example: Texture: 1000 Width x 500 height 
		 	 * Sprite.Recht(0,0,100,100) --> Sprite is on the bottom left
			 */

			rect.y = atlasSize.y - frame.y - rect.height;

			smd.rect = rect;
			smd.alignment =  1;
			smd.name = name;
			smd.pivot = this.frame.center;

			return smd;
		}
	}
	
	public class MetaData{
		public string image;
		public string format;
		public Vector2 size;
		public float scale;
		public string smartUpdate;
		
		public MetaData(Hashtable table){
			image = (string)table["image"];
			format = (string)table["format"];
			size = ((Hashtable)table["size"]).TPHashtableToVector2();
			scale = float.Parse(table["scale"].ToString());
			smartUpdate = (string)table["smartUpdate"];
		}
	}

	public static List<SpriteMetaData> ProcessToSprites(string text) {
		Hashtable table = text.hashtableFromJson();
		
		MetaData meta = new MetaData((Hashtable)table["meta"]);
		
		List<PackedFrame> frames = new List<PackedFrame>();
		Hashtable frameTable = (Hashtable)table["frames"];
		
		foreach(DictionaryEntry entry in frameTable){
			frames.Add(new PackedFrame((string)entry.Key, meta.size, (Hashtable)entry.Value));
		}

		SortFrames(frames);

		List<SpriteMetaData> sprites = new List<SpriteMetaData>();
		for(int i = 0; i < frames.Count; i++){
			SpriteMetaData smd = frames[i].BuildBasicSprite( 0.01f, new Color32(128,128,128,128));
			if(!smd.name.Equals("IGNORE_SPRITE"))
				sprites.Add(smd);
		}

		return sprites;

	}

	private static List<PackedFrame> SortFrames (List<PackedFrame> frames) {
		for (int i=frames.Count-1; i>0; i--) {
			for (int j=0; j<i; j++) {
				if (string.Compare(frames[j+1].name, frames[j].name) < 0) {
					PackedFrame temp = frames[j+1];
					frames[j+1] = frames[j];
					frames[j] = temp;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity的Sprite Multiple功能是用来处理多个图片在一个图集中的情况的。在使用这个功能之前,你需要准备一个包含多个小图的大图集。然后,你可以通过以下步骤来拆分这个图集。 首先,打开Unity编辑器,并将大图集导入到项目中。将图集拖拽到场景中的一个空的游戏对象上,创建一个Sprite Renderer组件。然后,将Sprite Mode设置为Multiple,这样unity就会把图集视为一个多精灵图。 接下来,点击Sprite Editor按钮,这会打开Sprite Editor窗口。在窗口中,你会看到图集中所有小图的预览。你可以使用鼠标选择并拖拽来选择一个小图,并在预览面板中预览选择的小图。 在Sprite Editor窗口的左侧,你可以调整小图的位置和大小,以确保它们正确地对应着图集中的位置。你还可以裁剪小图来确保只显示你想要的部分。你可以使用切分工具来裁剪小图,也可以使用设置工具来调整其精确位置和大小。 一旦你完成了所有的拆分和调整,点击Apply按钮来应用更改。此时,unity会自动创建一个Sprite Asset,它会将图集中的每个小图作为一个独立的精灵。 现在,你可以在Unity中使用这些独立的精灵了。你可以将它们分别用于不同的游戏对象,也可以使用Sprite Renderer组件的Sprite属性来动态更换精灵。 总的来说,Unity的Sprite Multiple功能非常方便,它使得管理和使用图集中的多个小图变得简单而高效。无论是制作2D游戏还是创建用户界面,都可以通过这个功能来提高工作效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值