c1_unity/Assets/Scripts/Component/Effects/UIImageSheetAnimation.cs
2023-04-03 11:04:31 +08:00

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);
}
}