본문 바로가기
개발/Unity 내일배움캠프 TIL

Unity2D 궁수의 전설 UI 따라만들기 (1)

by 석시 2023. 9. 19.



다음 영상을 참고하여 제작하면서 나오는 방법들을 정리해보았다.

궁수의 전설 UI 수직 수평 스크롤 뷰 완벽하게 만들기
예전부터 궁수의 전설 UI가 정말 궁금했는데, 만들었습니다! UI가 굉장히 세련되고 움직이는 게 신기해서 열심히 연구해 봤는데요 수직 수평 스크롤 뷰를 이용하면 많은 분야에서 멋진 UI를 만드실 수 있습니다 탭 버튼 움직이는 것도 만족스러워요~ 보너스로 초간단 탭 메뉴도 이 영상에 포함했습니다 아래 탭 클릭시 수직으로 올라가는 것은 블로그와 스크립트 수정되었습니다. # 스크립트 보기 https://goraniunity2d.blogspot.com/2020/02/ui.html # 프로젝트, 리소스 다운받기 https://drive.google.com/file/d/1QL3u_CEF9qQA8Yhf50fa2UIroacjlM7x/view?usp=sharing
https://youtu.be/K_ujyelRZUA?si=KRGwSosmElfD3GoH


프로젝트 세팅

2D 프로젝트를 하나 새로 생성하고 화면비를 1080x1920으로 만들자.


스프라이트 준비

위 영상에서 사용한 애셋은 다음 링크에서 받을 수 있다.

https://drive.google.com/file/d/1QL3u_CEF9qQA8Yhf50fa2UIroacjlM7x/view

UI에 사용할 애셋들의 기본 설정을 해줘야 한다.

Inspector에서 속성을 변경할 Sprite 선택 → Pixels Per Unit을 26으로 지정 → Filter Mode를 Point (no filter) 로, Compression을 None으로 지정

이제 Sprite Mode를 Multiple로 바꾸고 Sprite Editor에서 Sprite를 다음과 같이 잘라주자.

Grid by Cell count로 Slice 한 뒤 개별 설정을 해주면 된다.


Horizontal Scroll View 세팅

Hierarchy에 우클릭 후 UI → Scroll View 생성

Canvas 크기 설정

이 때 씬에 보이는 Canvas가 너무 크니 크기를 적당히 줄여주자.

Canvas의 Inspector에서 Canvas → Render Mode를 Screen Space - Camera로 설정

그 후 Render Camera를 씬의 Main Camera로 설정해주자.

이제부턴 작업이 제법 된다.

Canvas에 Canvas Scaler Component 추가 → UI Scale Mode를 Scale With Screen Size로 설정 → Reference Resolution을 X: 1080, Y: 1920으로 설정 → Screen Match Mode를 Expand로 지정

이렇게 만들면 비율이 정확하게 맞는다.

Scroll View 크기 설정

Scroll View의 Rect Transform을 다음과 같이 설정

이 스크롤은 좌우로만 움직이게 하고 싶은데 세로로도 스크롤이 가능하다.

세로 스크롤이 가능하게 만들어주는 자식을 제거하자.

Scroll View의 자식 중 Scrollbar Vertical을 삭제

그렇게 만들면 가로로 밖에 스크롤이 되지 않는다.

하지만 스크롤 뷰의 바가 보이기 때문에 이를 보이지 않게 가려주도록 하자.

Scroll View의 Inspector → Scroll Rect에서 Spacing을 0으로 설정 → 자식 Scrollbar Horizontal의 Rect Transform에서 Right와 Height를 0으로 설정 & Anchor의 Max도 전부 0으로 설정 → 마찬가지로 모든 자식 오브젝트의 Rect Transform의 Position값을 전부 0으로 설정

이제 Scroll View 안에 내용을 추가해주자.

다음과 같이 Scroll View를 생성했으면 Viewport 아래에 기본적으로 Content라는 자식이 추가되어 있는 것을 볼 수 있다.

Content의 자식으로 Image를 네 개 추가 → Content에 Component로 Horizontal Layout Group 추가

이 때 같이 추가된 Component인 Content Size Filter에서 Horizontal FitPreferred Size로 설정해주면 크기도 자동으로 맞춰주게 된다.

모든 크기를 Canvas size인 1080x1750.8에 맞춰주자.

구분을 위해 각 패널의 색깔도 적절히 바꿔주자.

기본적인 모양이 나온다.

현재 상태로라면 세로로도 움직여지는데, 세로 움직임은 Scroll Rect에서 막을 수 있다.

Scroll View의 Inspector에서 → Scroll Rect의 Vertical을 체크 해제

이제 완벽하게 가로로만 움직인다.

자석처럼 붙는 화면 패널 만들기

위 화면에서 아무런 조작을 가하지 않을 때, 한 색깔만 보이게 자동으로 조정되도록 하고 싶다.

이를 구현해보자.

Nested Scroll Manager라는 이름의 스크립트 생성 후 Scroll View에 추가

스크립트의 상단에 using UnityEngine.EventSystems;를 추가해주고, 다음과 같은 인터페이스들을 상속하게 해주자.

 
using UnityEngine;
using UnityEngine.EventSystems;

public class NestedScrollManager : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{

}
 

이걸 사용하지 않고 만약 Update()에서 Input.GetMouseButton(0)을 사용해서 구현하면 해당 스크립트는 스크롤뷰를 참조하는 것이 아니라서 바깥을 마우스로 클릭해도 해당 스크립트가 실행이 된다.

해당 스크롤뷰 안에서만 마우스 입력을 받고 싶기 때문에 해당 작업들을 해주는 것이다.

IBeginDragHandler, IDragHandler, IEndDragHandlerUnityEngine.EventSystemsIEventSystemHandler를 상속받는 애들이다.

해당 스크립트가 스크롤 뷰에 붙어 있기 때문에 이 범위 안에서만 이벤트를 수신받게 된다.

바깥은 클릭해도 이벤트 수신이 되지 않는 것이다.

IBeginDragHandler는 드래그를 시작했을 때, IDragHandler는 드래그를 하는 중일 때, IEndDragHandler는 드래그가 끝났을 때 이벤트를 수신한다.

참고로 인터페이스의 내용을 스크립트 안에서 구현을 해줘야 하는데, 이 형태를 간단하게 하는 방법이 있다.

아직 구현이 안되어서 에러를 뱉는다.

빨간 줄이 쳐진 인터페이스를 우클릭 → 빠른 작업 및 리팩터링을 클릭 후 인터페이스 구현 클릭

그러면 다음과 같이 인터페이스 구현부를 알아서 작성해준다.

이 때 eventData.delta를 참조할 수 있는데, 이는 마우스 포인터 위치의 순간변화율을 의미한다.

미분값이기 때문에 속도가 빠를수록 높게 나온다.

이제 스크립트를 다음과 같이 써주고, Inspector에서 다음과 같이 연결해주자.

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class NestedScrollManager : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    [SerializeField] Scrollbar scrollbar;

    const int SIZE = 4; // Contents의 자식(패널) 개수
    float[] pos = new float[SIZE]; // 각 패널의 Scrollbar value값 저장
    float distance; // pos들 간의 간격

    float targetPos; // 목표 위치 : Update에서 해당 위치로 서서히 움직임
    bool isDrag; // 현재 드래그 중인지 아닌지 확인
    
    void Start()
    {
        distance = 1f / (SIZE - 1);
        for (int i = 0; i < SIZE; ++i) pos[i] = distance * i;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        isDrag = true;
    }

    public void OnDrag(PointerEventData eventData)
    {
        
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        isDrag = false;

        for (int i = 0; i < SIZE; ++i)
            if (scrollbar.value < pos[i] + distance * 0.5f && scrollbar.value > pos[i] - distance * 0.5)
            {   // 스크롤뷰 드래그를 멈추면 한 패널만 보이도록 위치를 조정
                targetPos = pos[i];
            }
    }

    void Update()
    {
        if (!isDrag) scrollbar.value = Mathf.Lerp(scrollbar.value, targetPos, 0.1f);
    }
}

자석처럼 착하고 붙는다.

이동 위치가 반을 넘어가지 않아도 드래그 속도가 충분히 빠를 경우에 패널이 넘어가게 할 수 있을까?

코드를 다음과 같이 고쳐주자.

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class NestedScrollManager : MonoBehaviour, IBeginDragHandler, IEndDragHandler
{
    [SerializeField] Scrollbar scrollbar;
    [SerializeField] float thresholdSpeed = 18f;

    const int SIZE = 4; // Contents의 자식(패널) 개수
    float[] pos = new float[SIZE]; // 각 패널의 Scrollbar value값 저장
    float distance; // pos들 간의 간격

    bool isDrag; // 현재 드래그 중인지 아닌지 확인
    float curPos; // 기존 위치
    float targetPos; // 목표 위치 : Update에서 해당 위치로 서서히 움직임
    
    void Start()
    {
        distance = 1f / (SIZE - 1);
        for (int i = 0; i < SIZE; ++i) pos[i] = distance * i;
    }

    float SetPos()
    {
        for (int i = 0; i < SIZE; ++i)
            if (scrollbar.value < pos[i] + distance * 0.5f && scrollbar.value > pos[i] - distance * 0.5)
            {   // 절반거리를 기준으로 가까운 위치를 반환
                return pos[i];
            }
        return 0f;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        isDrag = true;
        curPos = SetPos();
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        isDrag = false;

        targetPos = SetPos();
        // 스크롤뷰 드래그를 멈추면 한 패널만 보이도록 targetPos를 설정
        if (curPos == targetPos)
        {
            if (eventData.delta.x > thresholdSpeed && curPos - distance >= 0)
                targetPos = curPos - distance;
            else if (eventData.delta.x < -thresholdSpeed && curPos + distance < 1f)
                targetPos = curPos + distance;
        }
    }

    void Update()
    {
        if (!isDrag) scrollbar.value = Mathf.Lerp(scrollbar.value, targetPos, 0.1f);
    }
}

이렇게 하면 속도가 충분히 빨라도 넘어가게 된다.

이제 각 패널마다 세로 스크롤을 추가해줄 차례다.

이는 다음 글에서 다루도록 하겠다.

Unity 2D 궁수의 전설 UI 따라만들기 (2)
다음의 영상을 참고하여 궁수의 전설 UI를 제작하고 있다. 궁수의 전설 UI 수직 수평 스크롤 뷰 완벽하게 만들기예전부터 궁수의 전설 UI가 정말 궁금했는데, 만들었습니다! UI가 굉장히 세련되고 움직이는 게 신기해서 열심히 연구해 봤는데요 수직 수평 스크롤 뷰를 이용하면 많은 분야에서 멋진 UI를 만드실 수 있습니다 탭 버튼 움직이는 것도 만족스러워요~ 보너스로 초간단 탭 메뉴도 이 영상에 포함했습니다 아래 탭 클릭시 수직으로 올라가는 것은 블로그와 스크립트 수정되었습니다. # 스크립트 보기 https://goraniunity2d.blogspot.com/2020/02/ui.html # 프로젝트, 리소스 다운받기 https://drive.google.com/file/d/1QL3u_CEF9qQA8Yhf50..
https://seoksii.tistory.com/48

Uploaded by N2T