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()函数开始播放。


总结

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