AnimePlayer.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  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 CGTool
  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. private SpriteRenderer _spriteRenderer;
  72. private Image _imageRenderer;
  73. private int _paletIndex = 0;
  74. public int PaletIndex
  75. {
  76. get { return _paletIndex; }
  77. set
  78. {
  79. _paletIndex = value;
  80. if (_currentAnime != null) _play(_currentAnime);
  81. }
  82. }
  83. //绑定RectTransform
  84. private RectTransform _rectTransform;
  85. //绑定BoxCollider2D(可选)
  86. private BoxCollider2D _boxCollider2D;
  87. //动画动作帧监听
  88. public AnimeEffectListener onEffectListener;
  89. public AnimeAudioListener onAudioListener;
  90. //鼠标移入事件监听
  91. public MouseListener onMouseEnterListener;
  92. //鼠标移出事件监听
  93. public MouseListener onMouseExitListener;
  94. //获取偏移量(无用)
  95. public Vector2 offset
  96. {
  97. get
  98. {
  99. float offsetX = -_frames[_currentFrame].AnimeFrameInfo.OffsetX;
  100. float offsetY = _frames[_currentFrame].AnimeFrameInfo.OffsetY;
  101. return new Vector2(offsetX, offsetY);
  102. }
  103. }
  104. //实例初始化时获取相关绑定
  105. private void Awake()
  106. {
  107. //调整渲染
  108. _imageRenderer = GetComponent<Image>();
  109. _spriteRenderer = GetComponent<SpriteRenderer>();
  110. _rectTransform = GetComponent<RectTransform>();
  111. //碰撞盒,仅当需要添加鼠标事件时使用
  112. _boxCollider2D = GetComponent<BoxCollider2D>();
  113. if(_imageRenderer == null) _imageRenderer = gameObject.AddComponent<Image>();
  114. if(_spriteRenderer == null) _spriteRenderer = gameObject.AddComponent<SpriteRenderer>();
  115. if(_rectTransform == null) _rectTransform = gameObject.AddComponent<RectTransform>();
  116. // if(_boxCollider2D == null) _boxCollider2D = gameObject.AddComponent<BoxCollider2D>();
  117. }
  118. private void Start()
  119. {
  120. _updateRenderMode();
  121. }
  122. //鼠标移入监听
  123. private void OnMouseEnter()
  124. {
  125. if(onMouseEnterListener!=null) onMouseEnterListener(this);
  126. }
  127. //鼠标移出监听
  128. private void OnMouseExit()
  129. {
  130. if(onMouseExitListener!=null) onMouseExitListener(this);
  131. }
  132. // 使用Image模式渲染
  133. public bool RenderByImage
  134. {
  135. get => isRenderByImage;
  136. set
  137. {
  138. isRenderByImage = value;
  139. _updateRenderMode();
  140. }
  141. }
  142. // 设置当前播放序列,默认方向North,动作Stand,播放类型Loop,播放速度1f
  143. public uint Serial
  144. {
  145. get => _currentSerial;
  146. set
  147. {
  148. Anime.DirectionType direction =
  149. _currentAnime?.Direction ?? Anime.DirectionType.North;
  150. Anime.ActionType actionType = _currentAnime?.actionType ?? Anime.ActionType.Stand;
  151. Anime.PlayType playType = _currentAnime?.playType ?? Anime.PlayType.Loop;
  152. float speed = _currentAnime?.Speed ?? 1f;
  153. AnimeCallback onFinishCallback = _currentAnime?.onFinishCallback;
  154. play(value, direction, actionType, playType, speed, onFinishCallback);
  155. }
  156. }
  157. // 动态调整播放类型
  158. public Anime.PlayType PlayType
  159. {
  160. get => _currentAnime?.playType ?? Anime.PlayType.Loop;
  161. set
  162. {
  163. if (_currentAnime != null)
  164. {
  165. _currentAnime.playType = value;
  166. }
  167. }
  168. }
  169. // 更新渲染模式
  170. private void _updateRenderMode()
  171. {
  172. if (isRenderByImage)
  173. {
  174. _imageRenderer.enabled = true;
  175. _spriteRenderer.enabled = false;
  176. }
  177. else
  178. {
  179. _imageRenderer.enabled = false;
  180. _spriteRenderer.enabled = true;
  181. }
  182. }
  183. /**
  184. * 播放动画,调用此方法将会清空当前播放队列,调用完成可通过链式调用nextPlay方法添加动画到播放队列
  185. * @param Serial 动画序列号
  186. * @param Direction 动画方向
  187. * @param ActionType 动画动作
  188. * @param PlayType 播放类型
  189. * @param Speed 播放速度,以 1s 为基准,根据动画帧率计算实际播放周期时长
  190. * @param onFinishCallback 动画结束回调
  191. * @return AnimePlayer
  192. */
  193. public AnimePlayer play(uint Serial, Anime.DirectionType Direction = Anime.DirectionType.North,
  194. Anime.ActionType actionType = Anime.ActionType.Stand, Anime.PlayType playType = Anime.PlayType.Once,
  195. float Speed = 1f, AnimeCallback onFinishCallback = null)
  196. {
  197. if (_spriteRenderer == null)
  198. {
  199. // Debug.Log("AnimePlayer:SpriteRenderer is null");
  200. return this;
  201. }
  202. AnimeOption animeOption = CreateAnimeOption(Serial, Direction, actionType, playType, Speed, onFinishCallback);
  203. if (animeOption == null)
  204. {
  205. if (onFinishCallback != null) onFinishCallback(actionType);
  206. // Debug.Log("AnimePlayer:AnimeOption create failed");
  207. return this;
  208. }
  209. //清空播放队列
  210. _animeQueue.Clear();
  211. //播放
  212. _currentSerial = Serial;
  213. _play(animeOption);
  214. //链式调用,后续可通过nextPlay方法添加动画到播放队列
  215. return this;
  216. }
  217. //播放动画
  218. public AnimePlayer play(uint Serial, Anime.PlayType playType, float speed = 1f,
  219. AnimeCallback onFinishCallback = null)
  220. {
  221. return play(Serial,Anime.DirectionType.North,Anime.ActionType.Stand,playType,speed,onFinishCallback);
  222. }
  223. //播放一次
  224. public AnimePlayer playOnce(Anime.DirectionType directionType,Anime.ActionType actionType,float Speed=1f,AnimeCallback onFinishCallback=null)
  225. {
  226. return play(_currentSerial, directionType, actionType, Anime.PlayType.Once,
  227. Speed, onFinishCallback);
  228. }
  229. //播放循环
  230. public AnimePlayer playLoop(Anime.DirectionType directionType,Anime.ActionType actionType,float Speed=1f,AnimeCallback onFinishCallback=null)
  231. {
  232. return play(_currentSerial, directionType, actionType, Anime.PlayType.Loop,
  233. Speed, onFinishCallback);
  234. }
  235. //调整动画方向
  236. public void changeDirection(Anime.DirectionType directionType)
  237. {
  238. if (directionType == _currentAnime.Direction || directionType == Anime.DirectionType.NULL) return;
  239. _currentAnime = CreateAnimeOption(_currentAnime.AnimeSerial, directionType, _currentAnime.actionType,
  240. _currentAnime.playType, _currentAnime.Speed, _currentAnime.onFinishCallback);
  241. _play(_currentAnime);
  242. }
  243. public Anime.DirectionType DirectionType
  244. {
  245. get => _currentAnime?.Direction ?? Anime.DirectionType.NULL;
  246. set
  247. {
  248. if (_currentAnime != null)
  249. {
  250. changeDirection(value);
  251. }
  252. }
  253. }
  254. //调整动画动作类型
  255. public void changeActionType(Anime.ActionType actionType)
  256. {
  257. if (actionType == _currentAnime.actionType) return;
  258. _currentAnime = CreateAnimeOption(_currentAnime.AnimeSerial, _currentAnime.Direction,actionType,
  259. _currentAnime.playType, _currentAnime.Speed, _currentAnime.onFinishCallback);
  260. _play(_currentAnime);
  261. }
  262. public Anime.ActionType ActionType
  263. {
  264. get => _currentAnime?.actionType ?? Anime.ActionType.NULL;
  265. set
  266. {
  267. if (_currentAnime != null)
  268. {
  269. changeActionType(value);
  270. }
  271. }
  272. }
  273. //播放
  274. private void _play(AnimeOption animeOption)
  275. {
  276. isPlayable = false;
  277. _currentAnime = null;
  278. AnimeFrame[] frames = new AnimeFrame[animeOption.AnimeDetail.FrameCount];
  279. if (isFrameBatch)
  280. {
  281. Debug.Log("AnimePlayer:Batch");
  282. Anime.BakeAnimeFrames(animeOption.AnimeDetail);
  283. //获取动画帧数据
  284. for (int i = 0; i < animeOption.AnimeDetail.AnimeFrameInfos.Length; i++)
  285. {
  286. if(animeOption.AnimeDetail.AnimeFrameInfos[i].AnimeSprite == null) continue;
  287. //创建帧数据
  288. frames[i] = new AnimeFrame();
  289. frames[i].Index = i;
  290. frames[i].GraphicInfo = animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicInfo;
  291. frames[i].Sprite = animeOption.AnimeDetail.AnimeFrameInfos[i].AnimeSprite;
  292. frames[i].AnimeFrameInfo = animeOption.AnimeDetail.AnimeFrameInfos[i];
  293. }
  294. }
  295. else
  296. {
  297. //获取动画帧数据
  298. for (int i = 0; i < animeOption.AnimeDetail.AnimeFrameInfos.Length; i++)
  299. {
  300. AnimeFrameInfo animeFrameInfo = animeOption.AnimeDetail.AnimeFrameInfos[i];
  301. GraphicInfoData graphicInfoData = GraphicInfo.GetGraphicInfoDataByIndex(animeOption.AnimeDetail.Version, animeOption.AnimeDetail.AnimeFrameInfos[i].GraphicIndex);
  302. if (graphicInfoData == null)
  303. {
  304. Debug.Log("GraphicInfo Version:" + animeOption.AnimeDetail.Version + " Index:" +
  305. animeOption.AnimeDetail.AnimeFrameInfos[i] + " is null");
  306. continue;
  307. }
  308. GraphicData graphicData = Graphic.GetGraphicData(graphicInfoData, _paletIndex);
  309. if (graphicData == null)
  310. {
  311. Debug.Log("GraphicData Version:" + animeOption.AnimeDetail.Version + " Index:" +
  312. animeOption.AnimeDetail.AnimeFrameInfos[i] + " is null");
  313. continue;
  314. }
  315. //创建帧数据
  316. frames[i] = new AnimeFrame();
  317. frames[i].Index = i;
  318. frames[i].GraphicInfo = graphicInfoData;
  319. frames[i].Sprite = graphicData.Sprite;
  320. frames[i].AnimeFrameInfo = animeFrameInfo;
  321. }
  322. }
  323. _currentAnime = animeOption;
  324. _frames = frames;
  325. _currentFrame = -1;
  326. isPlayable = true;
  327. gameObject.SetActive(true);
  328. UpdateFrame();
  329. }
  330. //播放延时
  331. public void DelayPlay(float delayTime)
  332. {
  333. _delay = delayTime*1000;
  334. }
  335. public void Stop()
  336. {
  337. isPlayable = false;
  338. _currentAnime = null;
  339. _frames = null;
  340. _currentFrame = -1;
  341. gameObject.SetActive(false);
  342. }
  343. //修改播放类型---重复方法--考虑删掉
  344. public void ChangePlayType(Anime.PlayType playType)
  345. {
  346. if (_currentAnime == null) return;
  347. _currentAnime.playType = playType;
  348. }
  349. //创建动画配置
  350. private AnimeOption CreateAnimeOption(uint Serial, Anime.DirectionType Direction, Anime.ActionType ActionType,
  351. Anime.PlayType playType=Anime.PlayType.Once, float Speed = 1f, AnimeCallback onFinishCallback = null)
  352. {
  353. AnimeDetail animeDetail = Anime.GetAnimeDetail(Serial, Direction, ActionType);
  354. if (animeDetail == null)
  355. {
  356. // Debug.Log("AnimePlayer:AnimeDetail is null");
  357. return null;
  358. }
  359. AnimeOption animeOption = new AnimeOption()
  360. {
  361. AnimeSerial = Serial,
  362. Direction = Direction,
  363. actionType = ActionType,
  364. playType = playType,
  365. Speed = Speed,
  366. FrameRate = animeDetail.CycleTime / Speed / animeDetail.FrameCount,
  367. AnimeDetail = animeDetail,
  368. onFinishCallback = onFinishCallback,
  369. };
  370. return animeOption;
  371. }
  372. //加入链式动画播放队列
  373. public AnimePlayer nextPlay(uint Serial, Anime.DirectionType Direction, Anime.ActionType ActionType,
  374. Anime.PlayType playType=Anime.PlayType.Once, float Speed = 1f, AnimeCallback onFinishCallback = null)
  375. {
  376. AnimeOption animeOption = CreateAnimeOption(Serial, Direction, ActionType, playType, Speed, onFinishCallback);
  377. if (animeOption == null)
  378. {
  379. if (onFinishCallback != null) onFinishCallback(ActionType);
  380. return this;
  381. }
  382. if (_animeQueue.Count == 0)
  383. {
  384. _play(animeOption);
  385. }
  386. else
  387. {
  388. _animeQueue.Enqueue(animeOption);
  389. }
  390. return this;
  391. }
  392. //加入链式动画播放队列
  393. public AnimePlayer nextPlay(Anime.DirectionType Direction, Anime.ActionType ActionType,
  394. Anime.PlayType playType=Anime.PlayType.Once, float Speed = 1f, AnimeCallback onFinishCallback = null)
  395. {
  396. return nextPlay(_currentSerial, Direction, ActionType, playType, Speed, onFinishCallback);
  397. }
  398. //更新计算
  399. private void Update()
  400. {
  401. float now = Time.time * 1000;
  402. if (_currentAnime != null && (now - _timer - _delay) >= _currentAnime.FrameRate) UpdateFrame();
  403. }
  404. //更新帧
  405. private void UpdateFrame()
  406. {
  407. _delay = 0;
  408. if (!isPlayable || _frames.Length == 0) return;
  409. _currentFrame++;
  410. //动画结束
  411. if (_currentFrame >= _currentAnime.AnimeDetail.FrameCount)
  412. {
  413. if(_currentAnime.onFinishCallback!=null) _currentAnime.onFinishCallback(_currentAnime.actionType);
  414. //循环播放
  415. if (_currentAnime.playType == Anime.PlayType.Loop)
  416. {
  417. _currentFrame = 0;
  418. }else if (_currentAnime.playType == Anime.PlayType.Once || _currentAnime.playType == Anime.PlayType.OnceAndDestroy)
  419. {
  420. if (_currentAnime.playType == Anime.PlayType.OnceAndDestroy)
  421. {
  422. _spriteRenderer.sprite = null;
  423. _imageRenderer.sprite = null;
  424. _rectTransform.sizeDelta = Vector2.zero;
  425. // gameObject.SetActive(false);
  426. }
  427. //播放下一个动画
  428. if(_animeQueue.Count>0)
  429. {
  430. AnimeOption animeOption = _animeQueue.Dequeue();
  431. _play(animeOption);
  432. return;
  433. }else
  434. {
  435. isPlayable = false;
  436. return;
  437. }
  438. }
  439. }
  440. //问题帧自动跳过
  441. if (_currentFrame<_frames.Length && _frames[_currentFrame] == null) return;
  442. //自动偏移
  443. // float graphicWidth = _frames[_currentFrame].Sprite.rect.width;
  444. // float graphicHeight = _frames[_currentFrame].Sprite.rect.height;
  445. // float offsetX = -_frames[_currentFrame].GraphicInfo.OffsetX;
  446. // float offsetY = _frames[_currentFrame].GraphicInfo.OffsetY;
  447. //根据当前帧Sprite动态调整对象大小
  448. float width = _frames[_currentFrame].Sprite.rect.width * 1f;
  449. float height = _frames[_currentFrame].Sprite.rect.height * 1f;
  450. if (isRenderByImage)
  451. {
  452. _imageRenderer.sprite = _frames[_currentFrame].Sprite;
  453. _imageRenderer.SetNativeSize();
  454. Vector3 pos = Vector3.zero;
  455. pos.x = _frames[_currentFrame].GraphicInfo.OffsetX;
  456. pos.y = -_frames[_currentFrame].GraphicInfo.OffsetY;
  457. _rectTransform.localPosition = pos;
  458. _rectTransform.pivot = new Vector2(0f,1f);
  459. }
  460. else
  461. {
  462. _spriteRenderer.sprite = _frames[_currentFrame].Sprite;
  463. _rectTransform.sizeDelta = new Vector2(width, height);
  464. _spriteRenderer.size = new Vector2(width, height);
  465. _rectTransform.pivot = new Vector2(0.5f,0f);
  466. _rectTransform.localPosition = Vector3.zero;
  467. }
  468. // Vector2 offset = Vector2.zero;
  469. // offset.x += -(_frames[_currentFrame].GraphicInfo.OffsetX * 1f) / _frames[_currentFrame].GraphicInfo.Width;
  470. // offset.y -= (-_frames[_currentFrame].GraphicInfo.OffsetY * 1f) / _frames[_currentFrame].GraphicInfo.Height;
  471. // _rectTransform.pivot = offset;
  472. // pos.x = (width + _frames[_currentFrame].GraphicInfo.OffsetX)/1f;
  473. // pos.y = (height + _frames[_currentFrame].GraphicInfo.OffsetY)/1f;
  474. // 2D碰撞器自动调整,但是动态碰撞器反而会导致重叠大物体选中效果不稳定,效果不如固定大小碰撞器好
  475. // if (_boxCollider2D != null)
  476. // {
  477. // Vector2 newSize =_boxCollider2D.size
  478. // _boxCollider2D.size = new Vector2(width, height);
  479. // }
  480. // _rectTransform.pivot = new Vector2(offsetX,offsetY);
  481. // _rectTransform.localPosition = new Vector3(0f, 0f);
  482. _timer = Time.time * 1000;
  483. //动画事件帧监听
  484. if(_frames[_currentFrame].AnimeFrameInfo.Effect >0 && onEffectListener!=null) onEffectListener(_frames[_currentFrame].AnimeFrameInfo.Effect);
  485. //音频事件帧监听
  486. if(_frames[_currentFrame].AnimeFrameInfo.AudioIndex >0 && onAudioListener!=null) onAudioListener(_frames[_currentFrame].AnimeFrameInfo.AudioIndex);
  487. }
  488. }
  489. }