AnimePlayer.cs 23 KB

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