当前位置:   article > 正文

Unity2D更换图片纹理实现动画_unity spine替换纹理

unity spine替换纹理

Unity2D更换图片纹理实现动画

目录

Unity2D更换图片纹理实现动画

思路分析

一、基本功能的实现

代码分析:

二、功能扩展

1.想要扩展的功能

2.具体的代码:

3.代码分析:

总结


 

思路分析

用途:在2D游戏里或者游戏的2D界面中,我们会经常发现一些动态图片,实现了动画的效果。动态图片的实现让画面更具有动感,更能吸引玩家的眼球,给玩家更好的视觉体验。当然也可以用来实现一些2D特效,比如炸弹爆炸等。

实现思路:图片是有纹理的,我们可以通过代码动态的修改纹理,计算机执行效率是很快的,当我们更改图片的纹理频率很快时,运行出来的效果就成了动画,当然前提是要是一组图片,这个思路跟我们小时候看的连环画一样。


一、基本功能的实现

              首先我们期望是能实现一组图片动态更换纹理,在脚本上能够动态拖动图片组,设置是否循环播放以及动画播放的频率。我以做过的捕鱼达人案例中鱼的游动为例子说明,具体代码实现如下:

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. public class Swimming : MonoBehaviour
  6. {
  7. public Sprite[] frames;
  8. public bool loop = false;
  9. public float frequency = 0.2f;
  10. float calTime = 0f;
  11. int index = 0;
  12. Image img_spritr;
  13. // Start is called before the first frame update
  14. void Start()
  15. {
  16. img_spritr = GetComponent<Image>();
  17. img_spritr.sprite = frames[index];
  18. }
  19. // Update is called once per frame
  20. void Update()
  21. {
  22. calTime += Time.deltaTime;
  23. if (calTime > frequency)
  24. {
  25. calTime = 0;
  26. if (!loop)
  27. {
  28. if (index == frames.Length - 1)
  29. {
  30. index = 0;
  31. }
  32. img_spritr.sprite = frames[++index];
  33. }
  34. else
  35. {
  36. img_spritr.sprite = frames[index++];
  37. if (index == frames.Length - 1)
  38. {
  39. // Destroy(this.gameObject);
  40. index = 0;
  41. }
  42. }
  43. }
  44. }
  45. IEnumerator Animation()
  46. {
  47. while (true)
  48. {
  49. yield return new WaitForSeconds(frequency);
  50. img_spritr.sprite = frames[++index];
  51. if (index == frames.Length - 1)
  52. {
  53. if (!loop)
  54. {
  55. yield break;
  56. }
  57. else
  58. {
  59. index = 0;
  60. }
  61. }
  62. }
  63. }
  64. }

代码分析:

        首先在外部我们需要调用一组图片存放在Sprite[]中,设置bool值loop判断是否循环播放,设置动画的播放频率frequency,默认值是0.2f。用calTime来记录运行的时间。index来存放材质组的下标。

        在Start函数中,我们首先获取Image组件,然后将Iamge的材质设置为图片组中第一个。

        在Update函数中,用calTime来记录运行的时间,当运行的时间大于频率时,将calTime置为0重新计时,并且判断是否循环。循环条件下:判断临界值,当Sprite[]显示最后一张图片时,将此时的下标index置为0,图片组中下标不断地++。如果不循环:图片组下标不断++,同时判断是否显示到最后一张图,显示最后的一张图时根据需求,可以直接销毁图片(比如制作炸弹特效),也可以置为0,恢复到初始图片。

        当然同样的功能我们也可以放到线程中实现:在循环体中先等待一次频率时间,然后更换图片为下一张,判断临界值,当显示到最后一张的时候,判断是否循环,不循环就直接,最后显示的是图片组中最后的一张,循环的话将下标置为0继续循环。

二、功能扩展

1.想要扩展的功能

这里我们考虑让图片组不仅能正放,还能倒着播放,能够自动播放,暂停,继续播放,停止播放,重播。考虑用bool值来控制各种状态,具体的功能封装到函数中执行。

2.具体的代码:

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. public class SpriteAnimation : MonoBehaviour
  6. {
  7. private Image ImageSource;
  8. private int mCurFrame = 0;
  9. private float mDelta = 0;
  10. public float FPS = 15;
  11. public List<Sprite> SpriteFrames;
  12. public bool IsPlaying = false;
  13. public bool Foward = true;
  14. public bool AutoPlay = false;
  15. public bool Loop = false;
  16. public int FrameCount
  17. {
  18. get
  19. {
  20. return SpriteFrames.Count;
  21. }
  22. }
  23. void Awake()
  24. {
  25. ImageSource = GetComponent<Image>();
  26. }
  27. void Start()
  28. {
  29. if (AutoPlay)
  30. {
  31. Play();
  32. }
  33. else
  34. {
  35. IsPlaying = false;
  36. }
  37. }
  38. private void SetSprite(int idx)
  39. {
  40. ImageSource.sprite = SpriteFrames[idx];
  41. //该部分为设置成原始图片大小,如果只需要显示Image设定好的图片大小,注释掉该行即可。
  42. //ImageSource.SetNativeSize();
  43. }
  44. public void Play()
  45. {
  46. IsPlaying = true;
  47. Foward = true;
  48. }
  49. public void PlayReverse()
  50. {
  51. IsPlaying = true;
  52. Foward = false;
  53. }
  54. void Update()
  55. {
  56. if (!IsPlaying || 0 == FrameCount)
  57. {
  58. return;
  59. }
  60. mDelta += Time.deltaTime;
  61. if (mDelta > 1 / FPS)
  62. {
  63. mDelta = 0;
  64. if (Foward)
  65. {
  66. mCurFrame++;
  67. }
  68. else
  69. {
  70. mCurFrame--;
  71. }
  72. if (mCurFrame >= FrameCount)
  73. {
  74. if (Loop)
  75. {
  76. mCurFrame = 0;
  77. }
  78. else
  79. {
  80. IsPlaying = false;
  81. return;
  82. }
  83. }
  84. else if (mCurFrame < 0)
  85. {
  86. if (Loop)
  87. {
  88. mCurFrame = FrameCount - 1;
  89. }
  90. else
  91. {
  92. IsPlaying = false;
  93. return;
  94. }
  95. }
  96. SetSprite(mCurFrame);
  97. }
  98. }
  99. public void Pause()
  100. {
  101. IsPlaying = false;
  102. }
  103. public void Resume()
  104. {
  105. if (!IsPlaying)
  106. {
  107. IsPlaying = true;
  108. }
  109. }
  110. public void Stop()
  111. {
  112. mCurFrame = 0;
  113. SetSprite(mCurFrame);
  114. IsPlaying = false;
  115. }
  116. public void Rewind()
  117. {
  118. mCurFrame = 0;
  119. SetSprite(mCurFrame);
  120. Play();
  121. }
  122. }

3.代码分析:

           命名的参数通过英文意思就很容易理解,我们这里就不再多解释。这里的FrameCount属性是用来获取图片组中的图片数。

           在Awake函数里面我们获取Image组件。在Start函数中判断是否自动播放,自动播放调用Play函数,Play函数默认是正向播放。不播放就将IsPlaying播放状态置为false。

           SetSprite(int idx)函数是用来设置图片纹理更换的函数。

           PlayReverse()函数控制倒着播放。

           在Update函数中先判断是否在播放状态或者图片组中是否有图片。没有播放或者没有纹理就直接结束。用mDelta参数记录运行时间,判断mDelta与切换时间(采用FPS频率倒数,这样FPS值越大,图片切换的越快)大小。对Foward方向进行判断确定是正放(图片下标就++)还是倒放(图片下标就--)。对临界值进行判断,当运行到图片组最后一张图片时,判断是否循环播放,循环就将下标重新置为0,反之就结束播放并结束函数执行。因为设置了倒放的功能,所以这里还要对0值进行判断。当运行到第一张图片时,下一帧判断是否循环播放,循环播放就将下标置为图片组最后一张图片,反之停止播放并结束函数执行。当然进行了一大堆状态的判断以后不要忘了调用SetSprite函数让图片动起来。

           Pause()暂停函数中就很简单了,直接将IsPlaying状态置为false即可。

           Resume()继续播放函数,判断IsPlaying没有播放,就将IsPlaying置为true,继续播放。

           Stop()停止函数,将mCurFrame置为0,将图片纹理置为图片组中第一张,IsPlaying播放状态置为false。

           Rewind()重播函数,将mCurFrame置为0,将图片纹理置为图片组中第一张,并调用Play()函数开始播放。


总结

             可以将这两段代码当作工具来使用,在设计界面的时候相信能够用到。当然我们可以通过上面的代码实现图片播放结束就销毁,并将图片设置为预设体(预制件)动态加载,这样能够实现调用预设体时屏幕出现一次动画就销毁,做出一些特效,比如斗地主中出炸弹时屏幕上显示一个炸弹爆炸后消失的特效。当然还有其他的用途,但基本思想与实现大同小异,需要读者自己发掘举一反三了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/122545
推荐阅读
相关标签
  

闽ICP备14008679号