Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

booooox

[Unity] Reverse Mask UI 팝업 (구멍 팝업) 본문

Unity/System

[Unity] Reverse Mask UI 팝업 (구멍 팝업)

booooox 2024. 7. 25. 22:53
반응형

1. Reverse Mask : 이미지를 타켓이미지 모양대로 출력하는 방식의 Mask를 역으로 사용한 방식

 

2. 기대효과 : 

    1) Fade Out효과와 함께 사용하여 씬 변경에 이용할 수 있다.

 

3. 사용법 :

    1) - MaskImage (부모) : 구멍 낼 이미지

            - MaskedImage (자식) : 배경 이미지

 

    2) MaskedImage (자식) 오브젝트에 <Image> 컴포넌트를 지우고 아래 스크립트를 추가하고 사이즈를 넉넉하게 해준다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

public class MaskedUI : Image
{
    public override Material materialForRendering
    { 
        get
        {
            Material material = new Material(base.materialForRendering);
            material.SetInt("_StencilComp", (int)CompareFunction.NotEqual);
            return material;
        }
    }

    protected override void Start()
    {
        base.Start();
        StartCoroutine(Fix());
    }

    /// Fix for async loading scenes
    private IEnumerator Fix()
    {
        yield return null;
        maskable = false;
        maskable = true;
    }
}

 

    3) MaskImage (부모) 오브젝트에 <Image> 컴포넌트에 적용할 모양의 이미지를 넣고 구멍 안쪽으로 이미지 크기를 설정한다.

 

    4) 아래 스크립트등 으로 팝업으로 활용 가능하다. (페이드 인, 아웃 적용)

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

public class FadePopup : MonoBehaviour
{
    [SerializeField] private Image maskImage;
    [SerializeField] private Image maskedImage;
    [SerializeField, Range(0.1f, 3f)] private float fadeSpeed = 1f;
    [ReadOnly] private float maskImageMaxWidth;
    [ReadOnly] private float maskImageMaxHeight;

    private void Awake()
    {
        // 이미지 안가리도록 maskImage 마스크 설정 해 두기
        maskImage.TryGetComponent<RectTransform>(out RectTransform maskImageRect);
        maskImageMaxWidth = maskImageRect.rect.width;
        maskImageMaxHeight = maskImageRect.rect.height;

        // UnActive maskImage
        maskImage.gameObject.SetActive(false);
    }

    /// <summary>
    /// Call Fade_Out
    /// </summary>
    /// <param name="fadeAction">Action that Completes Fade Out</param>
    public void FadeOut(Action fadeAction = null) => StartCoroutine(FadeOutCoroutine(fadeAction));

    IEnumerator FadeOutCoroutine(Action fadeAction)
    {
        yield return null;
        maskImage.TryGetComponent<RectTransform>(out RectTransform maskImageRect);
        maskImageRect.sizeDelta = new Vector2(maskImageMaxWidth, maskImageMaxHeight);
        maskImage.gameObject.SetActive(true);

        float currentTime = 0;
        float currentWidth = maskImageMaxWidth;
        float currentHeight = maskImageMaxHeight;

        while(true) {
            yield return null;
            currentTime += Time.deltaTime;
            currentWidth = currentWidth <= 0f ? 0f : Mathf.Lerp(maskImageMaxWidth, 0f, currentTime / fadeSpeed);
            currentHeight = currentHeight <= 0f ? 0f : Mathf.Lerp(maskImageMaxHeight, 0f, currentTime / fadeSpeed);

            maskImageRect.sizeDelta = new Vector2(currentWidth, currentHeight);

            if (currentWidth <= 0f && currentHeight <= 0f) break;
        }
        fadeAction?.Invoke();
    }

    /// <summary>
    /// Call Fade_In
    /// </summary>
    public void FadeIn() => StartCoroutine(FadeInCoroutine());

    IEnumerator FadeInCoroutine()
    {
        yield return null;
        maskImage.TryGetComponent<RectTransform>(out RectTransform maskImageRect);
        maskImageRect.sizeDelta = new Vector2(0, 0);
        maskImage.gameObject.SetActive(true);

        float currentTime = 0;
        float currentWidth = 0;
        float currentHeight = 0;

        while(true) {
            yield return null;
            currentTime += Time.deltaTime;
            currentWidth = currentWidth >= maskImageMaxWidth ? maskImageMaxWidth : Mathf.Lerp(0f, maskImageMaxWidth, currentTime / fadeSpeed);
            currentHeight = currentHeight >= maskImageMaxHeight ? maskImageMaxHeight : Mathf.Lerp(0f, maskImageMaxHeight, currentTime / fadeSpeed);

            maskImageRect.sizeDelta = new Vector2(currentWidth, currentHeight);

            if (currentWidth >= maskImageMaxWidth && currentHeight >= maskImageMaxHeight) break;
        }
        maskImage.gameObject.SetActive(false);
    }
}

 

 

반응형