오-개) VR UI 페이지식 스크롤뷰 시스템 구성

astray36·2021년 6월 28일
0

오늘의 개발

목록 보기
6/10

일반적인? 사용의 스크롤뷰 혹은 UI 리스트라고 말할 수 있는 것들은 일반적으로 동일한 양식을 나열하게 된다. 뭐 예를들어
요런식이다. 태블릿으로 그렸는데 이지경이다. 아무튼 이런 형식이면 매우 단순하다 Unity에서 제공하는 Scroll View만 잘 사용하면 문제될 소지가 없다. 가로가 싫으면 세로도 가능하고 그게 싫으면 마치 인벤토리처럼 그리드 형식도 가능하다.
그런데 만들어야 하는 것은 이런식의 모양이다. 고민을 많이 했다. 어떻게 해야 쉽게 개발하고 확장성도 있게 개발할 수 있을까?
결국 선택한 방식은 스크롤뷰의 한 오브젝트를 페이지로 만들고 즉 저 5개의 네모들을 한 페이지의 자식 오브젝트로 만들어 관리하는 것이다. 문제는 이렇게 하면 페이지의 확장성은 쉬워지지만 각각의 네모들의 관리는 따로 해야된다는 것이다.

뭐 여러가지 이슈가 있었다. 만약 컨텐츠가 5의 배수로 떨어지지 않으면 어떻게 할 것인가 같은 단순한거부터 시작해서 그렇다면 썸네일의 이미지를 저 한개의 이상한 모양의 틀 때문에 2개씩 가지고 있어야 한다던지. 사실 저 UI는 내 생각으로는 굉장히 비효율적인 구성이다. 아니 심지어 그 뜻도 모호하다. 단순히 나열하는 레이아웃을 탈피하자는 의미에서 했다고 하는데.. 말도 안되는 발상이다. UX를 고려한것도 아니고 도데체 이 콘텐츠들은 무슨차이가 있는거지? 라는 쓸데없는 의문을 갖게 될 것이고 콘텐츠를 관리하는 입장에서도 그렇다면 1페이지에 1개만 강조할 수 있고 그럼 그 나머지는 2페이지의 첫번째 콘텐츠보다 추천을 안한다는 뜻인가..? 라는 생각을 하게된다.
결국 의미가 모호한 디자인이라는 것이다. 디자인 자체의 심미성만으로 이런 중요한 레이아웃을 정하는 것은 과하다고 생각한다. 물론 애플의 제품은 디자인을 먼저 만들고 그 하드웨어들과 소프트웨어를 디자인에 맞춰왔고 디자인은 그 자체만으로 엄청난 역할을 할 수 있을 수도 있다. 뭐 아무튼 이것은 내가 선택할 수 있는 사안이 아니었고 설득도 잘 먹히지 않았다.

자 이 시스템 구조는 이렇다.

이미지 없이 설명하려니 어렵지만 일단 해보고 나중에 이미지를 추가하도록 하겠다.
가장 먼저, 싱글톤으로 선언된 VideoManager가 있다. 이곳에서 변수들을 미리 선언해놓고 CSV테이블을 불러와 넣고 그 데이터들을 만들고 뿌리는 함수를 만들어 놓았다.
뭐 함수명만 보더라도 제일 큰 기능이 LoadDataTable, AddVideo, DisplayVideo이다. LoadDataTable는 말 그대로 CSV를 불러와 선언해온 변수를 넣는 함수,
AddVideo는 그 CSV에 저장되어있는 인덱스에 따라 내가 원하는 Video데이터를 추가할 수 있는 함수 그리고 DisplayVideo는 말그대로 UI에 저장되어있는 데이터를 뿌리는 역할을 한다.

그리고 이런 매니저의 기능들을 UI가장 상위오브젝트에 스크립트를 달아놓고 오브젝트들을 가져다 놓고 쏘는 부분이 있고 페이지 가장 안쪽 그러니까 각각의 비디오 슬롯을 프리펩화해놓고 스크립트를 붙여놔서 한번에 출력할 수 있도록 만들어놨다. 어쨋든 이런 방식으로 코딩할때 가장 중요한 것이 아까 말했듯이 VideoManager처럼 데이터를 매니징할 수 있는 부분을 따로 만들어놓고 편리하게 가져다 쓸수있도록 Singleton으로 쓰는것이다.

사실 이 방식은 어떤 인벤토리나 상점같은 UI에 모두 적용할 수 있는 방식이다. 여기서 페이지를 어떻게 구성했나만 들여다보면 페이지 자체를 프리펩화하여 비디오 총갯수에 따라 계산하여 페이지를 미리 생성하고 카테고리에 따라서 페이지를 비활성화, 활성화 하는 방식이다.

public void CreatePageSlot()
{
    if(pageSlot == null)
    {
        pageSlot = new List<GameObject>();
    }
    int pageCount = 0;
    videoCount = VideoManager.Instance.mVideos.Count;

    if(videoCount % 5 == 0)
    {
        pageCount = (videoCount / 5);            
    }
    else
    {
        pageCount = (videoCount / 5) + 1;
    }

    if (pageCount > pageSlot.Count)
    {
        for (int i = pageSlot.Count; i < pageCount; i++)
        {
            GameObject tempSlotObj = Instantiate(Resources.Load("Prefabs/PageSlot")) as GameObject;
            pageSlot.Add(tempSlotObj);
            VideoManager.Instance.pageSlot.Add(tempSlotObj);
            //VideoManager.Instance.mVideoInfoList.Add(mVideoSlot[i].GetComponent<VideoInfo>());
            pageSlot[i].transform.SetParent(mVideoContainer.transform, false);
        }
    }
}

public void SetVideo()
{
    List<GameObject> VideoSlotObjects = new List<GameObject>();

    // 인벤 아이템 정보
    for (int i = 0; i < mVideoContainer.transform.childCount; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            Transform childTransform = mVideoContainer.transform.GetChild(i).GetChild(j);
            VideoSlotObjects.Add(childTransform.gameObject);
        }       
        
    }
    VideoManager.Instance.mVideoInfos = VideoSlotObjects.ToArray();

    for (int i = 0; i < VideoManager.Instance.mVideoInfos.Length; i++)
    {
        VideoManager.Instance.mVideoInfos[i].GetComponent<VideoInfo>().CreateVideo(i);
    }
}

뭐 이런식으로 말이다.

사실 이 부분에서 여러가지 옵션이 있었지만 이런 방식을 적용한것은 내가 생각하는 한 효율적이라고 생각했기 때문이다. 많은 수의 슬롯을 생성할 필요도 없고 처음 생성만 하면 그 후로는 오브젝트 활성화/비활성화와 데이터 넣기의 반복일 뿐이라서 특별한 문제도 일어나지 않을 것이라 생각한다.

profile
한줄로는 어렵다

0개의 댓글