각 절기 마다 발표자를 선정해 공부한 내용을 발표하는 발표 모임이 있다. 이번 하지(6월 21일)에 발표 기회를 얻어 발표를 하게 되었는데, 발표 주제는 게임 엔진의 역사와 동작 원리이다.
현재 유니티 개발을 하면서, 게임 엔진에 대한 호기심이 생기기 시작했다. 또한, 이전 이직 준비를 하며서, 피드백을 들은 내용 중
게임 로직 개발을 당연히 해야 하는 것이다. 그렇기에, 자신의 강점을 가지고 가야 한다. 네트워크, 쉐이더, 서버 등 각분야 중 자신의 강점을 가지고 가야 경쟁력을 키울 수 있다
이런 피드백을 듣고 나니, 게임 분야에 어떤 분야들이 있고, 그에 대해 깊이 파보지 않았던 것 같다. 단순한 인디 게임 개발이라면, 현재 나와있는 통합 게임 개발 솔루션을 통해 간단한 게임은 개발 할수가 있다. 게임 개발에 대한 장벽이 낮아지고, 1인 개발에 용이 해진 현 상황에서 앞으로 어떻게 나의 특성을 살리고 게임 개발에 더 깊은 이해를 할 필요가 있나 하는 고민은, 어쩌면 불필요 해 보일수가 있다. 하지만, 미래에 어떤 일을 할지 모르기도 하거니와, 어떤식으로 각자의 영역들일 유기적으로 돌아가는 지에 대한 이해가 머릿속에 들어와있으면 분명 도움이 될거라고 생각하다. 서론이 길었으니 이만 각설 하고 본내용을 보려고 한다. 다음과 같은 순서로 발표를 하였다.
1. 게임 엔진의 등장 이전
2. 게임 엔진의 시작
3. 발전
4. 현재 대 게임 엔진의 시대
5. 동작 원리
위의 순서 대로 발표를 하였다. 마지막 동작 원리에서는 동작의 원리라기 보단, 게임 개발의 영역들과 게임의 개발 요소들을 살표보는 단계라고 보면 된다. 이를 함축적으로 단원을 따려고 하다보니 동작원리라고 표현 했으나, 오해를 일으킬 여지가 있다고 생각한다. 동작원리라고 하였지만, 게임 엔진의 하드웨어 제어 원리/렌더링/네트워크/엔진 내부 코드등의 설명을 기대시킬수 있다고 생각한다.. 하지만 이런면은 너무 넓고 깊은 지식이며, 지금 당장 내가 20분정도의 발표를 하는 데 과한 내용이라고 생각한다. 다음 기회가 된다면 각각 심도있게 알아보도록 할 것이다.
1. 게임엔진의 등장 이전
게임 엔진이 존재하기 이전의 시절, 게임을 구현하기 위한 영역과 게임을 만들기 위한 도구 사이의 경계가 모호하던 시기 였다. 현재의 코드를 생각하면, 유니티 같은 경우 Unity.Engine 같은 라이브러리를 사용하고 거기에서 engine제어 메소드를 우리가 가져와 사용 할수 가 있다. 하지만 우리는 이러한 엔진 라이브러리를 수정 할수가 없다. 하지만 이시절은 이런 라이브러리가 존재 하지 않았기에, 어떤 오브젝트를 생성한다 하면 오브젝트를 생성 할수 있게 해주는 따로 정형화된 코드가 존재 하지 않았고, 오브젝트르 받아서 생성을 직접 구현하는 코드가 게임 코드 안에 있었다. 그나마 이전에 성공적으로 만든 게임에서 코드를 재사용하고, 하드웨어 제어코드를 돌려 쓰는 정도가 최선이었다. 이 시절, 심지어 핵심코드는 전문가가 어셈블리로 만들었기에, 대체 불가에 가까웠다. 이 이후, 스크립트언어로 즉, 코드를 규격화 해서 이후 스크립트가 변환 시켜주는 방법으로 플랫폼 변환기를 만들어서 한번의 제작으로 여러 플랫폼에 출시 가능 하게 했다.
2. 게임 엔진의 시작
이제 엔진이라는 개념이 나오기 시작 하는 태동기이다. 1990년대중반에 들어서면서, 게임 개발을 더 쉽게 하기 위한 방안이 본격적으로 나오기 시작한다. 사전 개발 설정의 표준화가 시작 되면서, 개발을 하는 데 서로 다른 회사가 만든 게임이더라도 이런 표준화에 의해 비슷한부분이 많아 지면서, 이런 공통 분모의 핵심코드를 엔진이라고 얘기하였다. 사전 개발 설정이란 사운드나 그래픽을 의미하고, 사운드 블래스터 같은 기기의 표준화가 진행이 되어서 이런 표준화가 생겨났다. 이전 세대의 하드웨어의 파편화가 어느 정도 해소가 됨으로 써, 이런결과가 나온거라고 볼수 있다. 첫 엔진의 결과물은 id tech로 만든 둠2가 있다.
3. 발전
이때 특징은 고급 기술들이 산발적으로 존재했다는 것이다. 3D 게임의 유행으로 개발 난이도가 올라감에 따라 영역별로 전문 분야가 나뉘었고, 그에따른 라이브러리가 등장하기 시작했다. 이때, 3D그래픽 개발 수준이 올라가면서, 게임 개발사들을 대상으로 판매하는 회사들이 존재했다. 그중하나가 넷이머스 현재는 게임 브리오 라는 이름으로 존재하는 회사인데, 이회사가 기여한 게임으로 폴아웃이 있고, 이후에 한국에서 유명한 게임인 그랜드 체이스 메이플스토리2등 들어 봤을 법한 게임에 솔루션을 제공하였고, 하고 있다. 최근엔 업데이트를 거의 안하고 있는 중이라고 한다.
4. 대 게임 엔진의 시대
2004년 통합 게임 개발 솔루션을 발표하며 언리얼 3가 나왔다. 엔진의 모든 기능을 커스터마이징이 가능하면서도 상호간에 유기적으로 융합되는 유연한 구조로 기술의 추가나 변형이 용이해 게임의 장르나 플랫폼에 관계없이 어떤 형태의 게임도 개발이 가능하며, 엔진 코드와 게임 코드의 완전한 분리, 필요한 기능만 선택적으로 사용 가능, 하나의 작업물에서 다양한 플랫폼으로 릴리즈, 모드 툴이나 더미 데이터의 포함 여부, 또는 다양한 빌드 시스템 등 하나의 엔진으로 게임 개발에 대한 모든 것이 가능함을 지향하는 출시를 했다. 다양한 엔진들이 나왔는 데, 언리얼의 udk 등장이후 다 사그러졌다. 그나마 유니티가 살아있는 정도. 유니티는 소규모 게임/ 인디게임들에 강세를 보이고 언리얼은 이와 반대이다. 이러한 엔진의 등장과 이용료가 저렴해짐에 따라, 1인 개발, 인디게임 개발의 시장이 열리게 되었다.
5. 동작원리
게임 개발에는 다양한 개발 영역이 있다. 예를 들어,
- Renderer : 화면상에 그래픽을 출력하는 기술
- Streaming Terrain : 실외 배경으로써 주로 지형을 표현
- 3D Mesh Rendering : 캐릭터나 기하 객체의 표현
- Character Animation : 캐릭터의 움직임 표현
- Collision System : 객체의 실시간 충돌 검사
- Physics Engine : 물리학적인 제어 시스템으로 충돌 후 반응을 제어
- Sound System : 장면 내에 삽입되는 사운드 시스템을 구현
- Particle System : 안개, 구름, 불꽃 등 입자를 표현
- Path Finding / Waypoint Generator : Npc와 캐릭터의 움직임 제어를 위해 사용되는 인공지능적인 기법으로 유니티엔 navmesh가 있다.
- Scripting System : 전반적인 게임을 제어하기 위해 사용
이외에도 더 있을 것이다. 하지만, 다 보진 않을 것이고, 목표는 거시적으로 이해하는 것이기 때문에, 더 단순화된 그림으로 이해해볼것이다.
위의 그림은 엔진에서 개발을 도와주는 영역들을 단순화한 그림이다. 아까의 세분화된 system들을 영역화하고, 그영역 마저 더 포괄적으로 생각한다면 이와 같은 그림이 나올것이다. 하드웨어의 제어, 그위에 미들웨어, 그위의 사용자와 게임의 상호작용/ 데이터/ 게임 로직 이 존재한다. 영역을 봤으면, 이제 게임의 런타임 주기에 어떻게 작동을 하는 지 확인 해보자.
그래서 게임엔진의 주기를 살펴보면, 크게 시작 loop 종료 이렇게 세가지이다. 여기서 세분화가 되는 건데, 밑에 그림을 보시면 초기화 업데이트 화면 출력 순서로 반복이 되는 것을 확인 할수 있다.
이때, 그래픽, 사운드,네트워크등의 다양한 시스템들이 사용되어 지고, 우리가 게임할때 보여지는 결과물이 보여지게 됩니다.
하나 간단한 예시를 들자면, 몬스터 오브젝트가 보여지기 까지의 단계이다.
- 리소스 로딩:
- 몬스터 모델, 애니메이션, 텍스처 등의 리소스를 게임 엔진에 로드
- 이는 몬스터를 표현하는데 필요한 그래픽과 애니메이션 데이터를 메모리에 올리는 과정
- 몬스터 오브젝트 생성:
- 몬스터를 표현하기 위한 게임 오브젝트를 생성하고, 그에 따른 컴포넌트를 추가
- 예를 들어, 몬스터 모델을 렌더링하기 위한 렌더러 컴포넌트, 애니메이션을 재생하기 위한 애니메이터 컴포넌트, 물리 시뮬레이션을 적용하기 위한 물리 컴포넌트 등을 추가
- 애니메이션 제어:
- 몬스터의 애니메이션을 제어, 애니메이터 컴포넌트를 사용하여 몬스터의 상태와 행동에 따라 애니메이션을 변경하고 재생
- 이를 통해 몬스터가 걷기, 공격, 피격 등의 동작을 수행하며, 그에 따라 애니메이션도 변경됩니다.
- 물리 시뮬레이션 적용:
- 몬스터에게 물리 시뮬레이션을 적용할 경우, 물리 컴포넌트를 사용하여 몬스터의 운동 및 충돌을 처리
- 몬스터에 중력을 적용하거나, 충돌 체크를 통해 다른 객체와의 상호작용을 처리
- 이를 통해 몬스터의 움직임과 물리적 상호작용을 현실적으로 표현할 수 있다.
- 게임 루프 처리:
- 이 단계는, 포괄적인 단계이다. 1번부터 7번까지의 단계가 모두 포함되어 있다. 하지만 이를 게임주기의 루프가 아닌 단순 프레임 별로 구현 되어진 게임코드라고 생각하다면, 게임의 상태를 업데이트하고 렌더링한다의 단계로 보면 되겠다.
- 렌더링:
- 게임 엔진은 렌더링 파이프라인을 통해 몬스터의 그래픽을 화면에 출력
- 몬스터 모델과 텍스처를 사용하여 몬스터를 그린다.
- 조명, 쉐이딩, 효과 등을 적용하여 몬스터를 시각적으로 표현
- 유저 상호작용:
- 게임 엔진은 유저의 입력을 감지하고, 몬스터에 대한 상호작용을 처리
- 예를 들어, 유저의 공격 입력을 받아 몬스터에게 피해를 입히는 동작을 수행
- 몬스터의 생명력, 상태 변화 등을 게임 엔진에서 관리하여 유저와의 상호작용을 구현
- 컴포넌트 구조의 차이(unity vs unreal)
유니티 : 유니티의 씬은 여러 개의 게임 오브젝트(Game Object)로 구성되며 게임 오브젝트를 통해 상호작용이 일어난다. 구조를 보면 게임 오브젝트는 하나의 트랜스폼(Transform)을 가지며, 추가로 여러 개의 컴포넌트(Component)를 포함할 수 있다. 트랜스폼은 오브젝트의 위치, 회전, 크기, 부모-자식 상태를 저장한다.
언리얼 : 언리얼의 레벨은 여러 개의 액터(Actor)로 구성되며 액터를 통해 상호작용이 일어난다. 액터는 하나의 루트 컴포넌트(Root Component)라는 이름으로 씬 컴포넌트(Scene Component)를 가진다. 추가로 여러 개의 액터 컴포넌트(Actor Component)를 포함할 수 있다. 씬 컴포넌트는 유니티의 트랜스폼과 유사하며 오브젝트의 위치, 회전, 크기, 부모-자식 상태를 저장한다.
언리얼이 뎁스 하나가 더 있다라는 직관적인 차이가 있다. 그에서 오는 개발의 유용성 차이는 아직 잘 모르겠다.
- 유니티 컴포넌트 스크립트 동작원리
컴포넌트와 오브젝트
컴포넌트는 구현하고자 하는 기능 단위를 컴포넌트화 하고, 이를 빈 게임 오브젝트에 붙인다. 컴포넌트는 상속이 아닌 소유의 개념으로 독립성이 추가와 제거가 쉽고, 재사용성이 높다.
메세지와 브로드 캐스팅
메세지와 브로드캐스팅은 이런 컴포넌트들에게 이벤트 메세지들을 전달해주고, 동작 가능하게 해준다. 기능을 구현 했으니 이들을 콜해주는 역할을 엔진에서 해준다. 이때, start(), update() 등 이런 함수를 monobehaviour를 상속 받으면 불려와질수가 있다. monobehaviour를 상속 받는 클래스이어야만, 컴포넌트화 하여 오브젝트에 등록될수 있다.
브로드 캐스팅 즉, mono를 상속 받는 모든 오브젝트에대해 해당되는 모든 콜은 동작하라고 메세지를 뿌려줍니다
'Game Dev > Unity' 카테고리의 다른 글
GitActions Unity CI/CD 개발기 - 무엇을 써야할까 (0) | 2023.07.03 |
---|---|
커스텀 디버그 - Editor에서만 포함하기 (0) | 2023.07.03 |
Unity - Nuget 패키지 적용 하는 법 (1) | 2023.05.19 |
UniTask - How to use UniTask (태스크 생성, 취소) (0) | 2023.05.15 |
Unity 리소스 관리 - 어드레서블(Addressable) (0) | 2023.04.23 |