174 lines
4.9 KiB
C#
174 lines
4.9 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
|
|
namespace GeneralTools
|
|
{
|
|
/// <summary>
|
|
/// 序列帧动画播放器
|
|
/// 支持UGUI的Image和Unity2D的SpriteRenderer
|
|
/// </summary>
|
|
public class FrameAnimator : MonoBehaviour
|
|
{
|
|
|
|
//目标Image组件
|
|
private RawImage image;
|
|
/// <summary>
|
|
/// 序列帧
|
|
/// </summary>
|
|
private List<Texture> frames = null;
|
|
/// <summary>
|
|
/// 帧率
|
|
/// </summary>
|
|
private float framerate = 24.0f;
|
|
/// <summary>
|
|
/// 是否忽略timeScale
|
|
/// </summary>
|
|
private bool ignoreTimeScale = true;
|
|
/// <summary>
|
|
/// 是否循环
|
|
/// </summary>
|
|
private bool loop = true;
|
|
/// <summary>
|
|
/// 是否允许播放
|
|
/// </summary>
|
|
private bool isAllowPlay = false;
|
|
/// <summary>
|
|
/// 结束事件
|
|
/// 在每次播放完一个周期时触发
|
|
/// 在循环模式下触发此事件时,当前帧不一定为结束帧
|
|
/// </summary>
|
|
public event Action OnFinishEvent;
|
|
|
|
//当前帧索引
|
|
private int currentFrameIndex = 0;
|
|
//下一次更新时间
|
|
private float timer = 0.0f;
|
|
|
|
public FrameAnimator Init(List<Texture> _frames, bool _loop, float _framerate = 24)
|
|
{
|
|
Stop();
|
|
image = GetComponent<RawImage>();
|
|
if (image == null)
|
|
{
|
|
Debug.LogError("未找到RawImage", gameObject);
|
|
}
|
|
frames = _frames;
|
|
loop = _loop;
|
|
framerate = _framerate;
|
|
image.texture = _frames[0];
|
|
OnFinishEvent = null;
|
|
return this;
|
|
}
|
|
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 (frames.Count > 0)
|
|
{
|
|
image.texture = frames[currentFrameIndex];
|
|
}
|
|
Play();
|
|
}
|
|
public void SetLoop(bool _loop)
|
|
{
|
|
loop = _loop;
|
|
}
|
|
/// <summary>
|
|
/// 重设动画索引
|
|
/// </summary>
|
|
private int ResetIndex()
|
|
{
|
|
currentFrameIndex = framerate > 0 ? 0 : frames.Count - 1;
|
|
return currentFrameIndex;
|
|
}
|
|
void FixedUpdate()
|
|
{
|
|
//帧数据无效,禁用脚本
|
|
if (frames == null || frames.Count == 0 || image == null || frames.Count == 1 || framerate == 0)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
//是否允许播放
|
|
if (!isAllowPlay) return;
|
|
//获取当前时间
|
|
float time = ignoreTimeScale ? Time.unscaledTime : Time.time;
|
|
//计算帧间隔时间
|
|
float interval = Mathf.Abs(1.0f / framerate);
|
|
//满足更新条件,执行更新操作
|
|
if (time - timer > interval)
|
|
{
|
|
//执行更新操作
|
|
DoUpdate();
|
|
}
|
|
}
|
|
}
|
|
//具体更新操作
|
|
private void DoUpdate()
|
|
{
|
|
//计算新的索引
|
|
int nextIndex = currentFrameIndex + (framerate > 0 ? 1 : -1);
|
|
//索引越界,表示已经到结束帧
|
|
if (nextIndex < 0 || nextIndex >= frames.Count)
|
|
{
|
|
//非循环,模式结束
|
|
if (loop == false)
|
|
{
|
|
isAllowPlay = false;
|
|
//播放结束事件
|
|
OnFinishEvent?.Invoke();
|
|
nextIndex = frames.Count - 1;
|
|
}
|
|
else
|
|
{
|
|
nextIndex = ResetIndex();
|
|
}
|
|
}
|
|
//钳制索引
|
|
currentFrameIndex = Mathf.Clamp(nextIndex, 0, frames.Count - 1);
|
|
//更新图片
|
|
RefreshTexture(currentFrameIndex);
|
|
//设置计时器为当前时间
|
|
timer = ignoreTimeScale ? Time.unscaledTime : Time.time;
|
|
}
|
|
private void RefreshTexture(int index)
|
|
{
|
|
image.texture = frames[index];
|
|
}
|
|
//正向手动刷新
|
|
public void ManualUpdatePositive()
|
|
{
|
|
DoUpdate();
|
|
}
|
|
//反向手动刷新
|
|
public void ManualUpdateReverse()
|
|
{
|
|
framerate *= -1;
|
|
DoUpdate();
|
|
framerate *= -1;
|
|
}
|
|
}
|
|
} |