AnimePlayer.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  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. //碰撞盒,仅当需要添加鼠标事件时使用
  113. // _boxCollider2D = GetComponent<BoxCollider2D>();
  114. if(_imageRenderer == null) _imageRenderer = gameObject.AddComponent<Image>();
  115. if(_spriteRenderer == null) _spriteRenderer = gameObject.AddComponent<SpriteRenderer>();
  116. if(_rectTransform == null) _rectTransform = gameObject.AddComponent<RectTransform>();
  117. // if(_boxCollider2D == null) _boxCollider2D = gameObject.AddComponent<BoxCollider2D>();
  118. }
  119. private void Start()
  120. {
  121. _updateRenderMode();
  122. }
  123. //鼠标移入监听
  124. private void OnMouseEnter()
  125. {
  126. if(onMouseEnterListener!=null) onMouseEnterListener(this);
  127. }
  128. //鼠标移出监听
  129. private void OnMouseExit()
  130. {
  131. if(onMouseExitListener!=null) onMouseExitListener(this);
  132. }
  133. // 使用Image模式渲染
  134. public bool RenderByImage
  135. {
  136. get => isRenderByImage;
  137. set
  138. {
  139. isRenderByImage = value;
  140. _updateRenderMode();
  141. }
  142. }
  143. // 设置当前播放序列,默认方向North,动作Stand,播放类型Loop,播放速度1f
  144. public uint Serial
  145. {
  146. get => _currentSerial;
  147. set
  148. {
  149. Anime.DirectionType direction =
  150. _currentAnime?.Direction ?? Anime.DirectionType.North;
  151. Anime.ActionType actionType = _currentAnime?.actionType ?? Anime.ActionType.Stand;
  152. Anime.PlayType playType = _currentAnime?.playType ?? Anime.PlayType.Loop;
  153. float speed = _currentAnime?.Speed ?? 1f;
  154. AnimeCallback onFinishCallback = _currentAnime?.onFinishCallback;
  155. play(value, direction, actionType, playType, speed, onFinishCallback);
  156. }
  157. }
  158. // 动态调整播放类型
  159. public Anime.PlayType PlayType
  160. {
  161. get => _currentAnime?.playType ?? Anime.PlayType.Loop;
  162. set
  163. {
  164. if (_currentAnime != null)
  165. {
  166. _currentAnime.playType = value;
  167. }
  168. }
  169. }
  170. // 更新渲染模式
  171. private void _updateRenderMode()
  172. {
  173. if (isRenderByImage)
  174. {
  175. _imageRenderer.enabled = true;
  176. _spriteRenderer.enabled = false;
  177. }
  178. else
  179. {
  180. _imageRenderer.enabled = false;
  181. _spriteRenderer.enabled = true;
  182. }
  183. }
  184. /**
  185. * 播放动画,调用此方法将会清空当前播放队列,调用完成可通过链式调用nextPlay方法添加动画到播放队列
  186. * @param Serial 动画序列号
  187. * @param Direction 动画方向
  188. * @param ActionType 动画动作
  189. * @param PlayType 播放类型
  190. * @param Speed 播放速度,以 1s 为基准,根据动画帧率计算实际播放周期时长
  191. * @param onFinishCallback 动画结束回调
  192. * @return AnimePlayer
  193. */
  194. public AnimePlayer play(uint Serial, Anime.DirectionType Direction = Anime.DirectionType.North,
  195. Anime.ActionType actionType = Anime.ActionType.Stand, Anime.PlayType playType = Anime.PlayType.Once,
  196. float Speed = 1f, AnimeCallback onFinishCallback = null)
  197. {
  198. if (_spriteRenderer == null)
  199. {
  200. // Debug.Log("AnimePlayer:SpriteRenderer is null");
  201. return this;
  202. }
  203. AnimeOption animeOption = CreateAnimeOption(Serial, Direction, actionType, playType, Speed, onFinishCallback);
  204. if (animeOption == null)
  205. {
  206. if (onFinishCallback != null) onFinishCallback(actionType);
  207. // Debug.Log("AnimePlayer:AnimeOption create failed");
  208. return this;
  209. }
  210. //清空播放队列
  211. _animeQueue.Clear();
  212. //播放
  213. _currentSerial = Serial;
  214. _play(animeOption);
  215. //链式调用,后续可通过nextPlay方法添加动画到播放队列
  216. return this;
  217. }
  218. //播放动画
  219. public AnimePlayer play(uint Serial, Anime.PlayType playType, float speed = 1f,
  220. AnimeCallback onFinishCallback = null)
  221. {
  222. return play(Serial,Anime.DirectionType.North,Anime.ActionType.Stand,playType,speed,onFinishCallback);
  223. }
  224. //播放一次
  225. public AnimePlayer playOnce(Anime.DirectionType directionType,Anime.ActionType actionType,float Speed=1f,AnimeCallback onFinishCallback=null)
  226. {
  227. return play(_currentSerial, directionType, actionType, Anime.PlayType.Once,
  228. Speed, onFinishCallback);
  229. }
  230. //播放循环
  231. public AnimePlayer playLoop(Anime.DirectionType directionType,Anime.ActionType actionType,float Speed=1f,AnimeCallback onFinishCallback=null)
  232. {
  233. return play(_currentSerial, directionType, actionType, Anime.PlayType.Loop,
  234. Speed, onFinishCallback);
  235. }
  236. //调整动画方向
  237. public void changeDirection(Anime.DirectionType directionType)
  238. {
  239. if (directionType == _currentAnime.Direction || directionType == Anime.DirectionType.NULL) return;
  240. _currentAnime = CreateAnimeOption(_currentAnime.AnimeSerial, directionType, _currentAnime.actionType,
  241. _currentAnime.playType, _currentAnime.Speed, _currentAnime.onFinishCallback);
  242. _play(_currentAnime);
  243. }
  244. public Anime.DirectionType DirectionType
  245. {
  246. get => _currentAnime?.Direction ?? Anime.DirectionType.NULL;
  247. set
  248. {
  249. if (_currentAnime != null)
  250. {
  251. changeDirection(value);
  252. }
  253. }
  254. }
  255. //调整动画动作类型
  256. public void changeActionType(Anime.ActionType actionType)
  257. {
  258. if (actionType == _currentAnime.actionType) return;
  259. _currentAnime = CreateAnimeOption(_currentAnime.AnimeSerial, _currentAnime.Direction,actionType,
  260. _currentAnime.playType, _currentAnime.Speed, _currentAnime.onFinishCallback);
  261. _play(_currentAnime);
  262. }
  263. public Anime.ActionType ActionType
  264. {
  265. get => _currentAnime?.actionType ?? Anime.ActionType.NULL;
  266. set
  267. {
  268. if (_currentAnime != null)
  269. {
  270. changeActionType(value);
  271. }
  272. }
  273. }
  274. //播放
  275. private void _play(AnimeOption animeOption)
  276. {
  277. isPlayable = false;
  278. _currentAnime = null;
  279. AnimeFrame[] frames = new AnimeFrame[animeOption.AnimeDetail.FrameCount];
  280. if (isFrameBatch)
  281. {
  282. Anime.BakeAnimeFrames(animeOption.AnimeDetail, _paletIndex);
  283. //获取动画帧数据
  284. for (int i = 0; i < animeOption.AnimeDetail.AnimeFrameInfos.Length; i++)
  285. {
  286. if(!animeOption.AnimeDetail.AnimeFrameInfos[i].AnimeSprites.ContainsKey(_paletIndex)) continue;
  287. if(animeOption.AnimeDetail.AnimeFrameInfos[i].AnimeSprites[_paletIndex] == null) continue;
  288. //创建帧数据
  289. frames[i] = new AnimeFrame();
  290. frames[i].Index = i;
  291. frames[i].GraphicInfo = animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicInfo;
  292. frames[i].Sprite = animeOption.AnimeDetail.AnimeFrameInfos[i].AnimeSprites[_paletIndex];
  293. frames[i].AnimeFrameInfo = animeOption.AnimeDetail.AnimeFrameInfos[i];
  294. }
  295. }
  296. else
  297. {
  298. //获取动画帧数据
  299. for (int i = 0; i < animeOption.AnimeDetail.AnimeFrameInfos.Length; i++)
  300. {
  301. AnimeFrameInfo animeFrameInfo = animeOption.AnimeDetail.AnimeFrameInfos[i];
  302. GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(
  303. animeOption.AnimeDetail.Version, animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicIndex);
  304. if (graphicInfoData == null)
  305. {
  306. Debug.Log("GraphicInfo Serial:" +
  307. animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicIndex + " is null");
  308. continue;
  309. }
  310. GraphicDetail graphicData = GraphicData.GetGraphicDetail(graphicInfoData, _paletIndex);
  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. //自动偏移
  449. // float graphicWidth = _frames[_currentFrame].Sprite.rect.width;
  450. // float graphicHeight = _frames[_currentFrame].Sprite.rect.height;
  451. // float offsetX = -_frames[_currentFrame].GraphicInfo.OffsetX;
  452. // float offsetY = _frames[_currentFrame].GraphicInfo.OffsetY;
  453. //根据当前帧Sprite动态调整对象大小
  454. float width = _frames[_currentFrame].Sprite.rect.width * 1f;
  455. float height = _frames[_currentFrame].Sprite.rect.height * 1f;
  456. if (isRenderByImage)
  457. {
  458. _imageRenderer.sprite = _frames[_currentFrame].Sprite;
  459. _imageRenderer.SetNativeSize();
  460. Vector3 pos = Vector3.zero;
  461. pos.x = _frames[_currentFrame].GraphicInfo.OffsetX;
  462. pos.y = -_frames[_currentFrame].GraphicInfo.OffsetY;
  463. _rectTransform.localPosition = pos;
  464. _rectTransform.pivot = new Vector2(0f,1f);
  465. }
  466. else
  467. {
  468. _spriteRenderer.sprite = _frames[_currentFrame].Sprite;
  469. _rectTransform.sizeDelta = new Vector2(width, height);
  470. _spriteRenderer.size = new Vector2(width, height);
  471. _rectTransform.pivot = new Vector2(0.5f,0f);
  472. _rectTransform.localPosition = Vector3.zero;
  473. }
  474. frameTexture = _frames[_currentFrame].Sprite.texture;
  475. // Vector2 offset = Vector2.zero;
  476. // offset.x += -(_frames[_currentFrame].GraphicInfo.OffsetX * 1f) / _frames[_currentFrame].GraphicInfo.Width;
  477. // offset.y -= (-_frames[_currentFrame].GraphicInfo.OffsetY * 1f) / _frames[_currentFrame].GraphicInfo.Height;
  478. // _rectTransform.pivot = offset;
  479. // pos.x = (width + _frames[_currentFrame].GraphicInfo.OffsetX)/1f;
  480. // pos.y = (height + _frames[_currentFrame].GraphicInfo.OffsetY)/1f;
  481. // 2D碰撞器自动调整,但是动态碰撞器反而会导致重叠大物体选中效果不稳定,效果不如固定大小碰撞器好
  482. // if (_boxCollider2D != null)
  483. // {
  484. // Vector2 newSize =_boxCollider2D.size
  485. // _boxCollider2D.size = new Vector2(width, height);
  486. // }
  487. // _rectTransform.pivot = new Vector2(offsetX,offsetY);
  488. // _rectTransform.localPosition = new Vector3(0f, 0f);
  489. _timer = Time.time * 1000;
  490. //动画事件帧监听
  491. if(_frames[_currentFrame].AnimeFrameInfo.Effect >0 && onEffectListener!=null) onEffectListener(_frames[_currentFrame].AnimeFrameInfo.Effect);
  492. //音频事件帧监听
  493. if(_frames[_currentFrame].AnimeFrameInfo.AudioIndex >0 && onAudioListener!=null) onAudioListener(_frames[_currentFrame].AnimeFrameInfo.AudioIndex);
  494. }
  495. }
  496. }