0413 게임엔진디자인
게임엔진디자인
제일 좋은 것은,
코어의 App의 다중생성이 가능해서
코어 위에서 에디터를 돌리고, 그 에디터가
코어에게 "이 경로의 프로젝트를 열어 주세요" 하면
런타임 디버그가 실행되는 것임.
이러면 런타임 디버그를 단독 응용 프로그램으로 컴파일 할 필요 없음.
이런 식으로 해서
멀티스레드인경우:
모든 App에 대해 스레드 만들기
(MultiWindow-OpenGL 참고)
싱글스레드인경우:
while(true) 안에 모든 App의 Window* 에 대해 make_currrent해주고 그린 다음 swap_buffers해주고
프레임 끝나면 글로벌하게 poll_events
Engine > App > Scene > Object
MyEngine().run();
** 중요** 엔진은 전역 객체(또는 클래스 정적멤버) 여야 한다.
DLL을 통한 스크립팅을 전역 함수로 하게 되는데, 그 전역 함수는 전역 변수밖에 쓰질 못한다.
예를 들어, 특정 오브젝트의 좌표를 바꿨다면,
1. Engine 안에 있는 여러 App들 중에, "런타임"을 찾아야 한다.
2. 런타임 App 안에 있는 여러 씬들 중에, "현재 씬"을 찾아야 한다.
3. 현재 Scene 안에 있는 여러 오브젝트 중에, "특정 오브젝트"를 찾아야 한다.
** (찾을 때는, 엔진의 내부 콜에서 받아온 오브젝트 ID를 사용한다.) **
4. 특정 오브젝트를 찾았다면, 그 오브젝트의 좌표를 바꾸면 된다.
만약 Engine을 "확장 가능하게 만든다" 면 (뇌절)
Engine* g_Engine = nullptr;
int main() {
g_Engine = new MyEngine();
g_Engine->run(); // MyEngine안에서 내부적으로 이미 커스텀 앱들이 추가되어 있음.
delete g_Engine;
}
만약 Engine을 "확장 불가능하게 만든다" 면 (이게 더 나을 것 같긴 하다. 굳이 엔진을 인터페이스로 만들 이유가 없다)
Engine* g_Engine = nullptr;
int main() {
g_Engine = new Engine();
g_Engine->add_application<Editor>("Editor App"); // 명시적으로 에디터와 디버그 런타임을 추가합니다.
g_Engine->add_application<RuntimeDebug>("RtDbg App");
g_Engine->execute_application_by_name("Editor App");
// g_Engine->execute_application_by_ptr(editorApp);
g_Engine->run();
delete g_Engine;
}
에디터를 만들때:
CustomEngine에다가 App 2개를 붙인다.
하나는 에디터UI + 월드 뷰어
하나는 런타임 디버그
에디터UI에서 실행을 누르면 CustomEngine에다가 "자신이 생성한 프로젝트 파일로" 런타임 디버그 App 실행을 요청한다.
정지를 누르면 런타임 디버그 App 종료를 요청한다.
런타임 디버그 App이 사용자에 의해 꺼졌을 경우 CustomEngine은 에디터 UI에게 꺼짐을 알린다.
런타임 (디버그 아님)을 만들때:
CustomEngine에다가 App 1개만 붙인다.
그냥 런타임 하나만...
"아까 생성한 프로젝트 파일"이 아닌, "하나의 패키지 파일"을 읽는 런타임이다.
=> 따라서
"프로젝트 파일을 읽어서 씬 / 오브젝트를 구성하는 파서"
"패키지 파일을 읽어서 씬 / 오브젝트를 구성하는 파서"
이렇게 2개가 필요하다 (직렬화 코어 로직은 변하지 않으니, 후자를 가공해서 전자의 시퀀스에 붙여쓰자).
고려해야 할 것은,
유니티처럼 중앙에 월드 뷰어가 있으려면
보이지 않는 가상 씬(<-이거를 그냥 씬과 똑같이 취급해서 그냥 씬에 렌더 타겟을 만들지,
아니면 여러 오브젝트를 담고 있는 새로운 클래스를 만들지는 잘 모르겠다.
월드 뷰어란 게 월드 뷰어 고유의 3D카메라가 있고 기즈모가 있어서
월드 뷰어 안의 오브젝트들은 일단 "렌더링"만 하게 하면 어떨까.
업데이트를 통해 있지도 않는 app을 참조하게 하면 안된다.)
을 만든 다음
렌더 패스를 시작해서 가상 씬을 그리고
그 프레임버퍼를 가져와서 2D텍스쳐로 그려야 하는데,
씬에 선택적으로 렌터 타겟에 그리는 기능을 넣어야 할 듯 하다.
지금 바로 위의 문제는 다음과 같이 해결된다.
1. Viewport라는 오브젝트가 있다(Godot와 같다)
2. Viewport는 각각 다른 FBO를 가진다 (...그냥 똑같은 FBO돌려쓰면 안되나?? 첨부물만 그때그때 바꿔서????).
3. Viewport의 자식들이 그려지기 전, 각 FBO는 바인딩된다.
4. Viewport의 자식들이 모두 그려진 후, 이전 FBO로 바인딩된다.
5. SpriteND에 Viewport의 주소를 지정하여 텍스쳐를 띄울 수 있다.
6. 씬의 최상단에는 보이지 않는 기본 Viewport 가 존재한다(그의 바로 자식이 루트 노드).
7. 루트 노드 밑에는 두 개의 섹션으로 나뉜다.
7-1. 하나는 에디터 섹션. 말 그대로 가운데 Sprite2D를 감싸는 Container하나와 주변을 둘러싸는 판넬이 있다.
7-2. 나머지는 월드 뷰어 섹션. 이 섹션의 최상단에는 Viewport가 위치하며,
에디터 섹션의 Sprite2D는 이 뷰포트를 참조해서 뷰어를 그린다.
8. 즉, 렌더 패스조차 오브젝트인 것이다.
크게 세 개로 나뉜다.
1. 코어 (동적 / 정적 라이브러리)
- 렌더러 제공
- UI 시스템 제공
- 스크립팅 제공
- 물리 제공
- 오디오 제공
- 애니메이터 제공
- 로거 제공
- 유틸리티 제공
- 씬 & 오브젝트 기반
"코어만으로는 아무것도 돌릴 수 없다"
"코어를 기반으로 에디터와 런타임을 만든다"
"에디터와 런타임은 코어 없이는 돌아가지 않는다"
2. 에디터 (응용 프로그램)
- 코어를 사용하여 UI를 렌더링한다.
- 코어를 사용하여 창을 전환한다.
- 프로젝트 파일을 생성 / 저장 / 핫 리로드 추적한다.
- 네이티브 디알로그 사용
3. 런타임 디버그 (응용 프로그램)
- 코어를 사용하여 프로젝트를 돌린다.
- 프로젝트 파일을 읽어 씬을 배치한다.
- UI 파일, 리소스 파일, 스크립트 파일을 읽어 적절히 배치한다.
4. 런타임 릴리즈 (응용 프로그램)
- 런타임 디버그와 매우 유사하다.
- 단 하나의 패키지 파일을 읽어 씬과 오브젝트를 배치한다.
- 단독 실행 가능하다.