AnimePlayer.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /**
  2. * 魔力宝贝图档解析脚本 - CGTool
  3. *
  4. * @Author HonorLee (dev@honorlee.me)
  5. * @Version 1.0 (2023-04-15)
  6. * @License GPL-3.0
  7. *
  8. * AnimePlayer.cs 动画播放器-挂载类
  9. */
  10. using System.Collections.Generic;
  11. using UnityEngine;
  12. using UnityEngine.UI;
  13. namespace CrossgateToolkit
  14. {
  15. //动画周期回调
  16. public delegate void AnimeCallback(Anime.ActionType actionType);
  17. //动画动作帧监听
  18. public delegate void AnimeEffectListener(Anime.EffectType effect);
  19. //动画音频帧监听
  20. public delegate void AnimeAudioListener(int audioIndex);
  21. //鼠标移入事件监听
  22. public delegate void MouseListener(AnimePlayer animePlayer);
  23. /**
  24. * 动画播放器,用于播放CG动画,支持多动画队列播放
  25. * 脚本需绑定至挂载了SpriteRenderer、Image和RectTransform的对象上
  26. * ########除此之外,还需绑定BoxCollider2D(可选),用于监听鼠标的移入移出事件#####此条删除
  27. *
  28. * 当动画播放完成后会自动调用onFinishCallback回调函数
  29. * 另外可指定onActionListener和onAudioListener监听动画动作帧和音频帧
  30. * 目前已知的动作帧有:
  31. * 击中 伤害结算
  32. */
  33. public class AnimePlayer : MonoBehaviour
  34. {
  35. //动画帧数据
  36. private class AnimeFrame
  37. {
  38. public int Index;
  39. public GraphicInfoData GraphicInfo;
  40. public Sprite Sprite;
  41. public AnimeFrameInfo AnimeFrameInfo;
  42. }
  43. //播放配置数据
  44. private class AnimeOption
  45. {
  46. public uint AnimeSerial;
  47. public Anime.DirectionType Direction;
  48. public Anime.ActionType actionType;
  49. public Anime.PlayType playType;
  50. public float Speed;
  51. public float FrameRate;
  52. public AnimeDetail AnimeDetail;
  53. public AnimeCallback onFinishCallback;
  54. }
  55. //当前播放
  56. private uint _currentSerial;
  57. private AnimeOption _currentAnime;
  58. private AnimeFrame[] _frames;
  59. private int _currentFrame;
  60. //是否播放
  61. private bool isPlayable;
  62. //待播放队列
  63. private Queue<AnimeOption> _animeQueue = new Queue<AnimeOption>();
  64. //计时器
  65. private float _timer;
  66. //下一帧延迟
  67. private float _delay;
  68. //绑定渲染对象
  69. [SerializeField,Header("Image渲染")] public bool isRenderByImage = false;
  70. [SerializeField,Header("序列帧合批")] public bool isFrameBatch = false;
  71. [Header("序列帧Texture")] public Texture2D frameTexture;
  72. private SpriteRenderer _spriteRenderer;
  73. private Image _imageRenderer;
  74. private int _paletIndex = 0;
  75. public int PaletIndex
  76. {
  77. get { return _paletIndex; }
  78. set
  79. {
  80. _paletIndex = value;
  81. if (_currentAnime != null) _play(_currentAnime);
  82. }
  83. }
  84. //绑定RectTransform
  85. private RectTransform _rectTransform;
  86. //绑定BoxCollider2D(可选)
  87. private BoxCollider2D _boxCollider2D;
  88. //动画动作帧监听
  89. public AnimeEffectListener onEffectListener;
  90. public AnimeAudioListener onAudioListener;
  91. //鼠标移入事件监听
  92. public MouseListener onMouseEnterListener;
  93. //鼠标移出事件监听
  94. public MouseListener onMouseExitListener;
  95. //获取偏移量(无用)
  96. public Vector2 offset
  97. {
  98. get
  99. {
  100. float offsetX = -_frames[_currentFrame].AnimeFrameInfo.OffsetX;
  101. float offsetY = _frames[_currentFrame].AnimeFrameInfo.OffsetY;
  102. return new Vector2(offsetX, offsetY);
  103. }
  104. }
  105. //实例初始化时获取相关绑定
  106. private void Awake()
  107. {
  108. //调整渲染
  109. _imageRenderer = GetComponent<Image>();
  110. _spriteRenderer = GetComponent<SpriteRenderer>();
  111. _rectTransform = GetComponent<RectTransform>();
  112. if(_imageRenderer == null) _imageRenderer = gameObject.AddComponent<Image>();
  113. if(_spriteRenderer == null) _spriteRenderer = gameObject.AddComponent<SpriteRenderer>();
  114. if(_rectTransform == null) _rectTransform = gameObject.AddComponent<RectTransform>();
  115. }
  116. private void Start()
  117. {
  118. _updateRenderMode();
  119. }
  120. //鼠标移入监听
  121. private void OnMouseEnter()
  122. {
  123. if(onMouseEnterListener!=null) onMouseEnterListener(this);
  124. }
  125. //鼠标移出监听
  126. private void OnMouseExit()
  127. {
  128. if(onMouseExitListener!=null) onMouseExitListener(this);
  129. }
  130. // 使用Image模式渲染
  131. public bool RenderByImage
  132. {
  133. get => isRenderByImage;
  134. set
  135. {
  136. isRenderByImage = value;
  137. _updateRenderMode();
  138. }
  139. }
  140. // 设置当前播放序列,默认方向North,动作Stand,播放类型Loop,播放速度1f
  141. public uint Serial
  142. {
  143. get => _currentSerial;
  144. set
  145. {
  146. Anime.DirectionType direction =
  147. _currentAnime?.Direction ?? Anime.DirectionType.North;
  148. Anime.ActionType actionType = _currentAnime?.actionType ?? Anime.ActionType.Stand;
  149. Anime.PlayType playType = _currentAnime?.playType ?? Anime.PlayType.Loop;
  150. float speed = _currentAnime?.Speed ?? 1f;
  151. AnimeCallback onFinishCallback = _currentAnime?.onFinishCallback;
  152. play(value, direction, actionType, playType, speed, onFinishCallback);
  153. }
  154. }
  155. // 动态调整播放类型
  156. public Anime.PlayType PlayType
  157. {
  158. get => _currentAnime?.playType ?? Anime.PlayType.Loop;
  159. set
  160. {
  161. if (_currentAnime != null)
  162. {
  163. _currentAnime.playType = value;
  164. }
  165. }
  166. }
  167. // 更新渲染模式
  168. private void _updateRenderMode()
  169. {
  170. if (isRenderByImage)
  171. {
  172. _imageRenderer.enabled = true;
  173. _spriteRenderer.enabled = false;
  174. }
  175. else
  176. {
  177. _imageRenderer.enabled = false;
  178. _spriteRenderer.enabled = true;
  179. }
  180. }
  181. /// <summary>
  182. /// 播放动画。调用此方法将会清空当前播放队列,调用完成可通过链式调用 <c>nextPlay</c> 方法添加动画到播放队列。
  183. /// </summary>
  184. /// <param name="Serial">动画序列号</param>
  185. /// <param name="Direction">动画方向</param>
  186. /// <param name="ActionType">动画动作</param>
  187. /// <param name="PlayType">播放类型</param>
  188. /// <param name="Speed">播放速度,以 1s 为基准,根据动画帧率计算实际播放周期时长</param>
  189. /// <param name="onFinishCallback">动画结束回调</param>
  190. /// <returns>AnimePlayer</returns>
  191. public AnimePlayer play(uint Serial, Anime.DirectionType Direction = Anime.DirectionType.North,
  192. Anime.ActionType actionType = Anime.ActionType.Stand, Anime.PlayType playType = Anime.PlayType.Once,
  193. float Speed = 1f, AnimeCallback onFinishCallback = null)
  194. {
  195. if (_spriteRenderer == null)
  196. {
  197. // Debug.Log("AnimePlayer:SpriteRenderer is null");
  198. return this;
  199. }
  200. AnimeOption animeOption = CreateAnimeOption(Serial, Direction, actionType, playType, Speed, onFinishCallback);
  201. if (animeOption == null)
  202. {
  203. if (onFinishCallback != null) onFinishCallback(actionType);
  204. // Debug.Log("AnimePlayer:AnimeOption create failed");
  205. return this;
  206. }
  207. //清空播放队列
  208. _animeQueue.Clear();
  209. //播放
  210. _currentSerial = Serial;
  211. _play(animeOption);
  212. //链式调用,后续可通过nextPlay方法添加动画到播放队列
  213. return this;
  214. }
  215. //播放动画
  216. public AnimePlayer play(uint Serial, Anime.PlayType playType, float speed = 1f,
  217. AnimeCallback onFinishCallback = null)
  218. {
  219. return play(Serial,Anime.DirectionType.North,Anime.ActionType.Stand,playType,speed,onFinishCallback);
  220. }
  221. //播放一次
  222. public AnimePlayer playOnce(Anime.DirectionType directionType,Anime.ActionType actionType,float Speed=1f,AnimeCallback onFinishCallback=null)
  223. {
  224. return play(_currentSerial, directionType, actionType, Anime.PlayType.Once,
  225. Speed, onFinishCallback);
  226. }
  227. //播放循环
  228. public AnimePlayer playLoop(Anime.DirectionType directionType,Anime.ActionType actionType,float Speed=1f,AnimeCallback onFinishCallback=null)
  229. {
  230. return play(_currentSerial, directionType, actionType, Anime.PlayType.Loop,
  231. Speed, onFinishCallback);
  232. }
  233. //调整动画方向
  234. public void changeDirection(Anime.DirectionType directionType)
  235. {
  236. if (directionType == _currentAnime.Direction || directionType == Anime.DirectionType.NULL) return;
  237. _currentAnime = CreateAnimeOption(_currentAnime.AnimeSerial, directionType, _currentAnime.actionType,
  238. _currentAnime.playType, _currentAnime.Speed, _currentAnime.onFinishCallback);
  239. _play(_currentAnime);
  240. }
  241. public Anime.DirectionType DirectionType
  242. {
  243. get => _currentAnime?.Direction ?? Anime.DirectionType.NULL;
  244. set
  245. {
  246. if (_currentAnime != null)
  247. {
  248. changeDirection(value);
  249. }
  250. }
  251. }
  252. //调整动画动作类型
  253. public void changeActionType(Anime.ActionType actionType)
  254. {
  255. if (actionType == _currentAnime.actionType) return;
  256. _currentAnime = CreateAnimeOption(_currentAnime.AnimeSerial, _currentAnime.Direction,actionType,
  257. _currentAnime.playType, _currentAnime.Speed, _currentAnime.onFinishCallback);
  258. _play(_currentAnime);
  259. }
  260. public Anime.ActionType ActionType
  261. {
  262. get => _currentAnime?.actionType ?? Anime.ActionType.NULL;
  263. set
  264. {
  265. if (_currentAnime != null)
  266. {
  267. changeActionType(value);
  268. }
  269. }
  270. }
  271. //播放
  272. private void _play(AnimeOption animeOption)
  273. {
  274. isPlayable = false;
  275. _currentAnime = null;
  276. AnimeFrame[] frames = new AnimeFrame[animeOption.AnimeDetail.FrameCount];
  277. if (isFrameBatch)
  278. {
  279. Anime.BakeAnimeFrames(animeOption.AnimeDetail, _paletIndex);
  280. //获取动画帧数据
  281. for (int i = 0; i < animeOption.AnimeDetail.AnimeFrameInfos.Count; i++)
  282. {
  283. if(!animeOption.AnimeDetail.AnimeFrameInfos[i].AnimeSprites.ContainsKey(_paletIndex)) continue;
  284. if(animeOption.AnimeDetail.AnimeFrameInfos[i].AnimeSprites[_paletIndex] == null) continue;
  285. //创建帧数据
  286. frames[i] = new AnimeFrame();
  287. frames[i].Index = i;
  288. frames[i].GraphicInfo = animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicInfo;
  289. frames[i].Sprite = animeOption.AnimeDetail.AnimeFrameInfos[i].AnimeSprites[_paletIndex];
  290. frames[i].AnimeFrameInfo = animeOption.AnimeDetail.AnimeFrameInfos[i];
  291. }
  292. }
  293. else
  294. {
  295. //获取动画帧数据
  296. for (int i = 0; i < animeOption.AnimeDetail.AnimeFrameInfos.Count; i++)
  297. {
  298. AnimeFrameInfo animeFrameInfo = animeOption.AnimeDetail.AnimeFrameInfos[i];
  299. GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(
  300. animeOption.AnimeDetail.Version, animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicIndex);
  301. if (graphicInfoData == null)
  302. {
  303. Debug.Log("GraphicInfo Serial:" +
  304. animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicIndex + " is null");
  305. continue;
  306. }
  307. int subPaletIndex = 0;
  308. if (animeOption.AnimeDetail.IsHighVersion) subPaletIndex = (int)animeOption.AnimeDetail.Serial;
  309. GraphicDetail graphicData =
  310. GraphicData.GetGraphicDetail(graphicInfoData, _paletIndex, subPaletIndex);
  311. if (graphicData == null)
  312. {
  313. Debug.Log("GraphicData Serial:" +
  314. animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicIndex + " is null");
  315. continue;
  316. }
  317. //创建帧数据
  318. frames[i] = new AnimeFrame();
  319. frames[i].Index = i;
  320. frames[i].GraphicInfo = graphicInfoData;
  321. frames[i].Sprite = graphicData.Sprite;
  322. frames[i].AnimeFrameInfo = animeFrameInfo;
  323. }
  324. }
  325. _currentAnime = animeOption;
  326. _frames = frames;
  327. _currentFrame = -1;
  328. isPlayable = true;
  329. gameObject.SetActive(true);
  330. UpdateFrame();
  331. }
  332. //播放延时
  333. public void DelayPlay(float delayTime)
  334. {
  335. _delay = delayTime*1000;
  336. }
  337. public void Stop()
  338. {
  339. isPlayable = false;
  340. _currentAnime = null;
  341. _frames = null;
  342. _currentFrame = -1;
  343. gameObject.SetActive(false);
  344. }
  345. public void Pause()
  346. {
  347. isPlayable = false;
  348. }
  349. //修改播放类型---重复方法--考虑删掉
  350. public void ChangePlayType(Anime.PlayType playType)
  351. {
  352. if (_currentAnime == null) return;
  353. _currentAnime.playType = playType;
  354. }
  355. //创建动画配置
  356. private AnimeOption CreateAnimeOption(uint Serial, Anime.DirectionType Direction, Anime.ActionType ActionType,
  357. Anime.PlayType playType=Anime.PlayType.Once, float Speed = 1f, AnimeCallback onFinishCallback = null)
  358. {
  359. AnimeDetail animeDetail = Anime.GetAnimeDetail(Serial, Direction, ActionType);
  360. if (animeDetail == null)
  361. {
  362. // Debug.Log("AnimePlayer:AnimeDetail is null");
  363. return null;
  364. }
  365. AnimeOption animeOption = new AnimeOption()
  366. {
  367. AnimeSerial = Serial,
  368. Direction = Direction,
  369. actionType = ActionType,
  370. playType = playType,
  371. Speed = Speed,
  372. FrameRate = animeDetail.CycleTime / Speed / animeDetail.FrameCount,
  373. AnimeDetail = animeDetail,
  374. onFinishCallback = onFinishCallback,
  375. };
  376. return animeOption;
  377. }
  378. //加入链式动画播放队列
  379. public AnimePlayer nextPlay(uint Serial, Anime.DirectionType Direction, Anime.ActionType ActionType,
  380. Anime.PlayType playType=Anime.PlayType.Once, float Speed = 1f, AnimeCallback onFinishCallback = null)
  381. {
  382. AnimeOption animeOption = CreateAnimeOption(Serial, Direction, ActionType, playType, Speed, onFinishCallback);
  383. if (animeOption == null)
  384. {
  385. if (onFinishCallback != null) onFinishCallback(ActionType);
  386. return this;
  387. }
  388. if (_animeQueue.Count == 0)
  389. {
  390. _play(animeOption);
  391. }
  392. else
  393. {
  394. _animeQueue.Enqueue(animeOption);
  395. }
  396. return this;
  397. }
  398. //加入链式动画播放队列
  399. public AnimePlayer nextPlay(Anime.DirectionType Direction, Anime.ActionType ActionType,
  400. Anime.PlayType playType=Anime.PlayType.Once, float Speed = 1f, AnimeCallback onFinishCallback = null)
  401. {
  402. return nextPlay(_currentSerial, Direction, ActionType, playType, Speed, onFinishCallback);
  403. }
  404. //更新计算
  405. private void Update()
  406. {
  407. float now = Time.time * 1000;
  408. if (_currentAnime != null && (now - _timer - _delay) >= _currentAnime.FrameRate) UpdateFrame();
  409. }
  410. //更新帧
  411. private void UpdateFrame()
  412. {
  413. _delay = 0;
  414. if (!isPlayable || _frames.Length == 0) return;
  415. _currentFrame++;
  416. //动画结束
  417. if (_currentFrame >= _currentAnime.AnimeDetail.FrameCount)
  418. {
  419. if(_currentAnime.onFinishCallback!=null) _currentAnime.onFinishCallback(_currentAnime.actionType);
  420. //循环播放
  421. if (_currentAnime.playType == Anime.PlayType.Loop)
  422. {
  423. _currentFrame = 0;
  424. }else if (_currentAnime.playType == Anime.PlayType.Once || _currentAnime.playType == Anime.PlayType.OnceAndDestroy)
  425. {
  426. if (_currentAnime.playType == Anime.PlayType.OnceAndDestroy)
  427. {
  428. _spriteRenderer.sprite = null;
  429. _imageRenderer.sprite = null;
  430. _rectTransform.sizeDelta = Vector2.zero;
  431. // gameObject.SetActive(false);
  432. }
  433. //播放下一个动画
  434. if(_animeQueue.Count>0)
  435. {
  436. AnimeOption animeOption = _animeQueue.Dequeue();
  437. _play(animeOption);
  438. return;
  439. }else
  440. {
  441. isPlayable = false;
  442. return;
  443. }
  444. }
  445. }
  446. //问题帧自动跳过
  447. if (_currentFrame<_frames.Length && _frames[_currentFrame] == null) return;
  448. //根据当前帧Sprite动态调整对象大小
  449. float width = _frames[_currentFrame].Sprite.rect.width * 1f;
  450. float height = _frames[_currentFrame].Sprite.rect.height * 1f;
  451. Vector3 pos = Vector3.zero;
  452. pos.x = _frames[_currentFrame].GraphicInfo.OffsetX;
  453. pos.y = -_frames[_currentFrame].GraphicInfo.OffsetY;
  454. if (isRenderByImage)
  455. {
  456. _imageRenderer.sprite = _frames[_currentFrame].Sprite;
  457. _imageRenderer.SetNativeSize();
  458. if (_currentAnime.AnimeDetail.FLAG!=null)
  459. {
  460. if (_currentAnime.AnimeDetail.FLAG.REVERSE_X)
  461. {
  462. _imageRenderer.transform.localScale = new Vector3(-1, 1, 1);
  463. pos.x = -pos.x;
  464. }
  465. if (_currentAnime.AnimeDetail.FLAG.REVERSE_Y)
  466. {
  467. _imageRenderer.transform.localScale = new Vector3(1, -1, 1);
  468. pos.y = -pos.y;
  469. }
  470. }
  471. else
  472. {
  473. _imageRenderer.transform.localScale = new Vector3(1, 1, 1);
  474. }
  475. _rectTransform.localPosition = pos;
  476. _rectTransform.pivot = new Vector2(0f,1f);
  477. }
  478. else
  479. {
  480. _spriteRenderer.sprite = _frames[_currentFrame].Sprite;
  481. _rectTransform.sizeDelta = new Vector2(width, height);
  482. _spriteRenderer.size = new Vector2(width, height);
  483. _rectTransform.pivot = new Vector2(0.5f,0f);
  484. if (_currentAnime.AnimeDetail.FLAG!=null)
  485. {
  486. if (_currentAnime.AnimeDetail.FLAG.REVERSE_X)
  487. {
  488. _spriteRenderer.flipX = true;
  489. }
  490. if (_currentAnime.AnimeDetail.FLAG.REVERSE_Y)
  491. {
  492. _spriteRenderer.flipY = true;
  493. }
  494. }
  495. else
  496. {
  497. _spriteRenderer.flipX = false;
  498. _spriteRenderer.flipY = false;
  499. }
  500. _rectTransform.localPosition = Vector3.zero;
  501. }
  502. frameTexture = _frames[_currentFrame].Sprite.texture;
  503. _timer = Time.time * 1000;
  504. //动画事件帧监听
  505. if(_frames[_currentFrame].AnimeFrameInfo.Effect >0 && onEffectListener!=null) onEffectListener(_frames[_currentFrame].AnimeFrameInfo.Effect);
  506. //音频事件帧监听
  507. if(_frames[_currentFrame].AnimeFrameInfo.AudioIndex >0 && onAudioListener!=null) onAudioListener(_frames[_currentFrame].AnimeFrameInfo.AudioIndex);
  508. }
  509. }
  510. }