155 lines
6.1 KiB
C#
155 lines
6.1 KiB
C#
using System.Collections;
|
||
using DG.Tweening;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
namespace AibisDream.Framework
|
||
{
|
||
/// <summary>
|
||
/// UI Image窗帘展开效果工具类(使用Shader实现)
|
||
/// 实现从左到右的展开动画,保持图片原始宽高比不被压扁
|
||
/// </summary>
|
||
public static class CurtainRevealKit
|
||
{
|
||
private static readonly int RevealProgressPropertyID = Shader.PropertyToID("_RevealProgress");
|
||
private static readonly int EdgeSoftnessPropertyID = Shader.PropertyToID("_EdgeSoftness");
|
||
|
||
/// <summary>
|
||
/// 从左到右显示图片(窗帘拉开效果),使用Shader实现,保持图片原始宽高比
|
||
/// </summary>
|
||
/// <param name="image">目标Image组件</param>
|
||
/// <param name="duration">动画时长</param>
|
||
/// <param name="easeType">缓动类型</param>
|
||
/// <param name="edgeSoftness">边缘柔化程度(0-0.1)</param>
|
||
/// <returns>协程</returns>
|
||
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();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 同步版本:从左到右显示图片
|
||
/// </summary>
|
||
/// <param name="image">目标Image组件</param>
|
||
/// <param name="duration">动画时长</param>
|
||
/// <param name="easeType">缓动类型</param>
|
||
/// <param name="edgeSoftness">边缘柔化程度(0-0.1)</param>
|
||
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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置窗帘展开进度(手动控制)
|
||
/// </summary>
|
||
/// <param name="image">目标Image组件</param>
|
||
/// <param name="progress">进度值(0-1)</param>
|
||
/// <param name="edgeSoftness">边缘柔化程度(0-0.1)</param>
|
||
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));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重置窗帘展开效果(恢复原始状态)
|
||
/// </summary>
|
||
/// <param name="image">目标Image组件</param>
|
||
public static void ResetReveal(this Image image)
|
||
{
|
||
if (image == null || image.material == null) return;
|
||
|
||
Material material = EnsureMaterialInstance(image);
|
||
material.SetFloat(RevealProgressPropertyID, 1f);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 确保Material有独立实例(避免影响其他对象)
|
||
/// </summary>
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
|