SFMB - Technologies
    sfmb
    서론
이 문서에서는 SFMB 개발에 사용된 기술을 나열하고 설명한다.
개발 툴
- Visual Studio 2015
- Visual Studio 2017
- Visual Studio 2019
- Visual Studio 2022
- Visual Studio Code
프로그래밍 언어
- C++ 17
- Javascript (NodeJS)
게임 엔진
기초 라이브러리
NaLib
- 게임이 아닌 곳에도 활용될 것으로 예상되는 기초 코드들을 묶은 라이브러리로 직접 만들어 사용하였다.
- 전 직장에서의 경험을 통해 크로스 플랫폼을 염두에 두고 개발하였다.
- "Na"는 NeoArc를 줄여 클래스의 Prefix로 사용한 것이다. 나트륨을 의미하는 것이 아님
- 사실상 NaLib이 SFMB의 여러 핵심 코드를 가지고 있으며, SFMB는 이것을 활용하는 형태로 구현되어 있다.
ExtLib
- 오픈 소스 라이브러리를 가져다가 묶은 것이다.
- Box2D
    - 앵그리버드 등에 사용된 유명한 2D 물리엔진
- 게임의 물리엔진 교체에 사용해보려고 가져왔지만, 사용되지 못했다.
 
- catch2
    - 단위 테스트 프레임워크
 
- cppcodec
- cxxopts
- dirent
    - 파일시스템 관련 라이브러리
- 게임 초기 구현시 사용되었으나, 모던 C++를 사용하게 됨에 따라 필요없게 되었다.
 
- fmt
    - 문자열 포맷 라이므러리
 
- JsonLib
- libpng
- MemoryModule
- miniz
- miniz-cpp
- msgpack
- PicoSHA2
- zlib
- discordbuddy
    - BatteryShark가 구현한 discordbuddy를 포팅하여 직접 구현한 것
 
- discord-rpc
- discord-sdk
    - Discord Rich Presense 연동을 위해 사용
 
- rapidjson
    - discord 라이브러리에서 사용되기 때문에 포함되었다.
 
- curl
    - 네트워킹 라이브러리
 
- DirectX 9.1
- OpenGL
- SDL
- FMOD
- BASE
랜더 엔진
- 최초에는 DirectX 9.1을 기준으로 구현했다가, OpenGL을 지원해보기 위해 추상화하게 되었다.
- 다음의 기능들을 각각의 랜더러에 맞도록 구현하였다.
    - 레터 박스 (그려질 내용의 비율을 유지하고 그 외의 부분은 검은 바탕 출력)
- 비트맵 로딩 (bmp, png)
- 텍스쳐의 일부분을 원하는 위치에 그리기
        - 회전하기
 
- 커스텀 텍스쳐 생성
- 픽셀 셰이더를 통한 효과
- Windows 폰트로 텍스트 출력
 
픽셀 셰이더
- 주로 색상 변환에 사용되고 있다.
- 아직 초보 수준의 구현
스프라이트 처리
- 필요한 테마에 적합한 텍스쳐를 로딩하고, .sprite 파일을 통해 스프라이트 시트의 분할 영역 데이터를 제어한다.
- HD 텍스쳐
    - 텍스쳐 파일명 + @2x 에 해당하는 파일이 존재하면 함께 로딩하여 HD 텍스쳐로 사용한다.
- 2배 크기의 텍스쳐를 로딩하여 50% 로 축소하여 랜더링하는 것이다.
 
- 매 프레임마다 그려야 할 스프라이트 정보를 수집하고 Z-order별로 정렬하여 순서대로 랜더링
입력 처리
DirectInput
- 조이스틱 입력 처리
    - 조이스틱 입력을 분석하여 키보드 입력으로 치환하고 있다.
 
- 키보드 입력 처리
마우스
- 마우스 입력은 단순히 마우스 메세지 (WM_MOUSE…)를 사용한다.
- UI 엔진에서 마우스 클릭을 버튼 클릭으로 변환하여 처리한다.
사운드 처리
FMod
- mp3, ogg, wav 파일 재생에 사용된다.
- 다중 채널 동시 재생, 개별 볼륨 설정을 지원한다.
- Loop point를 지원한다.
BASE
- 마리오 메이커와 다른 방식으로 음악 블록을 구현하기 위해 사용되었다.
- 사운드 폰트를 로딩하고 미디 음원을 재생할 수 있다.
장면
- State Machine으로 구현
- 주로, 장면에서 장면으로 전환을 처리한다.
    - 특정 시간이 흐르면 자동으로
- UI를 통해
 
- 일부 장면 전환은 플레이어 객체가 요청하여 처리하기도 한다.
네트워킹
- 게임 내 대부분의 네트워킹은 비동기로 처리하기 위해 트랜젝션 쓰레드에서 처리된다.
- 트랜젝션 쓰레드에서 네트워킹 작업이 끝나면 GameState 내에 구현된 콜백을 호출하는 방식
게임 오브젝트
- State Machine으로 구현
- 모든 게임 오브젝트가 공통된 상태 목록을 사용한다.
    - Idle
- Walk
- Jump
- Die
- …
 
- 초기에는 Raw pointer를 직접 사용하는 형태로 구현했었으나, 알 수 없는 크래시의 추적에 한계를 느끼고
스테이지
- 게임 내 가장 많은 코드를 가진 클래스 중 하나
- 타일 맵 관리
- 맵 내 살아있는 객체 관리
카메라
- 스테이지의 어느 부분을 보여줄지 처리하는 클래스
- 땅의 흔들림이나 강제 스크롤도 카메라를 통해 처리하고 있다.
물리 엔진
- 내가 직접 구현한 것으로, 단순 무식하게 구현되었다.
- 여러번 위기에 도달했을때마다 성능 개선을 위해 구조를 크게 바꾸었다.
- 대략 다음과 같은 역할을 매 프레임마다 수행한다.
    - 스테이지 내 살아있는 모든 객체를 수집
- 각 객체를 현재 속도에 기반하여 이동될 위치로 이동시킴
- 각 객체들이 타일과 충돌하는지 판단
        - 충돌한다면 각 타일 타입에 따라 flag 세팅
            - 일반 타일
- 점프 블록
- 마림마 블록
- 물
- 용암
- 독
- 스타 블록/데스 블록
 
 
- 충돌한다면 각 타일 타입에 따라 flag 세팅
            
- 각 객체들이 경사로와 충돌하는지 판단하여 위치/속도 보정
- 각 객체들을 서로 비교하여 충돌하는지 확인 (N^2)
        - 기본적으로 AABB 로 검사하나, 원형 히트박스 또는 다중 히트박스를 가진 객체도 지원
- 서로 충돌한 객체들의 목록을 생성하여 저장
 
- 충돌한 객체들의 상태에 따라 피드백 처리
        - 충돌 상태만 기억하고 있거나 (기본)
- 밀리거나 (둘중 하나가 겹치는 것을 허용하지 않는 물체일때)
- 탑승하거나 (발판 등)
 
- 각 객체를 원래 위치로 복원
 
UI 엔진
- 직접 구현한 것으로 꼭 필요한 최소한의 컴포넌트와 최소한의 기능만 갖고 있다.
- 컴포넌트
    - Panel
- Text
- Button
- CheckBox
- Edit
- Spin
- Rectangle (Image)
- VirtualList
- …
 
게임
어플리케이션
Windows
- Win32 응용프로그램으로 구현하였다.
- 윈도우를 생성하고 윈도우 핸들을 DirectX, OpenGL에 넘겨 랜더링되도록 했다.
- SDL의 경우는 윈도우를 생성하는 것부터 SDL이 처리하게 되어 있어서, 다른 방식으로 처리했다.
CustomURL Scheme
- "sfmb://" 프로토콜을 통한 여러 연동 기능 구현에 사용한다.
- 게임 실행시 CustomURL scheme을 등록한다. (레지스트리에 직접 등록)
- Force Update 및 Direct Play에 사용한다.
MAC OS
- (오래되어 잘 기억나지 않지만) GLView를 가진 응용프로그램으로 개발하였다.
- GLView는 OpenGL을 지원하는 일종의 윈도우만 미리 만들어진 형태라고 보면 된다.
장면 (Scene)
로고
타이틀
…
맵 에디터
툴바
- 최초에는 툴바를 가진 MDI 형태의 프로그램으로 작성했었다.
- 툴바 버튼이 점점 많아짐에 따라 아이콘 구분이 어렵고, 정돈되지 않은 느낌이 강해 툴바를 리본바로 대체하였다.
리본바 동적 구성
- MFC의 디자인 툴을 통해 리본바를 만들지 않고, 코드레벨에서 동적으로 메뉴를 구성한다.
    - 아이콘으로 사용할 비트맵도 DesignPalette 이미지에서 동적으로 생성
 
- 메뉴 구성은 서버에서 보내준다.
    - 즉, 오프라인 크랙을 통해 플레이할 수 없도록 설계했다. (7.0 부터)
 
Design Palette 동적 전환
- 각 테마마다 보여줘야 하는 아이콘이 달라지기 때문에, 활성화된 스테이지가 변경될 때마다 리본바 전체의 아이콘을 새로 로딩한다.
- 모든 버튼 컨트롤을 수집한 후, 새로 만든 비트맵으로 교체하는 방식
- 이 기능을 구현하기 위해 기본 리본 버튼을 사용하지 않고 직접 만든 클래스를 사용한다.
속성창
- MFC의 PropertyGrid를 사용한다.
- NaPropertyObjectBase 클래스를 상속하여 구현한 모든 객체의 속성을 쉽게 보여줄 수 있다.
- 일부 속성값 타입에 대한 PropertyItem 클래스를 필요에 따라 직접 구현하였다.
    - Bool : true/false를 선택하는 대신 체크박스 표시
- Enum(int) : 실제로는 int 값이지만, 매직 넘버로 보이지 않도록 의미에 해당하는 텍스트를 보여줌
- Color(int) : 클릭하면 커스텀된 컬러 선택창이 표시된다.
- Extended : value란을 버튼 형태로 표시하여, 클릭하면 별도의 편집창을 보여주는 방식
 
상태바
문서창
- MDI Document 내부를 게임 엔진이 직접 그리는 형태
- 높은 성능을 내기 위해 WM_PAINT 메세지가 발생할 때, 1프레임만 랜더링한다.
각종 다이얼로그
테마 관리 창
테마 정의 창
픽셀아트 관리 창
커스텀 적 템플릿 관리 창
코스튬 선택 창
AbilityFlag 선택 창
게임 서버
- 최초에 온라인 모드가 도입되었을 때는 서버리스(serverless)로 구현되어 서버 앱이 존재하지 않았었다.
- 해킹으로 서버 데이터베이스를 모두 날려먹은 후에 재발방지를 위해 서버 앱을 개발하게 되었다.