Anime.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /**
  2. * 魔力宝贝图档解析脚本 - CGTool
  3. *
  4. * @Author HonorLee (dev@honorlee.me)
  5. * @Version 1.0 (2023-04-15)
  6. * @License GPL-3.0
  7. *
  8. * Anime.cs 动画基础类
  9. */
  10. using System;
  11. using System.Collections.Generic;
  12. using System.IO;
  13. using System.Linq;
  14. using UnityEngine;
  15. namespace CrossgateToolkit
  16. {
  17. //动画信息
  18. public class AnimeInfo
  19. {
  20. // 版本
  21. public string Version;
  22. //4 bytes 动画序号
  23. public uint Serial;
  24. //4 bytes 动画文件地址
  25. public uint Addr;
  26. //2 bytes 动作数量
  27. public int ActionCount;
  28. //2 bytes 未知字节
  29. public byte[] Unknow;
  30. //动画数据 Direction -> ActionType -> AnimeData
  31. public Dictionary<int, Dictionary<int, AnimeDetail>> AnimeDatas = new Dictionary<int, Dictionary<int, AnimeDetail>>();
  32. }
  33. //动画帧数据
  34. public class AnimeFrameInfo
  35. {
  36. //图档编号
  37. public uint GraphicIndex;
  38. //宽度
  39. public int Width;
  40. //高度
  41. public int Height;
  42. //偏移X
  43. public int OffsetX;
  44. //偏移Y
  45. public int OffsetY;
  46. //音效编号
  47. public int AudioIndex;
  48. //动效编号
  49. public Anime.EffectType Effect;
  50. //GraphicInfo;
  51. public GraphicInfoData GraphicInfo;
  52. //动画Sprite
  53. public Dictionary<int,Sprite> AnimeSprites = new Dictionary<int, Sprite>();
  54. }
  55. //动画数据
  56. public class AnimeDetail
  57. {
  58. // 动画编号
  59. public uint Serial;
  60. // 动画版本
  61. public string Version;
  62. // 方向
  63. public int Direction;
  64. // 动作
  65. public int ActionType;
  66. // 动画循环时间
  67. public uint CycleTime;
  68. // 帧数
  69. public uint FrameCount;
  70. // 高版本 - 标识
  71. public bool IsHighVersion;
  72. // 高版本 - 调色板
  73. public int Palet;
  74. // 高版本 - 图像反转
  75. public bool Reverse;
  76. // 高版本 - 结束标识
  77. public byte[] END_FLAG;
  78. public Dictionary<int,Texture2D> AnimeTextures = new Dictionary<int, Texture2D>();
  79. // public Texture2D AnimeTexture;
  80. public List<AnimeFrameInfo> AnimeFrameInfos;
  81. // public byte[] unknown;
  82. }
  83. //动画相关Enum类型
  84. public class Anime : MonoBehaviour
  85. {
  86. //方向
  87. public enum DirectionType
  88. {
  89. NULL = -1,
  90. North = 0,
  91. NorthEast = 1,
  92. East = 2,
  93. SouthEast = 3,
  94. South = 4,
  95. SouthWest = 5,
  96. West = 6,
  97. NorthWest = 7
  98. }
  99. //方向九宫映射表
  100. public static DirectionType[,] DirectionTypeMap = new DirectionType[3,3]
  101. {
  102. {DirectionType.North,DirectionType.NorthEast,DirectionType.East},
  103. {DirectionType.NorthWest,DirectionType.NULL,DirectionType.SouthEast},
  104. {DirectionType.West,DirectionType.SouthWest,DirectionType.South}
  105. };
  106. //动作
  107. public enum ActionType
  108. {
  109. NULL = -1,
  110. Stand = 0,
  111. Walk = 1,
  112. BeforeRun = 2,
  113. Run = 3,
  114. AfterRun = 4,
  115. Attack = 5,
  116. Magic = 6,
  117. Throw = 7,
  118. Hurt = 8,
  119. Defence = 9,
  120. Dead = 10,
  121. Sit = 11,
  122. Hi = 12,
  123. Happy = 13,
  124. Angry = 14,
  125. Sad = 15,
  126. Shake = 16,
  127. Rock = 17,
  128. Scissors = 18,
  129. Paper = 19,
  130. Fishing = 20,
  131. }
  132. //动效
  133. public enum EffectType
  134. {
  135. Hit =1,
  136. HitOver =2
  137. }
  138. public enum PlayType
  139. {
  140. Loop,
  141. Once,
  142. OnceAndDestroy
  143. }
  144. private static byte[] highVersionFlag = { 0xFF, 0xFF, 0xFF, 0xFF };
  145. //动画列表缓存 Serial -> AnimeInfo
  146. private static Dictionary<uint, AnimeInfo> _animeInfoCache = new Dictionary<uint, AnimeInfo>();
  147. //加载动画数据
  148. public static void Init(string Version,FileInfo animeInfoFile,FileInfo animeFile)
  149. {
  150. //创建流读取器
  151. FileStream infoFileStream = animeInfoFile.OpenRead();
  152. FileStream dataFileStream = animeFile.OpenRead();
  153. BinaryReader infoFileReader = new BinaryReader(infoFileStream);
  154. BinaryReader dataFileReader = new BinaryReader(dataFileStream);
  155. long DataLength = infoFileStream.Length / 12;
  156. //判断是否为高版本
  157. bool isHighVersion = false;
  158. dataFileStream.Position = 0x10;
  159. byte[] tmpBytes = dataFileReader.ReadBytes(4);
  160. if(tmpBytes.SequenceEqual(highVersionFlag)) isHighVersion = true;
  161. // 循环初始化动画数据
  162. for (int i = 0; i < DataLength; i++)
  163. {
  164. //初始化对象
  165. AnimeInfo animeInfo = new AnimeInfo();
  166. animeInfo.Version = Version;
  167. animeInfo.Serial = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0);
  168. // Debug.Log(animeInfo.Serial);
  169. animeInfo.Addr = BitConverter.ToUInt32(infoFileReader.ReadBytes(4),0);
  170. animeInfo.ActionCount = infoFileReader.ReadUInt16();
  171. animeInfo.Unknow = infoFileReader.ReadBytes(2);
  172. dataFileStream.Position = animeInfo.Addr;
  173. for (int j = 0; j < animeInfo.ActionCount; j++)
  174. {
  175. AnimeDetail animeData = new AnimeDetail();
  176. animeData.Version = Version;
  177. animeData.Serial = animeInfo.Serial;
  178. animeData.Direction = dataFileReader.ReadUInt16();
  179. animeData.ActionType = dataFileReader.ReadUInt16();
  180. animeData.CycleTime = BitConverter.ToUInt32(dataFileReader.ReadBytes(4),0);
  181. animeData.FrameCount = BitConverter.ToUInt32(dataFileReader.ReadBytes(4),0);
  182. // 高版本
  183. if (isHighVersion)
  184. {
  185. animeData.IsHighVersion = true;
  186. animeData.Palet = dataFileReader.ReadUInt16();
  187. animeData.Reverse = dataFileReader.ReadUInt16() % 2 == 1;
  188. animeData.END_FLAG = dataFileReader.ReadBytes(4);
  189. }
  190. animeData.AnimeFrameInfos = new List<AnimeFrameInfo>();
  191. // if (animeInfo.Index == 101201) Debug.Log("----------------------------------");
  192. for (int k = 0; k < animeData.FrameCount; k++)
  193. {
  194. byte[] frameBytes = dataFileReader.ReadBytes(10);
  195. BinaryReader frameReader = new BinaryReader(new MemoryStream(frameBytes));
  196. AnimeFrameInfo animeFrameInfo = new AnimeFrameInfo();
  197. //GraphicIndex序号
  198. animeFrameInfo.GraphicIndex = BitConverter.ToUInt32(frameReader.ReadBytes(4),0);
  199. animeFrameInfo.OffsetX = BitConverter.ToInt16(frameReader.ReadBytes(2),0);
  200. animeFrameInfo.OffsetY = BitConverter.ToInt16(frameReader.ReadBytes(2),0);
  201. //标识位
  202. int flag = BitConverter.ToInt16(frameReader.ReadBytes(2),0);
  203. if (flag>20000)
  204. {
  205. //击打判定
  206. animeFrameInfo.Effect = EffectType.Hit;
  207. animeFrameInfo.AudioIndex = flag - 20000;
  208. }
  209. else if(flag>10000)
  210. {
  211. //攻击动作结束判定
  212. animeFrameInfo.Effect = EffectType.HitOver;
  213. animeFrameInfo.AudioIndex = flag - 10000;
  214. }
  215. else
  216. {
  217. animeFrameInfo.AudioIndex = flag;
  218. }
  219. animeData.AnimeFrameInfos.Add(animeFrameInfo);
  220. }
  221. animeData.FrameCount = (uint) animeData.AnimeFrameInfos.Count;
  222. if (!animeInfo.AnimeDatas.ContainsKey(animeData.Direction))
  223. animeInfo.AnimeDatas.Add(animeData.Direction, new Dictionary<int, AnimeDetail>());
  224. animeInfo.AnimeDatas[animeData.Direction][animeData.ActionType] = animeData;
  225. _animeInfoCache[animeInfo.Serial] = animeInfo;
  226. }
  227. }
  228. infoFileReader.Dispose();
  229. infoFileReader.Close();
  230. dataFileReader.Dispose();
  231. dataFileReader.Close();
  232. infoFileStream.Close();
  233. dataFileStream.Close();
  234. Debug.Log("[CGTool] 加载AnimeInfo - 文件: [" +
  235. // (Graphic.Flag_HighVersion[Version] ? "H" : "N") + "] [" +
  236. Version + "] " +
  237. animeInfoFile.Name +
  238. " 动画总量: " + DataLength);
  239. }
  240. //获取动画数据信息
  241. public static AnimeInfo GetAnimeInfo(uint serial)
  242. {
  243. _animeInfoCache.TryGetValue(serial, out var animeInfo);
  244. return animeInfo;
  245. }
  246. //获取动画数据
  247. public static AnimeDetail GetAnimeDetail(uint serial,DirectionType Direction,ActionType Action)
  248. {
  249. AnimeInfo animeInfo = GetAnimeInfo(serial);
  250. if (animeInfo == null) return null;
  251. if (animeInfo.AnimeDatas.ContainsKey((int)Direction))
  252. {
  253. if (animeInfo.AnimeDatas[(int) Direction].ContainsKey((int) Action))
  254. {
  255. AnimeDetail animeDetail = animeInfo.AnimeDatas[(int) Direction][(int) Action];
  256. // if(animeDetail.AnimeTexture == null) prepareAnimeFrames(animeDetail);
  257. return animeDetail;
  258. }
  259. }
  260. return null;
  261. }
  262. //预处理动画图形合批烘焙
  263. public static void BakeAnimeFrames(AnimeDetail animeDetail,int palet = 0)
  264. {
  265. if(animeDetail.AnimeTextures.ContainsKey(palet)) return;
  266. //所有帧的图形数据
  267. GraphicDetail[] graphicDetails = new GraphicDetail[animeDetail.FrameCount];
  268. //合并后的Texture2D尺寸
  269. uint textureWidth = 0;
  270. uint textureHeight = 0;
  271. for (var i = 0; i < animeDetail.FrameCount; i++)
  272. {
  273. //载入图档
  274. GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(animeDetail.Version,animeDetail.AnimeFrameInfos[i].GraphicIndex);
  275. if (graphicInfoData == null) continue;
  276. int subPaletIndex = 0;
  277. if (animeDetail.IsHighVersion) subPaletIndex = (int)animeDetail.Serial;
  278. GraphicDetail graphicDetail = GraphicData.GetGraphicDetail(graphicInfoData, palet, subPaletIndex);
  279. if(graphicDetail == null) continue;
  280. graphicDetails[i] = graphicDetail;
  281. if(graphicDetail.Height > textureHeight) textureHeight = graphicDetail.Height;
  282. textureWidth += graphicDetail.Width + 5;
  283. animeDetail.AnimeFrameInfos[i].Width = (int) graphicDetail.Width;
  284. animeDetail.AnimeFrameInfos[i].Height = (int) graphicDetail.Height;
  285. animeDetail.AnimeFrameInfos[i].OffsetX = (int) graphicInfoData.OffsetX;
  286. animeDetail.AnimeFrameInfos[i].OffsetY = (int) graphicInfoData.OffsetY;
  287. animeDetail.AnimeFrameInfos[i].GraphicInfo = graphicInfoData;
  288. }
  289. //合并图档
  290. Texture2D texture2dMix = new Texture2D((int) textureWidth, (int) textureHeight, TextureFormat.RGBA4444, false,false);
  291. texture2dMix.filterMode = FilterMode.Point;
  292. Color32 transparentColor = new Color32(0, 0, 0, 0);
  293. Color32[] transparentColors = new Color32[texture2dMix.width * texture2dMix.height];
  294. for (var i = 0; i < transparentColors.Length; i++)
  295. {
  296. transparentColors[i] = transparentColor;
  297. }
  298. texture2dMix.SetPixels32(transparentColors,0);
  299. int offsetX = 0;
  300. for (var i = 0; i < animeDetail.FrameCount; i++)
  301. {
  302. GraphicDetail graphicDetail = graphicDetails[i];
  303. if(graphicDetail == null) continue;
  304. texture2dMix.SetPixels32((int) offsetX, 0, (int) graphicDetail.Width,
  305. (int) graphicDetail.Height,
  306. graphicDetail.Sprite.texture.GetPixels32());
  307. offsetX += (int) graphicDetail.Width + 5;
  308. }
  309. texture2dMix.Apply();
  310. animeDetail.AnimeTextures.Add(palet,texture2dMix);
  311. //创建动画每帧Sprite
  312. offsetX = 0;
  313. for (var l = 0; l < animeDetail.FrameCount; l++)
  314. {
  315. if(graphicDetails[l] == null) continue;
  316. AnimeFrameInfo animeFrameInfo = animeDetail.AnimeFrameInfos[l];
  317. Vector2 pivot = new Vector2(0f, 1f);
  318. pivot.x += -(animeFrameInfo.OffsetX * 1f) / animeFrameInfo.Width;
  319. pivot.y -= (-animeFrameInfo.OffsetY * 1f) / animeFrameInfo.Height;
  320. Sprite sprite = Sprite.Create(texture2dMix, new Rect(offsetX, 0,
  321. animeDetail.AnimeFrameInfos[l].Width, animeDetail.AnimeFrameInfos[l].Height),
  322. pivot, 1, 1, SpriteMeshType.FullRect);
  323. offsetX += animeDetail.AnimeFrameInfos[l].Width + 5;
  324. animeFrameInfo.AnimeSprites.Add(palet, sprite);
  325. }
  326. }
  327. }
  328. }