Unity 내일배움캠프 TIL 0919 | 프로그래머스 n^2 배열 자르기 | ScrollView가 작동하지 않을 때 Content Size Fitter

cheeseonrose·2023년 9월 19일
0

Unity 내일배움캠프

목록 보기
39/89
post-thumbnail

무난한 화요일..
인줄 알았으나 인터넷이 또 터진 건에 대하여.

온몸으로 이세상 억까를 맞아내는 이 감자의 최후는 과연

n^2 배열 자르기

  • 예전에 풀었던 문제인데 놀랍게도 예전에 생각하던 과정 그대로 삽질하다가 풀어냄
    인간은 변하지 않는다

생각의 흐름

  • left와 right를 n으로 나눈 몫과 나머지가 2차원 배열의 좌표와 연관성이 있을 것 같다

    • n = 3, left = 2, right = 5 일 때, 2차원 배열에서의 시작 좌표는 (2 / 3, 2 % 3) = (0, 2)
    • 끝 좌표는 (5 / 3, 5 % 3) = (1, 2)
  • 2차원 배열의 x, y 좌표와 배열의 값 사이의 연관성이 있을 것 같다

  • 좌표 (n, m)의 값은 y좌표가 0~n까지는 n+1이고, 그 이후부터 1씩 늘어나는 형태 (n+2, n+3 ...)

  • 아래와 같은 배열에서 x좌표가 1인 줄을 예로 들어보자
    (1, 0) ~ (1, 1)까지는 배열의 값이 2이고, 그 이후부터는 1씩 늘어나서 3, 4... 가 된다.

    idx0123
    01234
    12234
    23334
    34444
  • 이제 삽질 시작 -> 그럼 이 규칙대로 배열에 값을 넣어주고 아까 구한 시작과 끝 좌표를 이용해서 배열 값을 읽어오면 되겠네??
    겠냐고요.
    저 어마어마한 제한 사항을 보렴
    정신이 드니?


풀이

  • 규칙을 하나만 보고 둘은 못본다면 삽질하게 되는 것이다
    위에서 설명한 좌표 값과 배열 값 사이의 규칙은 사실 저게 끝이 아니다.
    좌표 (n, n)을 기준으로 (0 ~ n-1, n)과 (n+1 ~ , n)을 생각해보자
    그러니까 좌표 하나 잡고 y값 고정, x 값만 그 위아래로 움직여보자는 말
    n을 기준으로 위쪽에는 y + 1이, 아래쪽에는 x + 1이 배열의 값이 된다
  • 이게 무슨 말이냐 하면 x 인덱스가 y 인덱스보다 작아지면 y 인덱스에 의해 값이 정해지고, 커지면 x 인덱스에 의해 값이 정해진다는 것
    그러니까 결국 배열의 값은 x, y 좌표를 비교해서 더 큰 인덱스에 의해 정해진다는 말
  • left와 right로 좌표를 구할 때로 돌아가보자
    x 좌표는 left / n 이고, y 좌표는 left % n 이었다
    그러면 우리는 left에서 right까지의 값을 순회하는 것만으로도 x, y 좌표를 얻을 수 있게 되며, 이는 곧 배열의 값을 얻을 수 있게 됨을 의미한다
  • 그래서 코드는
public class Solution {
    public int[] solution(int n, long left, long right) {
        int[] answer = new int[right - left + 1];
        int idx = 0;
        for (long i = left; i <= right; i++)
        {
            answer[idx++] = Math.Max((int)(i / n), (int)(i % n)) + 1;
        }
        return answer;
    }
}
  • 짜잔! 참 쉽죠?



개인 프로젝트

UI 구조 설계

  • UI 구조는 저번 팀 프로젝트에서 했던 것처럼 UIManager가 있고, 그 UIManager가 Dictionary에 UI Canvas별로 나누어진 UI Component들을 들고 있는 형태이다.
  • 저번에 튜터님께 피드백 받았던 대로 이번에는 Dictionary의 Value가 Monobehaviour 형태가 아닌 새로운 부모 UI Class 형태가 되도록 설계했다.

UIManager

  • UIManager 코드는 저번과 같음
public class UIManager : MonoBehaviour
{
    public static UIManager Instance;

    Dictionary<string, GameUIClass> uiDic;

    private void Awake()
    {
        Instance = this;
        uiDic = new Dictionary<string, GameUIClass>();
        
    }

    public T GetUIComponent<T>() where T : GameUIClass
    {
        string key = typeof(T).Name;
        if (!uiDic.ContainsKey(key))
        {
            var obj = Instantiate(Resources.Load($"Prefabs/{key}"));
            uiDic.Add(key, obj.GetComponent<T>());
        }
        return (T)uiDic[key];
    }
}

GameUIClass

  • 전체 UI 컴포넌트들이 상속받게 될 부모 UI Class
  • 공통적으로 자주 쓰이는 기능인 SetActive(true/false)를 메서드로 만들었다.
public class GameUIClass : MonoBehaviour
{
    public virtual void OpenUI()
    {
        gameObject.SetActive(true);
    }

    public virtual void CloseUI()
    {
        gameObject.SetActive(false);
    }
}

UIPlayerStatus

  • 그래서 위의 부모 UI 클래스를 상속받는 UI 컴포넌트는 다음과 같이 구성된다
  • 캔버스 내의 요소들은 인스펙터 창에서 연결시켜줄 수 있도록 SerializeField로 선언하고, Start 함수에서 버튼에는 클릭 리스너를 연결해준다.
    이때 연결해주는 CloseUI 함수가 바로 GameUIClass에서 만들어준 메서드 CloseUI이다.
  • UI의 정보를 Set하는 기능을 다른 클래스에서 사용할 수 있도록 public 메서드로 만들어줬다.
public class UIPlayerStatus : GameUIClass
{

    [SerializeField] private Button _closePlayerStatusButton;
    [SerializeField] private TMP_Text _attackStatText;
    [SerializeField] private TMP_Text _shieldStatText;
    [SerializeField] private TMP_Text _healthStatText;

    void Start()
    {
        _closePlayerStatusButton.onClick.AddListener(CloseUI);
    }

    public void SetPlayerStat(int attackStat, int shieldStat, int healthStat)
    {
        _attackStatText.text = attackStat.ToString();
        _shieldStatText.text = shieldStat.ToString();
        _healthStatText.text = healthStat.ToString();
    }
}

ScrollView

  • ScrollView를 이용해서 인벤토리 UI를 구현하던 중, 문제가 생겼다.
    스크롤 뷰가 제대로 작동하지 않는 것!

  • 스크롤 뷰의 Content 안에 버튼들을 넣어줘서 그런가 해서 구글링으로 버튼에 대한 touch event를 스크롤 뷰에도 넘겨주는 코드를 작성해 연결시켜줬는데 문제는 여전했다. 오히려 찔끔찔끔 되던 스크롤도 안 되길래 삭제..

  • 다시 구글링을 해보니까 Content의 크기가 스크롤 할 수 있는 범위이고, 때문에 Content의 크기를 담겨있는 아이템을 수용할 정도로 늘려줘야 제대로 동작한다는 것..!
    크기를 늘려주니 스크롤이 되었다.

  • 근데 언제 하나하나 크기 계산해서 늘려주겠나! 분명 동적으로 크기를 조절하는 방법을 유니티가 만들어놨을 것이라 믿었다

  • Content Size Fitter

    • 자체 레이아웃 요소의 크기를 제어하는 레이아웃 컨트롤러의 기능을 수행

    • 크기는 게임 오브젝트의 레이아웃 요소 컴포넌트에서 제공하는 최소 또는 기본 크기에 따라 결정됨

    • 피벗을 사용하여 크기 조정 방향 제어 가능

      Unconstrained레이아웃 요소에 기반하여 너비를 조정하지 않음
      Min Size레이아웃 요소의 최소 너비에 기반하여 너비를 조정
      Preferred Size레이아웃 요소의 기본 너비에 기반하여 너비를 조정
    • Min Size 옵션의 경우 단독으로 사용되는 경우는 거의 없고, Layout group 계열의 컴포넌트와 함께 주로 사용

    • Preferred Size 옵션은 텍스트나 이미지에 단독으로 Content Size Fitter를 사용하는 경우 주로 사용

  • 그래서 이렇게 Content에 Content Size Fitter 컴포넌트를 달아주니 스크롤이 정상적으로 작동했다!!! 세로 방향 스크롤이므로 Vertical Fit에 Min Size 옵션을 체크해줬다.



오늘은 UI 노동의 날이었기 때문에..
TIL은 여기까쥐...

사실 계획한 일의 반도 못한 기분이라 아무래도 야근해야겠다

암튼 끗!

0개의 댓글