프로젝트 개요

2019년에 시작한 오픈월드 게임이다. 내가 스토어에 처음 올린 프로젝트이기도 하다. 기여도는 100%, 즉 혼자 만들었다.

항목내용
시작2019년 6월
엔진Unity 2021.3.45f2
기여도100% (1인 개발)
리소스일부는 상업 이용 가능한 무료 에셋, 나머지는 직접 제작 (3D · 2D · 애니메이션)
상태출시 완료. 2022년을 기점으로 낮은 API 버전 문제로 스토어에서 내려감

Unity 입문 직후에 오픈월드 멀티플레이라는 기획으로 시작했다. 지금 돌아보면 무모한 규모였지만, 그 과정에서 코드 작성 능력과 유니티 전반의 사용법을 익혔다.

탈 것을 붙이는 방식

오픈월드에 탈 것을 추가하기 위해 여러 방법을 시도했다. Unity가 표준으로 제공하는 차량부터 강좌에서 알려주는 방식까지 다양하게 적용해 봤다.

그 결과 각각의 스크립트를 확인해 보면서, 여러 차량에 공통으로 적용할 수 있고 기능을 쉽게 추가할 수 있는 형태로 합쳤다. 차량마다 따로 스크립트를 두지 않고 하나로 모은 것이 이후에 도움이 됐다.

구동 방식이 주행감에 미치는 영향일반적으로 전륜구동(FWD)은 코너에서 앞바퀴가 먼저 접지를 잃어 바깥으로 밀리고, 후륜구동(RWD)은 뒷바퀴가 흘러 차체가 안으로 말린다. 사륜구동(AWD)은 구동력을 네 바퀴에 나눠 두 경향이 모두 완화된다. 바퀴별로 구동 토크를 얼마나 나눠 주느냐가 이 차이를 만든다.

트레일러 연결

유로트럭이라는 시뮬레이션 게임의 트럭·트레일러 시스템에 매력을 느껴서, 같은 것을 만들어 보고 싶었다. 수많은 시도 끝에 트레일러를 연결했을 때 자연스럽게 움직이도록 구현하는 데 성공했다.

NPC 레이싱 AI

체크포인트 시스템을 기반으로 NPC 차량 알고리즘을 만들었다. 길을 이탈했을 때 3가지 패턴으로 반응하며, 여기에는 현실적인 진로 변경 로직이 포함된다.

애니메이션과 상호작용

캐릭터 애니메이션은 처음에 구해와서 일부만 수정해 썼다. mixamo처럼 무료로 받을 수 있는 곳에서 애니메이션을 내려받고, 필요 없는 부분의 키프레임을 삭제한 뒤 위치를 조정하는 식이었다.

상호작용의 양을 늘리려다 보니 그것만으로는 부족해서, 이후에는 애니메이션을 직접 제작하고 수정했다. 덕분에 제작 시간을 줄이면서 원하는 애니메이션을 추가할 수 있게 됐다.

상호작용은 실내 가구, 차량 주유 같은 단순하면서도 게임 요소를 늘릴 수 있는 것들부터 추가해 나갔다.

로딩 화면

메인 메뉴에서 씬을 넘어갈 때 쓴 코드다. 당시 작성한 그대로 옮긴다.

IEnumerator LoadScene(string name)
{
    lodingImg.SetActive(true);
    yield return null;
    AsyncOperation op = SceneManager.LoadSceneAsync(name);
    op.allowSceneActivation = false;
    float timer = 0.0f;
    while (!op.isDone)
    {
        yield return null;
        timer += Time.deltaTime;
        if (op.progress < 0.9f)
        {
            progressBar.fillAmount = Mathf.Lerp(progressBar.fillAmount, op.progress, timer);
            if (progressBar.fillAmount >= op.progress)
            {
                timer = 0f;
            }
        }
        else
        {
            progressBar.fillAmount = Mathf.Lerp(progressBar.fillAmount, 1f, timer);
            if (progressBar.fillAmount == 1.0f)
            {
                op.allowSceneActivation = true;
                yield break;
            }
        }
    }
}

이 코드가 하는 일

allowSceneActivationfalse 로 막아두면 씬 로딩이 끝나도 전환되지 않는다. 로딩바를 끝까지 채운 다음 직접 true 로 바꿔 전환시키기 위한 구조다.

Unity의 AsyncOperation.progressallowSceneActivationfalse 일 때 0.9에서 멈춘다. 나머지 0.1은 씬 활성화 몫이라 활성화를 허용하기 전까지는 올라가지 않는다. 위 코드가 0.9f 를 기준으로 분기를 나눈 이유가 이것이다.

지금 다시 보면 보이는 것

당시에는 동작하니까 넘어갔지만, 지금 코드를 읽으면 걸리는 부분이 몇 군데 있다. 기록해 둔다.

데이터 유실과 복구

2022년, 작업하던 컴퓨터가 고장 나면서 프로젝트 파일 대부분을 잃었다.

그해에는 다른 활동과 맞물려 잠시 손을 놓았지만, 스토어 출시의 핵심인 key.store 파일만은 포기할 수 없었다. 이 파일이 없으면 같은 앱으로 업데이트를 올릴 수 없기 때문이다. 2023년부터 복구를 시도했고, 2025년에 복구에 성공했다.

key.store 가 왜 그렇게 중요한가안드로이드 앱은 서명 키로 동일성을 증명한다. 키를 잃으면 기존 앱의 업데이트를 올릴 수 없고, 다른 키로 새로 올리면 스토어상 완전히 별개의 앱이 된다. 다운로드 수와 리뷰도 함께 사라진다.

현재

Google Play Console 앱 목록에 자동차 오픈월드가 출시 안 됨, 업데이트 거부됨 상태로 표시된 화면
현재 콘솔 상태. 출시 안 됨 / 업데이트 거부됨으로 표시되어 있다.

출시 자체는 완료했지만 2022년을 기점으로 낮은 API 버전 문제로 스토어에서 내려갔다. 구글 플레이는 일정 시점마다 앱이 대상으로 하는 API 레벨의 하한을 올리는데, 그 기준을 넘기지 못한 앱은 신규 노출에서 제외되고 업데이트도 거부된다.

복구한 key.store 와 과거 기획 자료를 바탕으로 재개발에 착수했다. 재개발은 Unity로 진행하고 있다.

정리

성과라고 적어둘 만한 것은 두 가지다. 첫 출시작으로 1000회 이상 다운로드를 기록한 것, 그리고 당시 실력으로 오픈월드를 만들겠다는 집념 하나로 끝까지 짜냈다는 것.

그래픽 리소스를 직접 만들면서 겪은 어려움은 나중에 팀으로 작업할 때 그래픽 작업자의 상황을 이해하고 조율하는 데 도움이 됐다. 오픈월드라는 큰 기획을 구현부터 유실, 복구까지 겪으면서 프로젝트에 필요한 기초 설계와 개발 전 과정을 몸으로 익혔다고 생각한다.

복잡한 물리와 NPC 알고리즘을 독학으로 구현해 낸 것도 이 프로젝트에서 얻은 것이다. 아직 끝나지 않았다.