Unity3D UI遮罩和彈窗

詳細講解篇幅可能有點長,直接上圖和資源(實現的具體步驟往下看)

GIF圖看起來有點卡頓, 實際上運行是流暢的。

碼雲:https://gitee.com/NCAA_admin/Alert.git

具體實現步驟

1.創建一個背景圖片Background並設置相應屬性值

2.設置Canvas的屬性和Game窗口的比例

3.創建一個彈窗的遮罩蒙版 名爲Alert的Image,參數設置如下

4.在Alert下創建一個彈出的信息框 名爲Message的Image,各參數設置如下

5.在Message下創建一個文本對象 Text,參數設置如下

6.接在也在Alert下創建兩個按鈕 Confirm和Cancel

7.其中兩個按鈕的Text參數分別如下

8.創建一個Shader的蒙版,在Assets下創建Shaders文件夾,在Shaders文件夾下創建名爲Blur的Shader腳本

10.Shader腳本,內容如下(關於Shader的實現原理和步驟,有時間再做一個專題的解析)

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/Blur"
{
	// 屬性
	Properties
	{
		// 定義 1-255 範圍的半徑 默認 1
		_Radius("Radius", Range(1, 255)) = 1
	}

	Category
	{
		Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Opaque" }

		SubShader
	{

	GrabPass
	{
		Tags{ "LightMode" = "Always" }
	}

	Pass
	{
		Tags{ "LightMode" = "Always" }
		
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#pragma fragmentoption ARB_precision_hint_fastest
		#include "UnityCG.cginc"

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

	struct v2f
	{
		float4 vertex : POSITION;
		float4 uvgrab : TEXCOORD0;
	};

	v2f vert(appdata_t v)
	{
		v2f o;
		o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
		float scale = -1.0;
#else
		float scale = 1.0;
#endif
		o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
		o.uvgrab.zw = o.vertex.zw;
		return o;
	}

	sampler2D _GrabTexture;
	float4 _GrabTexture_TexelSize;
	float _Radius;

	half4 frag(v2f i) : COLOR
	{
		half4 sum = half4(0,0,0,0);

#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))

		sum += GRABXYPIXEL(0.0, 0.0);
		int measurments = 1;

		for (float range = 0.1f; range <= _Radius; range += 0.1f)
		{
			sum += GRABXYPIXEL(range, range);
			sum += GRABXYPIXEL(range, -range);
			sum += GRABXYPIXEL(-range, range);
			sum += GRABXYPIXEL(-range, -range);
			measurments += 4;
		}

		return sum / measurments;
	}
		ENDCG
	}
		GrabPass
	{
		Tags{ "LightMode" = "Always" }
	}

		Pass
	{
		Tags{ "LightMode" = "Always" }

		CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"

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

	struct v2f
	{
		float4 vertex : POSITION;
		float4 uvgrab : TEXCOORD0;
	};

	v2f vert(appdata_t v)
	{
		v2f o;
		o.vertex = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
		float scale = -1.0;
#else
		float scale = 1.0;
#endif
		o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
		o.uvgrab.zw = o.vertex.zw;
		return o;
	}

	sampler2D _GrabTexture;
	float4 _GrabTexture_TexelSize;
	float _Radius;

	half4 frag(v2f i) : COLOR
	{

		half4 sum = half4(0,0,0,0);
		float radius = 1.41421356237 * _Radius;

#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))

		sum += GRABXYPIXEL(0.0, 0.0);
		int measurments = 1;

		for (float range = 1.41421356237f; range <= radius * 1.41; range += 1.41421356237f)
		{
			sum += GRABXYPIXEL(range, 0);
			sum += GRABXYPIXEL(-range, 0);
			sum += GRABXYPIXEL(0, range);
			sum += GRABXYPIXEL(0, -range);
			measurments += 4;
		}

		return sum / measurments;
	}
		ENDCG
	}
	}
	}
}

11.在Assets下創建一個名Materials文件夾,在Materials文件夾下創建名爲MaskBlur的Material材質

12.在Alert下指定MaskBlur材質,並設置材質的模糊值爲5

13.爲了使交互效果具有動畫的過度感,在編輯器頂部的菜單欄中 Windows>Asset Store 下打開資源商店

14.搜索DoTween關鍵詞,並進入下載

15.下載完成後點擊導入即可

16.在Assets下創建Scripts文件夾,在Scripts下創建Alert.cs腳本

17.Alert.cs腳本內容

using UnityEngine;
using DG.Tweening;
using UnityEngine.UI;
using UnityEngine.EventSystems;
//顯示Alert會話
public class Alert : MonoBehaviour
{
    public static Alert Instance;
    private void Awake()
    {
        Instance = this;
    }
    [Tooltip("會話對象")] public RectTransform m_alert;
    //獲取ui blur(alert)初始大小
    private Vector2 _uiBlurSize;
    //獲取ui blur(alert)初始scale
    private Vector2 _uiBlurScale;
    //透明遮罩層
    private RectTransform _transparentMask;
    //透明遮罩層的初始顏色值值
    private Color _transparentMaskColor;
    //獲取confirm
    private RectTransform _confirm;
    //獲取confirm初始大小
    private Vector2 _confirmSize;
    //獲取confirm初始scale
    private Vector2 _confirmScale;
    //獲取text對象
    private Text _text;
    //獲取text的大小
    private Vector2 _textSize;
    //獲取text scale
    private Vector2 _textScale;
    void Start()
    {
        //判斷並且賦值
        if (!m_alert)
        {
            m_alert = transform.GetComponent<RectTransform>();
        }
        //獲取uiblur(alert)初始大小
        _uiBlurSize = m_alert.rect.size;
        _uiBlurScale = m_alert.localScale;
        //獲取透明遮罩層
        _transparentMask = m_alert.GetChild(0).GetComponent<RectTransform>();
        //透明遮罩層的顏色
        _transparentMaskColor = _transparentMask.GetComponent<Image>().color;
        //獲取confirm
        _confirm = m_alert.GetChild(1).GetComponent<RectTransform>();
        //獲取confirm初始大小
        _confirmSize = _confirm.rect.size;
        _confirmScale = _confirm.localScale;
        //獲取text對象
        _text = _confirm.GetChild(0).GetComponent<Text>();
        //獲取text的大小
        _textSize = _text.GetComponent<RectTransform>().rect.size;
        _textScale = _text.rectTransform.localScale;
        //確定取消按鈕
        _Confirm();
        _Cancel();
        //初始設置隱藏
        if (m_hideOnStart)
            _SetHideImmediate();
    }

    /// <summary>
    /// 無動畫立即隱藏
    /// </summary>
    public void _SetHideImmediate()
    {
        //設置隱藏
        m_alert.gameObject.SetActive(false);
        _confirm.gameObject.SetActive(false);
        _text.gameObject.SetActive(false);
        _transparentMask.gameObject.SetActive(false);
        //寬高設置0
        m_alert.DOScale(Vector3.zero, 0);
        _confirm.DOScale(Vector3.zero, 0);
        //設置遮罩層alpha = 0
        _transparentMask.GetComponent<Image>().DOFade(0, 0);
    }
    /// <summary>
    /// 開始時爲隱藏狀態
    /// </summary>
    [Tooltip("開始時爲隱藏狀態")]
    public bool m_hideOnStart = true;
    /// <summary>
    /// 隱藏
    /// </summary>
    public void _SetHide()
    {
        //設置隱藏
        _text.gameObject.SetActive(false);
        //寬高設置0
        m_alert.DOScale(Vector2.zero, _SetShow_duration)
            .onComplete = () =>
            {
                m_alert.gameObject.SetActive(false);
            };
        _confirm.DOScale(Vector2.zero, _SetShow_duration)
            .onComplete = () =>
            {
                _confirm.gameObject.SetActive(false);
            };
        //隱藏透明遮罩層
        _transparentMask.GetComponent<Image>().DOFade(0, _SetShow_duration)
            .onComplete = () =>
            {
                _transparentMask.gameObject.SetActive(false);
            };
    }
    /// <summary>
    /// 顯示
    /// </summary>
    public void _SetShow()
    {
        //設置顯示
        m_alert.gameObject.SetActive(true);
        _confirm.gameObject.SetActive(true);
        _transparentMask.gameObject.SetActive(true);
        //寬高設置成初始大小+5%再回到原來的大小
        m_alert.DOScale(_uiBlurScale + _uiBlurScale * 0.05f, _SetShow_duration)
            .onComplete = () =>
            {
                //完成後回到初始大小 時間爲原來的1/5
                m_alert.DOScale(_uiBlurScale, _SetShow_duration / 5f);
            };
        _confirm.DOScale(_confirmScale + _confirmScale * 0.05f, _SetShow_duration)
            .onComplete = () =>
            {
                //完成後回到初始大小 時間爲原來的1/5
                _confirm.DOScale(_confirmScale, _SetShow_duration / 5f);
                //並且顯示text
                _text.gameObject.SetActive(true);
            };
        //顯示透明遮罩層
        _transparentMask.GetComponent<Image>().DOFade(_transparentMaskColor.a, _SetShow_duration);
    }
    /// <summary>
    /// 顯示動畫時間
    /// </summary>
    private float _SetShow_duration = 0.3f;

    /// <summary>
    /// 按鈕的hover效果
    /// </summary>
    /// <param name="button">按鈕</param>
    public void _OnHover(Transform button)
    {
        if (!m_inited)
        {
            m_inited = true;
            //獲取初始大小
            m_initialScale = transform.GetComponent<RectTransform>().localScale.x;
        }
        if (!button.GetComponent<EventTrigger>()) button.gameObject.AddComponent<EventTrigger>();
        EventTrigger trigger = button.GetComponent<EventTrigger>();
        EventTrigger.Entry entry = new EventTrigger.Entry();
        entry.eventID = EventTriggerType.PointerEnter;
        entry.callback = new EventTrigger.TriggerEvent();
        entry.callback.AddListener(delegate (BaseEventData baseEvent) {
            button.GetComponent<RectTransform>().DOScale(m_localScale, 0.3f);
        });
        trigger.triggers.Add(entry);

        EventTrigger.Entry entry2 = new EventTrigger.Entry();
        entry2.eventID = EventTriggerType.PointerExit;
        entry2.callback = new EventTrigger.TriggerEvent();
        entry2.callback.AddListener(delegate (BaseEventData baseEvent) {
            button.GetComponent<RectTransform>().DOScale(m_initialScale, 0.3f);
        });
        trigger.triggers.Add(entry2);
    }
    /// <summary>
    /// 變大尺度默認1
    /// </summary>
    [Tooltip("變大尺度默認1.2f")]
    public float m_localScale = 1.2f;
    /// <summary>
    /// 初始的大小
    /// </summary>
    private float m_initialScale;
    /// <summary>
    /// 是否被初始化
    /// </summary>
    private bool m_inited = false;

    /// <summary>
    /// 確定
    /// </summary>
    public void _Confirm()
    {
        _OnHover(m_confirm);
        m_confirm.GetComponent<Button>().onClick.AddListener(delegate {
            _SetHide();
        });
    }
    /// <summary>
    /// 確定按鈕
    /// </summary>
    [Tooltip("確定按鈕")]
    public Transform m_confirm;
    /// <summary>
    /// 取消按鈕
    /// </summary>
    public void _Cancel()
    {
        _OnHover(m_cancel);
        m_cancel.GetComponent<Button>().onClick.AddListener(delegate {
            _SetHide();
        });
    }
    [Tooltip("取消按鈕")]
    public Transform m_cancel;

}

18.將Alert.cs腳本拖拽到Alert對象上,並分別將Confirm和Cancel對象拖拽到Alert對應的組件上

19.再在Assets>Scripts文件夾下新建鍵盤事件的腳本 KeyEvent.cs

20.KeyEvent.cs腳本內容

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class KeyEvent : MonoBehaviour
{
    /// <summary>
    /// 獲取Alert組件
    /// </summary>
    private Alert alert;
    void Start()
    {
        //實例化組件
        alert = Alert.Instance;
    }

    void Update()
    {
        //鍵盤事件
        _KeyDown();
    }

    /// <summary>
    /// 按下鍵盤執行
    /// </summary>
    public void _KeyDown()
    {
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            alert._SetShow();
        }
    }

}

21.在Hierarchy下新建一個腳本管理器的空物體Script,並將KeyEvent.cs腳本附在其上

22.爲了讓Hierarchy下的組件的層次更加明顯,分別新建了三個空物體,具體如下

23.最後運行遊戲,按下Esc鍵彈出信息框

結束:GIF效果圖請看文章頂部!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章