NOS-NightRaid Project 회고

https://apkpure.com/ninja-of-shadow-night-raid/com.juno.nosnightraid

Unity로 만든 횡스크롤 액션 게임. 고등학교 2학년 때 기획, 디자인, 개발을 혼자 진행했고 실제 Google Play에 출시까지 했던 프로젝트다.

프로젝트를 시작한 이유

Ninja of Shadow는 고등학교 2학년 때 만들었다.

처음 계기는 고군분투였다. 게임을 보다가 나도 이런 느낌의 게임을 한번 만들어 보고 싶다는 생각이 들었다.

그렇다고 기존 횡스크롤 게임처럼 좌우로 움직이고 점프하는 방식으로 만들고 싶지는 않았다.

게임을 만들기 전에 먼저 생각했던 건 “조작을 어떻게 하면 재미있게 만들 수 있을까?”였다.

그때 생각한 방식이 화면을 양쪽으로 나누는 것이었다.

오른쪽에서는 에임을 조작하고, 왼쪽에서는 점프나 로프, 스킬을 사용한다.

지금 생각하면 꽤 단순한 아이디어인데 당시에는 이게 상당히 재미있을 것 같았다.

그래서 이 조작 방식을 중심으로 게임을 만들기 시작했다.

기획부터 게임 시스템, 디자인, 개발까지 전부 혼자 했다.


조작 방식

Ninja of Shadow에서 가장 많이 고민했던 부분이다.

오른쪽에서 손가락을 움직여 에임을 조작하고 왼쪽의 버튼으로 캐릭터 행동을 실행하는 방식이다.

에임과 이동을 분리했기 때문에 캐릭터가 이동하는 방향과 바라보는 방향이 달라질 수 있었다.

예를 들어 오른쪽으로 이동하면서 왼쪽을 조준할 수 있다.

그래서 이동 방향과 캐릭터가 바라보는 방향을 따로 처리해야 했다.

에임 위치를 받아서 캐릭터 기준으로 방향을 계산하고, 그 결과에 따라 캐릭터의 좌우 방향과 공격 방향을 변경했다.

구조 자체는 복잡하지 않았지만 실제로 게임에 넣어 보니 생각보다 손볼 곳이 많았다.

특히 모바일에서는 에임 위치가 조금만 어긋나도 조작감이 바로 이상해졌다.

그래서 입력 영역이나 버튼 위치를 계속 바꿔 봤다.


로프를 Joint로 구현했다

개인적으로 이 프로젝트에서 가장 기억에 남는 부분이다.

처음부터 로프를 넣으려고 했다.

처음에는 단순히 로프를 쏘고 특정 위치에 도착하면 캐릭터를 그쪽으로 이동시키는 방식도 생각했다.

그런데 그렇게 만들면 로프라기보다는 그냥 이동 스킬에 가까웠다.

그래서 Unity의 물리 시스템을 이용하기로 했다.

로프가 닿은 위치에 플레이어를 연결하고 Joint를 이용해서 실제로 당겨지는 형태로 구현했다.

대략적인 구조는 이렇다.

에임 -> 로프 발사 -> 충돌 지점 확인 -> Joint 연결 -> 물리 이동 -> 로프 해제

로프가 연결되면 플레이어의 움직임에 따라 로프의 영향을 받도록 했다.

이걸 구현하면서 Rigidbody와 Joint가 같이 사용될 때 어떤 식으로 움직임이 만들어지는지도 직접 확인할 수 있었다.

문제도 있었다.

일반 이동 코드가 계속 캐릭터의 속도를 변경하고 있는데 Joint까지 물리 계산을 하고 있으니 서로 영향을 주는 상황이 생겼다.

그래서 로프를 사용하고 있을 때와 평소 이동 상태를 구분해서 처리했다.

지금 다시 만든다면 로프 상태를 별도의 상태로 관리하고 이동 시스템과 물리 시스템의 책임도 좀 더 명확하게 나눌 것 같다.

당시에는 일단 원하는 움직임이 나오게 만드는 데 집중했다.


Sprite Animation도 직접 만들었다

캐릭터 애니메이션은 Unity에서 제공하는 기능만 사용하는 대신 직접 Sprite Animation을 만들어 봤다.

여러 장의 Sprite를 순서대로 바꾸면서 애니메이션을 재생하는 방식이다.

예를 들어 걷기 애니메이션이라면 Sprite 여러 장을 배열로 가지고 있다가 일정한 시간마다 다음 Sprite로 변경한다.

Sprite 배열 -> 현재 프레임 -> Sprite 변경 -> 다음 프레임

여기에 반복 여부와 재생 속도 등을 넣었다.

캐릭터 상태가 바뀌면 그에 맞는 Sprite Animation을 실행하도록 연결했다.

지금이라면 상황에 따라 Animator를 사용하는 게 더 편한 경우가 많다.

그래도 이걸 직접 만들어 보면서 애니메이션이 생각보다 단순한 구조라는 것을 알게 됐다.

결국 일정 시간마다 이미지를 바꾸고, 어떤 상황에서 어떤 애니메이션을 재생할지만 관리하면 된다.

직접 만들어 본 덕분에 이후 Unity의 Animator를 사용할 때도 내부적으로 어떤 식으로 동작하는지 이해하기 쉬웠다.


캐릭터와 스킬

기본적인 캐릭터 이동 외에도 점프와 로프, 스킬을 사용할 수 있게 만들었다.

스킬은 각각 입력을 받아 실행하고 사용할 수 없는 상태에서는 입력을 무시하도록 했다.

당시에는 지금처럼 상태를 깔끔하게 분리해서 설계하지 못했다.

여러 플래그와 조건문으로 상태를 확인하는 방식이 많았다.

게임이 커졌다면 분명 문제가 됐을 구조다.

그래도 실제로 게임을 완성하면서 어떤 상황에서 입력을 막아야 하는지, 스킬 사용 중 다른 행동을 어떻게 제한해야 하는지 같은 문제를 직접 겪어 볼 수 있었다.


모바일 입력을 만들면서 생긴 문제

개발하면서 가장 크게 배운 부분은 오히려 기술적인 부분만은 아니었다.

나는 게임을 계속 만들고 있었기 때문에 조작법을 이미 알고 있었다.

그래서 직접 플레이할 때는 별로 어렵지 않았다.

그런데 다른 사람이 처음 플레이하는 걸 보니까 바로 문제가 보였다.

어디를 눌러야 하는지 모르고, 오른쪽을 움직여야 에임이 움직인다는 것도 바로 이해하지 못했다.

그래서 조작 관련 UI를 계속 수정했다.

버튼 위치도 바꿔보고 설명도 추가했다.

이때 처음으로 내가 알고 있는 것과 플레이어가 알고 있는 것은 다르다는 걸 확실하게 느꼈다.

개발자는 이미 게임의 규칙을 알고 있기 때문에 테스트할 때 무의식적으로 필요한 정보를 보충한다.

처음 보는 사람은 그런 정보가 없다.

이건 이후 게임을 만들 때도 계속 신경 쓰게 된 부분이다.


실제 출시까지 했다

Ninja of Shadow는 개발만 하고 끝낸 프로젝트가 아니다.

실제로 Google Play에 출시했다.

모바일 빌드를 만들고 스토어에 등록하는 과정까지 직접 진행했고, IAP도 연동했다.

당시에는 결제 기능을 실제 게임에 붙이는 것 자체가 재미있었다.

게임 내부에서 구매 요청을 보내고 결과를 받아서 처리하는 과정도 직접 연결했다.

개발 중에는 게임 코드만 보면 됐지만 출시 단계에서는 다른 문제가 생겼다.

빌드 설정이나 실제 기기 테스트, 스토어 등록처럼 게임 코드 외에도 확인해야 할 것들이 있었다.

이때 게임을 만드는 것과 게임을 출시하는 것은 꽤 다른 일이라는 걸 알게 됐다.


출시하고 나서 알게 된 것

게임을 출시하기 전에는 사람들이 게임을 올려두면 어느 정도 플레이할 거라고 생각했다.

지금 생각하면 너무 당연한 이야기인데, 당시에는 직접 출시해 보기 전까지 크게 생각하지 않았다.

홍보를 거의 하지 않았기 때문에 게임이 출시됐다는 사실을 아는 사람이 별로 없었다.

결과적으로 게임이 크게 잘되지는 않았다.

그래도 출시 자체는 의미가 있었다.

내가 만든 게임을 실제 스토어에 올려 봤고, 실제 기기에서 플레이할 수 있게 만들었고, 결제까지 연결해 봤다.

학교에서 Unity로 게임을 만드는 것과 실제 서비스를 하나 만들어 보는 것은 느낌이 많이 달랐다.


잘했던 점

가장 잘했다고 생각하는 것은 아이디어를 실제 게임으로 끝까지 만들었다는 것이다.

오른쪽 에임과 왼쪽 액션이라는 조작 방식을 생각했고, 실제 모바일 입력으로 구현했다.

로프도 단순한 이동 기능으로 끝내지 않고 Joint를 이용해서 물리적으로 연결되는 형태로 만들었다.

Sprite Animation 역시 직접 구현했다.

그 외에도 캐릭터 이동, 충돌 처리, 스킬, UI 등을 하나의 게임으로 묶었다.

무엇보다 마지막에 실제 Google Play까지 출시했다.

당시에는 하나하나 따로 보면 대단한 기술이라고 생각하지 않았다.

하지만 지금 돌아보면 기능 하나를 만들어 보는 것과 게임 하나를 완성해서 실제 사용자에게 배포하는 것은 상당히 다르다.


아쉬웠던 점

지금 다시 코드를 보면 구조적으로 부족한 부분이 많을 것 같다.

특히 기능을 빠르게 만들다 보니 여러 기능이 하나의 스크립트에 들어가거나 상태값과 플래그에 의존하는 경우가 많았다.

당시에는 코드 구조를 오래 고민하기보다 일단 동작하게 만드는 쪽을 선택했다.

로프 역시 물리와 캐릭터 이동 코드가 서로 강하게 연결되어 있었다.

지금이라면 입력, 이동, 스킬, 로프, 애니메이션을 각각 분리하고 상태 관리도 명확하게 만들 것이다.

또 하나 아쉬운 부분은 플레이 테스트다.

처음부터 다른 사람에게 자주 플레이시켜 봤다면 조작 UI를 그렇게 여러 번 수정하지 않아도 됐을 것 같다.

개발자가 재미있게 느끼는 것과 처음 보는 사람이 재미있게 느끼는 것은 다를 수 있다는 걸 너무 늦게 알았다.


지금 다시 만든다면

게임의 기본 아이디어 자체는 크게 바꾸지 않을 것 같다.

오히려 조작 방식을 더 다듬어 보고 싶다.

입력과 게임 로직을 분리해서 모바일 입력과 실제 게임 행동을 따로 관리하고, 로프 역시 Joint를 이용하는 방향은 유지할 것이다.

다만 로프의 생성, 연결, 해제와 캐릭터 이동 상태를 각각 분리한다.

Sprite Animation도 직접 프레임을 관리하는 방식 자체는 간단한 게임에서는 충분히 사용할 수 있지만, 캐릭터 상태와 애니메이션 상태를 명확하게 연결할 것이다.

그리고 개발 초반부터 다른 사람이 플레이하도록 할 것이다.

기능을 전부 만든 다음 테스트하는 게 아니라 조작 하나를 만들었을 때부터 바로 플레이시켜 보는 방식으로 진행할 것 같다.


이 프로젝트를 통해 배운 것

Ninja of Shadow를 만들면서 Unity를 단순히 사용하는 것과 게임을 만드는 것은 다르다는 걸 알게 됐다.

Rigidbody나 Joint를 사용하는 방법을 알고 있는 것만으로는 로프가 재미있어지지 않는다.

Sprite를 순서대로 바꾸는 방법을 알고 있다고 해서 애니메이션이 좋은 것도 아니다.

결국 각각의 기술을 게임 플레이에 맞게 연결해야 한다.

그리고 기술적인 부분만큼이나 플레이어가 그것을 어떻게 받아들이는지도 중요했다.

특히 조작 UI를 수정하면서 이걸 크게 느꼈다.

개발자는 게임의 모든 정보를 알고 있지만 플레이어는 아무것도 모른 상태에서 시작한다.

그 차이를 줄이는 것도 게임 개발의 일부라고 생각하게 됐다.


마치며

Ninja of Shadow는 고등학교 2학년 때 혼자 만든 게임이다.

고군분투를 보고 시작했지만 그대로 따라 만들지는 않았다.

어떻게 조작하면 재미있을지 생각하다가 오른쪽에서는 에임을 조작하고 왼쪽에서는 점프, 로프, 스킬을 사용하는 방식을 만들었다.

그 과정에서 Unity의 물리 시스템을 이용해 Joint 기반 로프를 구현했고, Sprite Animation도 직접 만들어 사용했다.

기획과 디자인, 개발을 혼자 진행했고 실제 Google Play 출시와 IAP 연동까지 했다.

게임 자체는 크게 성공하지 못했다.

홍보를 거의 하지 않았기 때문에 많은 사람이 게임을 알지는 못했다.

그래도 이 프로젝트는 지금까지 만든 게임 중 기억에 많이 남아 있다.

아이디어를 생각하고, 직접 구현하고, 다른 사람에게 플레이시켜 보고, 문제를 고치고, 마지막에는 실제 스토어에 올렸다.

결국 이 프로젝트에서 가장 많이 배운 것은 특정 Unity 기능 하나가 아니다.

게임은 기능을 만드는 것으로 끝나는 게 아니라, 그 기능들이 실제 플레이 경험으로 이어져야 완성된다는 것이다.