
유니티 Slider 는 값이 바뀔 때마다 onValueChanged 가 불리고, 그 값을 TMP 글자에 넣으면 「볼륨 70%」 같은 표시가 됩니다. 정수로만 움직이게 하려면 wholeNumbers 를, 저장해 둔 값을 이벤트 없이 넣으려면 SetValueWithoutNotify 를 씁니다.
slider.onValueChanged.AddListener(value => Debug.Log(value)); // 움직일 때마다 불림
slider.SetValueWithoutNotify(0.5f); // 값만 바꾸고 이벤트는 안 부름
게임 설정 화면의 볼륨, 밝기, 마우스 감도는 대부분 슬라이더로 만듭니다. 슬라이더를 움직이면 숫자가 따라 바뀌고, 게임을 껐다 켜도 그 값이 남아 있어야 합니다. 이 블로그의 예전 글 UI Slider 기능 할당/삭제 in Script 는 예전 Text 로 값을 보여 주고 최솟값 · 최댓값 · 정수 단계를 스크립트로 정하는 데까지였습니다. 이번 글에서는 TMP 글자로 값을 보여 주고, PlayerPrefs 에 저장했다가 다음 실행 때 불러오는 볼륨 슬라이더를 만들겠습니다. 불러오는 순간 onValueChanged 가 불려 저장이 한 번 더 일어나는 문제도 함께 막겠습니다.
C# (UNITY 3D)

▲ 아래 VolumeSlider 의 동작을 옮긴 웹 데모입니다(Unity 화면 아님). 불러오기와 저장 흐름은 Unity 에서 확인한 결과와 같습니다.
처음 실행하면 저장된 값이 없어 70 으로 시작하고, 이때 onValueChanged 는 한 번도 불리지 않습니다. 손잡이를 끌면 정수가 바뀔 때마다 onValueChanged 가 불려 글자가 바뀌고 값이 저장됩니다. 다시 실행하면 저장된 25 에서 시작합니다.
1. 준비 — 슬라이더 하나와 글자 하나
Hierarchy 에서 UI (Canvas) > Slider 로 슬라이더를, UI (Canvas) > Text - TextMeshPro 로 값을 보여 줄 글자를 만듭니다(예전 버전 메뉴는 UI > …). VolumeSlider 는 Canvas 나 빈 오브젝트에 붙이고, slider_volume 칸에 슬라이더를, text_volume 칸에 글자를 끌어다 넣습니다. 최솟값 · 최댓값 · Whole Numbers 는 코드가 정하므로 인스펙터 값은 그대로 두어도 됩니다.
using UnityEngine;
using UnityEngine.UI;
using TMPro;
Slider 를 쓰기 위해 UnityEngine.UI 를, TMP_Text 를 쓰기 위해 TMPro 를 사용합니다.
2. 볼륨 슬라이더 코드
using UnityEngine;
using UnityEngine.UI;
using TMPro;
//CodeFinder 코드파인더
//From https://codefinder.janndk.com/
public class VolumeSlider : MonoBehaviour
{
public Slider slider_volume; // 볼륨 슬라이더
public TMP_Text text_volume; // 「볼륨 70%」 를 보여 줄 글자
const string KEY_VOLUME = "volume"; // PlayerPrefs 에 저장할 이름
void Start()
{
if (slider_volume == null)
return;
Init_Slider();
int volume_saved = PlayerPrefs.GetInt(KEY_VOLUME, 70); // 저장된 값(처음이면 70)
slider_volume.SetValueWithoutNotify(volume_saved); // 불러올 때는 이벤트 없이
Apply_Volume(slider_volume.value); // 글자와 소리는 직접 한 번 맞춤
slider_volume.onValueChanged.RemoveAllListeners();
slider_volume.onValueChanged.AddListener(Change_Volume); // 이제부터 움직일 때마다
}
void Init_Slider()
{
slider_volume.minValue = 0;
slider_volume.maxValue = 100;
slider_volume.wholeNumbers = true; // 0, 1, 2 … 100 정수로만
}
void Change_Volume(float value)
{
Apply_Volume(value);
PlayerPrefs.SetInt(KEY_VOLUME, (int)value); // 바뀔 때마다 저장
}
void Apply_Volume(float value)
{
AudioListener.volume = value / 100f; // 0~100 을 0~1 로
if (text_volume != null)
text_volume.text = "볼륨 " + (int)value + "%";
}
}
Play 하면 「볼륨 70%」 가 보이고, 슬라이더를 움직이면 글자와 AudioListener.volume 이 함께 바뀝니다. 바뀐 값은 바로 PlayerPrefs 에 저장되어 다음 실행 때 그 값에서 시작합니다.
이 스크립트는 Unity 6000.6.3f1 에서 컴파일 오류 없이 들어갔고, 배치 모드에서 슬라이더와 글자를 만들어 붙여 보니 처음 Start 뒤 「볼륨 70%」 · 저장 없음, value 에 35.4 를 넣으면 35 로 맞춰져 「볼륨 35%」 와 저장값 35, 새로 만든 슬라이더는 저장된 25 에서 시작했습니다. Game 창에서 손으로 끌어 본 것은 아닙니다.
변수(variable)
slider_volume(Slider) : 볼륨을 고를 슬라이더
text_volume(TMP_Text) : 지금 볼륨을 보여 줄 글자
KEY_VOLUME(string) : PlayerPrefs 에 저장할 이름
함수(function)
Init_Slider : 범위를 0~100 으로, 값을 정수 단계로 정합니다.
Change_Volume : 슬라이더가 움직일 때 불려, 값을 적용하고 저장합니다.
Apply_Volume : 소리 크기와 글자를 값에 맞춥니다.
3. 소수 값을 보여 줄 때 — ToString 과 normalizedValue
slider_speed.minValue = 0.5f;
slider_speed.maxValue = 2f;
slider_speed.onValueChanged.AddListener(value =>
{
text_speed.text = "x" + value.ToString("0.0"); // x1.3
text_percent.text = (slider_speed.normalizedValue * 100f).ToString("0") + "%"; // 범위 안에서 몇 %
});
게임 속도처럼 소수로 움직이는 슬라이더는 값을 그대로 붙이면 1.3333 같은 긴 숫자가 나옵니다. ToString("0.0") 으로 자릿수를 정하면 「x1.3」 처럼 보입니다. normalizedValue 는 지금 값이 범위 안에서 어디쯤인지를 0~1 로 돌려줍니다. 범위가 0.5~2 일 때 값 1 은 0.333 이라 「33%」 가 됩니다.
4. wholeNumbers — 정수 단계로 움직이기
int level = Mathf.RoundToInt(slider.value); // int 로 쓸 때는 바꿔서

wholeNumbers 를 켜면 값이 정수로 반올림되지만 value 의 타입은 그대로 float 입니다. int 변수에 넣을 때는 (int) 나 Mathf.RoundToInt 로 바꿔야 합니다. 이 반올림은 Mathf.Round 를 써서 .5 는 짝수 쪽으로 갑니다. 직접 넣어 보니 3.5 는 4 가 되고 4.5 도 4 가 되었습니다. 또 SetValueWithoutNotify 로 넣은 값도 같은 규칙으로 맞춰져서, 3.7 을 넣으면 4 가 됩니다.
5. 이벤트가 엉뚱하게 불릴 때 — 자주 하는 실수
불러오기만 했는데 저장 · 효과음이 돈다
value 에 값을 넣으면 손으로 움직인 것과 똑같이 onValueChanged 가 불립니다. 저장값을 slider.value = 25 로 넣었을 때 리스너가 한 번 불리는 것을 확인했습니다. 리스너에 저장이나 효과음이 들어 있다면 불러올 때는 SetValueWithoutNotify 를 쓰고, 글자처럼 화면에 보이는 것은 2절의 Apply_Volume 처럼 직접 한 번 맞춥니다. 같은 값을 다시 넣을 때는 이벤트가 불리지 않습니다.
slider.minValue = 50; // 값이 30 이었다면 50 으로 바뀌고 onValueChanged 도 불림
범위를 바꿨더니 이벤트가 불린다
minValue · maxValue · wholeNumbers 를 바꾸면 슬라이더가 지금 값을 새 범위에 다시 맞추고, 값이 달라졌다면 onValueChanged 를 부릅니다. 그래서 2절 코드는 범위를 먼저 정하고 리스너를 나중에 연결합니다. 인스펙터의 On Value Changed 칸에 직접 넣은 함수는 RemoveAllListeners 로 지워지지 않으니 코드로 연결할 때는 그 칸을 비워 둡니다.
함께 보기: 슬라이더와 버튼에 함수를 붙이고 떼는 기본 예제는 예전 글 UI Slider 기능 할당/삭제 in Script 에 있습니다.
Slider 동작은 Unity 공식 문서 Slider (uGUI) · UnityEventBase.RemoveAllListeners 와 Unity 6000.6.3f1 의 ugui 패키지 소스를 기준으로 적었습니다.
'Unity3D > C#' 카테고리의 다른 글
| 유니티 HEX 색상 코드 ↔ Color 변환 (Unity color from hex / to hex) (0) | 2026.10.22 |
|---|---|
| 유니티 토글(Toggle) 켜기/끄기 · 토글 그룹 하나만 고르기 (0) | 2026.10.21 |
| 유니티 드롭다운(TMP Dropdown) 값 읽기 · 옵션 코드로 넣기 (0) | 2026.10.20 |
| 유니티 타이머 카운트다운 · 스톱워치 · 일시정지 (Time.deltaTime, unscaledDeltaTime) (0) | 2026.10.19 |
| 유니티 마우스 커서 이미지 바꾸기 (Cursor.SetCursor, 커스텀 커서 hotspot) (0) | 2026.10.18 |