首页 > 代码库 > 从gif到unity sprite——批量转换gif、批量导入texture packer图集为sprite、批量生成sprite预制体

从gif到unity sprite——批量转换gif、批量导入texture packer图集为sprite、批量生成sprite预制体

背景是我有几百个角色gif资源,每个都有:站立、攻击、技能攻击的gif,我想用此资源作2d unity游戏,因此第一关就是如何把gif转成unity动画

 

GIF 转 PNG —— http://blog.csdn.net/leinchu/article/details/24806433 ,不再赘述了。

 

之后是批量gif用tp打包,我用php写了一个脚本遍历目录,下的gif把他们重命名并每个角色建立一个文件夹,把它的所有动作的png序列移动到他自己的目录去,再用tp打包:

上php代码,因为我是分布做的,你根据自己的情况改改吧

 

<?php
$arr = scandir(dirname(__FILE__));

$count = 0;
foreach($arr as $f)
{	
	if($f==‘.‘||$f==‘..‘ ||!is_dir($f) || in_array($f,array(‘LAsset‘,‘deal_name.php‘))) continue;
	$strs = explode("_",$f);
	$pre = $strs[0];
	$id = str_replace(‘.png‘,‘‘,$strs[1]);
	$num = intval(preg_replace("/[^\d]/","",$strs[2]));
	
	$folder = ‘bb_‘.$id;
	if(!file_exists($folder)) mkdir($folder);
	
	if($num<1) $num =1;
	$cmd = "move ".$f.‘ ‘.$folder.‘/‘.$pre.‘_‘.$num.‘.png‘;
	exec($cmd);
	$cmd = ‘C:\TexturePacker\bin\TexturePacker --trim-sprite-names  --inner-padding 1 --disable-rotation ‘.$f.‘ --data ‘.$f.‘/‘.$f.‘.txt --format unity --sheet LAsset/‘.$f.‘.png --max-width 8192 --max-height 8192‘;
	exec($cmd);
	$txt = file_get_contents($f.‘/‘.$f.‘.txt‘);
	$arr =(array) json_decode($txt);

	$a = array();
	$h = $arr[‘meta‘]->size->h;
	$arr = (array) $arr[‘frames‘];


	//var_dump($arr);die();
	foreach($arr as $name=>$fr){
		$a[] = $name.‘,‘.$fr->frame->x.‘,‘.$fr->frame->y.‘,‘.$fr->frame->w.‘,‘.$fr->frame->h
		.‘,‘.$fr->spriteSourceSize->x//用于计算Pivot
		.‘,‘.$fr->spriteSourceSize->y
		.‘,‘.$fr->spriteSourceSize->w
		.‘,‘.$fr->spriteSourceSize->h
		.‘,‘.$h//tp的原点在左上角,unity的在右下角,需要用图集高度来转换
		.‘,‘.$fr->sourceSize->w
		.‘,‘.$fr->sourceSize->h
		;
	}
	file_put_contents(‘LAsset/‘.$f.‘.txt‘,implode("\r\n", $a));
	echo $f." OK\n";
	//if($count++<5) echo $cmd."\n";else break;
}

 

之后是自动把png图集转换成sprite集合,我写了脚本,你只要把这个脚本放进你的项目就可以了,然后再asset目录下建立个目录LAsset,右键这个目录把png图集导入进来,就会自动转成sprite集合了

 

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

/*
Your origin picture diretory should be like:
/folder
/folder/LAsset/hero_1
/folder/LAsset/hero_1/spriteAltas.png
/folder/LAsset/hero_1/spriteAltas.txt
/folder/LAsset/hero_2/spriteAltas.png
/folder/LAsset/hero_2/spriteAltas.txt

spriteAltas.txt should be in format of "stand_1,x,y,width,height\r\nstand_2,x,y,width,height\r\nattack_1,x,y,width,height\r\nattack_2,x,y,width,height\r\nattack_3,x,y,width,height"
and finally you will got two prefabs(hero_1, hero_2) both of them has a sprite which has five members(sprites): stand_1,stand_2,attack_1,attack_2,attack_3
 */
public class LAssetPostprocessor : AssetPostprocessor
{
		void OnPostprocessAllAssets (
		string[] importedAssets,
		string[] deletedAssets,
		string[] movedAssets,
		string[] movedFromAssetPaths)
		{	
				Debug.Log ("====================== *OnPostprocessAllAssets* ===================");
				foreach (string str in importedAssets) {
						Debug.Log ("Reimported Asset: " + str);
				}

				foreach (string str in deletedAssets) {
						Debug.Log ("Deleted Asset: " + str);
				}

				for (int i=0; i < movedAssets.Length; i++) {
						Debug.Log ("Moved Asset: " + movedAssets [i] + " from: " + movedFromAssetPaths [i]);
				}
		}

		void OnProcessSprite ()
		{
				Utils.log ("++++++++++++++++++++ OnProcessSprite ++++++++++++++++++", 1);
		}

		public static string autoPathMark = "Pets";//
		private string spriteLoadFrom = "C:/D/2014/poke/img/images/bb/test/Result/LAsset/";
		private int padding = 1;
		
		void OnPreprocessTexture ()
		{
				Utils.log ("OnPreprocessTexture: " + assetPath);
				if (Path.GetExtension (assetPath) == ".png" && assetPath.IndexOf (autoPathMark) != -1) {
						string[] path;
						if (assetPath.IndexOf ("/") != -1)
								path = assetPath.Substring (assetPath.IndexOf (autoPathMark) + autoPathMark.Length + 1).Split (new string[]{"/"}, StringSplitOptions.RemoveEmptyEntries);
						else
								path = assetPath.Substring (assetPath.IndexOf (autoPathMark) + autoPathMark.Length + 1).Split (new string[]{"\\"}, StringSplitOptions.RemoveEmptyEntries);
						string spriteName = path [0].Replace (".png", "");

						string atlasPath = spriteLoadFrom + spriteName + ".txt";
						Utils.log ("Auto make sprite: " + assetPath + ", atlasPath=" + atlasPath);

						if (File.Exists (atlasPath)) {
								TextureImporter importer = assetImporter as TextureImporter;

								importer.spriteImportMode = SpriteImportMode.Multiple;
								importer.spritePixelsToUnits = 100;
								importer.spritePackingTag = spriteName;
								spriteSheetRow[] spriteSheet = spriteSheetConfigReader.getSpriteSheet (atlasPath);
								int count = spriteSheet.Length;

								Utils.log ("------------------------------------> Frame count: " + count);
								spriteSheetRow row;
								List<SpriteMetaData> spriteMetaData = http://www.mamicode.com/new List ();>


 

因为在导入过程中sprite没有生成,也没有生成后再调用的方法,所以只能再通过一个菜单来批量转换为prefab,把下面的脚本放到你的项目里面,在unity里面选中Asset/LAsset目录,点击菜单Assets/+> Build Prefabs From Selection...预制体就会被打包到Resources下(具体自己改路径吧)

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

public class LExportPrefabs
{
		private static string[] state_type = new string[]{"stand","attack","skill"};

		[MenuItem("Assets/+> Build Prefabs From Selection...")]
		static void LExportResource ()
		{ 
				//List<string> pathList = new List<string> ();  
				UnityEngine.Object[] objs = Selection.GetFiltered (typeof(UnityEngine.Object), SelectionMode.DeepAssets);  
				foreach (UnityEngine.Object _obj in objs) {  
						string path = AssetDatabase.GetAssetPath (_obj);
						Utils.log (path);
						if (Path.GetExtension (path) == ".png" && path.IndexOf (LAssetPostprocessor.autoPathMark) != -1) {
								string filename = Path.GetFileName (path);
								string spriteName = filename.Replace (".png", "");
								//pathList.Add (path);
								Utils.log (path + " creating prefab for " + spriteName + "...");
								GameObject obj = new GameObject (spriteName);
								obj.AddComponent<SpriteRenderer> ();
								TurnModeRPGAnimator animator = obj.AddComponent<TurnModeRPGAnimator> ();

								List<Dictionary<int, int>> frameOrderOfState = new List<Dictionary<int, int>> ();
								frameOrderOfState.Add (new Dictionary<int, int> ());
								frameOrderOfState.Add (new Dictionary<int, int> ());
								frameOrderOfState.Add (new Dictionary<int, int> ());

								UnityEngine.Object[] arr = AssetDatabase.LoadAllAssetsAtPath (path);
								int len = arr.Length;

								//List<Sprite> sprites = new List<Sprite> ();
								Utils.log ("length: " + len);
								for (int i=0; i<len; i++)
										if (arr [i] is Sprite) {
												for (int j=0; j<3; j++)
														if (arr [i].name.IndexOf (state_type [j]) != -1) {
																frameOrderOfState [j].Add (Utils.parseInt (arr [i].name.Replace (state_type [j] + "_", "")), animator.sprites.Count);
																break;
														}
												animator.sprites.Add (arr [i] as Sprite);
										}
								int idx = 0;
								foreach (Dictionary<int, int> item in frameOrderOfState) {

										int[] arrFrames = new int[item.Count];
										for (int i=0; i<item.Count; i++)
												arrFrames [i] = item [i+1];

										if (idx == 0)
												animator.standFrames = arrFrames;
										else if (idx == 1)
												animator.attackFrames = arrFrames;
										else 
												animator.skillFrames = arrFrames;

										idx++;
								}
				animator.dics.Add(1,2);
				animator.dics.Add(2,317);
					PrefabUtility.CreatePrefab ("Assets/Resources/Pets/" + spriteName + ".prefab", obj);
								GameObject.DestroyImmediate (obj);
								Utils.log ("OK");
						}
						
				}  

		}  
}


 

预制体使用:

 

UnityEngine.GameObject _obj = Resources.Load ("Pets/bb_" + id) as GameObject;
				if (_obj != null) {
						Utils.log ("Resources loaded OK");
				} else
						Utils.log ("Resources failt to load");
				Instantiate (_obj, new Vector3 (id % 3, 0, 0), new Quaternion ());



 

我的QQ群:

PHPer&页游&Mobile&U3D 2D,群号:95303036
加群除了提问之外,请记得帮助别人,谢谢。