UI 슬라이더와 실제 값이 따로 노는 문제 해결기 (feat. 정규화)

순한양·2025년 8월 1일
0

[Unity] UI 슬라이더와 실제 값이 따로 노는 문제 해결기 (feat. 정규화)

Unity Logo
C# Logo

🤔 문제 현상: 설정을 바꿨는데 이상하게 적용돼요!

프로젝트의 설정 메뉴를 구현하던 중 이상한 버그를 만났습니다.

  • 현상 1: 설정 메뉴에 들어갔다가 아무것도 안 하고 나오기만 해도 카메라 감도가 확 줄어드는 문제.
  • 현상 2: 효과음(SFX) 볼륨 슬라이더를 조작했는데, 상관없는 카메라 감도가 영향을 받는 문제.

Debug.Log를 찍어보니 이벤트 연결이나 함수 호출 자체에는 아무런 문제가 없었습니다. 그런데도 두 시스템이 서로에게 이상한 영향을 주고 있었습니다.

💥 원인 분석: "단위가 다른 숫자들"

문제의 원인은 아주 간단한 수학에 있었습니다. 바로 '값의 범위(Range)'가 서로 맞지 않았기 때문입니다.

비유하자면:

  • CameraManager는 '시속(km/h)' 단위로 속도를 이해합니다. (예: sensitivity = 50f)
  • UI 슬라이더는 '퍼센트(%)' 단위로만 값을 표시합니다. (0 ~ 1)

LoadSettings() 함수가 PlayerPrefs에서 '시속 50km'라는 값을 가져와서 '퍼센트'만 표시하는 슬라이더에 억지로 넣으니, 슬라이더는 자기 최대치인 '100%(값: 1)'로 값을 잘라버렸습니다.

결과적으로, 설정창을 열었다 닫기만 해도 카메라 감도가 의도치 않게 '시속 1km'로 줄어드는 현상이 발생했던 것입니다.

✅ 해결책: 값의 범위를 '정규화(Normalization)'하기

이 문제를 해결하려면, 두 시스템이 서로 알아들을 수 있도록 단위를 변환해주는 과정이 필요합니다.

  • 정규화: 실제 감도 값(1~100)을 슬라이더의 범위(0~1)에 맞는 비율로 변환.
  • 역정규화: 슬라이더의 비율(0~1)을 실제 감도 값으로 다시 변환.

다행히 Unity의 Mathf 클래스는 이 과정을 위한 아주 편리한 함수들을 제공합니다.

SettingsMenu.cs 수정 코드

public class SettingsMenu : UiBase
{
    // 1. 카메라 감도의 실제 범위를 변수로 정의합니다.
    [Header("감도 범위 설정")]
    [SerializeField] private float _minCameraSensitivity = 1f;
    [SerializeField] private float _maxCameraSensitivity = 10f;

    // ...

    private void LoadSettings()
    {
        // 2. 불러온 값을 슬라이더의 0~1 범위로 '정규화'합니다.
        float savedSens = PlayerPrefs.GetFloat("CameraSensitivity", 3f);
        _cameraSensitivitySlider.SetValueWithoutNotify(
            Mathf.InverseLerp(_minCameraSensitivity, _maxCameraSensitivity, savedSens)
        );
        
        // ...
    }

    public void OnCameraSensitivityChanged()
    {
        if (GameManager.Instance?.CameraManager != null)
        {
            // 3. 슬라이더의 0~1 값을 실제 감도 범위로 '역정규화'합니다.
            float actualSensitivity = Mathf.Lerp(
                _minCameraSensitivity, 
                _maxCameraSensitivity, 
                _cameraSensitivitySlider.value
            );
            GameManager.Instance.CameraManager.Sensitivity = actualSensitivity;
        }
    }

    public void OnApplyButton()
    {
        // 4. 저장할 때도 실제 감도 값을 저장합니다.
        float actualSensitivity = Mathf.Lerp(
            _minCameraSensitivity, 
            _maxCameraSensitivity, 
            _cameraSensitivitySlider.value
        );
        PlayerPrefs.SetFloat("CameraSensitivity", actualSensitivity);
        
        // ...
    }
    
    // ...
}
,,,

💡 핵심 함수

Mathf.InverseLerp(최소, 최대, 현재값): 특정 범위 안에서 현재 값이 차지하는 비율(0~1)을 계산해줍니다. (실제 값 -> 슬라이더 값)

Mathf.Lerp(최소, 최대, 비율): 0~1 사이의 비율 값을 실제 값 범위에 맞게 변환해줍니다. (슬라이더 값 -> 실제 값)

🚀 결론

UI와 실제 게임 로직 사이에서 값을 주고받을 때는, 각 시스템이 사용하는 값의 '단위'와 '범위'를 명확히 이해하고, 필요에 따라 정규화/역정규화하는 과정이 필수적이라는 것을 배웠습니다. 이 수정을 통해 모든 설정 관련 버그가 해결되었습니다.

profile
개발 입문자

0개의 댓글