背景是我有几百个角色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 = new List<SpriteMetaData> (); for (int i=0; i<count; i++) { row = spriteSheet [i]; string n = row.name; int x = row.x; int y = row.y; int w = row.w; int h = row.h; int height = row.height; //Utils.log ("==>> x=" + x + ", y=" + y + ", w=" + w + ", h=" + h + ", height=" + height); SpriteMetaData metaData = new SpriteMetaData (); // According to Unity docs, Center = 0, Custom = 9 metaData.alignment = 9; metaData.name = n; metaData.pivot = Vector2.zero; //metaData.pivot = new Vector2 ((row.ox + row.ow - row.sw / 2.0f) / (float)w, (row.oy + row.oh - row.sh / 2.0f) / (float)h);// Vector2 (0.5f, 0.5f); metaData.rect = new Rect (x, height - h - y + padding, w, h); spriteMetaData.Add (metaData); } importer.spritesheet = spriteMetaData.ToArray (); importer.name = spriteName; } } } } public struct spriteSheetRow { public string name; public int x; public int y; public int w; public int h; public int ox; public int oy; public int ow; public int oh; public int height;//图集的高度 public int sw;//当前帧的没有裁切的宽度 public int sh;//当前帧的没有裁切的高度 } public class spriteSheetConfigReader { public static spriteSheetRow[] getSpriteSheet (string configFilePath) { //Get content of the config file, config file is suppose to in format of "name,x,y,width,height\r\nname,x,y,width,height\r\nname,x,y,width,height" string[] config_strs = FileUtils.getInstance ().ReadFile (configFilePath, "").Split (new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); int len = config_strs.Length; spriteSheetRow[] arr = new spriteSheetRow[len]; for (int i=0; i<len; i++) { //for debug message, you can delete it ConfigLoader.log_head = configFilePath + " > row " + i; string[] tmp = config_strs [i].Split (new string[]{","}, StringSplitOptions.RemoveEmptyEntries); spriteSheetRow row; row.name = tmp [0]; row.x = Utils.parseInt (tmp [1]); row.y = Utils.parseInt (tmp [2]); row.w = Utils.parseInt (tmp [3]); row.h = Utils.parseInt (tmp [4]); row.ox = Utils.parseInt (tmp [5]); row.oy = Utils.parseInt (tmp [6]); row.ow = Utils.parseInt (tmp [7]); row.oh = Utils.parseInt (tmp [8]); row.height = Utils.parseInt (tmp [9]); row.sw = Utils.parseInt (tmp [10]); row.sh = Utils.parseInt (tmp [11]); arr [i] = row; } return arr; } }
因为在导入过程中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
加群除了提问之外,请记得帮助别人,谢谢。
从gif到unity sprite——批量转换gif、批量导入texture packer图集为sprite、批量生成sprite预制体
时间: 2024-11-08 07:39:55