게임개발 예제모음

스크롤뷰 방향키로 조작하기 본문

유니티 메모장

스크롤뷰 방향키로 조작하기

게임을만들어보자 2025. 6. 9. 12:40

○ 구현목표

- 유니티의 스크롤뷰는 마우스(또는 터치)등을 통한 드래그 또는 스크롤바를 조작하여 동작한다
- 이 포스팅에선 UI상 목록을 버튼(Button)으로 구현하며 현재 보이는 영역보다 목록이 더 많아 스크롤이 필요한 경우를 한정한다.
- 또한 버튼의 이동은 컨트롤러 또는 키보드등 InputSystem의 Vector2값으로 이동하는 경우를 위주로 서술한다.
  ※ 어차피 마우스나 터치 조작은 다른 설정 없이도 잘 작동하기 때문이다.

 

○ 또한 이 포스팅은 아래의 포스팅에서 설명한 현재 선택중인 버튼을 확인하는 EventSystem기능을 활용한다.

2025.06.05 - [유니티 메모장] - 현재 선택중인 버튼 확인

 

현재 선택중인 버튼 확인

2025.06.04 - [유니티 메모장] - UI만들기 : 하위 메뉴버튼 이동 및 복귀 UI만들기 : 하위 메뉴버튼 이동 및 복귀○ 구현목표메인메뉴에서의 선택으로 하위메뉴 버튼이 나타나 커서가 이동서브메뉴를

capsuleer.tistory.com

○ 방향키를 통한 버튼 이동은 아래 포스팅을 참고 하자.

2025.06.03 - [유니티 메모장] - UI 만들기 : 버튼 선택

 

UI 만들기 : 버튼 선택

○ 새로 메뉴를 구성하고 컨트롤러(액션맵)을 통한 선택이 가능하도록 구성○ 원하는 메뉴를 만들기 위한 버튼 오브젝트 추가○ 추가한 버튼을 정렬 * Creat Empty를 이용하여 빈 오브젝트 생성후

capsuleer.tistory.com

 

 

○ 구현방법

- 최초에 스크롤뷰 내부에 버튼의 위치를 받아와서 화면을 벗어날 경우 스크롤바를 움직이는 로직을 구성했음.
- 하지만 스크롤뷰 내부의 버튼은 스크롤뷰 부모 오브젝트의 상대 위치를 받아오면서 화면 밖으로 벗어나는지 판단하지 못한다.
- 따라서 별도 스크롤뷰 외부에 RectTransform을 보유한 오브젝트를 추가하고 이 오브젝트를 기준점으로 스크롤을 조절한다.

 

 

○ 버튼 배치

  ① 버튼 배치 전에 스크롤뷰 오브젝트를 만든다. [ Hierarchy (우클릭) -  UI - Scroll View]

 

  ② 스크롤뷰를 만들면 자식 오브젝트로 Viewport, Scrollbar Horizontal, Scrollbar Vertical이 같이 생성된다.

    ※ 스크롤 시킬 오브젝트 (버튼따위)는 Viewport - Content 하위에 위치시킨다.

    ※ Scrollview의 Scroll Rect 컴포넌트에서 Movement Type을 [Unrestricted]로 변경한다.

옵션명 기능
Unrestricted 제한 없음
Elastic Viewport 내부의 컨텐트 내용이 화면 밖으로 벗어나면 부드럽게 화면 안으로 복귀시킨다
Clamped Viewport 내부의 컨텐트 내용이 화면 밖으로 벗어나지 못한다

    ※ 이 포스팅에선 유저의 움직임에 따라 수동으로 스크롤을 조절하므로 제한이 없는 Unrestricted로 설정한다.

    ※ 이 포스팅에선 가로 스크롤은 사용하지 않으므로 Scrollbar Horizontal은 비활성화 한다.

    ※ 스크롤뷰 외부에 위치 확인을 위한 오브젝트 하나를 생성한다. (Empty Object로 충분함 - 이후 Cursor오브젝트로 기술)

 

  ③ Cursor의 위치 확인을 위한 스크립트 작성  (MyPosition.cs)

    ※ 새로운 스크립트를 생성하여 Cursor에 추가

    ※ 스크립트 작성 - 변수 설정

using UnityEngine;
using UnityEngine.EventSystems;

public class MyPosition : MonoBehaviour
{
	// EventSystem을 캐싱하기위한 변수 선언
    [SerializeField] GameObject ObjectEventSystem;
    EventSystem myEventSystem;
    
    // Cursor오브젝트의 위치변경 및 현재위치 확인을 위한 변수
    RectTransform myRectTransform;
    
    // 오브젝트의 위치 확은 후  y좌표값을 저장하기위한 변수
    [HideInInspector] public float cursorVertical;
    
    void Start()
    {
    	// Cursor오브젝트의 RectTransfrom캐싱
        myRectTransform = GetComponent<RectTransform>();
        
        // objectEventSystem의 EventSystem캐싱
        myEventSystem = ObjectEventSystem.GetComponent<EventSystem>();
    }
}

      - cursorVertical변수는 다른 스크립트에서도 참조하기 때문에 public변수로 선언

      - 다만 인스펙터에선 보이지 않는것을 원하기 때문에 앞에 [HideInInspector]를 붙여준다

 

    ※ 선언한 objectEventSystem에 EventSystem오브젝트를 어태치

    ※ 스크립트 작성 - 오브젝트의 위치 변경 및 현재 Y좌표값 반환

void Update()
{
	// 선택중인 버튼의 현재 위치값을 저장
    var temp = myEventSystem.currentSelectedGameObject.transform.position;
    // 위에서 확인한 위치로 Cursor오브젝트 이동
    myRectTransform.position = temp;
    // Cursor오브젝트의 Y좌표값 저장
    cursorVertical = myRectTransform.anchoredPosition.y;
}

 

  ④ Scrollbar Vertical 조절을 위한 스크립트 작성 (AutoScroll.cs)

    ※ 새로운 스크립트를 생성하여 Cursor에 추가

    ※ 스크립트 작성 - 변수선언

public class AutoScroll : MonoBehaviour
{
    //ScrollView 관련 변수 선언
    [SerializeField] GameObject scrollWindow; //오브젝트 캐싱
    RectTransform scrollRectTransfrom; // 오브젝트 캐싱
    Vector2 scrollViewSize; // ScrollView의 크기
    Vector2 scrollViewPos; // ScrollView의 위치
    float svMax; // ScrollView의 최상단 좌표
    float svMin; // ScrollView의 최하단 좌표


    //Cursor 관련 변수 선언
    [SerializeField] GameObject objectCursor; // 오브젝트 캐싱
    MyPosition cusorPosition; // 오브젝트 캐싱
    
    //Scrollbar Vertical 관련 변수 선언
    [SerializeField] float scrollSpeed = 0.1f;
    Scrollbar myScrollbar;
}

    ※ 관련 오브젝트 어태치

    ※ 스크립트 작성 - 변수 초기화

void Start()
{
	// Scrollbar 캐싱
    myScrollbar = GetComponent<Scrollbar>();
    
    // Cursor오브젝트의 스크립트 MyPosition 캐싱
    cusorPosition = objectCursor.GetComponent<MyPosition>();
    
    // ScrollView의 RectTransform캐싱
    scrollRectTransfrom = scrollWindow.GetComponent<RectTransform>();

	// ScrollView의 세로 크기 확인
    scrollViewSize.y = scrollRectTransfrom.rect.height;
    // ScrollView의 세로좌표 확인
    scrollViewPos.y = scrollRectTransfrom.anchoredPosition.y;

	// ScrollView의 최상단, 최하단 위치 확인
    svMax = scrollViewPos.y + (scrollViewSize.y / 2) - 50;
    svMin = scrollViewPos.y - (scrollViewSize.y / 2) + 50;
}

    ※ 스크립트 작성 - Scrollbar Vertical 조절 (Scrollbar 컴포넌트의 Value속성)

void Update()
{
    if (scrollWindow.activeInHierarchy) // Scrollview오브젝트가 활성화시에만 동작
    {
        if (cusorPosition.cursorVertical < svMin) // Cursor가 최하단 아래에 위치할 때
        {
            myScrollbar.value -= scrollSpeed * Time.deltaTime; // Value값을 삭감
        }
        else if (cusorPosition.cursorVertical > svMax) // Cursor가 최상단 위에 위치할 때
        {
            myScrollbar.value += scrollSpeed * Time.deltaTime; // Value값을 증가
        }
    }
}

 

 

○ 실행 테스트

 

 

○ 스크립트 전문

  ※ MyPosition.cs

using UnityEngine;
using UnityEngine.EventSystems;

public class MyPosition : MonoBehaviour
{

    [SerializeField] GameObject ObjectEventSystem;
    EventSystem myEventSystem;

    RectTransform myRectTransform;
    
    [HideInInspector] public float cursorVertical;

    void Start()
    {
        myRectTransform = GetComponent<RectTransform>();
        myEventSystem = ObjectEventSystem.GetComponent<EventSystem>();
    }

    void Update()
    {
        var temp = myEventSystem.currentSelectedGameObject.transform.position;
        myRectTransform.position = temp;
        cursorVertical = myRectTransform.anchoredPosition.y;
    }
}

  ※ AutoScroll.cs

using UnityEngine;
using UnityEngine.UI;

public class AutoScroll : MonoBehaviour
{
    [SerializeField] GameObject scrollWindow;
    RectTransform scrollRectTransfrom;
    Vector2 scrollViewSize;
    Vector2 scrollViewPos;
    float svMax;
    float svMin;

    [SerializeField] GameObject objectCursor;
    MyPosition cusorPosition;
    
    [SerializeField] float scrollSpeed = 0.1f;
    Scrollbar myScrollbar;

    void Start()
    {
        myScrollbar = GetComponent<Scrollbar>();
        cusorPosition = objectCursor.GetComponent<MyPosition>();
        scrollRectTransfrom = scrollWindow.GetComponent<RectTransform>();

        scrollViewSize.y = scrollRectTransfrom.rect.height;
        scrollViewPos.y = scrollRectTransfrom.anchoredPosition.y;

        svMax = scrollViewPos.y + (scrollViewSize.y / 2) - 50;
        svMin = scrollViewPos.y - (scrollViewSize.y / 2) + 50;
    }

    void Update()
    {
        if (scrollWindow.activeInHierarchy)
        {
            if (cusorPosition.cursorVertical < svMin)
            {
                myScrollbar.value -= scrollSpeed * Time.deltaTime;
            }
            else if (cusorPosition.cursorVertical > svMax)
            {
                myScrollbar.value += scrollSpeed * Time.deltaTime;
            }
        }
    }
}