TIL

2024 11 15 TIL

noc777 2024. 11. 15. 23:30

팀 과제 시작 후 역할 분담의 시간을 가졌음

이번 주제는 자유주제 장르는 공포  현재 맡은 역할은 Navmesh AI를 이용한 적 구현

전체적으로 팀 빌딩은 마치고 폴더링 후 제네릭 싱글톤만 구현하고 변경사항을 적용시켜 기본 틀을 만들어두었다.

 

새로 배우거나 좀 더 확실히 알게 된 개념

 

1. 제네릭 싱글톤 개선점

 

이번에 제네릭 싱글톤을 다같이 만들면서 DontDestroyOnLoad 할 싱글톤과 아닌 싱글톤을 기능을 나누어서 하려했는데

처음엔 두개의 제네릭 싱글톤 스크립트로 나누어 관리를 하려고 하였다.  그렇지만 만들고보니 비슷한 기능의 스크립트를 두개로 만들어 관리하는 것이 좋은 지에 대해 의구심이 좀 든다.

 

그래서 팀원분의 조언을 참고하여 두개의 싱글톤으로 구현하는 것이 아닌 상속시키는 클래스에서 커스텀하여 적용하는 식으로 하기로 하였다.  밑의 스크립트는 개선한 내용의 스크립트를 담고있다.

 

먼저 상속하는 클래스 쪽에서 똑같이 제네릭 싱글톤을 구현한 후 Virtual 키워드로 DontDestroyOnLoad 기능을 구현할 것인 지 여부를 정해준다.

public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T _instance;

    public static T Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = FindObjectOfType<T>();

                if (_instance == null)
                {
                    GameObject obj = new GameObject(typeof(T).Name);
                    _instance = obj.AddComponent<T>();
                }
            }

            return _instance;
        }
    }

    protected virtual void Awake()
    {
        if (_instance == null)
        {
            _instance = this as T;
            DontDestroyOnLoad(_instance);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

 

상속받는 클래스에서는 base.Awake() 하여 기능을 구분해 하나의 싱글톤을 운영하는 방식으로 바꾸었다. 

public class GameManager : Singleton<GameManager>
{
    protected override void Awake()
    {
        base.Awake();
    }
}

 

이를 통해 좀 더 안정적인 제네릭 싱글톤 운용을 해볼 수 있을 것이다. 이후 오류가 있다면 분석하여 수정하는 쪽으로 운용해보기로 하였다.

 

2. Vector

 

오늘 특강에서는 최종 프로젝트 전에 유의할 사항 등을 정리해보는 시간을 가졌다. 

 

Vector는 방향과 크기를 정의하는 단위이다. 

 

Vector 에 대해서 자세하게 알아보자면 덧셈 뺄셈 스칼라 곱으로 볼수 있다.

일단 시간상 많은 것을 정리할 수 없을 것 같기에 덧셈과 뺄셈만 더 정리해본다.

 

덧셈을 먼저 보자면 

덧셈은 두 방향과 크기의 합이다. 

 

아래의 공식문서의 예제를 보았을 때 (3,5) + (2,-1) 를 하였을 때 (5,4)가 되는 것을 이해하려면

(2,-1)이 어떻게 그려지는 지 상상해볼 수 있어야한다.  (0,0) 에서 (2,-1) 로 이어진 선을 생각해본다면

아래 예제의 b와 같은 방향과 크기의 선을 볼 수 있을 것이다. 

즉 여기서 우리가 알 수 있는 건 위치는 중요한 것이 아니라는 것이다.   방향과 크기가 만 같다면 그것은 같은 벡터라고 할 수 있다.

출처 - 유니티 공식 Doc

 

뺄셈은 덧셈과 약간 다르게 접근해야한다.  

뺄셈은 두 지점 사이의 크기와 방향을 구한다. 

아래 예제를 보았을 때 지점 b 에서 a 를 뺐을 때 (5,4)가 계산되었다.  이것은 a가 b까지 가는 데 있어

방향과 크기를 구한 것으로 두 지점이 멀수록 거리가 멀어지기에 같은 시간동안 가려면 그만큼 크기가 커지는 것이다.  

방향 자체는 같더라도 가는 데 필요한 힘의 크기가 달라지는 것을 이용하여 우린 물리연산에 이를 속도로 이용하는 것이다.

카메라가 플레이어를 쫒아가게 할 때 cam의 transform position 값을 player의 tranform position 값에 빼는 것도 같은 원리이다.

출처 - 유니티 공식 Doc

 

magnitude
//크기만을 다루고 싶을 때

normalize
//방향만을 다루고 싶을 때
//이 때 크기는 1이 된다.

벡터는 힘과 방향을 나타내기 때문에 가끔 이 크기와 방향만을 다루고 싶을 때가 있다. 우리가 계속 배웠던 

magnitude와 normalize는 그것을 위해 만들어진 키워드였다. 

 

 

3. 최종 프로젝트 전에 알아둘 것

 

1. 폴더링을 잘하자 

협업을 하는 데 있어 그리고 나 자신에게도 있어 폴더링을 잘하면 작업하는 데 도움이 된다.

01.Scene   //자주 쓰이는 순으로 배치
02.Scripts
.
.
.
.
99.Assets // 유료에셋 이유는 따로빼두어 숨겨야할 때를 대비해 멀리 떨어진 숫자로 배정

 

2. 안쓰는 생명주기 함수를 지우자

안쓰는 생명주기를 지우는 이유는 MonoBehaviour 를 상속받았을 때 생명주기 함수를 리플렉션을 사용해서 호출하는 방식이라 안쓰고 있더라도 성능을 잡아먹는다.

 

3. 다 쓴 Debug.Log는 지우자 

빌드할 때 디버그로그 또한 출력되어 성능 상 문제 그리고 해킹에 실마리를 줄 수 있다.

 

이를 사전에 방지하고자 한다면 아래 코드를 사용하여 디버그하는 것도 방법이다.

Debug.Assert (조건,false면 뜨는 로그)
Debug.LogAssertion(""); // 빌드를 쓸 때 제외됨

 

4. Linq 의 남용은 피하자

Linq가 편리하긴 하지만 Linq로 구현 가능한 것은 for 와 if로도 구현이 가능하다.

Linq는 .netFramework에서 호환해서 동작하는 방식이기에 많이 쓰면 성능에 좋다고 하기 힘들다.

 

5. 문자열끼리 덧셈은 피하자

문자열끼리의 합은 힙 스택과 가비지컬렉터의 원리로 이해하여야 한다. 

요약하면 성능에 안좋다.
stringbuilder 사용을 권장한다.

 

6. 코루틴 유의점

코루틴을 쓸 때 while (true) 안에 new WaitforSeconds를 선언하는 것 처럼 사용된다면

계속 객체를 생성하기 떄문에 언젠가 가비지컬렉터가 회수하러 올 때 게임이 멈춰버린다.
WaitForSeconds wait  처럼 미리 캐싱을 해놓고 사용함이 현명하다. 

 

7. 오브젝트 풀을 꼭 활용하라

모든 생성되고 파괴되는 것들은 오브젝트 풀로 성능부하를 미리 사전에 방지하여야 한다. (미리 로딩 시간에 받아놓자는 것)

일반적인 오브젝트 뿐 아니라 사운드와 파티클 등도 오브젝트 풀로 관리해야한다.

그리고 오브젝트풀로 생성되는 객체는 자식 오브젝트로 두면 그것 또한 성능에 영향을 주므로 최상단 계층에서 운용하는 게 낫다.

 

8.언박싱을 피하라

값 참조를 넘나드는 행위도 가비지 컬렉터를 유발한다. 

진짜 필요한 상황이 아니라면 자제하는 것이 좋다.

'TIL' 카테고리의 다른 글

2024 11 19 TIL  (2) 2024.11.19
2024 11 18 TIL  (0) 2024.11.18
2024 11 14 TIL  (0) 2024.11.14
2024 11 13 TIL  (0) 2024.11.13
2024 11 12 TIL  (0) 2024.11.12