Files
aibis-dream/Assets/Scripts/Framework/OtherKit/CurtainRevealKit.cs
T
2025-11-19 15:08:08 +08:00

155 lines
6.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}
}