305 lines
9.7 KiB
C#
305 lines
9.7 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.UI;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.IO;
|
|||
|
|
using System.Linq;
|
|||
|
|
|
|||
|
|
namespace GeneralTools
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 序列帧动画播放器
|
|||
|
|
/// 支持UGUI的Image和Unity2D的SpriteRenderer
|
|||
|
|
/// </summary>
|
|||
|
|
public class FramesAnimator : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
//目标Image组件
|
|||
|
|
private RawImage image;
|
|||
|
|
|
|||
|
|
private List<FramesAttribute> framesList;
|
|||
|
|
/// <summary>
|
|||
|
|
/// 全部结束事件
|
|||
|
|
/// </summary>
|
|||
|
|
public event Action OnAllFinishEvent;
|
|||
|
|
|
|||
|
|
//是否允许播放
|
|||
|
|
private bool isAllowPlay = true;
|
|||
|
|
//当前帧索引
|
|||
|
|
private int currentFrameIndex = 0;
|
|||
|
|
//当前动画序号索引
|
|||
|
|
private int currentAnimationIndex = 0;
|
|||
|
|
//下一次更新时间
|
|||
|
|
private float timer = 0.0f;
|
|||
|
|
|
|||
|
|
|
|||
|
|
public FramesAnimator Init(List<FramesAttribute> frameAttritubes)
|
|||
|
|
{
|
|||
|
|
Stop();
|
|||
|
|
image = GetComponent<RawImage>();
|
|||
|
|
if (image == null)
|
|||
|
|
{
|
|||
|
|
Debug.LogError("未找到RawImage", gameObject);
|
|||
|
|
}
|
|||
|
|
framesList = frameAttritubes;
|
|||
|
|
OnAllFinishEvent = null;
|
|||
|
|
return this;
|
|||
|
|
}
|
|||
|
|
public FramesAnimator Init(params List<Texture>[] texArr)
|
|||
|
|
{
|
|||
|
|
List<FramesAttribute> temp = new List<FramesAttribute>();
|
|||
|
|
for (int i = 0; i < texArr.Length; i++)
|
|||
|
|
{
|
|||
|
|
FramesAttribute newFM = new FramesAttribute(texArr[i], i == texArr.Length - 1);
|
|||
|
|
temp.Add(newFM);
|
|||
|
|
}
|
|||
|
|
return Init(temp);
|
|||
|
|
}
|
|||
|
|
public FramesAnimator Init(List<List<Texture>> texList, List<bool> loopList, List<Action> finishEventList = null)
|
|||
|
|
{
|
|||
|
|
List<FramesAttribute> temp = new List<FramesAttribute>();
|
|||
|
|
if (finishEventList == null)
|
|||
|
|
finishEventList = new List<Action>();
|
|||
|
|
for (int i = 0; i < texList.Count; i++)
|
|||
|
|
{
|
|||
|
|
bool il = i < loopList.Count ? loopList[i] : false;
|
|||
|
|
FramesAttribute newFM = new FramesAttribute(texList[i], il);
|
|||
|
|
newFM.OnFinishEvent += i < finishEventList.Count ? finishEventList[i] : null;
|
|||
|
|
temp.Add(newFM);
|
|||
|
|
}
|
|||
|
|
return Init(temp);
|
|||
|
|
}
|
|||
|
|
public void Play()
|
|||
|
|
{
|
|||
|
|
isAllowPlay = true;
|
|||
|
|
gameObject.SetActive(true);
|
|||
|
|
}
|
|||
|
|
public void Pause()
|
|||
|
|
{
|
|||
|
|
isAllowPlay = false;
|
|||
|
|
}
|
|||
|
|
public void Stop()
|
|||
|
|
{
|
|||
|
|
isAllowPlay = false;
|
|||
|
|
ResetIndex();
|
|||
|
|
}
|
|||
|
|
public void Hide()
|
|||
|
|
{
|
|||
|
|
Stop();
|
|||
|
|
gameObject.SetActive(false);
|
|||
|
|
}
|
|||
|
|
public void RePlay()
|
|||
|
|
{
|
|||
|
|
isAllowPlay = false;
|
|||
|
|
ResetIndex();
|
|||
|
|
if (framesList.Count > 0)
|
|||
|
|
{
|
|||
|
|
if (framesList[0].framesList.Count > 0)
|
|||
|
|
{
|
|||
|
|
image.texture = framesList[0].framesList[currentFrameIndex];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
Play();
|
|||
|
|
}
|
|||
|
|
public void PlayIndex(int index)
|
|||
|
|
{
|
|||
|
|
if (framesList == null)
|
|||
|
|
return;
|
|||
|
|
if (index < 0 || index >= framesList.Count)
|
|||
|
|
return;
|
|||
|
|
isAllowPlay = false;
|
|||
|
|
currentAnimationIndex = index;
|
|||
|
|
currentFrameIndex = framesList[currentAnimationIndex].framerate > 0 ? 0 : framesList[currentAnimationIndex].framesList.Count - 1;
|
|||
|
|
if (framesList[currentAnimationIndex].framesList.Count > 0)
|
|||
|
|
{
|
|||
|
|
image.texture = framesList[currentAnimationIndex].framesList[currentFrameIndex];
|
|||
|
|
}
|
|||
|
|
Play();
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 改变一个索引的临时loop
|
|||
|
|
/// </summary>
|
|||
|
|
public void SetLoopOfIndex(int index, bool loop)
|
|||
|
|
{
|
|||
|
|
if (index >= 0 && index < framesList.Count)
|
|||
|
|
{
|
|||
|
|
framesList[index].loop = loop;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 改变一个索引的永久loop
|
|||
|
|
/// </summary>
|
|||
|
|
public void SetLoopOfIndexForever(int index, bool loop)
|
|||
|
|
{
|
|||
|
|
if (index >= 0 && index < framesList.Count)
|
|||
|
|
{
|
|||
|
|
framesList[index].InitialLoop = loop;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获得当前动画索引
|
|||
|
|
/// </summary>
|
|||
|
|
public int GetCurrentAnimationIndex()
|
|||
|
|
{
|
|||
|
|
return currentAnimationIndex;
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 改变当前索引的临时loop
|
|||
|
|
/// </summary>
|
|||
|
|
public void SetCurrentAnimationLoop(bool loop)
|
|||
|
|
{
|
|||
|
|
SetLoopOfIndex(currentAnimationIndex, loop);
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 动画全部设置为不循环,播放完销毁自身
|
|||
|
|
/// </summary>
|
|||
|
|
public void GoDestroy()
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < framesList.Count; i++)
|
|||
|
|
{
|
|||
|
|
SetLoopOfIndexForever(i, false);
|
|||
|
|
}
|
|||
|
|
OnAllFinishEvent += () =>
|
|||
|
|
{
|
|||
|
|
Destroy(gameObject);
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 重设动画索引
|
|||
|
|
/// </summary>
|
|||
|
|
private int ResetIndex()
|
|||
|
|
{
|
|||
|
|
currentAnimationIndex = 0;
|
|||
|
|
//重置Loop
|
|||
|
|
if (framesList != null)
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < framesList.Count; i++)
|
|||
|
|
{
|
|||
|
|
framesList[i].ReSetLoop();
|
|||
|
|
}
|
|||
|
|
currentFrameIndex = framesList[currentAnimationIndex].framerate > 0 ? 0 : framesList[currentAnimationIndex].framesList.Count - 1;
|
|||
|
|
}
|
|||
|
|
return currentFrameIndex;
|
|||
|
|
}
|
|||
|
|
void FixedUpdate()
|
|||
|
|
{
|
|||
|
|
if (framesList == null || framesList.Count == 0 || image == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
//是否允许播放
|
|||
|
|
if (!isAllowPlay) return;
|
|||
|
|
PlayOneFrame(framesList[currentAnimationIndex]);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
private void PlayOneFrame(FramesAttribute fm)
|
|||
|
|
{
|
|||
|
|
if (fm == null || fm.framesList.Count == 0 || fm.framerate == 0)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
//获取当前时间
|
|||
|
|
float time = fm.ignoreTimeScale ? Time.unscaledTime : Time.time;
|
|||
|
|
//计算帧间隔时间
|
|||
|
|
float interval = Mathf.Abs(1.0f / fm.framerate);
|
|||
|
|
//满足更新条件,执行更新操作
|
|||
|
|
if (time - timer > interval)
|
|||
|
|
{
|
|||
|
|
//执行更新操作
|
|||
|
|
DoUpdate(fm);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//具体更新操作
|
|||
|
|
private void DoUpdate(FramesAttribute fm)
|
|||
|
|
{
|
|||
|
|
//计算新的索引
|
|||
|
|
int nextIndex = currentFrameIndex + (fm.framerate > 0 ? 1 : -1);
|
|||
|
|
//索引越界,表示已经到结束帧
|
|||
|
|
if (nextIndex < 0 || nextIndex >= fm.framesList.Count)
|
|||
|
|
{
|
|||
|
|
nextIndex = 0;
|
|||
|
|
//不循环,整体动画索引+1
|
|||
|
|
if (fm.loop == false)
|
|||
|
|
{
|
|||
|
|
//播放结束事件
|
|||
|
|
fm.OnFinish();
|
|||
|
|
currentAnimationIndex += 1;
|
|||
|
|
|
|||
|
|
if (currentAnimationIndex >= framesList.Count)
|
|||
|
|
{
|
|||
|
|
//全部播放完毕,帧索引不归零
|
|||
|
|
isAllowPlay = false;
|
|||
|
|
OnAllFinishEvent?.Invoke();
|
|||
|
|
currentAnimationIndex = framesList.Count - 1;
|
|||
|
|
nextIndex = fm.framesList.Count - 1;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
//未结束,指向下一个动画,帧索引归零
|
|||
|
|
fm = framesList[currentAnimationIndex];
|
|||
|
|
nextIndex = fm.framerate > 0 ? 0 : fm.framesList.Count - 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
//循环,帧索引归零
|
|||
|
|
nextIndex = fm.framerate > 0 ? 0 : fm.framesList.Count - 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
//钳制索引
|
|||
|
|
currentFrameIndex = Mathf.Clamp(nextIndex, 0, fm.framesList.Count - 1);
|
|||
|
|
//更新图片
|
|||
|
|
RefreshTexture(fm, currentFrameIndex);
|
|||
|
|
//设置计时器为当前时间
|
|||
|
|
timer = fm.ignoreTimeScale ? Time.unscaledTime : Time.time;
|
|||
|
|
}
|
|||
|
|
private void RefreshTexture(FramesAttribute fm, int index)
|
|||
|
|
{
|
|||
|
|
image.texture = fm.framesList[index];
|
|||
|
|
}
|
|||
|
|
public void ManualUpdatePositive()
|
|||
|
|
{
|
|||
|
|
FramesAttribute fm = framesList[currentAnimationIndex];
|
|||
|
|
DoUpdate(fm);
|
|||
|
|
}
|
|||
|
|
//反向手动刷新
|
|||
|
|
public void ManualUpdateReverse()
|
|||
|
|
{
|
|||
|
|
FramesAttribute fm = framesList[currentAnimationIndex];
|
|||
|
|
fm.framerate *= -1;
|
|||
|
|
DoUpdate(fm);
|
|||
|
|
fm.framerate *= -1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
public class FramesAttribute
|
|||
|
|
{
|
|||
|
|
public List<Texture> framesList;
|
|||
|
|
public bool loop;
|
|||
|
|
public bool InitialLoop { get { return initialLoop; } set { loop = value; initialLoop = value; } }
|
|||
|
|
private bool initialLoop;
|
|||
|
|
public event Action OnFinishEvent;
|
|||
|
|
public float framerate = 24.0f;
|
|||
|
|
public bool ignoreTimeScale = true;
|
|||
|
|
public FramesAttribute()
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
public FramesAttribute(List<Texture> _framesList, bool _loop)
|
|||
|
|
{
|
|||
|
|
framesList = _framesList;
|
|||
|
|
InitialLoop = _loop;
|
|||
|
|
OnFinishEvent = null;
|
|||
|
|
}
|
|||
|
|
public void ReSetLoop()
|
|||
|
|
{
|
|||
|
|
InitialLoop = InitialLoop;
|
|||
|
|
}
|
|||
|
|
public void OnFinish()
|
|||
|
|
{
|
|||
|
|
OnFinishEvent?.Invoke();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|