경일 메타버스 20220718 16주차 1일 수업내용. 유니티 - 유니런 (마우스 입력 Input, 오디오 관리 AudioSource, 배경 스크롤링), Profiler(진단 도구), C# 문법 - 상수 등, 싱글톤 패턴
마우스 입력 관련
https://docs.unity3d.com/kr/current/ScriptReference/Input.html
mousePosition
mousePresent
touchCount
touches
GetMouseButton()
GetMouseButtonDown()
GetMouseButtonUp()
등
오디오 관리
https://docs.unity3d.com/kr/current/ScriptReference/AudioSource.html
Play()
Pause()
Stop()
UnPause()
PlayOneShot()
등
진단 도구, 프로파일링 툴 - Profiler, Profiling Tool
ex) private readonly int ANIM_ID_DIE = Animator.StringToHash("Die");
둘의 차이 : 평가 시점
앞에 static 키워드를 붙여 정적 멤버를 만들 수 있다.
함수 내에서는 static 키워드를 사용할 수 없다.
이름 공간 (namespace)이나 클래스로 기호 상수를 묶어 관리할 수 있다.
열거형은 컴파일 단위에서 사용 → C#의 특성 상 자주 사용하지 않는다.
이번 케이스에서 namespace가 아닌 class를 사용하는 이유 :
namespace는 using문으로 생략이 가능하다.
생략을 하면 “강직성”이 손상될 수 있다.
따라서 생략이 불가한 class를 사용, 강직성을 보존한다.
private static class AnimationID
{
public static readonly int IS_ON_GROUND = Animator.StringToHash("IsOnGround");
// string을 참조하지 않기 위해 해시 값으로 변환 // 최적화, 리팩토링에 해당하는 부분
public static readonly int DIE = Animator.StringToHash("Die");
// string을 참조하지 않기 위해 해시 값으로 변환 // 최적화, 리팩토링에 해당하는 부분
}
Sprite Renderer
그리는 순서를 지정하자
Sorting Layer :
레이어를 여러 개 지정하여 나눈다.
각 레이어의 위치와 움직이는 속도를 다르게 하여
원근감을 표현할 수 있다.
Order in Layer :
레이어 내에서 그림을 그리는 순서를 지정한다.
어떤 그림이 앞에 나오는 지 지정한다고 보면 된다.
객체 지향적 설계를 도와주기 위한 패턴
객체 지향 프로그래밍
객체로 프로그램을 제작한다.
객체 :
상태(데이터)와 행동(기능)을 갖고 있는 어떤 것
현실 세계를 그대로 모델링 할 수 있다는 장점이 있다.
특징
캡슐화 :
데이터와 함수를 함께 적을 수 있는 것
상속 :
코드를 물려받는 것. 즉, 재사용할 수 있는 것
추상화 :
일반적인 인터페이스를 정의하는 것
다형성 :
하나의 인터페이스로 다양한 동작을 할 수 있는 것
디자인 패턴은 크게 3가지로 나뉜다.
생성 패턴
객체의 생성에 관련
ex) 단일체 (Singleton) 패턴
구조 패턴
구조를 잡을 때 다형성을 잘 활용할 수 있도록 설계
ex) 컴포넌트 → 복합체 (Composite) 패턴
행동 패턴
오직 한 개의 인스턴스만을 갖도록 보장하고, 이에 대한 전역적인 접근점을 제공하는 패턴
객체 지향적으로 전역 변수를 만드는 것
추상 클래스인 Singleton 클래스를 상속 받아 싱글톤 클래스를 만드는 것이 일반적
구현 방법은 상황에 따라 달라질 수 있다.
아래는 참고용
template <typename T>
class Singleton abstract
{
public:
Singleton(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton& operator=(Singleton&&) = delete;
Singleton& GetInstance()
{
static T instance;
return instance;
}
};
// 사용할 때는 상속을 받는다.
class GameManager : public Singleton<GameManager> { };
public abstract class Singleton<T>
{
private static T _instance = new T();
static Singleton()
{
}
public static T Instance
{
get
{
return _instance;
}
}
}
// 사용할 때는 아래와 같이 사용한다.
public class Temp : Singleton<Temp>{}
인스턴스의 유일성을 보장한다.
인스턴스가 유일하도록 컴파일 단계에서 강제한다.
인스턴스의 개수를 늘리고자 할 때도 유연하게 바꿀 수 있다.
→ 물론, 이때 유일성은 깨지고 전역적인 접근점만 제공한다.
게으른 초기화(Lazy Initialization)가 일어난다.
사용하지 않는다면 생성되지 않는다.
런타임에 초기화가 된다.
어디서든 쉽게 접근할 수 있다.
이름 공간을 좁힌다.
결국 전역 변수
전역 변수보다 조금 낫지만 결국 전역 변수와 같다.
전역 변수는 코드 간 결합도를 높여 유지 보수를 어렵게 한다.
스레드 동기화 문제가 있다.
게으른 초기화를 방지할 수 없다.
초기화 시점을 제어해야 하는 경우
초기화에 오랜 시간이 걸릴 경우
메모리 단편화를 방지하기 위해 메모리 풀링(Memory Pooling)을 사용하는 경우
하지만 싱글톤 패턴에서는 초기화 시점의 제어가 불가능하다.
두 가지 문제를 풀려고 한다.
싱글톤 패턴은 인스턴스의 유일성도 보장하고 전역적인 접근점도 제공한다.
둘 중 하나의 문제만 해결하고자 한다면 곤란해진다.
싱글톤은 굉장히 조심해서 써야 하는 패턴이다.
특히나 편하다는 이유로 남용되기 쉬운 패턴이다.
꼭 클래스가 필요한가?
다른 객체를 관리하는 매니저 객체를 싱글톤으로 만드는 경우
→ 이는 OOP를 해칠 수 있다.
정적 변수를 이용해 인스턴스 개수를 제한
전역적인 접근점 대신에 다른 방법을 사용
의존성 주입(Dependency Injection)을 사용하자.
상위 클래스를 이용
이미 전역인 객체를 이용
중재자 패턴을 사용
모노스테이트(Monostate)를 활용할 수도 있다.
모노스테이트는 싱글톤 패턴을 살짝 튼 것으로 모든 멤버나 혹은 필드만 정적으로 두는 것
싱글톤 패턴이 꼭 필요한 경우는 생각보다 많이 없다.
구현 :
https://haedallog.tistory.com/193
Generic :
C#에서의 템플릿(C++)
where 절 :
제네릭(Generic)을 썼을 때만 사용할 수 있는 제약 조건
public class SingletonBehaviour<T> : MonoBehaviour where T : MonoBehaviour
인스턴스 초기화 시점
주의 :
Unity 컴포넌트는 생성자를 이용하여 초기화하면 안된다.
Unity 엔진이 알아서 생성하고 관리하기 때문.
https://docs.unity3d.com/kr/current/Manual/CreatingAndUsingScripts.html
따라서 스크립트에 있는 멤버의 초기화는 Unity 이벤트 함수의 실행 순서에 따라 Awake, OnEnable, Start 중에서 하게 된다.
초기화 시점에 적절한 것은 Awake
Awake, OnEnable, Start의 차이점
https://haedallog.tistory.com/192
Awake :
스크립트가 비활성화 되어 있더라도 게임 오브젝트가 활성화 되어 있으면 무조건 호출
OnEnable :
게임 오브젝트가 활성화 된 경우에만 게임 오브젝트 혹은 스크립트가 비활성화된 상태에서 활성화될 때 호출
Start :
게임 오브젝트와 스크립트 모두 활성화된 경우에만 호출
SingletonBehaviour를 상속 받는 게임 오브젝트가 다른 모든 게임 오브젝트보다 먼저 Awake()를 처리(즉, 초기화)해야 한다.
⇒ 하지만 이 순서를 강제할 수 없다.
Awake()는 가상 함수가 아니다
→ 부모와 자식 클래스의 Awake()가 겹칠 수 있다
→ 접근 한정자를 바꿔준다.
추가 : 게임 매니저가 씬 자체에 없다면, 동적으로 만들어서 배치하는 방법도 있다.
void Awake()
{
// (생략)
// 만약 깜빡하고 해당 오브젝트를 생성하지 않았다면 만들어 준다.
if(instance == null)
{
GameObject go = new GameObject("@GameManager");
instance = go.AddComponent<T>();
}
}
https://docs.unity3d.com/kr/current/ScriptReference/index.html
[SM's Development Log:티스토리]
https://haedallog.tistory.com/184