오늘 학습 키워드

오디오 매니저 만들기, 싱글톤, 제네릭,프로퍼티

오늘 학습 한 내용을 나만의 언어로 정리하기

오디오 매니저 만들기

사용자가 정한 값을 불러올 수 있게 PlayerPrefs를 활용했음.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class AudioManager : MonoBehaviour
{
 
    public static AudioManager instance;
 
    public AudioSource bgmAudioSource;
    public AudioSource sfxAudioSource;
    public AudioClip bgmClip;
    public AudioClip matchClip;
    public AudioClip flipClip;
 
    public float bgmVolume;
    public float sfxVolume;
    public bool isBgmMuted;
    public bool isSfxMuted;
 
    private void Awake()
    {
        if(instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
 
        PrefCheck();
    }
 
    // Start is called before the first frame update
    void Start()
    {
        bgmAudioSource.clip = this.bgmClip;
        bgmAudioSource.Play();
    }
 
    private void Update()
    {
        // bgmAudioSource.volume = bgmVolume;
    }
 
    public void PrefCheck()
    {
        if (PlayerPrefs.HasKey("bgmVolume"))
        {
            bgmVolume = PlayerPrefs.GetFloat("bgmVolume");
        }
        else
        {
            bgmVolume = 1.0f;
        }
 
        if(PlayerPrefs.HasKey("sfxVolume"))
        {
            sfxVolume = PlayerPrefs.GetFloat("sfxVolume");
        }
        else
        {
            sfxVolume = 1.0f;
        }
 
        if (PlayerPrefs.HasKey("isBgmMuted"))
        {
            isBgmMuted = PlayerPrefs.GetInt("isBgmMuted") == 1 ? true : false;
        }
        else
        {
            isBgmMuted = false;
        }
 
        if (PlayerPrefs.HasKey("isSfxMuted"))
        {
            isSfxMuted = PlayerPrefs.GetInt("isSfxMuted") == 1 ? true : false;
        }
        else
        {
            isSfxMuted = false;
        }
 
    }
 
    public void BgmSliderChanged(float changedData)
    {
        bgmVolume = changedData;
        bgmAudioSource.volume = bgmVolume;
        PlayerPrefs.SetFloat("bgmVolume", bgmVolume);
    }
 
    public void SfxSliderChanged(float changedData)
    {
        sfxVolume = changedData;
        sfxAudioSource.volume = sfxVolume;
        PlayerPrefs.SetFloat("sfxVolume", sfxVolume);
    }
 
    public void BgmToggleChanged(bool changedData)
    {
        isBgmMuted = changedData;
        bgmAudioSource.mute = isBgmMuted;
        PlayerPrefs.SetInt("isBgmMuted", changedData ? 1 : 0);
    }
 
    public void SfxToggleChanged(bool changedData)
    {
        isSfxMuted = changedData;
        sfxAudioSource.mute = isSfxMuted;
        PlayerPrefs.SetInt("isSfxMuted", changedData ? 1 : 0);
    }
 
    public void FlipSound()
    {
        sfxAudioSource.PlayOneShot(flipClip);
    }
 
    public void MatchSound()
    {
        sfxAudioSource.PlayOneShot(matchClip);
    }
 
}
 

팀원 분이 사용하신 싱글톤 만들기 방법

public class SingleTon<T> where T : new()
    {
		private T instance;
 
		public T GetInstance
		{
			get 
			{
				if (instance == null)
                {
                    Init();
                    instance = new T();
                }
				return instance;
			}
		}
 
        public virtual void Init() { }
 
		public void Release()
		{
			instance = default(T);
		}
	}

이 코드에서 제네릭과 가상 메소드 사용법을 확인할 수 있었음.

T

어떤 클래스 타입이든 될 수 있다는 의미.

// 예시
 
public class GameManager
{
	public void PrintSomething() 
	{
		Debug.Log("Hello!");
	}
}
 
public class GameManagerSingleton : Singleton<GameManager> { }

여기서는 GameManager 형태의 싱글톤을 만듬.

where T : new()

제네릭 타입인 T가 매개변수 없는 기본 생성자 를 가져야만 한다는 의미.
위에서 만든 예시를 이용해 추가 설명

// 말이 되는 예시
 
public class GameManager
{
	public GameManager()
	{
		Debug.Log("저는 말이 됩니다.");
	}
 
	public GameManager(int idx)
	{
		Debug.Log($"정수 idx를 받아오지만 그래도 위에 기본 생성자가 있으니 말이 됩니다.")
	}
}
 
public class GameManagerSingleton : Singleton<GameManager> { }
 
// 말이 안되는 예시
 
public class GameManager
{
	public GameManager(int idx)
	{
		Debug.Log($"저는 말이 안됩니다. 왜냐면 기본 생성자 없이 매개변수가 포함된 생성자만 있기 때문입니다.");
	}
}
 
public class GameManagerSingleton : Singleton<GameManager> { }

C#은 컴파일 타임에 타입 안정성을 보장해야 하기 때문에, new() 제약이 없으면 new T를 제한함.

프로퍼티

// 이 부분이 프로퍼티
public T GetInstance
{
	get 
	{
		if (instance == null)
        {
            Init();
            instance = new T();
        }
		return instance;
	}
}

프로퍼티와 함수의 차이

프로퍼티는 데이터 접근용, 함수는 로직 수행용.

프로퍼티는 변수를 감싸서 외부에서 접근할 수 있도록 하는 역할.

가상 메소드

public virtual void Init() { }

아무것도 없는 것처럼 보임.

실제로 그러함.

하지만 가상 메소드로 만들어 두었기 때문에, 상속해서 오버라이드하면 초기 설정을 어떻게 할지 정할 수 있음.

부모 클래스도 해당 함수를 가지고, 자식 클래스가 그 함수에 대한 오버라이드를 허용하게 하려면 Virtual을 사용해야 함.

함수의 로직을 정확히 구현하지 않고 이를 상속하는 클래스가 구현하게 하려면 Virtual이 아니고 Abstract를 사용해야 함. (이 때, 부모 클래스토 abstract 클래스여야 함.)

인스턴스 해제

인스턴스를 없애야 할 때도 있을 수 있음. 그 때 사용함

public void Release()
{
	instance = default(T);
}

이 때 기본값은 null일 것임.

학습하며 겪었던 문제점 & 에러

문제 1

  • 문제&에러에 대한 정의

BGM 볼륨 조절용 슬라이더를 아무리 움직여도, 위에서 만든 BgmSliderChanged에 float 인수가 0으로 들어갔다.

  • 내가 한 시도

여기 0을 다른 수로 바꾸면 BgmSliderChanged에 들어가는 값이 바뀌는 것 까지는 확인함

  • 해결 방법

Static Parameters가 아니고 Dynamic Float로 함수를 지정해 주어야 했음

  • 새롭게 알게 된 점

내가 만든 함수에 슬라이더, 토글 등의 변경 값이 적용되게 하려면 Dynamic 칸에 있는 함수를 클릭해 주어야 한다.

  • 이 문제&에러를 다시 만나게 되었다면?

UI를 사용하려는 방법에 따라 호출을 어떻게 할 지 고민해 보아야겠다.

문제 2

함수가 virtual이 아니면 override가 안된다.

내일 학습 할 것은 무엇인지

개인 공부 (아마도)