using System.Collections;
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;
namespace AibisDream.Framework
{
///
/// UI Image窗帘展开效果工具类(使用Shader实现)
/// 实现从左到右的展开动画,保持图片原始宽高比不被压扁
///
public static class CurtainRevealKit
{
private static readonly int RevealProgressPropertyID = Shader.PropertyToID("_RevealProgress");
private static readonly int EdgeSoftnessPropertyID = Shader.PropertyToID("_EdgeSoftness");
///
/// 从左到右显示图片(窗帘拉开效果),使用Shader实现,保持图片原始宽高比
///
/// 目标Image组件
/// 动画时长
/// 缓动类型
/// 边缘柔化程度(0-0.1)
/// 协程
public static IEnumerator RevealFromLeftAsync(this Image image, float duration = 1f,
Ease easeType = Ease.OutQuad, float edgeSoftness = 0.02f)
{
image.gameObject.SetActive(true);
// 确保Image有Material实例(避免影响其他使用相同Material的对象)
Material material = EnsureMaterialInstance(image);
// 设置边缘柔化
material.SetFloat(EdgeSoftnessPropertyID, edgeSoftness);
// 初始状态:进度为0(完全隐藏)
material.SetFloat(RevealProgressPropertyID, 0f);
// 动画:进度从0到1
float currentProgress = 0f;
Tweener tween = DOTween.To(
() => currentProgress,
value =>
{
currentProgress = value;
material.SetFloat(RevealProgressPropertyID, value);
},
1f,
duration
).SetEase(easeType);
yield return tween.WaitForCompletion();
}
///
/// 同步版本:从左到右显示图片
///
/// 目标Image组件
/// 动画时长
/// 缓动类型
/// 边缘柔化程度(0-0.1)
public static void RevealFromLeft(this Image image, float duration = 1f,
Ease easeType = Ease.OutQuad, float edgeSoftness = 0.02f)
{
image.gameObject.SetActive(true);
Material material = EnsureMaterialInstance(image);
material.SetFloat(EdgeSoftnessPropertyID, edgeSoftness);
material.SetFloat(RevealProgressPropertyID, 0f);
float currentProgress = 0f;
DOTween.To(
() => currentProgress,
value =>
{
currentProgress = value;
material.SetFloat(RevealProgressPropertyID, value);
},
1f,
duration
).SetEase(easeType);
}
///
/// 设置窗帘展开进度(手动控制)
///
/// 目标Image组件
/// 进度值(0-1)
/// 边缘柔化程度(0-0.1)
public static void SetRevealProgress(this Image image, float progress, float edgeSoftness = 0.02f)
{
if (image == null || image.material == null) return;
Material material = EnsureMaterialInstance(image);
material.SetFloat(EdgeSoftnessPropertyID, edgeSoftness);
material.SetFloat(RevealProgressPropertyID, Mathf.Clamp01(progress));
}
///
/// 重置窗帘展开效果(恢复原始状态)
///
/// 目标Image组件
public static void ResetReveal(this Image image)
{
if (image == null || image.material == null) return;
Material material = EnsureMaterialInstance(image);
material.SetFloat(RevealProgressPropertyID, 1f);
}
///
/// 确保Material有独立实例(避免影响其他对象)
///
private static Material EnsureMaterialInstance(Image image)
{
if (image.material == null)
{
// 如果没有Material,尝试加载Shader
Shader shader = Shader.Find("UI/CurtainReveal");
if (shader == null)
{
Debug.LogError("找不到Shader: UI/CurtainReveal,请确保Shader已正确导入");
return null;
}
image.material = new Material(shader);
}
else if (image.material.shader.name != "UI/CurtainReveal")
{
// 如果Material的Shader不对,创建新的Material
Shader shader = Shader.Find("UI/CurtainReveal");
if (shader == null)
{
Debug.LogError("找不到Shader: UI/CurtainReveal,请确保Shader已正确导入");
return image.material;
}
image.material = new Material(shader);
// 复制原始纹理和颜色
if (image.sprite != null)
{
image.material.SetTexture("_MainTex", image.sprite.texture);
}
image.material.SetColor("_Color", image.color);
}
else if (image.material.name.Contains("(Instance)") == false)
{
// 如果Material不是实例,创建实例以避免影响其他对象
image.material = new Material(image.material);
}
return image.material;
}
}
}