252 lines
7.2 KiB
C#
252 lines
7.2 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
public class UIImageSheetAnimation : MonoBehaviour
|
|
{
|
|
public enum AnimationType
|
|
{
|
|
WholeSheet,
|
|
SingleRow,
|
|
}
|
|
|
|
public enum TimeType
|
|
{
|
|
LifeTime,
|
|
FPS,
|
|
}
|
|
|
|
public enum StartFrameType
|
|
{
|
|
Constant,
|
|
RandomBetweenTwoConstants,
|
|
}
|
|
|
|
[HideInInspector]
|
|
public float lifeTime = 5f;
|
|
[HideInInspector]
|
|
public bool loop = true;
|
|
[HideInInspector]
|
|
public int sizeX = 1;
|
|
[HideInInspector]
|
|
public int sizeY = 1;
|
|
[HideInInspector]
|
|
public StartFrameType startFrameMode = StartFrameType.Constant;
|
|
[HideInInspector]
|
|
public float startFrameMin = 0;//默认使用下面的
|
|
[HideInInspector]
|
|
public float startFrame = 0;
|
|
[HideInInspector]
|
|
public AnimationType animationMode = AnimationType.WholeSheet;
|
|
[HideInInspector]
|
|
public bool randomRow = true;
|
|
private bool initRandomRow = false;
|
|
|
|
private int cacheRow;//用于处理random row
|
|
[HideInInspector]
|
|
public int row = 0;
|
|
|
|
[HideInInspector]
|
|
public TimeType timeMode = TimeType.LifeTime;
|
|
public ParticleSystem.MinMaxCurve frameOverTime;//因为CustomEditor中不好实现 所以这个暴露出来
|
|
[HideInInspector]
|
|
public float cycles = 1;
|
|
[HideInInspector]
|
|
public float FPS = 30;
|
|
|
|
private Image mainImg;
|
|
private bool imgEnable = true;
|
|
private Material mat;
|
|
private Material matInstance;//copy的实例
|
|
|
|
private float totalTime;//总运行时间
|
|
private float totalDis;//总偏移值
|
|
|
|
private const string UV_PROPERTY = "_MainTex_ST";
|
|
private int UV_ID;
|
|
|
|
private float cacheUV_X;
|
|
private float cacheUV_Y;
|
|
|
|
// Start is called before the first frame update
|
|
void Start()
|
|
{
|
|
//check param
|
|
if (sizeX <= 0 || sizeY <= 0)
|
|
{
|
|
Debug.LogError("SizeX和SizeY需要不小于0");
|
|
return;
|
|
}
|
|
|
|
mainImg = GetComponent<Image>();
|
|
|
|
imgEnable = mainImg.enabled;
|
|
mat = mainImg.material;
|
|
|
|
//Create material instance
|
|
matInstance = new Material(mat);
|
|
//Init
|
|
mainImg.material = matInstance;
|
|
|
|
UV_ID = Shader.PropertyToID(UV_PROPERTY);
|
|
|
|
//add offset
|
|
if (startFrameMode == StartFrameType.Constant)
|
|
totalDis += startFrame;
|
|
else
|
|
totalDis += Random.Range(startFrameMin, startFrame);
|
|
}
|
|
|
|
// Update is called once per frame
|
|
void Update()
|
|
{
|
|
if (sizeX > 0 && sizeY > 0)
|
|
{
|
|
bool updateUV = true;
|
|
|
|
//全序列 or 特定row
|
|
bool wholeSheet = animationMode == AnimationType.WholeSheet;
|
|
if (wholeSheet)
|
|
{
|
|
//无需修改
|
|
}
|
|
else
|
|
{
|
|
if (randomRow)
|
|
{
|
|
//初始一个随机row
|
|
if (!initRandomRow)
|
|
{
|
|
row = Random.Range(0, sizeY);
|
|
initRandomRow = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//无需修改
|
|
}
|
|
|
|
//对row做范围修订
|
|
if (row < 0) row = 0;
|
|
if (row >= sizeY) row = (sizeY - 1);
|
|
}
|
|
|
|
//根据loop和lifeTime控制Image的Enable属性
|
|
if (!loop && totalTime >= lifeTime && imgEnable)
|
|
{
|
|
mainImg.enabled = false;
|
|
imgEnable = false;
|
|
|
|
//重置
|
|
totalTime = 0;
|
|
totalDis = 0;
|
|
|
|
updateUV = false;
|
|
}
|
|
if (loop && !imgEnable)
|
|
{
|
|
mainImg.enabled = true;
|
|
imgEnable = true;
|
|
|
|
updateUV = true;
|
|
}
|
|
|
|
if (updateUV)
|
|
{
|
|
if (loop && totalTime >= lifeTime)
|
|
{
|
|
totalTime %= lifeTime;
|
|
}
|
|
|
|
//TimeLife Mode
|
|
if (timeMode == TimeType.LifeTime)
|
|
{
|
|
if (frameOverTime.mode == ParticleSystemCurveMode.Constant)
|
|
{
|
|
totalDis = frameOverTime.constantMax % (sizeX * sizeY);
|
|
}
|
|
else if (frameOverTime.mode == ParticleSystemCurveMode.Curve)
|
|
{
|
|
var curve = frameOverTime.curveMax;
|
|
|
|
totalDis = (sizeX * sizeY) * curve.Evaluate((totalTime / lifeTime * cycles) % 1);
|
|
}
|
|
else if (frameOverTime.mode == ParticleSystemCurveMode.TwoConstants)
|
|
{
|
|
totalDis = Random.Range(frameOverTime.constantMin, frameOverTime.constantMax) % (sizeX * sizeY);
|
|
}
|
|
else if (frameOverTime.mode == ParticleSystemCurveMode.TwoCurves)
|
|
{
|
|
var curve = frameOverTime.curveMin;
|
|
var curveMax = frameOverTime.curveMax;
|
|
|
|
float cTime = (totalTime / lifeTime * cycles) % 1;
|
|
|
|
totalDis = (sizeX * sizeY) * Random.Range(curve.Evaluate(cTime), curveMax.Evaluate(cTime));
|
|
}
|
|
}
|
|
//FPS Mode
|
|
if (timeMode == TimeType.FPS)
|
|
{
|
|
totalDis = (FPS * totalTime) % (sizeX * sizeY);
|
|
}
|
|
|
|
//random row update
|
|
if (animationMode == AnimationType.SingleRow && randomRow)
|
|
{
|
|
if (sizeY - Mathf.FloorToInt(totalDis) / sizeX - 1 != cacheRow)
|
|
{
|
|
row = Random.Range(0, sizeY);
|
|
}
|
|
}
|
|
|
|
float dTime = Time.deltaTime;
|
|
totalTime += dTime;
|
|
|
|
int index = Mathf.FloorToInt(totalDis);
|
|
if (loop)
|
|
index %= (sizeX * sizeY);
|
|
else
|
|
index = Mathf.Min(sizeX * sizeY - 1, index);
|
|
|
|
float uv_x = index % sizeX;
|
|
float uv_y = wholeSheet ? (sizeY - index / sizeX - 1) : sizeY - row - 1;
|
|
|
|
cacheRow = sizeY - index / sizeX - 1;//走whole sheet模式下本次的row值
|
|
|
|
uv_x /= sizeX;
|
|
uv_y /= sizeY;
|
|
|
|
//优化每帧调用
|
|
if (cacheUV_X != uv_x || cacheUV_Y != uv_y)
|
|
{
|
|
cacheUV_X = uv_x;
|
|
cacheUV_Y = uv_y;
|
|
|
|
matInstance.SetVector(UV_ID, new Vector4(1f / sizeX, 1f / sizeY, uv_x, uv_y));
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
//用于首次添加脚本和调用Reset时重置数据
|
|
frameOverTime.mode = ParticleSystemCurveMode.Curve;
|
|
|
|
frameOverTime.constantMin = 0;
|
|
frameOverTime.constantMax = 0;
|
|
|
|
frameOverTime.curveMin = AnimationCurve.EaseInOut(0, 0, 1, 1);
|
|
frameOverTime.curveMax = AnimationCurve.EaseInOut(0, 0, 1, 1);
|
|
|
|
frameOverTime.curveMultiplier = sizeX * sizeY;//Force Update
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
if (matInstance)
|
|
DestroyImmediate(matInstance);
|
|
}
|
|
}
|