PlayerPrefs - 간단한것만, 예를들어 환경변수, 옵션, 등


Binary Formatter - 과거 일반적으로 사용했던 방법

데이터를 볼수 없기에 보안에 좋은 줄 알았으나, MS에서 사용하지 말라고 권고,

https://docs.microsoft.com/ko-kr/dotnet/standard/serialization/binaryformatter-security-guide

대체제로 Xml 이나 Json 등이 거론됨..(이건 다 보이는데??)

직렬화 하고 알아서 암복호화 해서 쓰라는듯..


그렇다면 결론은 Json

Xml은 아무리 생각해도 은근히 사용하기도 어렵고 디버깅하기도 어려움.

Unity 내장 JsonUtility를 사용시 Vector3 같은것도 한번에 Serialize 가능한 장점이 있음.


Assembly Definition 도 정상이고,

Addressables도 잘 구성해놨는데


Addressables 를 빌드하면 오류가 발생하는 경우가 있다. 


원래 유니티에서 Editor 폴더는 빌드시 제외되는데 

Assembly Definition 으로 생성하면 Editor 폴더가 같이 포함되어 버린다. 

그때 Addressables로 빌드하면 해당 소스에서 구성요소를 찾을수 없다고 한다. 


Asset

- ThirdParty

  - Localization

    - Editor


이런구조에서 ThirdParty 에셋들을 통으로 Assembly Definition 으로 생성한다면

평소에는 오류가 발생하지 않는데, Addressables 을 빌드할때는 오류가 발생한다. 


이럴경우 

1. Editor 에 Localization.Editor 로 어셈블리정의 파일을 만들고, 

ThridParty 어셈블리 정의를 참조시켜버린다. 

원래라면 Localization 어셈블리 정의만들고, 그 것을 참조시켜야 하지만, 에디터 전용 모듈이니 대충 한다. 


2. Editor 폴더에 있던 스크립트에 전부 전처리를 넣어버린다. #if UNITY_EDITOR



요약 

사용하는 이유 : 

1. 스크립트 빌드 시간 감소

2. 단위테스트

사용시점 : 개발초기(학습이 아닌 실제 제품화 하려고 만들때)

유니티는 기본적으로 모든 프로젝트의 스크립트를 Assembly-CSharp.dll 로 컴파일 합니다. 

간단한 수정을 하더라도, 모든 스크립트를 빌드하기 때문에 여러 서드파티 에셋을 추가하거나, 프로젝트 규모가 커질경우에 빌드시간이 늘어나게 됩니다. 

그걸 모듈별로 나눠서 별도로 빌드해 놓으면 스크립트 컴파일시간이 대폭 줄어들게 됩니다. 

(예를들어 서드파티 에셋들의 경우 수정할일이 거의 없기 때문에 어셈블리 정의하는 편이 좋습니다

일부 에셋의 경우 어셈블리 정의된 파일을 포함해서 배포하고 있습니다.)


사용방법.

1. 에셈블리 정의를 할 폴더를 선택합니다.

(해당 폴더 아래 하위의 모든 스크립트에 대해서 정의됩니다.)



TextAsset 폴더구조는 다음과 같습니다. 
TestAsset 폴더의 어셈블리정의에는 아래 4개의 파일이 포함됩니다. 
- TestAsset : a.cs, b.cs
- Folder1 : c.cs, d.cs

Folder2 에는 어셈블리정의 파일이 있기 때문에 e.cs 파일이 다시 상위에서 정의되지 않습니다. 

여기서 헷갈렸던게
기존 C#의 dll 들은 동일 폴더내에서도 참조, 비참조를 할수 있었는데.
이 어셈블리 정의는 해당 폴더 및 하위 폴더에 대해서 참조 해버리기 때문에. 

종속성을 생각해서 폴더구조를 만들어줘야 한다는 것입니다. 

물론 각 파일별 폴더를 만들고 어셈블리정의 파일을 만들면 완벽하게 커스텀으로 사용 가능하지만 그럼 결국 정의 파일을 읽는데 시간이 더 소모하기 때문에 권장하진 않습니다. 










DB에서 직접 데이터 편집은 귀찮고 힘듬.

구글 시트에서 작업 -> 파일변환 후 DB에 입력 -> 실제 플레이시 DB에서 가져옴


구글시트에서 작업

Json으로 다운로드(Unity Editor)

모든 아이템 프리팹에 데이터 반영 및 저장

Addressbles 로 빌드

그룹을 만드는 방법


1. 모든 리소스를 어드레서블로 사용 + 세부 그룹을 만들고 트리 구성
- 참조하는 모든것에 대한 세부항목에 라벨 지정가능
- 각 오브젝트별로 Group가 생성되서 그룹 생성파일이 많이 생김
- Bundle Mode = Pack Together 사용

Monster2-Forest-Beez
2. 폴더를 어드레서블로 사용
- 세부 항목에 대한 개별 조작은 불가능(폴더의 라벨지정하면 세부도 동일하게 따라감)
- 세부 항목에는 어드레서블이 체크되지 않음(그러나 사용가능)
- 큰 그룹별로 설정파일 관리(ex Monster-Forest)
- Bundle Mode = Pack Separately를 사용하여 몬스터별로 번들이 생성되도록 처리

Monster-Forest

3. 에셋번들을 생성 후 해당 에셋번들을 어드레서블로 사용
(Unite 2019에서 소개하는 PPT에서 이렇게 사용하긴 했는데.. 에셋번들을 사용해본적 없어서 패스)




보통 설명을 보면 참조되는 리소스를 전부 Addressable로 만들지 않고, 프리팹만 Addressable 화 시킴. 그리고 빌드를 하면 참조되는것 전부 자동으로 묶어서 생성됨.
이렇게하면 어드레서블 그룹창에서는 관리가 편해지지만, 리소스에대한 관리가 명시적이지 않아서 추후 실수 할것같은 느낌이 듬.


폴더를 어드레서블로 했을때 유의사항

Beez <- 어드레스 네임으로는 로드 및 다운로드가 불가능하다. 1. Label 을 이용. 2. 하위항목을 직접 선택해서 불러오기를 사용해야 한다. ex) Beez/Beez_Honey.prefab


기본사용법

    //다운로드 하기
    downHandle = Addressables.DownloadDependenciesAsync(key, true);
    //downHandle.PercentComplete -> 잘못된 수치가 표현됨
    text = Mathf.Round(downHandle.GetDownloadStatus().Percent * 100) + " %";
    //다운로드한 파일 삭제
    Addressables.ClearDependencyCacheAsync(key);
    
    //다운로드 사이즈 구하기
    Addressables.GetDownloadSizeAsync(key).Completed +=
            (AsyncOperationHandle<long> sizeHandle) =>
            {
                string sizeText = string.Concat(sizeHandle.Result, " byte");
                Addressables.Release(sizeHandle);
            };

    //리소스 로드
    //여러번 핸들에 넣어도 내부적으로 주소가 참조되는지 전부 들어가있음.
    _handle = Addressables.LoadAssetAsync<GameObject>(key);

    //Load한 만큼 Release 가능.
    Addressables.Release(_handle);

    // 콜백 방식
    Addressables.LoadAssetAsync<GameObject>("AssetAddress").Completed += OnLoadDone;     // 대기 방식     var asset = await Addressables.LoadAssetAsync<GameObject>("AssetAddress").Task;


처음에는 리소스로드 후에 캐싱해서 Instantiate 해서 사용하려고 했었는데.

단점으로 Addressable 에서의 메모리 관리가 되지 않음. (GameObejct.Destory(obj); 를 하더라도 .Net의 가비지를 통해서 처리 되기 때문에)

물론 기존 프로젝트는 특별한 메모리 관리 없이 사용했기 때문에 문제는 없지만,

Addressable 의 최대장점인 리소스의 메모리를 확실하게 관리 할수 있는것을 포기 하기 어려움. (물론 Load 후에 Instantiate 사용한다 하더라도 좀더 어려울뿐 불가능한 것은 아니다. )


Try - Catch 에 Exception 이 캐치되지 않음. 내부코드를 보니 throw 하지 않음.

별도로 로그를 관리하는 경우에는 , 아래와 같이 핸들에 excption 있는지 체크하고 오류가 있을경우에 표시한다.

 if(handle.OperationException != null)
     LogHelper.LogError(handle.OperationException.ToString());

혹시나해서 폴더째로 Addressables을 만들었을때 하위항목을 로드하면 전체 부모쪽이 로드되는것이 아닌가 했는데, 테스트해보니 연관된것만 로드됨.

시중에 있는 던전 생성 알고리즘을 이용하여 2차원 행렬로 던전 데이터 구현


구조는 나왔으니 벽을 만드는 2가지 방법이 존재

1. 실제 플로어보다 높은 벽을 만들기

2. 실제 플로어 아래 벽을 만들기(뒷 배경)


2번의 경우에는 플로어가 공중에 떠있는거라 가정하고 맘대로 배경을 배치해도 좋음.

1번의 경우가 문제

1. 배치할 타일의 8방향을 검사해서 현재 어떤 타일이 올지 결정(대부분의 케이스 사용)

2. 그냥 다 동일한 타일로 배치(제일 쉽지만 퀄리티가..)


위 케이스의 단점은 오픈필드의 경우 디자인이 좋을 수가 없음.

ex 숲, 마을 배경의 던전의 경우

왜냐하면 숲이라면 나무를 반복시켜야 하고, 마을이라면 집? 을 넣을 방법이 없음.


그래서 오픈필드용으로 벽 타일에 들어갈 최대 사각형 크기를 구해서 Treemap 처럼 채워주는 방법을 사용.



2021.02

Terrain -> Detail 에서 Grass로 추가 가능

NavMesh 사용 가능

그러나 LOD 그룹을 사용할 수 없음.


Terrain -> Tree 로 사용

LOD 그룹 사용가능

Navmesh 사용 불가능

별도 Git으로 제공되는 NavMeshAgent 설치시 사용가능

그러나 Batch가 무한정 증가


결국은 일반 게임오브젝트로 추가해야함.