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; } } }