오늘 학습 키워드

오디오 설정, 챌린지 반 강의

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

오디오 설정 창 만들기

// SoundManager.cs
public void PrefCheck()
{
    if (PlayerPrefs.HasKey("BgmVolume"))
    {
        musicVolume = PlayerPrefs.GetFloat("BgmVolume");
    }
    else
    {
        musicVolume = 1.0f;
    }
 
    if (PlayerPrefs.HasKey("SfxVolume"))
    {
        soundEffectVolume = PlayerPrefs.GetFloat("SfxVolume");
    }
    else
    {
        soundEffectVolume = 1.0f;
    }
}
 
public void BgmSliderChanged(float changedData)
{
    musicVolume = changedData;
    musicAudioSource.volume = musicVolume;
    PlayerPrefs.SetFloat("BgmVolume", musicVolume);
}
 
public void SfxSliderChanged(float changedData)
{
    soundEffectVolume = changedData;
    PlayerPrefs.SetFloat("SfxVolume", soundEffectVolume);
}
// InputSettingUI.cs
 
/// <summary>
/// Bgm / Sfx 슬라이더 값 초기 설정
/// </summary>
private void UpdateSliders()
{
    bgmSlider.value = PlayerPrefs.HasKey("BgmVolume")
        ? PlayerPrefs.GetFloat("BgmVolume")
        : 1.0f;
 
    sfxSlider.value = PlayerPrefs.HasKey("SfxVolume")
        ? PlayerPrefs.GetFloat("SfxVolume")
        : 1.0f;
}

챌린지 반 강의

메모리 구조

메인보드 구조

  • CPU, 메모리, 시스템 버스
    • 시스템 버스를 통해서 보조기억장치와 입출력장치간의 데이터 송수신이 일어남

CPU와 메모리의 관계

  • 메모리 : 현재 실행하는 프로그램의 명령어와 데이터를 저장
  • CPU : 메모리에 저장된 명령어를 읽어 들이고 읽어 들인 명령어를 해석, 실행
    • 레지스터 : 메모리에 있는 데이터를 임시로 저장하는 공간
    • ALU : 산술논리 연산장치
    • 제어장치 : 메모리를 읽음

메모리 영역

  • 코드 영역 (텍스트 영역) : 기계어(0,1)가 저장되어있음.
    • CPU는 이 코드 영역에 있는 명령어들을 하나씩 가져가서 실행함
  • 데이터 영역
    • 전역 변수와 Static 변수가 할당됨.
    • 프로그램의 시작과 동시에 할당되고, 프로그램이 종료되어야 메모리가 소멸함
  • 힙 영역 : 런타임에 크기 결정
    • 인스턴스, 배열, 문자열등이 저장됨
      • new 로 만드는 것들이 포함됨.
    • 사용자의 동적 할당
    • 사용자가 할당을 해제해 주지 않으면 응용 프로그램이 종료될 때까지 메모리가 유지됨.
    • 가비지 컬렉터가 관리해줌.
      • 가비지 컬렉터를 호출하는게 비용이 많이 듬.
  • 스택 영역 : 컴파일 타임에 크기 결정
    • 지역변수, 매개변수, Struct 저장됨
      • 지역변수 : 함수 내에서 사용되는 변수
      • 매개변수 : 함수에 넣어주는 인자
    • 함수의 호출과 함께 할당됨
    • 함수의 호출이 끝나면 완전히 소멸됨
    • 데이터 영역보다 스택 영역을 많이 쓰는게 좋음.
    • 다만 너무 많이 쓰면 Stack Overflow가 일어나니 주의.

구조체?

  • 구조체는 대체로 값 타입으로 스택에 들어감. (가끔 힙에 들어가는 경우도 있음)
  • 구조체를 복잡하게 만들거면 그냥 클래스를 만드는게 나음.
  • 구조체는 New를 해도 힙에 저장되는게 아님 but 한 구조체가 일정 크기가 넘어가면 힙에 들어갈 수도 있음

클래스와 구조체의 차이

클래스구조체
타입참조 타입값 타입
영역힙 영역스택 영역
상속가능불가능

가비지 컬렉터

  • 자동 메모리 관리 도구

  • 메모리 누수를 방지하고, 효율적인 메모리 관리를 가능하게 함

  • C#에서 가비지 컬렉터는 .NET 프레임워크의 일부임

  • 힙 영역에서 작동함.

  • 장점

    • 자동 메모리 관리 가능
    • 메모리 누수 방지 - 명시적으로 해제할 필요가 없다!
    • 안정성 향상 - 객체가 참조되지 않을 때 해제하기 때문에, 잘못된 접근 오류 방지
    • 개발 생산성 향상
  • 단점

    • 성능 오버헤드 - 주기적 실행 때문에 앱이 중단될 수 있음. Full GC는 중단 시간이 김
    • 예측 불가능한 중단 - 원하는 타이밍에 실행되는게 아니라서 일어날 수 있음
    • 추가 메모리 사용
    • 복잡성 증가 - 최적화를 위해서는 또 메모리 프로파일링 및 관리 전략이 필요함
  • 가비지 컬렉션을 줄이는 방법 : 최대한 메모리를 덜 쓴다!!!

    • 오브젝트 풀링 : 생성되는게 많고 제거되는게 많을 때 사용함. 직접 삭제하는게 아니고 사용하지 않는건 잠깐 꺼두고 나중에 사용될 때 재사용 하는 방법. 메모리를 절약할 수 있다!
    • 구조체 사용 : 값 타입(struct)을 사용해서 힙 할당을 줄임
      • 너무 복잡하면 그냥 클래스 쓰기
    • 불필요한 할당 피하기

아틀라스

  • 이미지 압축하는 방법
  • 유니티는 2의 배수 사이즈의 이미지를 알아서 자동으로 압축해줌
    • 이게 아틀라스!
  • 사용할 이미지를 2의 배수 사이즈로 싹 다 집어넣으면 아틀라스로 알아서 압축됨

클래스, 제네릭, 확장메서드

클래스

  • 클래스는 그저 설계도일 뿐
  • 실제로 사용하려면 힙 메모리에 올리는 인스턴스화를 해줘야 함
  • 싱글톤 패턴 : 인스턴스가 하나!
  • 상속, 캡슐화, 다형성 이 세가지는 꼭 기억하고 가자
    • 상속 : 기존의 클래스를 재활용하여 새로운 클래스를 만드는 것
    • 캡슐화 : 서로 연관있는 속성과 기능들을 하나의 캡슐로 만들어 데이터를 외부로부터 보호하는 것
    • 다형성 : 객체의 속성이나 기능이 상황에 따라 여러 형태를 가질 수 있는 것

제네릭

  • 제네릭 : Cup of T! T가 무엇인지에 따라 오렌지 주스 컵, 커피 컵 등등이 결정됨

    • 넘어오는 데이터 형식에 따라 객체 성격을 변경하는 구조 (일반화)
    • 제네릭 클래스는 자료형을 일반화된 타입인 <T>로 표시한 클래스
  • 컬렉션 : 데이터를 효율적으로 저장, 검색, 조작할 수 있는 기능을 제공함.

    • 주요 컬렉션 클래스는 .NET 프레임워크 일부로 제공
    • System.Collections / System.Collections.Generic 안에 있음
제네릭 사용제네릭 미사용멀티스레드 동기화용용도
Dictionary<TKey, TValue>HashtableConcurrentDictionary<TKey, TValue>
ReadOnlyDictionary<TKey, TValue>
ImmutableDictionary<TKey, TValue>
Key로 빠르게 데이터를 조회할 때 사용. key-value로 데이터가 저장됨
List<T>Array,
ArrayList
ImmutableList<T>
ImmutableArray
데이터가 저장된 순서(인덱스)로 빠르게 탐색함
Queue<T>QueueConcurrentQueue<T>
ImmutableQueue<T>
FIFO(선입선출) 방식 데이터 사용
Stack<T>StackConcurrentStack<T>
ImmutableStack<T>
LIFO(후입선출) 방식 데이터 사용
SortedList<TKey,TValue>SortedListImmutableSortedDictionary<TKey,TValue>
ImmutableSortedSet<T>
입력된 순서와 상관없이 Key값으로 정렬
LinkedList<T>지원 X지원 X데이터 등록 / 삭제가 자주 일어날 때
ObservableColletion<T>지원 X지원 X목록에 데이터를 넣거나 뺄 때 알람을 표시
HashSet<T>
SortedSet<T>
지원 XImmutableHashSet<T>
ImmutableSortedSet<T>
중복된 데이터를 저장하지 않을 때 (집합 사용)
  • Array와 List의 차이

    • Array는 크기가 처음에 정해져있음
    • List는 삽입과 삭제가 원활하게 이루어질 수 있음
  • LINQ : Language Integrated Query. 쿼리문을 사용해 데이터를 조작할 수 있음. 확장 메소드 형태로 제공

    • 쿼리 : 데이터를 검색하는 식
    • LINQ는 확장 메소드를 사용함!

확장 메소드

  • 모든 클래스의 기능을 확장할 수 있는 메소드
  • 확장 메소드를 쓰려면 Static 클래스여야 함
  • 함수도 Static이어야 함
  • 매개변수 중에 this가 있어야 함
// 작성 방법
public static (반환값) ExtensionMethodName(this ClassToExtend o)
{
 // 여기다 작성
}
// 예시 1 : Vector2 
public static Vector2 SetX(this Vector2 vector, float x)
{
	return new Vector2(x, vector.y)
}
// 예시 2 : GameObject
 
// 조건 : T는 MonoBehaviour를 상속받는 클래스만 사용 가능
public static T GetOrAddComponent<T>(this GameObject gameObject) where T : MonoBehaviour
{
	var component = gameObject.GetComponent<T>;
	if (component == null) gameObject.AddComponent<T>();
	return component;
}
 
public static bool HasComponent<T>(this GameObject gameObject) where T : MonoBehaviour
{
	return gameObject.GetComponent<T>() != null;
}
// 예시 3 : List
 
public static T GetRandomItem<T>(this IList<T> list)
{
	return list[Random.Range(0, list.Count)];
}
// 예시 4 : Rigidbody
 
public static void ChangeDirection(this Rigidbody rb, Vector3 direction)
{
	// 크기는 그대로 하되 방향만 바꿈
	rb.velocity = direction.normalized * rb.velocity.magnitude;
}
// 예시 5 : Button
public static void SetOnClick(this Button bt, UnityAction call)
{
	bt.onClick.RemoveAllListeners();
	bt.onClick.AddListener(call);
}