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