본문 바로가기

[unity] 모듈 제작 : 팝업 시스템 만들기(3)

앤디가이 2022. 5. 24.

팝업을 관리하는 매니저 클래스인 PopupManager Class를 제작해보자.

 

1. 스크립트 작성

제작 해야될 스크립트는 총 7가지로 각 클래스 별 기능 설명을 하자면 다음과 같다.

 

1. Popup : 팝업 객체에 붙는 컴포넌트로 팝업 내 UI 요소들을 컨트롤 하는 클래스

2. PopupManager : 팝업을 관리하는 매니저 클래스

3. PopupAnimator : 팝업 애니메이션을 관리하는 클래스

4. PopupButton : 팝업 전용 버튼 클래스

5. PopupButtonInfo : 팝업 전용 버튼 정보 클래스

6. PopupButtonType : 팝업 버튼 타입 정의 Enum

7. PopupInfo : 팝업 생성을 위한 정보를 담은 클래스

 

1. Popup Class

 - 타이틀, 내용, 버튼의 UI 요소를 가지고 있으며, 초기화 시 해당 내용을 UI에 업데이트 해준다.

using UnityEngine;
using UnityEngine.UI;
using System;

namespace Container.Popup
{
    [Serializable]
    public class PopupInfoDictionary : SerializableDictionary<PopupButtonType, PopupButtonInfo> { }

    [RequireComponent(typeof(PopupAnimator))]
    public class Popup : MonoBehaviour
    {
        [SerializeField]
        protected Text txt_title = null;
        [SerializeField]
        protected Text txt_content = null;
        [SerializeField]
        protected Transform root_button = null;
        [SerializeField]
        protected GameObject basic_PopupButton = null;

        [SerializeField]
        private PopupInfoDictionary dic_popupButtonInfo;

        public bool IsShow => this.gameObject.activeSelf;

        /// <summary>
        /// 초기화 함수.
        /// </summary>
        /// <param name="info">팝업 정보</param>
        public void OnInitialize(PopupInfo info)
        {
            txt_title.text = info.Title;
            txt_content.text = info.Content;
            SetButtons(info.Buttons);
        }

        protected virtual void SetButtons(PopupButtonType[] btns)
        {
            for (int i = 0; i < btns.Length; i++)
            {
                GameObject popupObject = Instantiate(basic_PopupButton, root_button);
                popupObject.transform.localScale = Vector3.one;
                popupObject.SetActive(true);

                PopupButton popupButton = popupObject.GetComponent<PopupButton>();

                popupButton.Type = btns[i];
                try
                {
                    popupButton.Name = dic_popupButtonInfo[popupButton.Type].str_name;
                    popupButton.Color = dic_popupButtonInfo[popupButton.Type].color_button;
                }
                catch { Debug.Log("요청 타입이 PopupInfo에 정의되어 있지 않습니다."); }
            }
        }

        protected virtual void SetButtonColor()
        {
        }

        public void Show()
        {
            gameObject.SetActive(true);
        }

        public void Hide()
        {
            PopupButton[] popupButtons = root_button.GetComponentsInChildren<PopupButton>(true);

            foreach (PopupButton btn in popupButtons)
            {
                DestroyImmediate(btn.gameObject);
            }

            gameObject.SetActive(false);
        }

    }
}

 

2. PopupManager Class

 - 싱글톤으로 구현하여, Instance를 통해 어디서든 접근하기 용이하게 구성한다.

 - ShowPopup 함수를 통해 팝업을 Show 시킨다.

 - HidePopup 함수를 통해 팝업을 Hide 시킨다.

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

namespace Container.Popup
{
    public class PopupManager : MonoBehaviour
    {
        [SerializeField]
        protected GameObject dim = null;
        [SerializeField]
        protected Popup popup = null;

        protected PopupAnimator obj_Animator = null;

        protected System.Action<PopupButtonType> OnClosedPopupListener;

        public static PopupManager Instance { get; private set; }

        private void Awake()
        {
            Instance = this;

            if (popup == null)
                popup = GetComponentInChildren<Popup>(true);

            obj_Animator = popup.GetComponent<PopupAnimator>();
        }

        private void OnDestroy()
        {
            Instance = null;
        }

        public void ShowPopup(string contents)
        {
            ShowPopup(string.Empty, contents);
        }
        /// <summary>
        /// Basic 한 팝업 호출시 사용.
        /// </summary>
        /// <param name="title">타이틀 내용</param>
        /// <param name="contents">콘텐츠 내용</param>
        public void ShowPopup(string title, string contents)
        {
            PopupInfo info = new PopupInfo.Builder()
                     .SetTitle(title)
                     .SetContent(contents)
                     .SetButtons(PopupButtonType.Confirm)
                     .Build();
            ShowPopup(info);
        }

        /// <summary>
        /// 팝업의 다양한 정보를 가지고 호출할시 사용.
        /// </summary>
        /// <param name="info">팝업 정보</param>
        public void ShowPopup(PopupInfo info)
        {
            if(popup.IsShow)
            {
                return;
            }

            if (info.PauseScene)
                Time.timeScale = 0;

            popup.OnInitialize(info);
            OnClosedPopupListener = info.Listener;
            dim.SetActive(true);
            popup.Show();
            obj_Animator.startAnimation(info.Animation);
        }

        public void HidePopup()
        {
            Time.timeScale = 1;
            dim.SetActive(false);
            popup.Hide();
        }

        public virtual void OnClosePopup(PopupButtonType type)
        {
            if (OnClosedPopupListener != null)
            {
                OnClosedPopupListener(type);
                OnClosedPopupListener = null;
            }
            HidePopup();
        }
    }
}

 

3. PopupAnimator

 - 팝업이 Show/Hide 될때 약간의 Tween 효과를 주기 위해 필요한 클래스이다.

 - LeanTweenType을 설정하여, 다양한 Tween 효과를 줄 수 있다.

 - PopupAnimationType 은 4가지로 제공한다.

    . Alpha : 팝업이 천천히 나오고 천천히 사라지는 컬러 효과

    . Scale : 팝업이 스케일 0에서 1까지 나오는 효과

    . LeftToRight : 팝업이 왼쪽에서 나와서 오른쪽으로 사라지는 효과

    . TopToBottom : 팝업이 위에서 나와서 아래로 사라지는 효과

 

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

namespace Container.Popup
{
    public enum PopupAnimationType
    {
        None = 0,
        Alpha = 1,
        Scale = 2,
        LeftToRight = 3,
        TopToBottom = 4,
    }

    public class PopupAnimator : MonoBehaviour
    {
        protected const float MOTION_SPEED = 0.5f;

        public LeanTweenType tweenType = LeanTweenType.easeOutBack;

        private RectTransform rect_Target = null;

        private void Awake()
        {
            if (rect_Target == null)
                rect_Target = GetComponent<RectTransform>();
        }

        
        public virtual void startAnimation(PopupAnimationType animationType)
        {
            if (rect_Target == null)
                rect_Target = GetComponent<RectTransform>();

            switch (animationType)
            {
                case PopupAnimationType.Scale:
                    {
                        rect_Target.localScale = Vector3.zero;
                        LeanTween.scale(rect_Target, Vector3.one, MOTION_SPEED)
                            .setEase(tweenType)
                            .setIgnoreTimeScale(true);
                        break;
                    }
                case PopupAnimationType.Alpha:
                    {
                        if (!GetComponent<CanvasGroup>())
                            gameObject.AddComponent<CanvasGroup>();

                        GetComponent<CanvasGroup>().alpha = 0;
                        LeanTween.alphaCanvas(GetComponent<CanvasGroup>(), 1, MOTION_SPEED)
                            .setEase(tweenType)
                            .setIgnoreTimeScale(true);
                        break;
                    }
                case PopupAnimationType.LeftToRight:
                    {
                        rect_Target.localPosition = new Vector3(-Screen.width, 0);
                        LeanTween.move(rect_Target, Vector2.zero, MOTION_SPEED)
                            .setEase(tweenType)
                            .setIgnoreTimeScale(true);
                        break;
                    }
                case PopupAnimationType.TopToBottom:
                    {
                        rect_Target.localPosition = new Vector3(0, Screen.height);
                        LeanTween.move(rect_Target, Vector2.zero, MOTION_SPEED)
                            .setEase(tweenType)
                            .setIgnoreTimeScale(true);
                        break;
                    }
            }
        }
    }
}

댓글