batteryDiagnosis/Assets/3rdParty/Sci-Fi VFX/Scripts/Utils/ProjectorTextureAnimation.cs

119 lines
3.5 KiB
C#

using System;
using System.Collections;
using UnityEngine;
namespace Assets.Scripts.Utils
{
[RequireComponent(typeof(Projector))]
internal sealed class ProjectorTextureAnimation : MonoBehaviour
{
public int TilesX = 4;
public int TilesY = 4;
public float Fps = 30;
public AnimationCurve FrameOverTime = AnimationCurve.Linear(0, 1, 1, 1);
private Projector _projector;
private Material _projectorMaterial;
private Material _originalMaterial;
private float _animationLifeTime;
private int _index;
private int _countOfTextures, _currentNumOfTexture;
private bool _isStarted;
private bool _isCanceled;
private float _animationStartTime;
private void Start()
{
_projector = GetComponent<Projector>();
if (_projector == null)
throw new InvalidOperationException("Could not get projector");
_animationLifeTime = TilesX * TilesY / Fps;
_index = TilesX - 1;
_countOfTextures = TilesY * TilesX;
Play();
}
private void Play()
{
if (_isStarted)
return;
if (_projector == null || _projector.material == null)
return;
_originalMaterial = _projector.material;
_projectorMaterial = Instantiate(_projector.material);
_projector.material = _projectorMaterial;
if (_originalMaterial == null)
return;
var offset = Vector3.zero;
var size = new Vector2(1f / TilesX, 1f / TilesY);
_projectorMaterial.SetTextureScale("_MainTex", size);
_projectorMaterial.SetTextureOffset("_MainTex", offset);
_isStarted = true;
StartCoroutine(UpdateCorutine());
}
private IEnumerator UpdateCorutine()
{
_animationStartTime = Time.time;
while (!_isCanceled)
{
UpdateFrame();
var frameTime = (Time.time - _animationStartTime) / _animationLifeTime;
var currentSpeedFps = FrameOverTime.Evaluate(Mathf.Clamp01(frameTime));
yield return new WaitForSeconds(1f / (Fps * currentSpeedFps));
}
}
private void UpdateFrame()
{
++_currentNumOfTexture;
++_index;
if (_index >= _countOfTextures)
_index = 0;
if (_currentNumOfTexture == _countOfTextures)
{
_animationStartTime = Time.time;
_currentNumOfTexture = 0;
}
var offset = new Vector2((float)_index / TilesX - (int)(_index / TilesX), 1 - (int)(_index / TilesX) / (float)TilesY);
if (_projector != null)
_projectorMaterial.SetTextureOffset("_MainTex", offset);
}
private void Stop()
{
_isStarted = false;
_isCanceled = true;
StopAllCoroutines();
_projector.material = _originalMaterial;
//_projectorMaterial.SetTextureScale("_MainTex", new Vector2(1, 1));
//_projectorMaterial.SetTextureOffset("_MainTex", new Vector2(0, 0));
}
private void OnEnable()
{
Play();
}
private void OnDisable()
{
Stop();
}
private void OnDestroy()
{
Stop();
}
}
}