개발이야기

폭격방어자 포스트모템 #3: 프로그래밍

하늘흐늘 2022. 2. 19. 20:46
반응형

최근 1년간 폭격방어자(영문판: Bombing Defender, 일어판: 爆撃の防御者)란 게임을 개발하였습니다. 게임은 터치로 하는 모바일 슈팅 게임입니다. 

해당 게임은 유니티로 개발하였습니다. 처음 파일럿 데모로 프로그램을 작성한 뒤 언리얼과 코코스 2D로 개발할까도 생각해 보았습니다. 언리얼은 살펴보았을 때 만들려는 게임은 2D인데 2D보다는 3D에 적합해보였습니다. 또한 언리얼은 전반적인 엔진의 느낌이 회사에서 개발하는 AAA급 게임에 적합하여 보았습니다. 1인 개발하는 입장에서 언리얼 수준의 그래픽을 만들어 내기는 힘들어 보였습니다. 코코스 2D와 같은 경우는 당시에 유니티를 유튜브로 빠르게 익히는 중이라 한글 유튜브 관련 좋은 자료가 없는게 아쉬웠습니다. 코코스 2D는 모바일 2D에 가장 강력하고 C++를 사용한다는 이점이 있지만 유니티의 강력한 툴에 끌리고 있는 때로 더 이상 자세히 잘펴보지는 않았습니다. 안드로이드와 iOS 버전를 만들고 다양한 하드웨어 지원을 테스트한 현재 입장에서는 유니티의 강력한 툴 기능이 많이 도움이 된거 같습니다. 확실히 1인 개발이고 모바일 관련 개발이 저처럼 초행길이라면 유니티가 좋은 선택인 듯 보입니다.

만들면서도 느꼈지만 확실히 게임 프로그래밍은 게임 라이브러리나 엔진 프로그래밍 혹은 다른 영역의 프로그래밍과는 다른 부분이 있는 듯 합니다. 프레임 안에서 실시간으로 다양한 객체들이 움직이고 해당 객체들에 대한 이런 저런 제어를 해야 됩니다. 어떻게 보면 프레임별 실행되는 함수가 게임 프로그래밍의 핵심인 듯 보입니다. 보통 프로그래밍이 GUI라면 이벤트 처리를 하고 네트워크 프로그래밍이라면 받은 패킷에 대한 처리를 합니다. 일반적인 콘솔 프로그래밍이라면 그냥 로직을 쭉 실행하면 됩니다. 게임프로그래밍은 실시간 처리의 구조를 어떻게 가져가는가가 중요합니다. 그리고 성능상 프레임별 처리 함수에서 그것을 어떻게 쪼개서 처리하는가, 얼마나 빠르게 처리하는가가 중요한거 같습니다. 반응성을 위하여 프레임별 처리 함수의 속도를 올리는 것과 여러 실시간 객체들의 수를 조절하여 느려지지 않게 하는 것등이 중요한거 같습니다.  

게임 프로그래밍은 어떻게 보면 데이터를 읽어 플레이하는 플레이어를 만드는거 같습니다. 마치 동영상 데이터를 읽어서 동영상을 플레이하는 플레이어 같습니다. 실제로 만든 폭격 방어자는 스테이지별 데이터 부터 각종 데이터를 읽어서 적을 생성한다든지 아이템 새를 생성한다든지 혹은 데이터에 따라 적이 일정 간격으로 폭격을 합니다. 게임 골격을 프로그래밍을 한 후에 게임의 스테이지를 만드는 것이나 적의 패턴 등등은 거의 데이터 작업이었습니다. 이외에 랜덤 관련 사항도 거의 데이터 작업이었습니다.

폭격 방어자와 같은 경우는 철저하게 아래에서 부터 위로 디자인을 해나가면서 만들었습니다. 그런 관계로 코드가 위에서 부터 아래로 디자인한 형태 만큼 깔끔하지는 않습니다. 게임 로직을 만들고 이후에 스테이지 관련 처리를 추가하는 것 같은 형태입니다. 하지만 유니티 초행길에서 현실적으로 개발할 수 있는 방법인 듯 싶었습니다. 유니티는 코딩을 게임오브젝트에 넣는 업데이트 관련 컴포넌트에서 시작하는 경우가 많아서 엔진부터 만들 때 처럼 전체 골격을 만들고 객체들을 넣는 경우와는 틀린 것이 많았습니다. 게임 엔진을 사용하고 느낀 점이지만 돌아갈 수 있는 부분부터 만들고 큰 부분을 확장해 나가는 것이 현실적이라는 생각이 들었습니다.

게임의 초기 버전을 만든 뒤에 마스터링이라고 개인적으로 부른 과정으로 게임을 개선하였습니다. 이 때 버그 수정이나 난이도 개선을 하였고 프로그래밍 적으로는 최적화 작업을 하였습니다. 해당 과정에서 배우 거나 느낀 것들을 이 블로그에 최적화란 제목으로 많이 작성하여 놓았습니다. 인터넷을 보면 간단한 게임이 느린 것은 처음부터 잘못 만든 것이라는 편협한 글도 볼 수 있는데 참 잘못된 생각인 듯 싶습니다. 실제로 만들고 보니까 오프젝트 풀링 등을 사용하여 최대한 잘 만들어 놓아도 실제 모바일에서 실행하면 많은 문제가 보입니다. 유니티는 기본적으로 2가지 관점에서 보아야 합니다. 우선 유니티는 여러 플랫폼에서 돌아가는 범용 엔진입니다. 다음으로 유니티는 개발 언어로 C#를 사용합니다. 그런 관계로 실제로 모바일에서 원활히 돌아가기 위해서는 모바일에 최적화 되도록 설정을 하여야 합니다. 또한 쉐이더 같은 것들도 모바일에 최적화 되도록 사용해야 합니다. 그렇지 않으면 범용 엔진 특성상 유니티 엔진의 최고의 성능을 얻어낼 수 없습니다. 다음으로 개발 언어로 C#을 사용하는 관계로 언어 특성에 따라 느린 코드를 찾아서 바꾸어야 합니다. 이는 게임 프로그래밍의 특성상 프레임에서의 작은 지연도 프레임 수를 떨어뜨릴 수 있기 때문입니다. 또한 C#은 메모리 관리를 자동으로 하는 관계로 가비지 컬렉션과 관련하여 최적화 해야 합니다. 되도록 잠시 쓰고 버려지는 객체를 new해서 가비지 켈렉팅이 일어나게 만들어서는 안됩니다. 간단히 말해서 최적화란 빠른 알고리즘의 사용 외에 느려지는 부분을 수정하여 유니티 엔진이 최고의 성능을 만들어 내는 것을 말하는거 같습니다. 

최적화를 하고 난 후에 LG V10에서 처음 4x 나오던 프레임을 60 수준으로 만들어 놓았습니다. 슈팅 게임이라 그런지 30 프레임과 60 프레임의 느낌이 많이 틀립니다. RPG와 같이 프레임이 떨어져도 크게 느껴지지 않는 게임이라면 상관없겠지만 액션이나 슈팅 게임에는 프레임 수가 정말 중요한거 같습니다. 실제로 프레임이 떨어지면 게임의 난이도도 더 올라가는 효과도 발생합니다. 최적화로 512M의 저가 키드용 안드로이드 태블릿에서 30 프레임 정도 나왔습니다. 이 정도가 실제로 내가 만들던 게임에서 유니티 엔진의 한계인 듯 보이기도 했습니다. 렌더링 시간이 크게 나와 이 이상 프레임을 올리는 것은 힘들어 보였습니다. 하지만 게임이 단순한 관계로 최적화로 저사양의 모바일 기기에서도 원활히 게임을 돌릴 수 있게 하자는데는 성공한거 같습니다.

 

반응형