赞
踩
目录
用途:在2D游戏里或者游戏的2D界面中,我们会经常发现一些动态图片,实现了动画的效果。动态图片的实现让画面更具有动感,更能吸引玩家的眼球,给玩家更好的视觉体验。当然也可以用来实现一些2D特效,比如炸弹爆炸等。
实现思路:图片是有纹理的,我们可以通过代码动态的修改纹理,计算机执行效率是很快的,当我们更改图片的纹理频率很快时,运行出来的效果就成了动画,当然前提是要是一组图片,这个思路跟我们小时候看的连环画一样。
首先我们期望是能实现一组图片动态更换纹理,在脚本上能够动态拖动图片组,设置是否循环播放以及动画播放的频率。我以做过的捕鱼达人案例中鱼的游动为例子说明,具体代码实现如下:
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class Swimming : MonoBehaviour
- {
- public Sprite[] frames;
- public bool loop = false;
- public float frequency = 0.2f;
- float calTime = 0f;
- int index = 0;
- Image img_spritr;
-
- // Start is called before the first frame update
- void Start()
- {
- img_spritr = GetComponent<Image>();
- img_spritr.sprite = frames[index];
-
- }
-
- // Update is called once per frame
- void Update()
- {
- calTime += Time.deltaTime;
- if (calTime > frequency)
- {
- calTime = 0;
-
- if (!loop)
- {
- if (index == frames.Length - 1)
- {
- index = 0;
-
- }
- img_spritr.sprite = frames[++index];
- }
-
- else
- {
- img_spritr.sprite = frames[index++];
- if (index == frames.Length - 1)
- {
- // Destroy(this.gameObject);
- index = 0;
- }
-
- }
-
-
- }
- }
- IEnumerator Animation()
- {
- while (true)
- {
- yield return new WaitForSeconds(frequency);
- img_spritr.sprite = frames[++index];
- if (index == frames.Length - 1)
- {
- if (!loop)
- {
- yield break;
- }
- else
- {
- index = 0;
- }
- }
- }
-
- }
- }
首先在外部我们需要调用一组图片存放在Sprite[]中,设置bool值loop判断是否循环播放,设置动画的播放频率frequency,默认值是0.2f。用calTime来记录运行的时间。index来存放材质组的下标。
在Start函数中,我们首先获取Image组件,然后将Iamge的材质设置为图片组中第一个。
在Update函数中,用calTime来记录运行的时间,当运行的时间大于频率时,将calTime置为0重新计时,并且判断是否循环。循环条件下:判断临界值,当Sprite[]显示最后一张图片时,将此时的下标index置为0,图片组中下标不断地++。如果不循环:图片组下标不断++,同时判断是否显示到最后一张图,显示最后的一张图时根据需求,可以直接销毁图片(比如制作炸弹特效),也可以置为0,恢复到初始图片。
当然同样的功能我们也可以放到线程中实现:在循环体中先等待一次频率时间,然后更换图片为下一张,判断临界值,当显示到最后一张的时候,判断是否循环,不循环就直接,最后显示的是图片组中最后的一张,循环的话将下标置为0继续循环。
这里我们考虑让图片组不仅能正放,还能倒着播放,能够自动播放,暂停,继续播放,停止播放,重播。考虑用bool值来控制各种状态,具体的功能封装到函数中执行。
-
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- public class SpriteAnimation : MonoBehaviour
- {
- private Image ImageSource;
- private int mCurFrame = 0;
- private float mDelta = 0;
-
- public float FPS = 15;
- public List<Sprite> SpriteFrames;
- public bool IsPlaying = false;
- public bool Foward = true;
- public bool AutoPlay = false;
- public bool Loop = false;
-
- public int FrameCount
- {
- get
- {
- return SpriteFrames.Count;
- }
- }
-
- void Awake()
- {
- ImageSource = GetComponent<Image>();
- }
- void Start()
- {
- if (AutoPlay)
- {
- Play();
- }
- else
- {
- IsPlaying = false;
- }
- }
-
- private void SetSprite(int idx)
- {
- ImageSource.sprite = SpriteFrames[idx];
- //该部分为设置成原始图片大小,如果只需要显示Image设定好的图片大小,注释掉该行即可。
- //ImageSource.SetNativeSize();
- }
-
- public void Play()
- {
- IsPlaying = true;
- Foward = true;
- }
-
- public void PlayReverse()
- {
- IsPlaying = true;
- Foward = false;
- }
-
- void Update()
- {
- if (!IsPlaying || 0 == FrameCount)
- {
- return;
- }
-
- mDelta += Time.deltaTime;
- if (mDelta > 1 / FPS)
- {
- mDelta = 0;
- if (Foward)
- {
- mCurFrame++;
- }
- else
- {
- mCurFrame--;
- }
-
- if (mCurFrame >= FrameCount)
- {
- if (Loop)
- {
- mCurFrame = 0;
- }
- else
- {
- IsPlaying = false;
- return;
- }
- }
- else if (mCurFrame < 0)
- {
- if (Loop)
- {
- mCurFrame = FrameCount - 1;
- }
- else
- {
- IsPlaying = false;
- return;
- }
- }
-
- SetSprite(mCurFrame);
- }
- }
-
- public void Pause()
- {
- IsPlaying = false;
- }
-
- public void Resume()
- {
- if (!IsPlaying)
- {
- IsPlaying = true;
- }
- }
-
- public void Stop()
- {
- mCurFrame = 0;
- SetSprite(mCurFrame);
- IsPlaying = false;
- }
-
- public void Rewind()
- {
- mCurFrame = 0;
- SetSprite(mCurFrame);
- Play();
- }
- }
命名的参数通过英文意思就很容易理解,我们这里就不再多解释。这里的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()函数开始播放。
可以将这两段代码当作工具来使用,在设计界面的时候相信能够用到。当然我们可以通过上面的代码实现图片播放结束就销毁,并将图片设置为预设体(预制件)动态加载,这样能够实现调用预设体时屏幕出现一次动画就销毁,做出一些特效,比如斗地主中出炸弹时屏幕上显示一个炸弹爆炸后消失的特效。当然还有其他的用途,但基本思想与实现大同小异,需要读者自己发掘举一反三了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。