교재
게임 엔진에 대한 내용을 가지고 있는 jason Gregory 의 Game Engine Architecture
오늘날 Unity 와 unreal angine 이렇게 두 가지로 크게 양분된다.
언리얼의 경우 엔진으로 시작하기 보다는 게임을 만드는 과정에서 파생된 소프트웨어이다.
유니티의 경우 늦게 등장했지만 사용이 용이하게 만들어졌다.
최적화적인 부분 등에서는 언리얼에 비해 떨어진다.
언리얼은 open source 이다.
유니티 에셋스토어.
게임 엔진이라고 하는 것은 결국 비디오 게임을 만들기 위함인데, 이에 필요한 기술들은 아래와 같다.


가상 세계에서 그려지는 게임월드라는 것이 추상적으로 존재.
data만으로는 충분히 보일 수 없다. 따라서 사운드,입력 등에 대한것이 UI를 통해 Game world와 소통하게 된다. Data와 입출력 디바이스 사이에 연결점이 game Wolrd 라고 볼 수 있다.
이러한 Game World 에 동적인 움직임을 보여주기 위한것이 아래에 있는 여러 게임 엔진이다.

각 플랫폼(리눅스, 윈도우 등)에 대해서 일괄적으로 작용하기 위해 서로 다른 플랫폼의 API를 mapping 하여 동일 기능으로 작동하게 하는 Layer.

Platform Independce layer 위의 Core System 이있다.
아래의 기능들을 모아 놓는다.

앞서 말한 에셋을 어떻게 넣어 사용할 것인가와 runtime part 두 가지로 나뉜다.
the chain of off-line tools -> 게임 만들기 전의 단계
기본적인 게임에 들어가기 전의 파일이 가공이 필요하다
the resources at runtime - 기존의 파일이 사용될때 잘 불러오는 관리


vertex 들로 점을 찍고 폴리곤 -> 매쉬 -> 이를 통해 여러 픽셀들의 집합으로 만든다.
색칠하는 과정 shading
이러한 데이터들은 pixel 단계로 비춰져야 우리가 볼 수 있게된다. 이렇게 시각적으로 표현하는 Layer 가 Rendering Layer 이다.

원근법을 사용하는 Perspective 투영과 같은 크기로 바라보는 Orthographic 투영이 있다.

색깔을 칠하는 shading 추후 다시 소개 예정

Polygon 의 집합으로 표현하면 질감이 들어나지 않으니 이미지를 해당 Polygon 위에 mapping 을 통해 색감과 질감을 줄 수 있다.
눈에 보이지 않는 것을 미리 자르는 것을 Culling이라고 한다.


이미지 생성시 추후 처리를 거쳐 rendering 과정에 특색을 추가하는 방법.
많은 fillter , wrighting 기법들이 들어간다

각 물체간의 충돌을 효율적으로 감지할 필요가 있다. 이러한 충돌에 대한 처리가 물리 시뮬레이션에 가장 중요한 부분이다.

물리적인 법칙에 따른 방식의 애니메이션이 아니라 미리 구현해놓은 방식에 따르는 Animation을 의미한다.
inverse kinematics 인체 구학, 관절의 회전 정도를 통해 모션을 역으로 구해낼 수 있다. 이를 줄여 IK라고 한다.

사용자에게 입력 받는 여러 디바이스들
게임의 끝단 부분, 실질적으로 우리가 코딩하고 만드는 부분

특정 이벤트에 따른 반응을 코딩할 수 있도록 만드는 것.
화면에 보이는 것은 블루프린트 -> 언리얼 엔진에 사용되는 코딩 툴
unity - c#
unreal -블루프린트 , c++
리소스 관리를 중점으로 좀 더 살펴보자

리소스라는 것에 들어갈 만한 내용들은
Mesh - 3차원 다각형의 집합, 3차원의 표면
Meterails - 색깔의 변화 등
Texture - 이미지
Shader program - 색칠하는 것을 코딩을 통해서 한다했잖아 그런거
Animation - 에니메이션에 관련된 것들
Collisison Primitive - 충돌 감지에 사용되는 감지 범위
Physics Parameter - 물리적인 요소의 사용되는 매개변수들

resouce를 잘 정리된 방법으로 사용하려고 한다.
이를 위해선 메타데이터가 필요하다.
메타라고 하는 것은 좀 더 상위에 들어가는 개념이라고 보면된다.
예를 들어 texture 다 -> 압축을 얼마나했느냐

이런 메타데이터의 유연한 관리를 하기 방법
일반적으로는 같은 형태 끼리 같은 폴더에 저장된다.

필요한 기능
- 여러 resource를 다룰 수 있어야한다
- resource의 생성 및 삭제
- resource를 확인하고 볼 수 있어야한다.
- resource의 물리적인 위치(DB상의 위치) 가 중요하지 않아야함
- 상호 참조가능
결합되어 복잡한 형태를 가질 수 있다.(서로간의 reference)- Revision history
리소스의 변경사항 파악- Searching and querying
원하는 리소스를 찾고 확인 가능 해야함

프리펩 -> 미리 만들어 져있다는 뜻 pre-frabricate
이러한 것들을 통해 최종적인 Scene 에 보이게 한다.

각종 외부 editor 들이 있다. 이러한 것 들로 각종 convert 과정을 통해 최종적으로 유니티에서 사용할 수 있게 변화한다.
각각의 모델 파일이 여러개의 Mutiple asset으로 import된다.
fbx 파일을 import시키면 아래와 같이 나온다.
이와 같이 여러 tap 의 형태로 등장



모든 resource 가 동시에 올라올 필요는 없다. 그렇기에 특정 순간을 기점으로 로딩하는 것이 다를 것이다.
1.게임 전체에 사용되는 정보
2.레벨 단위 로딩
3. 드물게 나오는 이펙트
비동기적으로 한다. -> 로딩때 시간이 걸리면 싫으니까 백그라운드에서 필요한 순간에 미리

LSR 항상 로딩
Level-wise 각 레벨별 로딩
Temporary필요할때 잠깐
Streamed 스트리밍 ->

여기에 나오는 숫자는 Reference count 몇번 참조되는가
필요한 resource
level 1 -> ABC
level 2 -> BCDE
level 2 필요한 애들 1씩증가
level 1은 이제 안쓰니까 자기에게 필요했던애들 -1 씩
로딩단계에서 현재 0인 애들 (1)이렇게 로딩해주는것.

유니티는 레벨위에 올려놓으면 동시에 올라감
내가 runtime 에 필요의 경우에 따라서 로딩하는 경우는
AssetBundles.loadAsset()
ㄴ 유니티 플레이어 밖에 존재하는 외부 리소스
Resource.load()
ㄴ 플레이어안에 있는 리소스 폴더를 의미
동적으로 웹서버에 들어가 가져오는 것, 실행파일 안에 있는것 정도의 차이

GC가 존재해서 메모리를 관리해준다.
아까 말한 reference count를 써서 GC가 잡아서 메모리 공간에서 해제한다.
GC를 직접 동작시키고 싶다. System.GC.Collect()를 쓰면 된다.
ㄴ 실제론 잘 안씀- 교수님도 안씀
모든 게임이 가지고 있다.

게임 - 매 프레임 마다 새로운 상태로 변화시키고 그려주고 입력을 받는 것
어딘가에는 이러한 루프가 존재해야한다. 종료 전까지 계속해서.
보통 하는 일은

이런 식의 게임 로직
랜더링과 큰 줄기는 비슷하나 사용자에게 입력 받은 상태 변화를 반영한다는 것이 가장 큰 차이이다.
이러한 차이를 구현하는데 2가지 방식이 있는데
1.메세지 pump
2.Callback
대게 위와 같은 두가지 방식으로 구현한다.


callback 함수의 경우는 등록을 해놓으면 특정 이벤트 발생시 자동으로 넘어간다. framelistener 프레임에 관련된 이벤트 발생시 이를 처리하는 callback 함수를 처리해줌
메시지를 받아 처리하느냐 , callback 함수를 사용하느냐의 차이

이런 프레임 리스너는 상위의 클래스에서 함수를 불러온다. 원하는 이벤트에 맞는 함수를 오버라이딩하여 사용하게 된다. 프레임 마다 관심있는 객체들을 늘릴 수 있다.
예시
Playable Charater 뿐만 아니라 NPC도 등록을 하고 상호작용

유니티의 게임 오브젝트들은 MonoBehaviour 에 등록이 되어있다.
Update와 Start 등의 코드를 작성하게 된다.
위에 보이는 내용들은 유니티의 익숙해지면 그 차이에 익숙해지게된다.
Update - 매 프레임마다(1초에 60프레임)
FixedUpdate - 정규 시간마다
LateUpdate - Update가 끝난후

우선 이러한 것들이 있다는 것을 알면되고 필요시에 찾아서 사용할 줄 알면 된다.
내 프레임이 얼마나 빠르게 바껴나가느냐를 이야기하는 프레임의 비율

Frame Per Second
영화나 TV의 경우 24 FPS
게임의 경우 60 FPS
매프레임 마다 동일한 간격으로 Update 되면 좋겠지만 실제론 그렇게 되지 않을 수 있다. 그렇기에 현실세계의 시간이 필요하다
이러한 프레임과 프레임간의 시간을 Δt로 이야기한다

예시
얼마 만큼 이동했는지 Δt후 속도 = 속도 +가속도* Δt로 표현
Δt가 똑같은 Δt라도 좀 더 좋은 접근법이 있을 수 있다 이는 예시로 오일러 접근법을 사용했다.
우선 Δt가 크기 때문에 근사에 대한 오류가 있다.
Δt 가 일정하지 않으면 오류의 부정확도가 높아져서 더욱 문제가 발생할 수 있다.
Δt 를 고정 수치로 했을 때 컴퓨터의 성능에 따라 시뮬레이션의 속도가 결정 될 수 있다. (고성능 -> 빠른 시뮬 , 저성능->느린 시뮬)

컴퓨터의 속도에 따라 서로 다른 게임
ex) 테트리스의 터보 버튼 - 누르면 게임 속도가 빨라짐

모든 사람이 동일한 경험을 하게하려면 Δt를 고려해서 할 필요가 있다 그래서 현재 대부분의 컴퓨터에서 High-resolution timer를 제공한다.
펜티엄이라는 옛날 컴퓨터에도 엄청 작동을 잘한다.

위와 같은 함수들을 제공한다는 점만 인지하면된다. 이렇게 High-resolution timer 접근할 수 있다. 유니티는 High-resolution timer가 자동으로 적용되어 있고 Update()에서 해당 정보를 불러오는 API도 존재한다.

Time.time을 사용하여 시간의 대한 정보를 불러올 수 있다. 아래 코드는 연속적인 발사가 아닌 최소한의 대기시간을 넣어주는 역할을 한다.