개발 일지는 바로바로 작성하는 게 가장 좋지만, 개인 사정으로 인해 개발을 한동안 진행하지 못하면서 기획과 개발 기록 역시 예정했던 것보다 많이 늦어지게 되었습니다.
개인적인 이유 외에도 개발 과정에서 예기치 않은 문제들이 생기며 일정이 더 밀렸으며, 특히 Firebase 로그인(Google Login) 연동과 UI 연결 과정에서 여러 오류가 발생해 시간을 꽤 잡아먹었다. 해당 문제들은 나중에 각 파트에서 자세히 다루도록 하고, 여기서는 실제로 구현한 순서에 따라 개발 일지를 정리해보려고 한다.
Prototype Stage
우선 프로토타입 스테이지 에서는 기본적인 게임의 기능이 모두 적용되는지 확인하는 스테이지이다.

프로토타입 단계에서는 복잡한 연출이나 구조를 넣기보다, 게임이 제대로 동작하는지 확인하기 위한 최소한의 요소들을 중심으로 간단하게 임시 스테이지를 제작했다.
스테이지에는 점수를 제공하는 아이템들과 기본 플랫폼, 간단한 함정들, 그리고 최종 도착 지점을 배치해 러너형 게임의 기본 루프가 정상적으로 작동하는지 테스트했다.
아이템을 획득하면 점수가 증가하고, 코인을 획득할 경우에는 소량의 점수와 함께 Gold 자원도 추가로 얻을 수 있도록 기본적인 보상 구조도 구성했다.
아직은 아이템의 세부 기능이나 각 캐릭터의 스킬 시스템이 미구현 상태이지만, 우선 게임의 흐름을 우선으로 두고 있어 앞으로 단계적으로 구현할 예정이다.
앞으로 추가해야할 내역
- 아이템
- 회복아이템
- 쉴드 아이템
- 가속 아이템
- 거대화 아이템
- 캐릭터의 스킬
챕터 및 스테이지 구현
스테이지는 각각 챕터 내부에 포함되는 구조로 설계했다. 현재 프로토타입 단계에서는 챕터당 2~3개의 스테이지를 계획하고 있으며, 추후 게임 규모에 맞춰 스테이지 수를 더 늘릴 예정이다.
지금은 하나의 스테이지 프리팹을 복제하여 1-1, 1-2, 1-3과 같은 형태로 구성해 놓은 상태다. 기본적인 동작 확인이 목적이기 때문에 간단한 레이아웃만 바꿔 테스트하고 있으며, 이후 본격적인 제작 단계에서 각 스테이지마다 개성 있는 구조와 기믹을 추가할 예정이다.
챕터는 LobbyScene의 UI에 구현되어 있다.


챕터 버튼을 누르면 각 챕터에 해당하는 StageUI가 생성된다.


ChapterManager를 통해 각 ChapterButton에 순서대로 매핑시켜 사용합니다.

챕터 내부에 포함된 스테이지 정보를 기반으로, 게임이 시작될 때 해당 스테이지 데이터를 불러와 선택된 Stage의 프리팹을 생성하는 방식으로 구현했다. 이를 통해 스테이지 선택 → 데이터 전달 → 맵 생성의 흐름이 일관되도록 시스템을 구성했다.
스테이지를 선택하면 캐릭터 선택 UI가 활성화되고, 이 화면에서 선택된 캐릭터 정보와 스테이지 정보가 GameManager에 저장된다. 이후 탐색 시작 버튼을 누르면 GameScene으로 이동하며, GameManager가 들고 있는 데이터를 기반으로 실제 맵과 캐릭터가 동적으로 생성된다.
캐릭터 선택 시스템은 PlayerData에 저장된 보유 캐릭터 목록을 기준으로 작동한다. PlayerData에서 해당 캐릭터를 가지고 있을 경우에만 관련 버튼이 활성화되며, 버튼을 누르는 순간 해당 캐릭터의 정보가 GameManager로 전달된다.
Scene이 전환되면 이러한 선택 정보들을 바탕으로 본격적인 게임이 시작되는 구조다.

SCENES
- 현재 분류된 Scene의 종류는 LoginScene, LobbyScene, GameScene으로 3개의 Scene이 순환된다.
LoginScene
Firebase를 활용한 로그인과 데이터 저장
이번 프로젝트에서는 Firebase Authentication을 활용해 간단한 익명 로그인 기능을 먼저 구현했다.
초기 개발 단계에서는 별도의 계정 시스템보다, 플레이 데이터 저장이 가능한 최소한의 인증 구조를 마련하는 것이 중요했기 때문에 익명 로그인을 선택했다.
Firebase 익명 로그인은 사용자가 별도의 가입 과정을 거치지 않아도 고유 UID를 발급받을 수 있다는 장점이 있어, 이후 데이터 저장이나 로드 기능을 구현할 때 매우 유용하다.
이렇게 발급된 UID를 기반으로 Firestore와 연동해 플레이어의 기본 정보, 진행 상황, 보유 캐릭터 등의 데이터를 저장할 수 있는 구조를 구성했다.
앞으로는 익명 로그인 외에 Google 로그인 연동도 추가하여, 사용자가 기기를 변경해도 데이터를 이어서 플레이할 수 있는 형태로 확장할 예정이다.
가능하다면 기존 익명 계정을 Google 계정에 연결 하여 데이터를 그대로 이어받을 수 있도록 구현해보고자 한다.
이 방식이 성공하면, 초반에는 익명으로 플레이하던 사용자가 나중에 Google 로그인으로 전환할 때 기존 데이터를 그대로 Google 계정 데이터에 덮어쓰는 형태가 가능해진다.

Guest Login 버튼을 누르면 Firebase Authentication을 통해 익명 계정이 자동으로 생성된다.
이 과정에서 사용자는 별도의 정보 입력 없이도 바로 플레이할 수 있으며, Firebase는 내부적으로 고유한 UID를 발급해 Authentication 사용자 목록에 익명 사용자로 등록한다.
이 UID를 기반으로 Firestore에 플레이어 데이터를 생성하고 저장하기 때문에, 로그인 후 바로 게임 진행과 데이터 저장이 가능해진다.

익명 로그인 참고
Android에서 익명으로 Firebase에 인증 | Firebase Authentication
의견 보내기 Android에서 익명으로 Firebase에 인증 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Firebase Authentication을 사용하면 임시 익명 계정을 생성 및 사용
firebase.google.com
유니티 C# 파이어베이스 익명 로그인 간단 사용법 Firebase Auth Guest Login
파이어베이스 SDK 다운로드 Unity 프로젝트에 Firebase 추가 | Unity용 Firebase 의견 보내기 Unity 프로젝트에 Firebase 추가 Firebase Unity SDK를 활용하여 Unity 게임을 업그레이드 해보세요. Firebase를 Unity 프로
parksh3641.tistory.com
구글 로그인
Google 로그인을 구현하는 과정에서는 예상보다 많은 문제가 발생했다.
우선 Google 로그인을 사용하기 위해서는 Google Sign-In 패키지(Google Sign-In for Unity) 를 다운로드하여 프로젝트에 임포트해야 하는데, 이 단계부터 문제가 발생했다.
Google Signin Package
Releases · googlesamples/google-signin-unity
Google Sign-In API plugin for Unity game engine. Works with Android and iOS. - googlesamples/google-signin-unity
github.com
첫번째 문제는 Task충돌입니다.
Parse 폴더 내부의 Task 관련 부분 경로 충돌이 발생 합니다. 단순히 임포트하면 되겠지 라는 안일한 생각으로 임포트를 했다가 충돌이 발생했다.
이 Parse 폴더 내부의 Task 충돌이 발생한다는 사실을 알게 되었고 Task와 충돌이 발생해 에러창에 Parse 폴더 자체를 삭제해서 문제를 해결했다.


두번째 문제
SHA1, SHA256 키 등록 및 프로젝트, Firebase에 추가
Google 로그인을 사용하려면 Firebase 콘솔과 Google Cloud 콘솔에 SHA1 및 SHA256 키를 정확하게 등록해야 한다. 이 키들이 등록되어 있어야 Google 인증서가 Unity 앱을 ‘정상적인 앱’으로 인식하고 로그인 요청을 처리할 수 있다.
문제는 이 과정이 생각보다 단순하지 않았다는 점이다.
Unity 프로젝트의 키스토어 설정, 빌드 환경, 디버그/릴리즈 키 여부에 따라 필요한 SHA 값이 달라지는데, 처음에는 이 부분을 제대로 이해하지 못해 Firebase와 Google API 모두 로그인 요청을 거부하는 상황이 반복되었다.
결국 다음 과정을 통해 문제를 해결했다:
- Unity에서 사용하는 디버그 키스토어를 확인
- keytool 명령어로 SHA1, SHA256 값을 추출
- 추출한 값을 **Firebase 프로젝트 설정(Authentication → Sign-in method)과
Google Cloud Console(Android OAuth 클라이언트)에 모두 등록 - 앱을 재빌드하여 다시 Firebase와 연결
이 과정을 완료한 뒤에야 Google 로그인 요청이 정상적으로 승인되기 시작했다.

keystore를 통해 SHA1과 SHA256 확인방법은 아래의 영상을 참고했습니다.
keytool 환경변수 등록 참고
keytool 명령어를 찾지 못 할 때 해결 방안 (keytool은 내부 또는 외부 명령, 실행할 수 있는 프로그램
카카오 SDK를 사용하기 위해서 키를 생성하려던 중 에러가 발생하였다. 다음은 Windows에서 디버그 키를 생성하는 명령어이다. keytool -exportcert -alias androiddebugkey -keystore %USERPROFILE%\.android\debug.keystore
growth-coder.tistory.com
Keystore 참고
유니티에서 안드로이드 키스토어 생성하기(keystore)
유니티에서 안드로이드 키스토어 생성하기(keystore) 유니티에서 구글 플레이 업로드를 위한 앱 서명 https://developer.android.com/studio/publish/app-signing?hl=ko#app-signing-google-play 1)빌드 설정(build settings)에서
learnandcreate.tistory.com
KeyTool명령어를 통해 프로젝트에서 만든 KeyStore의 정보를 확인해 SHA1과 SHA256의 Data를 Firebase에 등록한다.

세번째 문제
Android Resolver와 google-signin-support 세팅하기
Assets -> External Dependency Manager -> Android Resolver -> Settings

google>signin>google-signin-support-1.04의 세팅 정보를 확인한다.

체크가 되지 않은 상태로 빌드한 앱에서 발생한 로그
해당 로그는 adb와 안드로이드 개발자모드를 켜서 확인한 내용이다.
DllNotFoundException: Unable to load DLL 'native-googlesignin'.
Tried the load the following dynamic libraries:
Unable to load dynamic library 'native-googlesignin' because of 'Failed to open the requested dynamic library (0x06000000)
dlerror() = dlopen failed: library "native-googlesignin" not found
11-18 02:19:32.211 17884 17912 E Unity : at Google.Impl.GoogleSignInImpl.GoogleSignIn_Create (System.IntPtr data) [0x00000] in <00000000000000000000000000000000>:0
11-18 02:19:32.211 17884 17912 E Unity : at Google.Impl.GoogleSignInImpl..ctor (Google.GoogleSignInConfiguration configuration) [0x00000] in <00000000000000000000000000000000>:0
11-18 02:19:32.211 17884 17912 E Unity : at Google.GoogleSignIn.get_DefaultInstance () [0x00000] in <00000000000000000000000000000000>:0
11-18 02:19:32.211 17884 17912 E Unity : at FirebaseManager.GoogleLogin () [0x00000] in <00000000000000000000000000000000>:0
11-18 02:19:32.211 17884 17912 E Unity : at LoginManager+<DelayedGoogleSignIn>d__38.MoveNext () [0x00000] in <00000000000000000000000000000000>:0
11-18 02:19:32.211 17884 17912 E Unity : at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00000] in <0000000000000000000000
나와 같은 버그 로그를 발견한 내용을 구글링해서 찾아 문제를 해결하게 되었다.
[버그] Google Signin SDK 'native googlesignin' 버그
▶ 참고 링크- 바로가기 DllNotFoundException: Unable to load DLL 'native-googlesignin': The specified module could not be found. · Issue #106 · googleIm getting an error when trying to signin with Google using the google-signin-unity plugin. its
lhy-info.tistory.com
안드로이드 체크를 하고 빌드를 해서 확인하면 아래와 같은 정상작동 로그가 출력된다.
adb를 통해 로그를 확인한 덕분에, 로그인 과정에서 어떤 단계가 정상적으로 호출되고 있는지 상세하게 파악할 수 있었다.
로그에는 로그인 요청이 실행되었는지, Google 인증 토큰을 제대로 받아왔는지, 그리고 Firebase Auth와의 연동이 성공했는지 등이 단계별로 출력된다.
이 로그들을 통해 어느 구간에서 문제가 발생했는지 빠르게 진단할 수 있었고, 앞서 설정한 Android Resolver와 google-signin-support 세팅이 제대로 적용되었는지 검증하는 데에도 큰 도움이 되었다.


GoogleSignIn SDK는 에디터에서 동작을 지원하지 않기 때문에 안드로이드 빌드를 마친 후 모바일 환경에서 테스트를 진행했다.
그리고 혹여나 에디터에서 구글 로그인 버튼을 누를 때를 방지해 전처리기인 #if , #endif를 사용했다.
구글 로그인하는데 사용한 메서드는 다음과 같다.
public void GoogleLogin()
{
#if UNITY_EDITOR
Debug.LogWarning("GoogleSignIn은 에디터에서 작동 X, 모바일 기기에서 테스트.");
return;
#else
// Configuration 세팅 확인
if (GoogleSignIn.Configuration == null)
{
GoogleSignIn.Configuration = googleConfig;
}
// 이메일 정보 요청 (기본적으로 ID토큰 + 이메일 제공)
GoogleSignIn.Configuration.RequestEmail = true;
// Google 로그인 팝업 호출
Task<GoogleSignInUser> signIn = GoogleSignIn.DefaultInstance.SignIn();
// Firebase 인증 결과를 반환하기 위한 TaskCompletionSource
TaskCompletionSource<FirebaseUser> signInCompleted = new TaskCompletionSource<FirebaseUser>();
// Google 로그인 완료 후 실행되는 콜백
signIn.ContinueWith(task =>
{
// 사용자가 로그인 취소
if (task.IsCanceled)
{
signInCompleted.SetCanceled();
Debug.Log("Cancelled");
}
// 로그인 중 오류 발생 (인터넷 문제, 구글 계정 문제 등)
else if (task.IsFaulted)
{
signInCompleted.SetException(task.Exception);
Debug.Log("Faulted " + task.Exception);
}
else
{
// GoogleSignInUser에서 ID Token 획득
// 이 토큰으로 Firebase에 로그인 가능
Credential credential = Firebase.Auth.GoogleAuthProvider.GetCredential(((Task<GoogleSignInUser>)task).Result.IdToken, null);
// Firebase 인증 시작
auth.SignInWithCredentialAsync(credential).ContinueWith(authTask =>
{
if (authTask.IsCanceled)
{
signInCompleted.SetCanceled();
}
else if (authTask.IsFaulted)
{
signInCompleted.SetException(authTask.Exception);
Debug.Log("Faulted In Auth " + task.Exception);
}
else
{
signInCompleted.SetResult(((Task<FirebaseUser>)authTask).Result);
Debug.Log("Success");
// 현재 로그인된 Firebase 사용자 정보 저장
user = auth.CurrentUser;
}
});
}
});
#endif
}
등록된 로그인 정보 저장 및 기초 데이터 저장
로그인이 정상적으로 이루어지면, 해당 계정 정보를 기반으로 플레이어의 기초 데이터를 Firebase에 저장해야 한다.
이 과정을 보다 유연하고 일관성 있게 관리하기 위해 별도의 SaveManager 스크립트를 추가했다.
SaveManager는 Firestore 또는 Realtime Database에 접근하는 전용 매니저로 사용되며, 프로젝트 전체에서 하나만 존재하도록 Singleton 패턴으로 구현했다.
플레이어의 레벨, 골드, 보유 캐릭터 같은 기초 정보는 PlayerData에 정리되어 있으며, SaveManager는 이 PlayerData의 내용을 바탕으로 Firebase에 데이터를 저장하거나 업데이트하는 역할을 맡는다.

플레이어 정보를 로드하는 메서드
/// <summary>
/// 플레이어 데이터 로드
/// </summary>
public async Task LoadPlayerData(PlayerData data)
{
if (!dbInitialized)
{
Debug.LogWarning("SaveManager Firestore가 아직 초기화되지 않음");
return;
}
if (FirebaseManager.instance.user == null)
{
Debug.LogWarning("SaveManager Load 호출 시 user가 아직 null, 나중에 다시 호출해야 한다.");
return;
}
var userId = FirebaseManager.instance.user.UserId;
var docRef = db.Collection("players").Document(userId);
var snapshot = await docRef.GetSnapshotAsync();
if (snapshot.Exists)
{
data.playerName = snapshot.GetValue<string>("playerNickname");
data.level = snapshot.GetValue<int>("playerLevel");
data.totalExp = snapshot.GetValue<int>("playerTotalExp");
data.playerGold = snapshot.GetValue<int>("gold");
data.playerGem = snapshot.GetValue<int>("gem");
data.playerStamina = snapshot.GetValue<int>("stamina");
data.playerMaxStamina = snapshot.GetValue<int>("maxStamina");
Debug.Log("SaveManager 기존 유저 데이터 불러오기 완료");
}
else
{
Debug.Log("SaveManager 신규 유저 감지, 닉네임 UI는 LoginManager에서 처리");
}
}
데이터 저장에 대한 참고 문서
Cloud Firestore에 데이터 추가 | Firebase
이 문서에서는 Cloud Firestore에서 개별 문서를 설정, 추가 또는 업데이트하는 방법을 설명합니다. 데이터를 일괄 쓰기하려면 트랜잭션 및 일괄 쓰기를 참조하세요. 개요 다음 방법 중 하나로 Cloud F
firebase.google.com
LobbyScene
LobbyScene에서는 자신이 보유한 행동력, 골드, GEM, 보유 캐릭터 확인, 캐릭터 뽑기, 강화, 상점 등이 이용이 가능하며, 현재 캐릭터의 Lv과 닉네임, 경험치를 확인할 수 있다.

현재 LobbyScene에서 구현된 기능은 캐릭터의 레벨 상승과 경험치 획득 정도다.
반면, 탐색을 제외한 하단 버튼들(캐릭터 뽑기, 강화, 상점 등)은 아직 미구현 상태이며, 상단의 설정과 공지 기능 또한 구현되지 않았다.
또한, 스테이지를 통해 게임을 시작했을 때 행동력이 차감되는 기능도 계획되어 있으나, 아직 구현 전이다.
현재 LobbyScene은 UI 구조와 기본 데이터 연동 테스트 중심으로 구성되어 있으며, 향후 기능 확장을 위해 틀을 잡아둔 단계이다.
GameScene
GameScene은 GameStage와 SelectCharacter가 생성되는 씬으로, 실제로 게임 플레이가 이루어지는 공간이다.
플레이어는 선택한 캐릭터로 스테이지를 탐색하며, 게임을 클리어할 경우 경험치와 인게임 재화(Gold, GEM 등)를 획득할 수 있다.
즉, GameScene은 실제 게임 루프가 작동하는 핵심 공간이며, 플레이어의 성장과 보상을 직접 경험할 수 있는 씬이다.

현재 GameScene에서는 각 스테이지마다 별을 획득할 수 있는 조건은 아직 구현되지 않았다.
획득한 경험치는 LobbyScene의 캐릭터 경험치와 레벨(Lv) 시스템과 연동되어, 플레이어가 스테이지를 클리어할 때 즉시 반영된다.
향후 계획으로는, 각 스테이지를 첫 클리어했을 때 추가 별 조건을 달성하면 Gem을 보상으로 획득할 수 있도록 구현할 예정이다.
이를 통해 플레이어는 단순히 클리어하는 것뿐만 아니라, 별 획득 조건을 고려한 전략적 플레이를 즐길 수 있도록 기획 및 구현할 계획이다..

앱 실행 영상
아직 저장 데이터 구조, 저장 타이밍, 그 외 다양한 기능 구현이 남아 있고, 지금까지 구현한 내역도 다소 부실한 상태다.
하지만 이번 개발 과정을 통해 문제를 발견하고 해결하는 경험을 쌓았으며, 앞으로 더 많은 기능을 개발하면서 지속적으로 배우고 개선해 나갈 계획이다.
이번 기록은 초기 프로토타입과의 기본 시스템 구축 과정의 일부를 정리한 것으로, 앞으로의 개발 방향과 학습 과정을 공유하는 밑거름이 될 것이다.
'Unity' 카테고리의 다른 글
| 개발 일지 - 포션 아이템 추가 및 점수, 골드 아이템 스크립트 변경(Interface) (0) | 2025.11.26 |
|---|---|
| 개발일지 - 프로토타입 구현 기획 작성 및 구현 내역 (0) | 2025.10.16 |
| 개발 일지 - 간단한 기획 및 게임 틀 제작기획 (0) | 2025.10.07 |
| Unity-Firebase등록 및 추가 (0) | 2025.09.26 |