게임 엔진이라는 것은 결국, 다음과 같은 로직으로 작동된다.
https://waterglass0105.tistory.com/91
[UE5 C++ Multiplayer Shooter] #01 언리얼 엔진의 프레임 워크와 기초 그리고 네트워크
일반적인 게임 엔진은 다음 코드의 흐름대로 진행된다.언리얼에서는 이러한 루프를 직접 다루지 않고, 기본함수가 아닌 인터페이스나 함수를 상속받아 확장하는 방법으로 구현한다. 이때, 언리
waterglass0105.tistory.com
이를 유니티 엔진에서 조금 심플하게 표현해보면 다음과 같이 표현할 수 있다.
그리고 이를 더욱 자세히 살펴보면, 다음과 같은 사이클을 가지게 된다.
이제 이 단계를 자세히 살펴보자
1. Initialization
[Awake -> OnEnable -> Reset -> Start]
Awake
- 스크립트가 활성화되기 전에 호출된다.
- 모든 스크립트에서 가정 먼저 호출된다.
- 게임 오브젝트가 비활성화된 상태에서도 호출된다.
- 다른 컴포넌트나 게임 오브젝트와의 참조를 초기화하는데 주로 사용한다.
OnEnable
- 스크립트가 활성화 될 때 호출된다.
- 게임 오브젝트나 컴포넌트가 활성화될 때마다 다시 호출된다.
Reset
- 오브젝트에 처음 연결하거나 Reset 커맨드를 사용할 때 호출된다.
- 스크립트의 프로퍼티를 초기화하기 위해 호출된다.
- Reset 단계는 스크립트가 부착된 상태에서, playmode가 아닐 경우에 호출된다.
Start
- 게임이 시작될 때 한 번 호출된다.
- 모든 Awake 함수가 실행된 후 호출된다.
- 주로 초기 상태를 결정하거나 데이터를 로드하는데 사용된다.
2. Physics
[FixedUpdate -> Internal animation update -> Internal physics Update -> Internal animation update -> OnTriggerXXX -> OnCollisionXXX -> yield WaitForFixedUpdate]
FixedUpdate
- 고정된 시간 간격으로 호출된다.
- 주로 물리 계산(Physics)을 처리하는데 사용된다.
- 프레임 속도와 무관하게, 항상 일정한 간격으로 실행된다.
Internal animation update - 1
- 애니메이션 시스템 업데이트 - 내부 물리 계산 전
- FixedUpdate 이후 물리 계산을 이전한다. 이 단계는 애니메이션 데이터(Animator에 설정된 값)와 관련된 변경 사항을 물리 계산 전에 반영하기 위한 작업으로, 다음과 같은 역할을 수행한다.
- 애니메이션 블렌딩: Animator에서 실행 중인 애니메이션 상태를 블렌딩하고, 이를 통해 애니메이션 클립 간의 전환이 부드럽게 이루어지게 만든다.
- 애니메이터 파라미터 적용: 애니메이터에 설정된 파라미터 (예를 들어 SetFloat, SetBool, SetTrigger)를 기반으로 현재 재생중인 상태를 결정하고 업데이트 한다.
- 루트모션 계산: 만일 루트 모션이 활성화된 경우라면, 애니메이션 데이터를 기반으로 물리적 움직임(위치 및 회전값)을 계산한다.
단, 이 위치 값은 즉시 적용되지 않고 물리 계산 이후에 반영된다. - 상태 머신 업데이트: 애니메이터의 상태 머신(State Machine)이 업데이트 되며, 현재 상태에서 다음 상태로의 전환 조건을 확인한다.
- FixedUpdate 이후 물리 계산을 이전한다. 이 단계는 애니메이션 데이터(Animator에 설정된 값)와 관련된 변경 사항을 물리 계산 전에 반영하기 위한 작업으로, 다음과 같은 역할을 수행한다.
Internal physics update
- 매 프레임마다 호출된다.
- 게임의 주 로직을 처리하는데 사용된다.
- 프레임 속도에 따라 호출 빈도가 달라질 수 있다.
Internal animation update - 2
- 애니메이션 시스템 업데이트 - 내부 물리 계산 이후
- 물리 계산 결과를 바탕으로, 애니메이션 데이터를 최종적으로 적용하고, Unity의 렌더링 시스템과 동기화하는 작업을 수행한다.
- 루트 모션 적용: 첫 번째 애니메이션 업데이트에서 계산된 루트 모션 값이 물리 계산 결과에 따라 실제로 Rigidbody에 적용된다. 이를 통해 물리적인 움직임(충돌, 힘의 반작용 등)과 애니메이션이 자연스럽게 결합된다.
- 최종 트랜스폼 업데이트: Rigidbody와 연결된 GameObject의 최종 위치 및 회전 값이 애니메이션 데이터를 기준으로 업데이트 된다. 이렇게 업데이트된 내용은 앞선 첫 번째 애니메이션 업데이트에서 설정된 값과 물리 엔진의 결과를 반영한 결과다.
- 스켈레탈 애니메이션 처리: 스켈레탈 애니메이션의 경우, 본(Bone)들의 위치와 회전 값이 물리 계산 이후 최종적으로 재적용된다.
- 물리 계산 결과를 바탕으로, 애니메이션 데이터를 최종적으로 적용하고, Unity의 렌더링 시스템과 동기화하는 작업을 수행한다.
OnTriggerXXX: OnTriggerEnter, OnTriggerStay, OnTriggerExit
- 트리거 충돌 이벤트가 발생할 때 호출된다.
- 트리거가 다른 콜라이더와 겹치기 시작한 순간 / 겹치는 순간 매 프레임 / 빠져 나올 때 각각 실행된다.
Enter와 Exit는 한 번씩 만 호출된다.
- 트리거가 다른 콜라이더와 겹치기 시작한 순간 / 겹치는 순간 매 프레임 / 빠져 나올 때 각각 실행된다.
OnCollisionXXX: OnCollisionEnter, OnCollisionStay, OnCollisionExit
- 실제 충돌 이벤트가 발생할 때 호출된다.
- 두 물리 오브젝트가 충돌할 때 / 충돌 중일 때 매 프레임 / 충돌에서 벗어났을 때 실행된다.
Enter와 Exit는 한 번씩 만 호출된다.
- 두 물리 오브젝트가 충돌할 때 / 충돌 중일 때 매 프레임 / 충돌에서 벗어났을 때 실행된다.
yield WaitForFixedUpdate
- 코루틴에서 yield return new WaitForFixedUpdate를 사용하면, 해당 코루틴은 FixedUpdate 루프가 완료된 후 다시 실행된다. 이를 통해 코루틴이 물리 루프와 동기화된다.
3. Input event
[OnMouseXXX]
OnMouseXXX: OnMouseEnter, OnMouseOver, OnMouseExit, OnMouseDown, OnMouseUp, OnMouseDrag
- 마우스와 관련된 특정 상호작용을 처리하기 위한 이벤트 콜백이다.
- 마우스 포인터가 게임 오브젝트의 Collider에 처음으로 진입했을 때 / Collider 위에 있는 동안 매 프레임 / Collider를 벗어날 때 / Collider 위에서 마우스 왼쪽 버튼을 클릭했을 때 / Collider 위에서 마우스 왼쪽 버튼을 클릭했다가 뗄 때 / 마우스 왼쪽 버튼을 누른 상태에서 마우스를 이동할 때 매 프레임 에 발생한다.
- 이 이벤트는 기본적으로 게임 오브젝트가 Collider를 가지고 있어야 하며, 카메라가 필요하다. (카메라가 GameObject를 보고 있는 경우에만 이벤트가 발생한다.) 특히, 카메라의 Culling Mask가 해당 오브젝트를 렌더링하고 있어야 한다.
- Raycast와의 차이: OnMouseXXX는 Unity가 내부적으로 Raycast를 사용하여 처리한다. 만일, 사용자 정의 Raycast를 사용하고자 한다면, Physics.Raycast를 직접 구현해야 한다.
- 기본적으로 OnMouseXXX 이벤트는 마우스 왼쪽버튼만 처리한다. 만일 오른쪽 버튼, 혹은 다른 버튼을 이용하고자 한다면 Input.GetMouseButton을 함께 사용해야 한다.
4. Game logic
[Update -> yield null -> yield waitForSeconds -> yield WWW(UnityWebRequest로 대체됨) -> yield StartCoroutine -> Internal animation update -> LateUpdate]
Update
- 매 프레임마다 호출되며, 기본 게임 로직을 실행하는 함수다.
- 게임의 핵심 로직을 업데이트 하는데 사용한다.
- 프레임에 따라 호출 횟수가 달라진다.
yield null
- 코루틴에서 yield return null을 사용하면 현재 프레임이 끝날 때까지 대기하고, 다음 프레임이 다시 실행된다.
- 한 프레임 동안 기다리는데 사용한다.
- 계산량이 많은 작업을 여러 프레임에 걸쳐 나눌 때 유용하다.
yield WaitForSeconds
- 네트워크 요청 작업이 완료될 때까지 기다린다.
- 외부 리소스(URL)에서 데이터를 가져올 때 사용한다.
- 파일 다운로드, API 호출 등을 처리한다.
IEnumerator FetchData()
{
UnityWebRequest request = UnityWebRequest.Get("https://example.com");
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
Debug.Log("Response: " + request.downloadHandler.text);
}
else
{
Debug.LogError("Request failed: " + request.error);
}
}
yield StartCoroutine
- 또 다른 코루틴이 끝날 때까지 기다렸다가 이어서 실행된다.
- 복잡한 작업을 여러 코루틴으로 분리하여 처리한다.
- 종속 작업이 있는 경우 유용하다.
Internal Animation Update
- 애니메이션 상태와 동작을 업데이트하고, 캐릭터의 움직임, 트랜스폼, 루트 모션 등을 최종적으로 반영하는 과정이다.
- State Machine Update: 상태 업데이트 및 전환 결정.
- OnStateMachineEnter/Exit: 상태 머신 진입/퇴출 시 콜백 호출.
- ProcessGraph: 상태 전환 및 블렌딩 계산.
- Fire Animation Events: 애니메이션 이벤트 실행.
- StateMachineBehaviour Callbacks: 상태 관련 콜백 실행.
- OnAnimatorMove: 루트 모션 처리.
- ProcessAnimation: 본 트랜스폼 업데이트.
- OnAnimatorIK: IK(역방향 운동학) 계산.
- WriteTransform: 최종 트랜스폼 데이터 적용.
- WriteProperties: 속성(Material 등) 업데이트.
LateUpdate
- 모든 Update 함수가 실행된 후 호출된다.
- 카메라 이동 또는 따라가기 같은 작업에 사용된다.
- 다른 오브젝트의 상태 변화 후에 로직을 처리할 때 유용하다.
5. Scene rendering
[OnPreCull -> OnWillRenderObject -> OnBecameVisible -> OnBecameInvisible -> OnPreRender -> OnRenderObject -> OnPostRender -> OnRenderImage]
OnPreCull
- 카메라가 씬을 렌더링하기 전, 카메라의 시야(Culling) 내에서 어떤 오브젝트가 렌더링 될지 결정하는 단계이다.
- 카메라의 시야각(Field of View)에 따라 렌더링할 오브젝트를 필터링한다.
- Culling Mask 설정에 따라 렌더링할 레이어를 선택한다.
OnWillRenderObject
- 씬의 개별 오브젝트가 렌더링될 준비가 되었을 때 호출한다.
- 렌더링될 오브젝트마다 호출되며, 해당 오브젝트의 렌더링 관련 데이터를 업데이트할 수 있다.
- 카메라와 상호작용하는 오브젝트에 대해 특정 작업을 수행할 수 있다.
- 이를 통해 오브젝트별로 카메라 기반 쉐이더를 업데이트할 수 있다.
OnBecameVisible
- 특정 오브젝트가 카메라의 뷰포트 안으로 들어올 때 호출된다.
- 카메라 시야에 들어온 오브젝트를 활성화하거나 관련 처리를 수행한다.
- 이를 통해 오브젝트가 보이는 동안 특정 효과(파티클 시스템 등)를 활성화할 수 있다.
OnBecameInVisible
- 특정 오브젝트가 카메라의 뷰포트에서 벗어날 때 호출된다.
- 카메라에 보이지 않는 오브젝트에 대해 비활성화 혹은 최적화를 수행한다.
- 이를 통해 오브젝트가 보이는 동안 특정 효과(파티클 시스템 등)를 활성화할 수 있다.
OnPreRender
- 카메라가 씬을 렌더링하기 직전에 호출된다.
- 카메라 기반의 설정(카메라 매트릭스, 색상 필터 등)을 수정한다.
- 이를 통해 카메라의 렌더링 설정을 조정하거나 효과를 추가할 수 있다.
OnWillRenderObject
- 씬의 개별 오브젝트가 렌더링될 준비가 되었을 때 호출된다.
- 렌더링될 오브젝트마다 호출되며, 해당 오브젝트의 렌더링 관련 데이터를 업데이트할 수 있다.
- 카메라와 상호작용하는 오브젝트에 대해 특정 작업을 수행할 수 있다.
- 이를 통해 오브젝트별로 카메라 기반 쉐이더를 업데이트할 수 있다.
OnRenderObject
- 모든 오브젝트가 렌더링된 후 호출된다.
- 씬 전체의 렌더링 과정에 관여하는 커스텀 렌더링 로직을 수행한다.
- 추가 그래픽 요소를 렌더링(디버그 라인, 추가 메쉬 등)한다.
- 이를 통해 자주 사용하는 디버그용 시작적 데이터 렌더링이 가능하다.
OnPostRender
- 카메라가 씬을 렌더링한 후 호출된다.
- 렌더링 후 작업(후처리 효과, 스크린 데이터 조작 등)을 수행한다.
- 이를 통해 화면에 추가적인 렌더링 효과를 적용한다.
OnRenderImage
- 카메라의 렌더링 결과가 화면에 출력되기 전 호출된다.
- 화면에 그려지는 최종 이미지를 조작할 수 있는 후처리 효과를 추가한다.
- 두 개의 RenderTexture를 사용하여 이미지를 조작한다.
- 이를 통해 블러, 색상 보정, 그림자 강화 등의 포스트 프로세싱 효과가 나타난다.
정리해보면
- OnPreCull: 카메라가 렌더링할 오브젝트를 결정하는 단계.
- OnWillRenderObject: 개별 오브젝트가 렌더링 준비를 마친 상태.
- OnBecameVisible: 오브젝트가 카메라에 처음 보이기 시작.OnBecameInvisible: 오브젝트가 카메라에서 사라질 때.
- OnPreRender: 카메라 렌더링 직전 호출.
- OnRenderObject: 모든 오브젝트가 렌더링된 후 커스텀 렌더링 작업 수행.
- OnPostRender: 카메라 렌더링이 끝난 후 작업 수행.
- OnRenderImage: 화면 출력 전에 최종 이미지를 수정하는 단계.
로 볼 수 있다.
6. Gizmo rendering
[OnDrawGizoms]
OnDrawGizoms
- 에디터에서만 호출된다.
- 디버깅 및 시각적 보조 도구로 사용되며, 오직 Scene View에서만 렌더링된다.
7. GUI rendering
[OnGUI]
OnGUI
- frame 업데이트시, 여러번 호출된다.
- GUI 요소를 렌더링하고 처리하는데 사용되는 유니티의 Immediate Mode GUI(IMGUI) 시스템의 일부다.
- 이를 통해 주로 디버깅 도구나 간단한 UI를 구현하는데 사용된다.
- MonoBehaviour 클래스에 정의된 메서드다.
8. End of frame
[yield WaitForEndOfFrame]
yield WaitForEndOfFrame
- 렌더링 프레임이 끝난 후, 모든 카메라 렌더링 작업이 완료된 경우 호출된다.
- 렌더링 작업이 모두 완료된 후 실행되기 때문에 화면에 모든 그래픽이 그려진 다음 호출된다.
- 이를 통해 렌더링된 데이터를 처리하거나 프레임 끝에 특정 작업을 수행하는데 유리하다.
- 보통 렌더링된 데이터를 캡쳐하거나 처리할때 사용하고, 렌더링된 데이터를 이용하여 추가 후처리 작업이 요구될 때 사용된다. 특히, 특정 타이밍에 필요한 작업을 제어한다.
9. Pausing
[OnApplicationPause]
OnApplicationPause
- Pause 상태에 들어가거나 다시 활성화될 때 호출된다. 하지만 정확하게 일시 정지 상태로 전환되는 바로 그 프레임에서 호출되지 않는다.
일시 정지 상태로 들어가기 직전의 프레임에서 호출되고, 그 후에 한 프레임이 더 진행된 다음 애플리케이션이 실제로 정지된다.
- 주로 모바일 플랫폼에서 앱이 백그라운드로 전환되거나 복귀하는 상태를 처리하는데 사용한다. 또는 전체화면으로 플레이중인 게임을 벗어나는 등 Pause 상태가 될 때 사용한다.
10. Decommissioning - 해체 or 종료
[OnApplicationQuit -> OnDisable -> OnDestroy]
OnApplicationQuit
- 애플리케이션이 종료될 때 호출된다.
- Unity 데이터에서 플레이 모드를 종료하거나, 빌드된 애플리케이션에서 종료 시 실행된다.
- 애플리케이션이 종료될 때 한 번만 호출된다.
- 모든 MonoBehaviour에서 실행된다.
- 호출 전, 로그를 기록하거나 데이터를 저장하는 로직을 추가하는 등 사용한다.
- Unity 데이터에서 플레이 모드를 종료하거나, 빌드된 애플리케이션에서 종료 시 실행된다.
OnDisable
- MonoBehaviour가 비활성화될 때 호출된다. 즉, 게임오브젝트나 스크립트가 비활성화되는 순간 실행된다.
- 게임 오브젝트의 SetActive가 false 될 때 호출된다.
- 스크립트가 비활성화될 때 호출된다.
- 즉, 씬 전환, 게임 오브젝트 비활성화 등의 상황에서 발생 가능하다.
OnDestroy
- 게임 오브젝트나 MonoBehaviour가 파괴되기 직전에 호출된다.
메모리에서 오브젝트가 제거되기 전 호출되는 마지막 메서드다.
- 오브젝트를 수동으로 파괴하거나 씬 전환 시 호출된다.
- 이를 통해 리소스 해제, 데이터 정리, 이벤트 핸들러 해제 등 마지막 작업을 수행하는 데 유용하다.
- 파괴 순서를 보장하지 않고, 다른 오브젝트가 이미 파괴되었을 가능성을 고려해야한다.
엔진 공부를 위해서는 흐름 파악이 중요하다. 공부하자.
'Study > Unity Engine' 카테고리의 다른 글
[Unity] 유니티 이해하기 04 - 유니티 Object와 그 하위 클래스들 (0) | 2025.01.24 |
---|---|
[Unity] 유니티 이해하기 03 - Input System (0) | 2025.01.24 |
[Unity] 유니티 이해하기 01 - 게임오브젝트와 컴포넌트 (0) | 2025.01.24 |
[Unity] 유니티 프레임 워크, .NET과 GC (0) | 2025.01.24 |
[Unity] Profiling (0) | 2025.01.18 |