본문 바로가기

Unity3D/C#

유니티 드롭다운(TMP Dropdown) 값 읽기 · 옵션 코드로 넣기

반응형

DROPDOWN TMP_Dropdown

 

유니티 TMP Dropdown 에서 고른 값은 value(몇 번째 칸, 0 부터)로 읽고, 그 칸의 글자는 options[value].text 로 읽습니다. 고를 때마다 무언가를 하려면 onValueChanged 에 함수를 붙입니다.

 

int index = dropdown_quality.value;                         // 몇 번째(0 부터)
string name_option = dropdown_quality.options[index].text;  // 그 칸의 글자

 

설정 화면의 그래픽 품질, 언어, 해상도처럼 고를 것이 여러 개면 버튼보다 드롭다운이 자리를 덜 차지합니다. 이 블로그의 예전 글 UI Dropdown 기능 할당/삭제 는 레거시 Dropdown 에 이미지 옵션을 붙이는 예제였습니다. 요즘 Unity 에서 UI > Dropdown - TextMeshPro 로 만들면 붙는 컴포넌트는 TMP_Dropdown 이라 형도 네임스페이스도 다릅니다. 이번 글에서는 TMP_Dropdown 에 프로젝트의 그래픽 품질 단계를 코드로 채우고, 고르면 품질이 바로 바뀌는 드롭다운을 만들어 보겠습니다. 코드로 값을 바꿀 때 onValueChanged 가 불리는 경우와 안 불리는 경우도 함께 정리합니다.

 

C# (UNITY 3D)

 

TMP 드롭다운 웹 데모 — 목록에서 고르거나 value 에 넣으면 onValueChanged 가 불리고, SetValueWithoutNotify 와 같은 칸 다시 고르기는 이벤트가 없다

▲ 아래 QualityDropdown 과 TMP_Dropdown 의 동작을 옮긴 웹 데모입니다(Unity 화면 아님). 칸은 새 프로젝트의 기본 품질 단계 여섯 개입니다.

 

목록에서 다른 칸을 고르거나 value 에 값을 넣으면 onValueChanged 가 불리고 아래 결과 글자도 바뀝니다. SetValueWithoutNotify 로 바꾸면 드롭다운 글자만 바뀌고 이벤트는 불리지 않습니다. 이미 골라져 있는 칸을 다시 골라도 값이 그대로라 이벤트가 없습니다.

 

1. 준비 — Dropdown - TextMeshPro 하나와 글자 하나

 

Hierarchy 에서 UI > Dropdown - TextMeshPro 로 드롭다운을 만들고, 고른 값을 보여 줄 글자는 UI > Text - TextMeshPro 로 하나 만듭니다. 아래 QualityDropdown 스크립트는 드롭다운 오브젝트에 직접 붙입니다. 같은 오브젝트의 TMP_Dropdown 을 GetComponent 로 가져오기 때문에 드롭다운은 따로 할당하지 않고, text_result 칸에만 글자를 끌어다 넣으면 됩니다.

 

using System.Collections.Generic;
using UnityEngine;
using TMPro;

 

옵션 이름을 List<string> 으로 넘기려고 System.Collections.Generic 을, TMP_Dropdown 과 TMP_Text 를 쓰려고 TMPro 를 사용합니다. TMP_Dropdown 만 쓰면 UnityEngine.UI 는 없어도 됩니다.

 

2. 그래픽 품질 드롭다운 코드

 

using System.Collections.Generic;
using UnityEngine;
using TMPro;

//CodeFinder 코드파인더
//From https://codefinder.janndk.com/
[RequireComponent(typeof(TMP_Dropdown))]
public class QualityDropdown : MonoBehaviour
{
    public TMP_Text text_result;          // 고른 값을 보여 줄 글자(없어도 됨)

    TMP_Dropdown dropdown_quality;

    void Awake()
    {
        dropdown_quality = GetComponent<TMP_Dropdown>();
    }

    void Start()
    {
        Init_Options();

        dropdown_quality.onValueChanged.RemoveAllListeners();          // 코드로 단 리스너만 지움(Inspector 에서 단 것은 남음)
        dropdown_quality.onValueChanged.AddListener(On_ValueChanged);
    }

    void Init_Options()
    {
        List<string> list_names = new List<string>(QualitySettings.names);

        dropdown_quality.ClearOptions();              // Inspector 에 적어 둔 Option A · B · C 를 지움
        dropdown_quality.AddOptions(list_names);      // 프로젝트의 품질 단계 이름으로 다시 채움

        // 지금 품질을 보여 주기만 하고 onValueChanged 는 부르지 않음
        dropdown_quality.SetValueWithoutNotify(QualitySettings.GetQualityLevel());
        Show_Result();
    }

    void On_ValueChanged(int index)
    {
        QualitySettings.SetQualityLevel(index, true);
        Show_Result();
    }

    public void Show_Result()
    {
        if (text_result == null || dropdown_quality.options.Count == 0)
            return;

        int index = dropdown_quality.value;                         // 몇 번째(0 부터)
        string name_option = dropdown_quality.options[index].text;  // 그 칸의 글자
        text_result.text = string.Format("value {0} : {1}", index, name_option);
    }
}

 

Play 하면 드롭다운에 처음 들어 있던 Option A · B · C 가 지워지고 Edit > Project Settings > Quality 에 있는 품질 단계 이름이 들어갑니다. 확인에 쓴 빈 프로젝트(빌트인 렌더 파이프라인)는 Very Low 부터 Ultra 까지 여섯 단계였고, 템플릿마다 단계 수와 이름이 다를 수 있습니다. 지금 품질 단계가 골라진 채로 시작하고, 다른 칸을 고르면 QualitySettings.SetQualityLevel 로 품질이 바뀐 뒤 text_result 에 「value 3 : High」 처럼 번호와 이름이 보입니다.

이 스크립트는 Unity 6000.6.3f1(TextMeshPro 가 들어 있는 ugui 2.6.0)에서 컴파일 오류 없이 들어가고, 오브젝트에 붙여 Awake · Start 를 불러 봤을 때 예외가 없었습니다. 품질이 실제로 바뀌는 모습은 Game 창에서 눈으로 본 것이 아닙니다.

 

변수(variable)
text_result(TMP_Text) : 고른 번호와 이름을 보여 줄 글자
dropdown_quality(TMP_Dropdown) : 같은 오브젝트의 드롭다운

 

함수(function)
Init_Options : 옵션을 지우고 품질 단계 이름으로 다시 채운 뒤, 지금 품질을 골라 둡니다.
On_ValueChanged : 드롭다운에서 고를 때마다 불려 품질을 바꿉니다.
Show_Result : value 와 options[value].text 를 읽어 글자로 보여 줍니다.

 

3. 고른 값 읽기 — value 와 options[value].text

 

value 는 int 로, 맨 위 칸이 0 입니다. 화면에 보이는 글자가 필요하면 options[value].text 를 읽습니다. onValueChanged 에 붙인 함수는 이 value 를 인자로 받으므로 On_ValueChanged(int index) 의 index 와 dropdown_quality.value 는 같은 값입니다.

이 예제는 QualitySettings.names 를 순서 그대로 넣었기 때문에 드롭다운의 번호가 곧 품질 단계 번호입니다. Unity 문서는 품질 단계가 늘 같은 번호에 있다고 기대하지 말고 목록을 받아서 그 번호를 쓰라고 적고 있는데, 이렇게 채우면 그 조건이 맞습니다. 옵션을 따로 고른 순서로 넣었다면 번호 대신 글자로 찾아야 합니다(5절).

 

4. 코드로 고르기 — value 대입 vs SetValueWithoutNotify

 

dropdown_quality.value = index;                   // 값이 바뀌면 onValueChanged 가 불림
dropdown_quality.SetValueWithoutNotify(index);    // 글자만 바뀌고 onValueChanged 는 안 불림

 

TMP_Dropdown 값 바꾸는 방법과 onValueChanged — 목록에서 고르기 · value 대입은 불림, SetValueWithoutNotify · ClearOptions · AddOptions · options.Add 는 안 불림

 

저장해 둔 설정을 불러와 드롭다운에 보여 줄 때는 SetValueWithoutNotify 를 씁니다. value 에 넣으면 onValueChanged 가 불려, 불러오기만 했는데 저장 · 적용 코드가 한 번 더 돕니다. Init_Options 에서도 같은 이유로 SetValueWithoutNotify 를 썼습니다.

하나 더 있습니다. ClearOptions 는 value 를 0 으로 되돌립니다(Placeholder 를 쓰면 -1). 그래서 다시 채운 뒤 value = 0 을 넣으면 값이 이미 0 이라 이벤트가 불리지 않고, 다른 번호를 넣을 때만 불립니다. 처음에 적용까지 해야 한다면 value 대입에 기대지 말고 SetValueWithoutNotify 로 보여 준 다음 적용 함수를 직접 부르는 편이 늘 같은 결과를 냅니다(ugui 2.6.0 의 TMP_Dropdown 소스 기준 · 플레이 중에는 같은 값이거나 옵션이 비어 있으면 값 바꾸기가 바로 끝남).

 

5. 옵션을 직접 고쳤을 때 — RefreshShownValue

 

dropdown_quality.options.Add(new TMP_Dropdown.OptionData(name_option));
dropdown_quality.RefreshShownValue();

dropdown_quality.options[dropdown_quality.value].text = name_option;
dropdown_quality.RefreshShownValue();

int index = dropdown_quality.options.FindIndex(o => o.text == name_option);   // 이름으로 칸 찾기
if (index >= 0)
    dropdown_quality.SetValueWithoutNotify(index);

 

AddOptions 와 ClearOptions 는 끝에서 드롭다운 글자를 알아서 새로 그립니다. options 리스트를 직접 고칠 때는 그렇지 않아서, 지금 골라진 칸의 text 를 바꾸거나 비어 있던 드롭다운에 options.Add 로 첫 칸을 넣으면 화면의 글자가 그대로 남습니다. 리스트를 직접 고쳤으면 RefreshShownValue 를 한 번 불러 두면 됩니다. options 는 List 라서 FindIndex 로 글자가 같은 칸의 번호를 찾을 수 있고, 못 찾으면 -1 이 나옵니다.

 

6. 드롭다운이 이상할 때 — 자주 하는 실수

 

public Dropdown 칸에 TMP 드롭다운이 안 들어감
UnityEngine.UI 의 Dropdown 과 TMPro 의 TMP_Dropdown 은 서로 다른 형입니다. UI > Dropdown - TextMeshPro 로 만든 오브젝트는 TMP_Dropdown 으로 받아야 끌어다 넣을 수 있습니다. 예전 글 /8 의 코드를 TMP 드롭다운에 쓰려면 형 이름과 using 을 바꿉니다.

 

같은 칸을 다시 골랐는데 아무 일도 안 일어남
onValueChanged 는 값이 바뀔 때만 불립니다. 「다시 적용」 처럼 같은 칸을 골라도 해야 하는 일이라면 드롭다운 옆에 버튼을 따로 둡니다.

 

한 번 골랐는데 함수가 두 번 불림
RemoveAllListeners 는 코드로 붙인 리스너만 지우고, Inspector 의 On Value Changed (Int32) 칸에 넣어 둔 함수는 그대로 둡니다. 같은 함수를 Inspector 와 코드 양쪽에 붙였다면 한쪽을 빼세요.

 

ArgumentOutOfRangeException
옵션이 하나도 없을 때 options[value] 를 읽으면 납니다. ClearOptions 바로 뒤나 목록을 아직 못 채운 때가 그렇습니다. Show_Result 처럼 options.Count 를 먼저 보고, Placeholder 를 쓴다면 value 가 -1(아무것도 안 고름)인지도 봅니다.

 

함께 보기: 드롭다운 칸에 아이콘 이미지를 넣는 방법은 예전 글 UI Dropdown 기능 할당/삭제 (이미지,텍스트 옵션 추가) 에 있습니다. 레거시 Dropdown 기준이지만 OptionData 에 글자와 이미지를 함께 넣는 방식은 TMP_Dropdown 도 같습니다.

 

TMP_Dropdown 동작은 Unity 공식 문서 TMP_Dropdown · Dropdown · QualitySettings.SetQualityLevel · UnityEventBase.RemoveAllListeners 를 기준으로 적었습니다.

 

 

반응형

Google Play 및 Google Play 로고는 Google LLC의 상표입니다.