* 대화 설계 구조 작업

- Excel에 사용할 Asset 및 대본을 작성후 해당 폴더에 넣으면 Json으로 변환 후 파싱하여

각 Command에 따라 기능이 동작하게 설계

 

- 기획에서 리소스 테스트를 위해 Dialog_Demo를 따로 제작하여 전달

ㄴ Dialog_Demo는 StreamAsset 폴더내에 외부 리소스(Spine,Sound,Image)를 넣어 빌드 버전에서 바로 사용하게 작업

ㄴ Build버전에서 사용할 [ Excel -> Json 변환 Tool ] 을 만들어 기획에게 전달

 

- 메인화면 에서 대화씬 진입시 로딩화면 연출 및 제작 

 

미구현 된 기능

- 채팅내역 보기

- 대화씬에서 특수연출(파티클,쉐이더)을 Excel을 통해 사용 할 수 있게 구현 

- 해당 진행도에 따라 스토리 해금 조건 및 보상 설계 구조 

이슈 상황 :

대화 스크립트 엑셀 파일에서 Command란에

 

$TokenType : Value $

를 작성하고 역직렬화 할때 , 파싱해서 사용을 하고 있다.

 

하지만 해당 문자열을 파싱할때 문제가 발생했다.

 

"$fade:true$ $duration:0.5$ $easygraph:4$"

 

fadeeasygraph는 토큰으로 인지하여 값을 분리했는데

duration value인 0.5가 값으로 안 읽히고 text 토큰 형태로 읽히는 문제가 발생했다.

 

원인 :

   private static readonly Regex TagRegex =
        new Regex(@"\$(\w+):(\w*)\$", RegexOptions.Compiled);

Command 문자열을 특정패턴으로 분리 할수있게 Regax를 사용하고 있다.

 

(\w*)

원인은 이 정규식(Regax) 때문이였다.

\w는 보통 영문자,숫자,밑줄(_)허용함,

예시 ) abc,A1,test_01 이런것만 정규식으로 인정이 된다는 것

0.5에는 점(.)이 있으므로 매칭이 되지 않는다. 

 

그렇기때문에 앞에 duration 토큰 탐색후 value값 탐색시에 조건이 안맞으므로

예외 처리로 text 토큰 처리를 하게 된것이다. 

 

해결 방법 : 

   private static readonly Regex TagRegex =
      new Regex(@"\$(\w+):([^$]*)\$", RegexOptions.Compiled);

 

(\w*) => ([^$]*)

로 정규식을 변경하였다.

 

[^$]* 해당 정규식을 사용한 의미

1. 값 부분은 $ 아니면 전부 허용

2. * 이므로 빈 문자열(공백)도 허용

 

예시 : 

$tag:0.5$
$tag:-1.25$
$tag:hello world$
$tag:50%$
$tag:test_01$
$tag:abc-def$
$tag:$

 

Value 부분에 어떤 값이 들어와도 해당 토큰에 따라 변경을 해놓게 해결하였다.

camelCase 소문자로 시작, 띄어쓰기 생략, 대문자로 구분
PascalCase 대문자로 시작, 띄어쓰기 생략, 대문자로 구분
snake_Case 소문자만 사용 ,띄어쓰기 대신 _ 사용
kebab-case 소문자만 사용 ,띄어쓰기 대신 - 사용

5-1. [namespace], [class] , [struct] 는 파스칼을 사용
5-2. [함수]는 파스칼을 사용 , 함수 내부는 카멜을 사용
5-3. [Enum]는 파스칼을 사용
5-4. public 변수는 파스칼을 사용 ex) public int Num;
5-5. 나머지 변수는 _ + 카멜을 사용 ex) private int _num;

1.컴퓨터 
저장 장치
하드디스크 -  컴퓨터에 물리적으로 파일을 저장
메모리 - 프로그램/어플리케이션이 실행하는데 필요한 데이터를 저장 
ex) 게임 - 레벨,소유골드 등등...

메모리는 배열처럼 생겼다 (배열은 아님!!!!)
Code : 프로그래머가 작성한 코드를 보관
Data : static,const 어플리케이션 전반에 필요한 데이터 저장
Heap : 참조 데이터 (객체) 저장
Stack : 로컬변수 ,매개변수 저장
어플리케이션 실행 순서에 필요한 데이터 보관

메모리는 2진수로된 주소값이 있다.
해당 메모리에 접근하기 위해 주소값을 가지고 있으면 된다 -> C/C++의 포인터 기능

int x = 10; 
해당 데이터(10)는 stack영역 메모리 첫번째에 저장된다.
메모리 첫번쨰는 0000 0000주소값을 가지고있는데

해당 데이터에 접근하기 위해 0000 0000 주소값을 가져오는게 아닌 x로 변경하여 사용하게 되는것이다.
x도 stack 영역에 저장됨

= : Rvalue를 Lvalue로 옮겨주는것이다.

class는 참조값이기에 heap 영역에 추가됨
heap은 어디에 저장되는지 모름, 그리고 알 필요도 없기에 빈 어딘가에 저장된다고 생각하면 됨

Class Person 
Class Data는 heap영역에
Calss로 만들어진 객체는 Stack 영역에 저장됨

사용할떄 주의할점
Stack 영역
변수할당시 생성
함수가 끝날때 삭제

참조가 한번 끊어지면 다시 heap영역의 data에 접근이 되지 안흔ㄴ다 -> heap영역의 과잉생산 -> 메모리 누수

데이터가 있지만 활용하지 못하는것 -> 쓰레기(가비지)
데이터가 언제 삭제되는지 모름, 단 한 조건은 있음
데이터가 사용되지 않을때 (참조가 끊겼을때)

GC가 언젠가 쓰지않는 데이터를 호출하여 처리해줌

가비지가 생긴다고 했을때
가비지를 1개만 가져가면 괜찮지만
가비지를 100개 1000개씩 한번에 가져갈때
컴퓨터가 과부하가 걸린다 -> 게임시 렉이 걸리는 이유

효율적으로 쓴다 = 가비지를 최대한 적게 생성시킨다.

Heap영역
new를 통해 생성 GC로 인해 삭제
Unity에서는 Instanitate() , Destroy()
하지만 Destroy()에서는 오브젝트가 삭제되는거지 Data는 남아있어 가비지로 남아있음 

유니티 inspector에 들어간 컴포넌트의 상위는 Class ->Monobehaviour 이다. 즉 ,  Instanitate() 를하면 new를 통해 생성하는것과 똑같은 의미이다.

최적화 -> 반복적으로 new 하는것을 줄인다
(Update,While 등등...)

최적화 1.
데이터를 한번 준비하고 **재활용**
-> 변수들을 미리 선언하여 호출하여 쓰기 

Unity에서 Vector는 구조체이기 때문
C/C++ 에서는 구조체나 class는 비슷하다.
(왜냐하면 프로그래머가 직접 메모리 할당 및 해지 , 포인터를 이용한 주소값 접근을  담당하기 때문)

하지만 C#은 다르다.
구조체는 데이터 자체가 Stack영역에 생성됨
즉, 구조체는 가비지가 남지 않게된다.
Stack 메모리가 heap 속도보다 더 빠르다
즉, Vector는 자주 사용되기 때문에 구조체로 Unity에서 만든것이다.

string str = "유저 레벨"

유 저  레 벨 이라는 5가지 저장됨

문자열은 불변객체 = 변하지 않는다는 뜻

str += "chad" 가 실행되면

내부적으로 간단하게
유저 레벨 뒤에 chad가 붙는것이 아니다.
즉, 유저 레벨 뒤 heap영역 메모리 데이터에 다른 데이터들도 있기에 붙일수가 없기 때문이다. 

유저레벨 + chad를 합친 문자열을 다른 heap영역에 새로 만들어진다. 

즉, heap에는 유저 레벨 , 유저레벨 chad 데이터가 2개가 동시에 존재하는 것이다
즉 string의 += 연산자를 계속 쓸때마다 heap영역을 쓰는 것이고 추가가 되어진다. 

이런 현상을 "파편화"라고 한다.

문자열 대처법
1.string을 한번에 제작 [ 보간문자열,스트링포맷,+연산자]
(추천)1-1.보간 문자열 : 문자열 앞에 $ 표시를 붙여 사용한다.
1-2.string.Format
1-3.+연산자를 한줄에 적어버리기

문자열을 한번에 제작하지 못하는경우
2.StringBuilder 사용하기

근데 왜 StringBuilder는 왜 이렇게 사용해도 괜찮은가??
ex)
유저 레벨 이 5글자이면 , StringBuilder는 추가로 공간을 확보해놓고 해당 확보한 공간을 넘어서는경우 새로 ㅏㄴ들게 된다. -> C#의 List와 유사하다.

stringBuilder는 처음에 16글자
넘어가면 2배인 32글자를 새로운 heap영역에 할당 이런식으로 된다.

stringBuilder는 일반 문자열보다 느리지만 파편화를 덜 방지 할 수 있기에 사용이 추천된다.

StringBuilder도 처음 초기화시 크기를 선언하고 사용 할 수 있다.

웬만한 문자열은 보간문자열을 사용할 수 ㅣㅆ고
중간중간 문자열이나 Data를 실시간으로 조합할때는 StringBuilder를 추천한다.
(개별 입력으로 받아들여서 합치는 경우에는 StringBuilder, 개발자가 처음 부터 값을 넣어주는 경우에는 $""를 쓰는 게 좋겠군요.)

Stack 값 형식 =  value
C#의 기본 타입(int,float,bool,char) , 구조체 , enum
Heap 참조형식 = referance
string class 배열 interface delegate

구조체는 Stack에 할당
메모리는 Stack에만 저장
큰 데이터나 외부 데이터를 가져와서 사용할떄 문제 발생

Calss는 Heap에 할당
Class의 객체(변수)는 stack에
Class 객체의 data는 heap영역에
데이터 접근은 Stack에 접근후 데이터의 주소를 파악후 heap영역에 접근한다. 

C#에서는 Class를 만들떄 new 어트리뷰트를 사용하여 생성한다. 유니티는 Instaiate는 new키워드와 유사한다

Static 키워드가 변수 ,메서드가 있으면
외부의 클래스의 이름을 바로 호출하여 바로 사용 할 수 있다.

Static을 메모리 관점으로 봤을때
Data영역에 배치 되어있음 
Data 영역은 프로그램 시작시 생성
프로그램 종료시 삭제

즉 , Static 키워드는 Data영역에 접근하여 언제든지 호출이 가능해진다.

Static 키워드 데이터는 Scene 사이의 데이터가 유지되어있다.

Static Class는 데이터를 세팅해줘야 됨
나머지 int,float은 언제든지 쓸 수 있음 
객체도 Class라서 초기값은 null이다.

Static 키워드들이 heap,stack영역 데이터에 접근해서 사용 할수는 없다.

'C#' 카테고리의 다른 글

Dirty Flag Pattern  (0) 2026.02.03
C# :: 메모리 구조  (0) 2024.10.14

* 타일맵의 정적 오브젝트 충돌 처리시 사용 방법 
composite collider : 타일 하나당 collider 적용되는것을 막기위해(연산 초과)  및 이상한 충돌처리를 막기위해 컴포넌트 추가
=> 리지드바디2D가 자동으로 추가 됨, body type을 static으로 변경 -> 정적으로 변경해서 고정된 얘들끼리는 충돌연산을 하지 않기에 비용이 매우 쌈

* Scene에서 리소스가 꺠져보이는 경우 발생
 원인 :  카메라의 해상도가 맞지 않기에 생기는 문제점 
대처법 : 스프라이트 아틀라스 사용하고 패킹 후 필터모드를 포인트로 변경 하면 부드럽고 리소스가 깨지는것을 방지 가능 

* 게임 중단 및 종료, 오브젝트 파괴시 사용되는 함수 

OnApplocationPause()
:모바일 개발시 많이 사용
home버튼을 누를떄 사용됨(검색할것)
OnApplicationQuit() 
:종료되는 시점을 알려주는 함수
Ondestroy()
:해당 오브젝트를 컴포넌트로 가지고있는경우 파괴 될때 알려줌

* Animator State Tip
Any State에서는 Settings에 Can Transition To Self 체크옵션을 빼주면 자기 자신한테 상태이전은 하지 않는다. 이로서 위처럼 깔끔하게 처리를 할수 있었다.

can Transsition self : 해당 컨디션에서 또 조건이 되면 애니메이션을 재생 

 

* 콜라이더 충돌 오브젝트 통과 판정 만들기
Collider 컴포넌트의 use-effect 체크 -> Surface Arc 사용가능
Surface Arc (표면각도)  : 이 각도 수치가 넘으면  이 오브젝트를 뚫고 지나가는지를 판단 

랜덤 맵 생성 기능
ㄴ하나의 스테이지 안에 맵을 랜덤으로 생성합니다.
ㄴ참고 키워드) 절차적 맵 생성 (Procedural Map Generation)
BigInteger 기능
ㄴ매우 큰 숫자를 처리하기 위한 기능입니다.
ㄴ방치형 게임에서 나오는 1a, 4d 등의 숫자를 구현합니다.
ㄴ참고) https://github.com/keiwando/biginteger

Cinemachine - VirtualCamera Inspector 

더보기

- Lens Vertical FOV
:카메라 컴포넌트에서 사용
: FOV (Field of View) 의 약자, 시야각이란 뜻
: 카메라의 렌즈에서 위에서 아래로 보이는 영역의 각도
:값이 크면 더 많은 영역을 볼 수 있지만, 특정 지점까지 가까워질수록 왜곡이나 물체의 크기 변화가 눈에 띌 수 있습니다. 작은 값은 시야가 제한되어 작은 영역만 볼 수 있지만, 더 멀리 있는 물체가 더 자연스럽게 보일 수 있습니다.

-Body :  가상 카메라의 위치와 회전을 결정하는 대상(Transform)을 지정
1.Transposer : Follow 대상에 대해 고정돤 관계로 움직입니다.
2.Do Nothing : 카메라가 움직이지 않음
3.Framing Transposer : Follow 대상에 대해 고정된 화면 공간관계로 이동 
4.Orbital Transposer : Follow 에 대한 변수 관계로 이동하며 선택적으로 플레이어 입력을 수락합니다.
5.Tracked Dolly : 사전 정의된 경로를 따라 이동합니다. 
6.Hard Lock to Target : Follow에서 동일한 위치를 사용

Body - Binding Mode : 가상 카메라의 위치와 회전을 어떻게 대상(Transform)과 연결할지 결정 - Follow 
1.World Space : 가상카메라의 위치와 회전이 월드 공간에서 대상과 동일하게 설정,
가상카메라 = 대상 와 동일시됨
2.World Space Offset : 위의 옵션과 동일하나
오프셋을 설정하여 오프셋 위치나 회전에 고정이나 이동가능해짐
3.Follow Target : 
Cinemachine의 추적 시스템을 활용하여 대상을 따라가도록 함, 카메라의 움직임에 대상의 속도,감속도,회전등 적용 가능
4.Follow Target With World Up :
위의 옵션과 유사하나 대상의 상단을 월드 업 벡터로 정렬하여 카메라 회전을 제어 

Aim : 가상카메라의 회전을 결정, - Look At
1.Composer :카메라 프레임에 Look At  대상을 유지
2.Group .Composer : 카메라 프레임에 여러 Look At 대상을 유지
3.Do Nothing : 가상 카메라를 회전시키지 않음
4. POV : 사용자 입력에 따라 회전시킴
5. Same As Follow Target : 카메라의 회전을 Follow Target 의 회전으로 설정
6.Hard Look At : 시선 대상을 카메라 프레임 중앙에 유지

Unity Animatior Controller Inspector

더보기

Animator controller (Weight : 가중치)
해당 레이어의 가중치를 몇% 만큼 합칠거냐라는 뜻( 투명도 x)
->서있는 포즈(1) , 총들고있는포즈(0.5)로 설정시  두 애니메이션이 합쳐져 어중간하게 서있는 포즈가 된다.  

Animator controller ( Kinemetics : 운동학(키네매틱))
애니메이션이 움직이면 하이어라키(계층구조)에 따라 부모가 움직이면 자식들이 영향을 받아 움직이는 구조를 나타냄 

하지만, 자식이 움직이면 부모가 따라 움직이는 구조를 IK(Iverese Kinematics) 라 한다.
-> 즉, 특정 위치를 중심으로 관절의 위치를 역(자식->부모)로 계산
IK Pass : ( IK기능을 활성화하는 기능)
-> 비용이 매우큼(지양적)
->오브젝트의 위치가 어디에 있든, 거기에 맞추어 시선이나 팔 등의 위치를 결정할 때 사용
-> 컴퓨터 그래픽스 이해목적으로 사용

 

 

* for문은 종료 될떄까지 메모리를 계속 쌓음 => for문이 다중으로 쓰일때마다 메모리가 계속 쌓임

* 재귀함수는 함수가 종료될때 함수 메모리가 쌓이지 않음

결론 : 메모리 확보 목적으로는 재귀함수 / 속도를 중시하면 for문

'기술면접질문' 카테고리의 다른 글

기술 면접 리스트  (0) 2024.12.12
기술 면접 질문과 답변(1)  (0) 2024.12.09

+ Recent posts