Unity之引导功能遮罩事件穿透

Unity之新手引导shader遮罩事件穿透

效果

新手指引演示

设计思路

1.新手引导我们期待开发内容不影响正常的功能模块,意思就是分层,新手引导在正常功能之上
2.新手引导层级用一层深色bg显示遮住正常功能层级,在需要引导的位置留出高亮区域
3.在这个新手引导层做事件渗透,给指定的对象或UI做事件渗透,如果点击交互位置处于指定UI或对象范围内,让事件渗透新手引导层,到正常功能层。

场景搭建

搭建两个层级

新手引导Hierarchy面板

新手引导Hierarchy面板

一个正常功能层级为Canvas下,一个新手引导层级在GuideHolder下。

制作新手引导的预制体

在这里插入图片描述

材质使用我们特制的带镂空效果的材质shader,并挂载一个事件渗透作用的脚本

代码

这里有两个比较重要的内容一个是遮罩层是深色的,并要镂空指定区域做高亮,这里使用shader去制作效果图。二是在合适时机做指定区域的事件渗透。

GuideMask.cs
    /// <summary>
    /// 创建圆形点击区域
    /// </summary>
    /// <param name="pos">圆心的屏幕位置</param>
    /// <param name="rad">圆的半径</param>
    /// <param name="CallBack">点击的回调</param>
    public void CreateCircleMask(Vector3 pos, float rad, GameObject target)
    {
        ShowGuideMask(()=> {
            ShowTween = true;
            ev.SetTargetimage(target);
            _rectTrans.sizeDelta = Vector2.zero;
            _materia.SetFloat("_MaskType", 0f);
            CurRadNum = rad;
            _materia.SetVector("_Origin", new Vector4(pos.x, pos.y, rad + 1000, 20));
        });

    }
        public  void ShowGuideMask(Action callback)
    {
        ShowTween = false;
        if (_rectTrans == null)
        {
            ResMgr.Instance.Load("GuideSystem", (obj) => {

                guide = Instantiate((GameObject)obj, ISceneManager.Instance.GuideHolder);
                _rectTrans = guide.GetComponent<RectTransform>();
                _rawImage = guide.GetComponent<RawImage>();
                _rawImage.color = new Color(1, 1, 1, 1);
                _materia = _rawImage.material;

                ev = guide.GetComponent<EventPenetrate>();
                callback();
            });
        }
        else
        {
            callback();
        }
    }
GuideMask.shader
Shader "UI/GuideMask"
{
	Properties
	{
		[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
		_Color("Tint", Color) = (1,1,1,1)
		_Blur("边缘虚化的范围", Range(1,1000)) = 100
		_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
		//中心
		_Origin("Circle",Vector) = (0,0,0,0)
		//裁剪方式 0圆形 1圆形
		_MaskType("Type",Float) = 0	
	}

		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 vertex : SV_POSITION;
		fixed4 color : COLOR;
		float2 texcoord : TEXCOORD0;
		float4 worldPosition : TEXCOORD1;
		UNITY_VERTEX_OUTPUT_STEREO
	};

	fixed4 _Color;
	fixed4 _TextureSampleAdd;
	float4 _ClipRect;
	float4 _Origin;
	float _MaskType;	
	float _Blur;
	v2f vert(appdata_t IN)
	{
		v2f OUT;
		UNITY_SETUP_INSTANCE_ID(IN);
		UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
		OUT.worldPosition = IN.vertex;
		OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
		OUT.texcoord = IN.texcoord;
		OUT.color = IN.color * _Color;
		return OUT;
	}

	sampler2D _MainTex;

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

		if (_MaskType == 0) {
			//if (distance(IN.worldPosition.xy, _Origin.xy) <= _Origin.z)
			//{
			//	color.a = 0;
			//}			
			  float dis = distance(IN.worldPosition.xy, _Origin.xy);
			  //过滤掉距离小于(半径-过渡范围)的片元
			  clip(dis - (_Origin.z - _Blur));
			  //优化if条件判断,如果距离小于半径则执行下一步,等于if(dis < _Radius)
			  fixed tmp = step(dis, _Origin.z);
			  //计算过渡范围内的alpha值
			  color.a *= (1 - tmp) + tmp * (dis - (_Origin.z - _Blur)) / _Blur;
		}
		else if (_MaskType == 1) {
			//UnityGet2DClipping这个函数实现了判断2D空间中的一点是否在一个矩形区域中
			if (UnityGet2DClipping(IN.worldPosition.xy, _Origin))
			{
				color.a = 0;

			}

		}
		else if (_MaskType == 2)
		{
			if (UnityGet2DClipping(IN.worldPosition.xy, _Origin))
			{
				color.a = 0;
				#ifdef UNITY_UI_CLIP_RECT
               color.a *= UnityGet2DClipping(IN.worldPosition.xy, _Origin);
                #endif
			}               
		}

		return color;
	}
		ENDCG
	}
	}
}
调用
 GuideMask.Instance.CreateCircleMaskoffset(button2.gameObject, 0, null);
  GuideMask.Instance.CloseGuideMask();

工程项目

链接:https://pan.baidu.com/s/1v4laE9QdqRGWKqfKJpnkxQ
提取码:s8qc

相关文章

实现Unity AssetBundle资源加载管理器 AssetBundle是实现资源...
Unity3D 使用LineRenderer绘制尾迹与虚线 1.添加LineRendere...
Unity 添加新建Lua脚本选项 最近学习Unity的XLua热更新框架的...
挂载脚本时文件名和类名的关联方式 写过Unity脚本的人应该都...
Unity单例基类的实现方式 游戏开发的过程中我们经常会将各种...
这篇文章主要介绍了Unity游戏开发中外观模式是什么意思,具有...