UNITY/Script

[UNITY C#] 팝업 상자(Pop-up Box) UI 구현

HYEOKJUN 2022. 8. 8. 18:00
반응형


기본 설정

Canvas를 생성하여 UI를 구성하고 팝업 상자를 띄울 Panel Object를 생성합니다.

(Canvas > Render Mode를 Screen Space - Camera로 설정했습니다.)
(Panel은 Raycast Target을 끄거나 최상단 자식으로 두어야 합니다. 마우스 Click, Enter, Exit 이벤트를 방해할 수 있습니다.)

Popup Panel의 자식으로 팝업 상자텍스트를 추가합니다.

(텍스트는 TextMeshPro를 사용했습니다.)


스크립트 추가

PopupManager.cs

더보기
using System.Collections;
using UnityEngine;
using TMPro;

/// <summary>
/// 팝업 상자를 관리하는 클래스입니다.
/// </summary>
public sealed class PopupManager : MonoBehaviour
{
    static PopupManager instance = null;
	public static PopupManager Instance {
		get {
			if(instance == null){
				instance = FindObjectOfType<PopupManager>();
			}
			return instance;
		}
	}

    void Update() {
        if(IsOnPopup) {
            RectTransformUtility.ScreenPointToLocalPointInRectangle(popup_panel.GetComponent<RectTransform>(), Input.mousePosition, Camera.main, out Vector2 position_adjusted);
            popup_object.transform.localPosition = position_adjusted;
        }
    }
    
    /// <summary>
    /// 팝업 상자를 띄우는 구역 Object입니다.
    /// </summary>
    [SerializeField] GameObject popup_panel = null;
    /// <summary>
    /// 팝업 상자 Object입니다.
    /// </summary>
    [SerializeField] GameObject popup_object = null;
    /// <summary>
    /// 팝업 상자 텍스트입니다.
    /// </summary>
    [SerializeField] TextMeshProUGUI popup_txt = null;
    
    /// <summary>
    /// 팝업 상자 활성화 여부입니다.
    /// </summary>
    bool isOnPopup = false; 
    /// <summary>
    /// 팝업 상자 활성화 여부입니다.
    /// </summary>
    public bool IsOnPopup { get { return isOnPopup; } }
    
    /// <summary>
    /// 팝업 상자 활성화 Coroutine입니다.
    /// </summary>
    Coroutine enterCount_coroutine;
    /// <summary>
    /// 팝업 상자 비활성화 Coroutine입니다.
    /// </summary>
    Coroutine exitCount_coroutine;

    /// <summary>
    /// 팝업 상자 활성화 대기 시간입니다.
    /// </summary>
    const float TIME_ENTER = 1f;
    /// <summary>
    /// 팝업 상자 비활성화 대기 시간입니다.
    /// </summary>
    const float TIME_EXIT = 0.4f;

    /// <summary>
    /// 팝업 상자 활성화를 준비합니다.
    /// (TIME_ENTER초 후에 팝업 상자를 띄웁니다.)
    /// </summary>
    /// <param name="description">팝업 상자 내용입니다.</param>
    /// <param name="position_target">팝업 상자를 띄울 위치입니다.</param>
    public void SetPopup(string description, Vector2 position_target) {
        if(enterCount_coroutine != null) { StopCoroutine(enterCount_coroutine); }
        if(exitCount_coroutine != null) {StopCoroutine(exitCount_coroutine); }
        if(IsOnPopup) {
            OnPopup(description, position_target);
        } else {
            enterCount_coroutine = StartCoroutine(CountEnterTime(description, position_target));
        }
    
        IEnumerator CountEnterTime(string description, Vector2 position_target) {
            float timer = 0f;
            while(timer < TIME_ENTER) {
                timer += Time.unscaledDeltaTime;
                yield return null;
            }
            OnPopup(description, position_target);
        }
    }
    /// <summary>
    /// 팝업 상자 비활성화를 준비합니다.
    /// (TIME_EXIT초 후에 팝업 상자를 닫습니다.)
    /// </summary>
    public void UnsetPopup() {
        if(enterCount_coroutine != null) { StopCoroutine(enterCount_coroutine); }
        if(exitCount_coroutine != null) { StopCoroutine(exitCount_coroutine); }
        if(IsOnPopup) {
            exitCount_coroutine = StartCoroutine(CountExitTime());
        }

        IEnumerator CountExitTime() {
            float timer = 0f;
            while(timer < TIME_EXIT) {
                timer += Time.unscaledDeltaTime;
                yield return null;
            }
            OffPopup();
        }
    }
    /// <summary>
    /// 팝업 상자를 띄웁니다.
    /// </summary>
    /// <param name="description">팝업 상자 내용입니다.</param>
    /// <param name="position_target">팝업 상자를 띄울 위치입니다.</param>
    public void OnPopup(string description, Vector2 position_target) {
        popup_txt.text = description;

        RectTransformUtility.ScreenPointToLocalPointInRectangle(popup_panel.GetComponent<RectTransform>(), position_target, Camera.main, out Vector2 position_adjusted);
        popup_object.transform.localPosition = position_adjusted;
        popup_object.SetActive(true);

        isOnPopup = true;
    }
    /// <summary>
    /// 팝업 상자를 닫습니다.
    /// </summary>
    public void OffPopup() {
        popup_object.SetActive(false);
        StartCoroutine(AvailablePopup());
        
        IEnumerator AvailablePopup(){
            yield return null;

            if(!popup_object.activeSelf) {
                isOnPopup = false;
            }
        }
    }
}

해당 Popup Panel에 위 PopupManager 스크립트를 추가합니다.

 

PopupArea.cs

더보기
using UnityEngine;
using UnityEngine.EventSystems;

/// <summary>
/// 팝업 상자를 띄우는 구역을 지정하는 클래스입니다.
/// </summary>
public class PopupArea : MonoBehaviour, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler
{
    /// <summary>
    /// 해당 구역에서 표시할 문자열입니다.
    /// </summary>
    [TextArea(3, 5)][SerializeField] string description;

    /// <summary>
    /// 마우스 클릭시 발생하는 이벤트입니다.
    /// </summary>
    public void OnPointerClick(PointerEventData pointerEventData) {
        PopupManager.Instance.OnPopup(description, pointerEventData.position);
    }
    /// <summary>
    /// 마우스가 구역 안으로 들어올 때 발생하는 이벤트입니다.
    /// </summary>
    public void OnPointerEnter(PointerEventData pointerEventData) {
        PopupManager.Instance.SetPopup(description, pointerEventData.position);
    }
    /// <summary>
    /// 마우스가 구역 밖으로 나갈 때 발생하는 이벤트입니다.
    /// </summary>
    public void OnPointerExit(PointerEventData pointerEventData) {
        PopupManager.Instance.UnsetPopup();
    }
}

팝업 상자를 띄울 영역(오브젝트)에 위 PopupArea 스크립트를 추가합니다.

(해당 오브젝트들의 Raycast Target 옵션이 켜져 있어야 합니다.)

 

다음과 같이 모든 필드 데이터를 할당합니다.

마지막으로 팝업 상자를 비활성화시킵니다.

위와 같이 팝업 상자가 뜨는 것을 확인할 수 있습니다.

(TIME_ENTER, TIME_EXIT 값을 조정하여 팝업 상자가 뜨고 내리는 시간을 조정할 수 있습니다.)

반응형