0
点赞
收藏
分享

微信扫一扫

Unity最简单引导实现方式

sin信仰 2022-04-04 阅读 39
unity

Unity最简单引导实现方式

转载自 Unity最简单引导实现方式
并去掉了一些无用的,混淆的shader代码,调整了代码结构。

效果

镂空shader代码

Shader "UI/Guide/Rect"
{
	Properties
	{
		[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
		_Color("Tint", Color) = (1,1,1,1)

		_StencilComp("Stencil Comparison", Float) = 8
		_Stencil("Stencil ID", Float) = 0
		_StencilOp("Stencil Operation", Float) = 0
		_StencilWriteMask("Stencil Write Mask", Float) = 255
		_StencilReadMask("Stencil Read Mask", Float) = 255
		
		_ColorMask("Color Mask", Float) = 15
		
		_Center("Center",vector) = (0,0,0,0)
		_SliderX("SliderX",Range(0,1500)) = 1500
		_SliderY("SliderY",Range(0,1500)) = 1500
	}

		SubShader
		{
			Tags
			{
				"Queue" = "Transparent"
				"IgnoreProjector" = "True"
				"RenderType" = "Transparent"
				"PreviewType" = "Plane"
				"CanUseSpriteAtlas" = "True"
			}

			Stencil
			{
				Ref[_Stencil]
				Comp[_StencilComp]
				Pass[_StencilOp]
				ReadMask[_StencilReadMask]
				WriteMask[_StencilWriteMask]
			}

			Cull Off
			Lighting Off
			ZWrite Off
			ZTest[unity_GUIZTestMode]
			Blend SrcAlpha OneMinusSrcAlpha
			ColorMask[_ColorMask]

			Pass
			{
				Name "Default"
			CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				#pragma target 2.0

				#include "UnityCG.cginc"
				#include "UnityUI.cginc"

	
				struct appdata_t
				{
					float4 vertex   : POSITION;
					float4 color    : COLOR;
					float2 texcoord : TEXCOORD0;
					UNITY_VERTEX_INPUT_INSTANCE_ID
				};

				struct v2f
				{
					float4 positionCS   : SV_POSITION;
					fixed4 color : COLOR;
					float2 texcoord  : TEXCOORD0;
					float4 positionOS : TEXCOORD1;
					UNITY_VERTEX_OUTPUT_STEREO
				};

				fixed4 _Color;
				float4 _ClipRect;

				float2 _Center;
				float _SliderX;
				float _SliderY;

				v2f vert(appdata_t v)
				{
					v2f output;
					output.positionOS = v.vertex;
					output.positionCS = UnityObjectToClipPos(output.positionOS);

					output.texcoord = v.texcoord;

					output.color = v.color * _Color;
					return output;
				}

				sampler2D _MainTex;

				fixed4 frag(v2f input) : SV_Target
				{
					half4 color = tex2D(_MainTex, input.texcoord)  * input.color;

					float2 dis = input.positionOS.xy - _Center.xy;

					
					color.a *= (abs(dis.x) > _SliderX) || (abs(dis.y) > _SliderY);
					
					color.rgb *= color.a;

					return color;
				}
			ENDCG
			}
		}
}

控制C#代码

using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Image))]
public class GuideController : MonoBehaviour, ICanvasRaycastFilter
{
    private Material m_Material;
    private Vector3 m_Center;
    private RectTransform m_Target;
    private Vector3[] m_TargetCorners = new Vector3[4];
    private Camera UICamera;

    private float m_Timer;
    private float m_Time;
    private bool m_IsScaling;
    private float m_Width;
    private float m_Height;
    private float m_ScaleWidth;
    private float m_ScaleHeight;
    private RectTransform m_RectTransform;
    // 弱引导整个传递下去 强引导传递Target范围内的事件
    private bool m_IsSoftGuide;
    
    
    
    
    
    private void Awake()
    {
        UICamera = GameObject.Find("Main Camera").GetComponent<Camera>();
        m_Material = GetComponent<Image>().material;
        m_RectTransform = GetComponent<RectTransform>();
    }
    
    protected virtual void Update()
    {
        if (m_IsScaling)
        {
            m_Timer += Time.deltaTime / m_Time;
            m_Timer = Mathf.Clamp(m_Timer, 0, 1);
            m_Material.SetFloat("_SliderX", Mathf.Lerp(m_ScaleWidth, m_Width, m_Timer));
            m_Material.SetFloat("_SliderY", Mathf.Lerp(m_ScaleHeight, m_Height, m_Timer));
            if (m_Timer >= 1)
            {
                m_Timer = 0;
                m_IsScaling = false;
            }
        }
    }
    
    // 这里是来获取目标物体的四个点来计算中心点,因为对于矩形或者圆形效果,他们面对的中心点是确定的
    public virtual void Guide(RectTransform target, bool isSoftGuide, float scale = 1, float time = 0)
    {
        if (target == null)
            return;
        
        
        m_Target = target;
        m_IsSoftGuide = isSoftGuide;
        
        target.GetWorldCorners(m_TargetCorners);
        
        for (int i = 0; i < m_TargetCorners.Length; i++)
        {
            m_TargetCorners[i] = WorldToScreenPoints(m_TargetCorners[i]);
        }
        
        // 中心点
        m_Center.x = m_TargetCorners[0].x + (m_TargetCorners[3].x - m_TargetCorners[0].x) / 2;
        m_Center.y = m_TargetCorners[0].y + (m_TargetCorners[1].y - m_TargetCorners[0].y) / 2;
        
        m_Material.SetVector("_Center", m_Center);

        m_Width = (m_TargetCorners[3].x - m_TargetCorners[0].x) / 2;
        m_Height = (m_TargetCorners[1].y - m_TargetCorners[0].y) / 2;
        
        if (scale <= 1)
            scale = 1;
        
        
        m_ScaleWidth = m_Width * scale;
        m_ScaleHeight = m_Height * scale;
        
        m_Material.SetFloat("_SliderX", m_ScaleWidth);
        m_Material.SetFloat("_SliderY", m_ScaleHeight);

        
        m_Time = time;
        m_Timer = 0;
        
        if (m_Time > 0)
            m_IsScaling = true;
    }

    public Vector2 WorldToScreenPoints(Vector3 world)
    {
        Vector2 screenPoint = RectTransformUtility.WorldToScreenPoint(UICamera, world);
        Vector2 localPoint;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(m_RectTransform, screenPoint, UICamera, out localPoint);
        return localPoint;
    }
    
    
    // RectangleContainsScreenPoint判断一个屏幕点是否在目标Rect范围内,如果在,则返回真
	// IsRaycastLocationValid为true时,事件向下传递是无效的,
	// 被拦截在当前UI界面,为false,则在当前界面是无效的
    public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
    {
        if (m_IsScaling) return true;
        if (m_IsSoftGuide) return false;
        
        return !RectTransformUtility.RectangleContainsScreenPoint(m_Target, sp, eventCamera);
    }
}

using UnityEngine;
using UnityEngine.UI;

public class Main : MonoBehaviour
{
    public Button StartBtn;
    public Button BtnA;
    public Button BtnB;
    public GuideController GuideController;
    public RectTransform Target;
    public bool IsSoft;
    public float Scale;
    public float Time;
    private void Awake()
    {
        StartBtn.onClick.AddListener(() => { GuideController.Guide(Target, IsSoft, Scale, Time); });
        BtnA.onClick.AddListener(() => { Debug.Log("点击事件A"); });
        BtnB.onClick.AddListener(() => { Debug.Log("点击事件B"); });
    }
}

示例工程

举报

相关推荐

0 条评论