Unity

Unity 자동슬라이드 Text 구현하기

sungmin08 2025. 4. 14. 14:16

 

오늘 구현할 자동 슬라이드 Text 미리보기

 

 

오늘 구현해볼 것은 Text가 자동으로 슬라이딩 되는 기능이다.

새로 추가된 업데이트나 새로운 소식을 사용자에게 제공해야 할 때 쓰면 유용 할 것 같다.

 

1. 하이어라키 세팅하기

먼저 Canvas 안에 새로운 Text 2개를 생성한다. 생성한 text는 동일한 Transform에 배치한다. 

TodayNews오브젝트는 News Text 부모로 있는 뒤에 있는 배경이미지이다. 

 

2. 코드 작성 및 설명

※  변수 선언

    [Header("Text Objects")]
    public RectTransform textA; //News1
    public RectTransform textB; //News2
  
    [Header("Animation Settings")]
    public float switchInterval = 2f; // 몇초마다 슬라이드 할지
    public float slideDuration = 0.5f; // 몇초동안 슬라이드 될지
    public float slotHeight = 100f; //얼마나 위로 Text를 옮길지
    
    //내부 상태
    private bool isTextAOnTop = true;

TextObjects ->  Text 2개의 위치를 받아올 2개의 RectTransform을 선언

Animation Settings -> 주석 설명

 

※  Start 함수

    private void Start()
    {
        // 초기 위치 설정
        if (textA != null) textA.anchoredPosition = Vector2.zero;
        if (textB != null) textB.anchoredPosition = new Vector2(0, slotHeight);

        StartCoroutine(SlotMachineRoutine());
    }

textA부터 시작, textB는 slotHeight만큼 위로 옮김(보이지않도록)

SlotMachineRoutine() 코루틴 함수 실행

 

※  SlotMachineRoutine() 코루틴 함수

private IEnumerator SlotMachineRoutine()
    {
        while (true)
        {
            yield return new WaitForSeconds(switchInterval);

            RectTransform current = isTextAOnTop ? textA : textB;
            RectTransform next = isTextAOnTop ? textB : textA;

            //두 텍스트를 동시에 슬라이드
            Coroutine slideCurrent = StartCoroutine(Slide(current, new Vector2(0, -slotHeight), slideDuration));
            Coroutine slideNext = StartCoroutine(Slide(next, Vector2.zero, slideDuration));

            //둘 다 완료될 때까지 대기
            yield return slideCurrent;
            yield return slideNext;

            //내려간 텍스트를 다시 위로 올리기
            current.anchoredPosition = new Vector2(0, slotHeight);

            //상태 전환
            isTextAOnTop = !isTextAOnTop;
        }
    }

textB가 TextA의 위치로 온 다음 TextA는 밑으로 내려간 후 다시 상단으로 올라가 내려갈 준비를 한다.

 

※  Slide 코루틴 함수

        /// <summary>
        /// RectTransform을 targetPos로 서서히 이동시키는 코루틴
        /// </summary>
        IEnumerator Slide(RectTransform rect, Vector2 targetPos, float duration)
        {
            Vector2 startPos = rect.anchoredPosition;
            float elapsed = 0f;

            while (elapsed < duration)
            {
                elapsed += Time.deltaTime;
                float t = Mathf.Clamp01(elapsed / duration);

                rect.anchoredPosition = Vector2.Lerp(startPos, targetPos, t);
                yield return null;
            }

            rect.anchoredPosition = targetPos;
        }

 

 

※  전체코드

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

public class SlotMachineText : MonoBehaviour
{
    [Header("Text Objects")]
    public RectTransform textA;
    public RectTransform textB;

    [Header("Animation Settings")]
    public float switchInterval = 2f;
    public float slideDuration = 0.5f;
    public float slotHeight = 100f;

    //내부 상태
    private bool isTextAOnTop = true;

    private void Start()
    {
        // 초기 위치 설정
        if (textA != null) textA.anchoredPosition = Vector2.zero;
        if (textB != null) textB.anchoredPosition = new Vector2(0, slotHeight);

        StartCoroutine(SlotMachineRoutine());
    }

    private IEnumerator SlotMachineRoutine()
    {
        while (true)
        {
            yield return new WaitForSeconds(switchInterval);

            RectTransform current = isTextAOnTop ? textA : textB;
            RectTransform next = isTextAOnTop ? textB : textA;

            //두 텍스트를 동시에 슬라이드
            Coroutine slideCurrent = StartCoroutine(Slide(current, new Vector2(0, -slotHeight), slideDuration));
            Coroutine slideNext = StartCoroutine(Slide(next, Vector2.zero, slideDuration));

            //둘 다 완료될 때까지 대기
            yield return slideCurrent;
            yield return slideNext;

            //내려간 텍스트를 다시 위로 올리기
            current.anchoredPosition = new Vector2(0, slotHeight);

            //상태 전환
            isTextAOnTop = !isTextAOnTop;
        }
    }

    /// <summary>
    /// RectTransform을 targetPos로 서서히 이동시키는 코루틴
    /// </summary>
    IEnumerator Slide(RectTransform rect, Vector2 targetPos, float duration)
        {
            Vector2 startPos = rect.anchoredPosition;
            float elapsed = 0f;

            while (elapsed < duration)
            {
                elapsed += Time.deltaTime;
                float t = Mathf.Clamp01(elapsed / duration);

                rect.anchoredPosition = Vector2.Lerp(startPos, targetPos, t);
                yield return null;
            }

            rect.anchoredPosition = targetPos;
        }
    }
}

 

 

코드를 부모오브젝트에 삽입 후 News1, News2 할당

 

실행 화면

 

여기서 문제 :
text들이 슬라이드는 잘 되지만 저 안에서만 보여야 하는데 바깥의 움직이는 것까지 다 보인다!

 

간단하게 Rect Mask 2D 추가

 

더보기

✅ Rect Mask 2D란?

"자식 오브젝트들의 보이는 영역을 사각형(Rect) 안으로 제한"하는 컴포넌트.

쉽게 말하면,
Rect 영역 안에 있을 때만 보이고,
영역을 벗어나면 자동으로 잘려서 안 보임.


✅ Rect Mask 2D 특징

특징설명
성능 일반 Mask보다 훨씬 가볍다. (Shader 계산 안 하고, 단순 잘라내기만 함)
사용 조건 UI (Canvas 안) 에서만 사용 가능하다.
적용 대상 RectTransform을 가진 자식 오브젝트들 (텍스트, 이미지, 버튼 등)
투명 처리 영역 바깥은 완전히 잘려서 아예 안 보인다 (반투명 같은 거 아님).
한계 둥근 모양, 불규칙 마스크는 못 만든다. 오직 사각형만 잘라낸다.

 

더보기

만약 Text가 여러개라면??

Text를 담을 List<>선언 -> 현재 보여줄 text를 currentIndex로 관리! (로직은 그대로) 

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

public class SlotMachineText : MonoBehaviour
{
    [Header("Text List")]
    public List<RectTransform> textList = new List<RectTransform>();

    [Header("Animation Settings")]
    public float switchInterval = 2f;
    public float slideDuration = 0.5f;
    public float slotHeight = 100f;

    private int currentIndex = 0; // 현재 중앙에 있는 텍스트 인덱스

    private void Start()
    {
        // 초기 위치 세팅
        for (int i = 0; i < textList.Count; i++)
        {
            if (i == 0)
                textList[i].anchoredPosition = Vector2.zero; // 첫 번째 텍스트는 중앙
            else
                textList[i].anchoredPosition = new Vector2(0, slotHeight); // 나머지는 위에 숨겨놓기
        }

        StartCoroutine(SlotMachineRoutine());
    }

    IEnumerator SlotMachineRoutine()
    {
        while (true)
        {
            yield return new WaitForSeconds(switchInterval);

            // current show text
            RectTransform current = textList[currentIndex];

            // next show text
            int nextIndex = (currentIndex + 1) % textList.Count;
            RectTransform next = textList[nextIndex];

            //Both Slide Start
            Coroutine slideCurrent = StartCoroutine(Slide(current, new Vector2(0, -slotHeight), slideDuration));
            Coroutine slideNext = StartCoroutine(Slide(next, Vector2.zero, slideDuration));

            //Wait until all Slides are finished
            yield return slideCurrent;
            yield return slideNext;

            //Slide text under Update Up
            current.anchoredPosition = new Vector2(0, slotHeight);

            //Update Index
            currentIndex = nextIndex;
        }
    }

    IEnumerator Slide(RectTransform rect, Vector2 targetPos, float duration)
    {
        Vector2 startPos = rect.anchoredPosition;
        float elapsed = 0f;

        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            float t = Mathf.Clamp01(elapsed / duration);
            rect.anchoredPosition = Vector2.Lerp(startPos, targetPos, t);
            yield return null;
        }

        rect.anchoredPosition = targetPos;
    }
}