251 lines
6.6 KiB
C#
251 lines
6.6 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
[RequireComponent(typeof(Image))]
|
|
public class idolMaterialController : MonoBehaviour
|
|
{
|
|
public enum SweepSide
|
|
{
|
|
FromLeft = 0,
|
|
FromRight = 1,
|
|
}
|
|
|
|
[Header("Material")]
|
|
public Material materialTemplate;
|
|
|
|
[Header("Animation")]
|
|
public SweepSide enterDirection = SweepSide.FromLeft;
|
|
public SweepSide exitDirection = SweepSide.FromRight;
|
|
public float enterDuration = 0.35f;
|
|
public float exitDuration = 0.25f;
|
|
[Range(0f, 1f)]
|
|
public float hiddenAmount = 0f;
|
|
[Range(0f, 1f)]
|
|
public float shownAmount = 1f;
|
|
public bool playEnterOnEnable = false;
|
|
|
|
private Image image;
|
|
private Material runtimeMaterial;
|
|
private Coroutine transitionCoroutine;
|
|
private Sprite pendingSprite;
|
|
|
|
private static readonly int DissolveAmountId = Shader.PropertyToID("_DissolveAmount");
|
|
private static readonly int DirectionId = Shader.PropertyToID("_Direction");
|
|
|
|
private void Awake()
|
|
{
|
|
image = GetComponent<Image>();
|
|
EnsureRuntimeMaterial();
|
|
ApplyInstantState(shownAmount, GetShaderDirectionForEnter(enterDirection));
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
EnsureRuntimeMaterial();
|
|
if (playEnterOnEnable && image != null && image.sprite != null)
|
|
{
|
|
PlayEnter();
|
|
}
|
|
else
|
|
{
|
|
ApplyInstantState(shownAmount, GetShaderDirectionForEnter(enterDirection));
|
|
}
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
if (transitionCoroutine != null)
|
|
{
|
|
StopCoroutine(transitionCoroutine);
|
|
transitionCoroutine = null;
|
|
}
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (runtimeMaterial != null)
|
|
{
|
|
if (image != null && image.material == runtimeMaterial)
|
|
{
|
|
image.material = null;
|
|
}
|
|
|
|
Destroy(runtimeMaterial);
|
|
}
|
|
}
|
|
|
|
public void SetSpriteImmediate(Sprite sprite)
|
|
{
|
|
EnsureRuntimeMaterial();
|
|
if (image == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
image.sprite = sprite;
|
|
ApplyInstantState(shownAmount, GetShaderDirectionForEnter(enterDirection));
|
|
}
|
|
|
|
public void PlayEnter()
|
|
{
|
|
EnsureRuntimeMaterial();
|
|
if (image == null || runtimeMaterial == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (transitionCoroutine != null)
|
|
{
|
|
StopCoroutine(transitionCoroutine);
|
|
}
|
|
|
|
transitionCoroutine = StartCoroutine(AnimateAmount(hiddenAmount, shownAmount, Mathf.Max(0.01f, enterDuration), GetShaderDirectionForEnter(enterDirection), null));
|
|
}
|
|
|
|
public void PlayExit()
|
|
{
|
|
EnsureRuntimeMaterial();
|
|
if (image == null || runtimeMaterial == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (transitionCoroutine != null)
|
|
{
|
|
StopCoroutine(transitionCoroutine);
|
|
}
|
|
|
|
transitionCoroutine = StartCoroutine(AnimateAmount(shownAmount, hiddenAmount, Mathf.Max(0.01f, exitDuration), GetShaderDirectionForExit(exitDirection), null));
|
|
}
|
|
|
|
public void TransitionToSprite(Sprite sprite)
|
|
{
|
|
EnsureRuntimeMaterial();
|
|
if (image == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pendingSprite = sprite;
|
|
|
|
if (transitionCoroutine != null)
|
|
{
|
|
StopCoroutine(transitionCoroutine);
|
|
}
|
|
|
|
bool hasCurrentSprite = image.sprite != null;
|
|
bool spriteChanged = image.sprite != sprite;
|
|
transitionCoroutine = StartCoroutine(TransitionRoutine(hasCurrentSprite, spriteChanged));
|
|
}
|
|
|
|
private IEnumerator TransitionRoutine(bool hasCurrentSprite, bool spriteChanged)
|
|
{
|
|
if (runtimeMaterial == null || image == null)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
if (hasCurrentSprite && spriteChanged)
|
|
{
|
|
yield return AnimateAmount(shownAmount, hiddenAmount, Mathf.Max(0.01f, exitDuration), GetShaderDirectionForExit(exitDirection), null);
|
|
}
|
|
|
|
image.sprite = pendingSprite;
|
|
if (pendingSprite == null)
|
|
{
|
|
ApplyInstantState(hiddenAmount, GetShaderDirectionForEnter(enterDirection));
|
|
transitionCoroutine = null;
|
|
yield break;
|
|
}
|
|
|
|
yield return AnimateAmount(hiddenAmount, shownAmount, Mathf.Max(0.01f, enterDuration), GetShaderDirectionForEnter(enterDirection), null);
|
|
transitionCoroutine = null;
|
|
}
|
|
|
|
private IEnumerator AnimateAmount(float from, float to, float duration, float directionValue, System.Action onComplete)
|
|
{
|
|
if (runtimeMaterial == null)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
runtimeMaterial.SetFloat(DirectionId, directionValue);
|
|
runtimeMaterial.SetFloat(DissolveAmountId, from);
|
|
|
|
float elapsed = 0f;
|
|
while (elapsed < duration)
|
|
{
|
|
elapsed += Time.unscaledDeltaTime;
|
|
float t = Mathf.Clamp01(elapsed / duration);
|
|
runtimeMaterial.SetFloat(DissolveAmountId, Mathf.Lerp(from, to, t));
|
|
yield return null;
|
|
}
|
|
|
|
runtimeMaterial.SetFloat(DissolveAmountId, to);
|
|
onComplete?.Invoke();
|
|
}
|
|
|
|
private void ApplyInstantState(float amount, float directionValue)
|
|
{
|
|
EnsureRuntimeMaterial();
|
|
if (runtimeMaterial == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
runtimeMaterial.SetFloat(DirectionId, directionValue);
|
|
runtimeMaterial.SetFloat(DissolveAmountId, Mathf.Clamp01(amount));
|
|
}
|
|
|
|
private void EnsureRuntimeMaterial()
|
|
{
|
|
if (image == null)
|
|
{
|
|
image = GetComponent<Image>();
|
|
}
|
|
|
|
if (image == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Material source = materialTemplate != null
|
|
? materialTemplate
|
|
: image.material;
|
|
|
|
if (source == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (runtimeMaterial != null && runtimeMaterial.shader == source.shader)
|
|
{
|
|
if (image.material != runtimeMaterial)
|
|
{
|
|
image.material = runtimeMaterial;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (runtimeMaterial != null)
|
|
{
|
|
Destroy(runtimeMaterial);
|
|
}
|
|
|
|
runtimeMaterial = new Material(source);
|
|
runtimeMaterial.name = source.name + " (idol runtime)";
|
|
image.material = runtimeMaterial;
|
|
}
|
|
|
|
private static float GetShaderDirectionForEnter(SweepSide side)
|
|
{
|
|
return side == SweepSide.FromLeft ? 0f : 1f;
|
|
}
|
|
|
|
private static float GetShaderDirectionForExit(SweepSide side)
|
|
{
|
|
return side == SweepSide.FromLeft ? 1f : 0f;
|
|
}
|
|
}
|