AnimePlayer.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  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.Length; 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.Length; 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. GraphicDetail graphicData = GraphicData.GetGraphicDetail(graphicInfoData, _paletIndex);
  308. if (graphicData == null)
  309. {
  310. Debug.Log("GraphicData Serial:" +
  311. animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicIndex + " is null");
  312. continue;
  313. }
  314. //创建帧数据
  315. frames[i] = new AnimeFrame();
  316. frames[i].Index = i;
  317. frames[i].GraphicInfo = graphicInfoData;
  318. frames[i].Sprite = graphicData.Sprite;
  319. frames[i].AnimeFrameInfo = animeFrameInfo;
  320. }
  321. }
  322. _currentAnime = animeOption;
  323. _frames = frames;
  324. _currentFrame = -1;
  325. isPlayable = true;
  326. gameObject.SetActive(true);
  327. UpdateFrame();
  328. }
  329. //播放延时
  330. public void DelayPlay(float delayTime)
  331. {
  332. _delay = delayTime*1000;
  333. }
  334. public void Stop()
  335. {
  336. isPlayable = false;
  337. _currentAnime = null;
  338. _frames = null;
  339. _currentFrame = -1;
  340. gameObject.SetActive(false);
  341. }
  342. public void Pause()
  343. {
  344. isPlayable = false;
  345. }
  346. //修改播放类型---重复方法--考虑删掉
  347. public void ChangePlayType(Anime.PlayType playType)
  348. {
  349. if (_currentAnime == null) return;
  350. _currentAnime.playType = playType;
  351. }
  352. //创建动画配置
  353. private AnimeOption CreateAnimeOption(uint Serial, Anime.DirectionType Direction, Anime.ActionType ActionType,
  354. Anime.PlayType playType=Anime.PlayType.Once, float Speed = 1f, AnimeCallback onFinishCallback = null)
  355. {
  356. AnimeDetail animeDetail = Anime.GetAnimeDetail(Serial, Direction, ActionType);
  357. if (animeDetail == null)
  358. {
  359. // Debug.Log("AnimePlayer:AnimeDetail is null");
  360. return null;
  361. }
  362. AnimeOption animeOption = new AnimeOption()
  363. {
  364. AnimeSerial = Serial,
  365. Direction = Direction,
  366. actionType = ActionType,
  367. playType = playType,
  368. Speed = Speed,
  369. FrameRate = animeDetail.CycleTime / Speed / animeDetail.FrameCount,
  370. AnimeDetail = animeDetail,
  371. onFinishCallback = onFinishCallback,
  372. };
  373. return animeOption;
  374. }
  375. //加入链式动画播放队列
  376. public AnimePlayer nextPlay(uint Serial, Anime.DirectionType Direction, Anime.ActionType ActionType,
  377. Anime.PlayType playType=Anime.PlayType.Once, float Speed = 1f, AnimeCallback onFinishCallback = null)
  378. {
  379. AnimeOption animeOption = CreateAnimeOption(Serial, Direction, ActionType, playType, Speed, onFinishCallback);
  380. if (animeOption == null)
  381. {
  382. if (onFinishCallback != null) onFinishCallback(ActionType);
  383. return this;
  384. }
  385. if (_animeQueue.Count == 0)
  386. {
  387. _play(animeOption);
  388. }
  389. else
  390. {
  391. _animeQueue.Enqueue(animeOption);
  392. }
  393. return this;
  394. }
  395. //加入链式动画播放队列
  396. public AnimePlayer nextPlay(Anime.DirectionType Direction, Anime.ActionType ActionType,
  397. Anime.PlayType playType=Anime.PlayType.Once, float Speed = 1f, AnimeCallback onFinishCallback = null)
  398. {
  399. return nextPlay(_currentSerial, Direction, ActionType, playType, Speed, onFinishCallback);
  400. }
  401. //更新计算
  402. private void Update()
  403. {
  404. float now = Time.time * 1000;
  405. if (_currentAnime != null && (now - _timer - _delay) >= _currentAnime.FrameRate) UpdateFrame();
  406. }
  407. //更新帧
  408. private void UpdateFrame()
  409. {
  410. _delay = 0;
  411. if (!isPlayable || _frames.Length == 0) return;
  412. _currentFrame++;
  413. //动画结束
  414. if (_currentFrame >= _currentAnime.AnimeDetail.FrameCount)
  415. {
  416. if(_currentAnime.onFinishCallback!=null) _currentAnime.onFinishCallback(_currentAnime.actionType);
  417. //循环播放
  418. if (_currentAnime.playType == Anime.PlayType.Loop)
  419. {
  420. _currentFrame = 0;
  421. }else if (_currentAnime.playType == Anime.PlayType.Once || _currentAnime.playType == Anime.PlayType.OnceAndDestroy)
  422. {
  423. if (_currentAnime.playType == Anime.PlayType.OnceAndDestroy)
  424. {
  425. _spriteRenderer.sprite = null;
  426. _imageRenderer.sprite = null;
  427. _rectTransform.sizeDelta = Vector2.zero;
  428. // gameObject.SetActive(false);
  429. }
  430. //播放下一个动画
  431. if(_animeQueue.Count>0)
  432. {
  433. AnimeOption animeOption = _animeQueue.Dequeue();
  434. _play(animeOption);
  435. return;
  436. }else
  437. {
  438. isPlayable = false;
  439. return;
  440. }
  441. }
  442. }
  443. //问题帧自动跳过
  444. if (_currentFrame<_frames.Length && _frames[_currentFrame] == null) return;
  445. //根据当前帧Sprite动态调整对象大小
  446. float width = _frames[_currentFrame].Sprite.rect.width * 1f;
  447. float height = _frames[_currentFrame].Sprite.rect.height * 1f;
  448. if (isRenderByImage)
  449. {
  450. _imageRenderer.sprite = _frames[_currentFrame].Sprite;
  451. _imageRenderer.SetNativeSize();
  452. Vector3 pos = Vector3.zero;
  453. pos.x = _frames[_currentFrame].GraphicInfo.OffsetX;
  454. pos.y = -_frames[_currentFrame].GraphicInfo.OffsetY;
  455. _rectTransform.localPosition = pos;
  456. _rectTransform.pivot = new Vector2(0f,1f);
  457. }
  458. else
  459. {
  460. _spriteRenderer.sprite = _frames[_currentFrame].Sprite;
  461. _rectTransform.sizeDelta = new Vector2(width, height);
  462. _spriteRenderer.size = new Vector2(width, height);
  463. _rectTransform.pivot = new Vector2(0.5f,0f);
  464. _rectTransform.localPosition = Vector3.zero;
  465. }
  466. frameTexture = _frames[_currentFrame].Sprite.texture;
  467. _timer = Time.time * 1000;
  468. //动画事件帧监听
  469. if(_frames[_currentFrame].AnimeFrameInfo.Effect >0 && onEffectListener!=null) onEffectListener(_frames[_currentFrame].AnimeFrameInfo.Effect);
  470. //音频事件帧监听
  471. if(_frames[_currentFrame].AnimeFrameInfo.AudioIndex >0 && onAudioListener!=null) onAudioListener(_frames[_currentFrame].AnimeFrameInfo.AudioIndex);
  472. }
  473. }
  474. }