🐧 들어가기 앞서

게임을 제작할 때 몬스터 사전에 들어갈 스크롤 뷰와 뷰를 움직이는 버튼이 필요했다.

구글에서 자료를 서치하면서 감사하게도 구현이 되어있는 코드를 발견했다.


🐧 기억할 것 & 진행

기존 코드

아래 스크립트는 Unity에서 스크롤 뷰의 내용 (content)을 조작하여 위나 아래로 움직이는 기능을 구현하고 있다.

  • 변수 정의
    content: 스크롤 될 내용을 담고 있는 RectTransform이다.
    count: 아마도 내용 항목의 총 개수를 나타내는 변수다.
    pos: content의 현재 위치 (Y축)를 저장하는 변수다.
    movepos: content가 이동해야 할 목표 위치 (Y축)를 나타낸다.
    IsScroll: 현재 스크롤 중인지 여부를 나타내는 부울 변수다.

  • Start() 메서드
    게임 오브젝트가 처음 활성화될 때 자동으로 호출된다.
    content의 초기 위치를 pos에 저장하고, 이동해야 할 초기 위치를 계산하여 movepos에 저장한다.
    그리고 디버그 로그를 출력하여 content의 최대 Y 위치, 최소 Y 위치, 그리고 계산된 이동 위치를 콘솔에 출력한다.

  • Up() 메서드
    스크롤 뷰의 내용을 위로 움직이는 메서드다.
    움직임의 경계를 검사하여 이미 최상단에 도달한 경우 추가로 움직이지 않는다.
    그렇지 않은 경우, 스크롤 목표 위치를 계산하고, scroll() 코루틴을 시작하여 실제로 움직이게 한다.

  • Down() 메서드
    스크롤 뷰의 내용을 아래로 움직이는 메서드다.
    움직임의 경계를 검사하여 이미 최하단에 도달한 경우 추가로 움직이지 않는다.
    그렇지 않은 경우, 스크롤 목표 위치를 계산하고, scroll() 코루틴을 시작하여 실제로 움직이게 한다.

  • scroll() 코루틴
    실제로 스크롤 뷰의 내용을 움직이는 로직을 담고 있다.
    Lerp 함수를 사용하여 부드럽게 스크롤될 내용을 움직인다.
    내용이 거의 목표 위치에 도달하면 스크롤을 중지한다.

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

public class ScrollVieController : MonoBehaviour
{
    [SerializeField] private RectTransform content;
    public int count;
    private float pos;
    private float movepos;
    private bool IsScroll = false;

    void Start()
    {
        pos = content.localPosition.y;
        movepos = content.rect.yMax - content.rect.yMax / count;
        Debug.Log(content.rect.yMax);
        Debug.Log(content.rect.yMin);
        Debug.Log(content.rect.yMax - content.rect.yMax / count + "|" + pos);
    }

    public void Up()
    {
        if (content.rect.yMin + content.rect.yMax / count == movepos)
        {
            return;
        }
        IsScroll = true;
        movepos = pos + content.rect.height / count;
        pos = movepos;
        StartCoroutine(scroll());
    }

    public void Down()
    {
        if (content.rect.yMax - content.rect.yMax / count == movepos)
        {
            return;
        }
        IsScroll = true;
        movepos = pos - content.rect.height / count;
        pos = movepos;
        StartCoroutine(scroll());
    }

    IEnumerator scroll()
    {
        while (IsScroll)
        {
            content.localPosition = Vector2.Lerp(content.localPosition, new Vector2(0, movepos), Time.deltaTime * 5);
            if (Vector2.Distance(content.localPosition, new Vector2(0, movepos)) < 0.1f)
            {
                IsScroll = false;
            }
            yield return null;
        }
    }
}

개선 코드

같은 역할을 하는 중복되는 코드를 리팩토링했다.

  1. Up과 Down을 MoveContent라는 메서드로 중복을 제거했다.
    MoveContent 메서드는 direction인자를 받아서 위 or 아래로 움직이는 로직을 처리한다.(1은 위, -1은 아래)

  2. 원래 코드에서는 경계를 검사하는 로직이 따로 있었지만, 부동 소수점 오차로 인한 문제를 줄이기 위해 Mathf.Approxtimately를 사용했다.

using UnityEngine;
using System.Collections;

public class ScrollVieController : MonoBehaviour
{
    [SerializeField] private RectTransform content;
    [SerializeField] private int count;
    private float pos;
    private float movepos;
    private bool IsScroll = false;

    private void Start()
    {
        pos = content.localPosition.y;
        movepos = content.rect.yMax - content.rect.yMax / count;
        Debug.Log(content.rect.yMax);
        Debug.Log(content.rect.yMin);
        Debug.Log(content.rect.yMax - content.rect.yMax / count + "|" + pos);
    }

    public void Up()
    {
        MoveContent(1);
    }

    public void Down()
    {
        MoveContent(-1);
    }

    private void MoveContent(int direction)
    {
        float boundaryCheckValue = direction > 0 ? content.rect.yMin + content.rect.yMax / count : content.rect.yMax - content.rect.yMax / count;

        if (Mathf.Approximately(boundaryCheckValue, movepos))
        {
            return;
        }

        IsScroll = true;
        movepos = pos + direction * content.rect.height / count;
        pos = movepos;
        StartCoroutine(scroll());
    }

    IEnumerator scroll()
    {
        while (IsScroll)
        {
            content.localPosition = Vector2.Lerp(content.localPosition, new Vector2(0, movepos), Time.deltaTime * 5);
            if (Vector2.Distance(content.localPosition, new Vector2(0, movepos)) < 0.1f)
            {
                IsScroll = false;
            }
            yield return null;
        }
    }
}

🐧 내일 할 일

포스몬 사전 개선하기.

0개의 댓글