오늘 학습 키워드
오디오 설정, 챌린지 반 강의
오늘 학습 한 내용을 나만의 언어로 정리하기
오디오 설정 창 만들기
// 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가 일어나니 주의.
- 지역변수, 매개변수, Struct 저장됨
구조체?
- 구조체는 대체로 값 타입으로 스택에 들어감. (가끔 힙에 들어가는 경우도 있음)
- 구조체를 복잡하게 만들거면 그냥 클래스를 만드는게 나음.
- 구조체는 New를 해도 힙에 저장되는게 아님 but 한 구조체가 일정 크기가 넘어가면 힙에 들어갈 수도 있음
클래스와 구조체의 차이
클래스 | 구조체 | |
---|---|---|
타입 | 참조 타입 | 값 타입 |
영역 | 힙 영역 | 스택 영역 |
상속 | 가능 | 불가능 |
가비지 컬렉터
-
자동 메모리 관리 도구
-
메모리 누수를 방지하고, 효율적인 메모리 관리를 가능하게 함
-
C#에서 가비지 컬렉터는 .NET 프레임워크의 일부임
-
힙 영역에서 작동함.
-
장점
- 자동 메모리 관리 가능
- 메모리 누수 방지 - 명시적으로 해제할 필요가 없다!
- 안정성 향상 - 객체가 참조되지 않을 때 해제하기 때문에, 잘못된 접근 오류 방지
- 개발 생산성 향상
-
단점
- 성능 오버헤드 - 주기적 실행 때문에 앱이 중단될 수 있음. Full GC는 중단 시간이 김
- 예측 불가능한 중단 - 원하는 타이밍에 실행되는게 아니라서 일어날 수 있음
- 추가 메모리 사용
- 복잡성 증가 - 최적화를 위해서는 또 메모리 프로파일링 및 관리 전략이 필요함
-
가비지 컬렉션을 줄이는 방법 : 최대한 메모리를 덜 쓴다!!!
- 오브젝트 풀링 : 생성되는게 많고 제거되는게 많을 때 사용함. 직접 삭제하는게 아니고 사용하지 않는건 잠깐 꺼두고 나중에 사용될 때 재사용 하는 방법. 메모리를 절약할 수 있다!
- 구조체 사용 : 값 타입(struct)을 사용해서 힙 할당을 줄임
- 너무 복잡하면 그냥 클래스 쓰기
- 불필요한 할당 피하기
아틀라스
- 이미지 압축하는 방법
- 유니티는 2의 배수 사이즈의 이미지를 알아서 자동으로 압축해줌
- 이게 아틀라스!
- 사용할 이미지를 2의 배수 사이즈로 싹 다 집어넣으면 아틀라스로 알아서 압축됨
클래스, 제네릭, 확장메서드
클래스
- 클래스는 그저 설계도일 뿐
- 실제로 사용하려면 힙 메모리에 올리는 인스턴스화를 해줘야 함
- 싱글톤 패턴 : 인스턴스가 하나!
- 상속, 캡슐화, 다형성 이 세가지는 꼭 기억하고 가자
- 상속 : 기존의 클래스를 재활용하여 새로운 클래스를 만드는 것
- 캡슐화 : 서로 연관있는 속성과 기능들을 하나의 캡슐로 만들어 데이터를 외부로부터 보호하는 것
- 다형성 : 객체의 속성이나 기능이 상황에 따라 여러 형태를 가질 수 있는 것
제네릭
-
제네릭 : Cup of T! ⇒ T가 무엇인지에 따라 오렌지 주스 컵, 커피 컵 등등이 결정됨
- 넘어오는 데이터 형식에 따라 객체 성격을 변경하는 구조 (일반화)
- 제네릭 클래스는 자료형을 일반화된 타입인 <T>로 표시한 클래스
-
컬렉션 : 데이터를 효율적으로 저장, 검색, 조작할 수 있는 기능을 제공함.
- 주요 컬렉션 클래스는 .NET 프레임워크 일부로 제공
- System.Collections / System.Collections.Generic 안에 있음
제네릭 사용 | 제네릭 미사용 | 멀티스레드 동기화용 | 용도 |
---|---|---|---|
Dictionary<TKey, TValue> | Hashtable | ConcurrentDictionary<TKey, TValue> ReadOnlyDictionary<TKey, TValue> ImmutableDictionary<TKey, TValue> | Key로 빠르게 데이터를 조회할 때 사용. key-value로 데이터가 저장됨 |
List<T> | Array, ArrayList | ImmutableList<T> ImmutableArray | 데이터가 저장된 순서(인덱스)로 빠르게 탐색함 |
Queue<T> | Queue | ConcurrentQueue<T> ImmutableQueue<T> | FIFO(선입선출) 방식 데이터 사용 |
Stack<T> | Stack | ConcurrentStack<T> ImmutableStack<T> | LIFO(후입선출) 방식 데이터 사용 |
SortedList<TKey,TValue> | SortedList | ImmutableSortedDictionary<TKey,TValue> ImmutableSortedSet<T> | 입력된 순서와 상관없이 Key값으로 정렬 |
LinkedList<T> | 지원 X | 지원 X | 데이터 등록 / 삭제가 자주 일어날 때 |
ObservableColletion<T> | 지원 X | 지원 X | 목록에 데이터를 넣거나 뺄 때 알람을 표시 |
HashSet<T> SortedSet<T> | 지원 X | ImmutableHashSet<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);
}