Unity2D更换图片纹理实现动画
目录
Unity2D更换图片纹理实现动画
思路分析
一、基本功能的实现
代码分析:
二、功能扩展
1.想要扩展的功能
2.具体的代码:
3.代码分析:
总结
思路分析
用途:在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继续循环。
二、功能扩展
1.想要扩展的功能
这里我们考虑让图片组不仅能正放,还能倒着播放,能够自动播放,暂停,继续播放,停止播放,重播。考虑用bool值来控制各种状态,具体的功能封装到函数中执行。
2.具体的代码:
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();
}
}
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()函数开始播放。
总结
可以将这两段代码当作工具来使用,在设计界面的时候相信能够用到。当然我们可以通过上面的代码实现图片播放结束就销毁,并将图片设置为预设体(预制件)动态加载,这样能够实现调用预设体时屏幕出现一次动画就销毁,做出一些特效,比如斗地主中出炸弹时屏幕上显示一个炸弹爆炸后消失的特效。当然还有其他的用途,但基本思想与实现大同小异,需要读者自己发掘举一反三了。