UNITY/Tool

[UNITY] Google Play Game Service (GPGS) 간단하지 않은 사용법

HYEOKJUN 2022. 2. 9. 18:00
반응형
GPGS는 Android와 IOS 플렛폼에서만 사용할 수 있습니다.

Google Play Console 기본 설정

https://play.google.com/console

Google Play Console | Google Play Console

Google Play Console로 앱과 게임을 게시 및 관리하고 Google Play에서 비즈니스를 성장시키세요. 앱의 품질을 개선하고, 잠재고객의 참여를 유도하고, 수익을 창출하는 데 도움이 되는 기능을 알아보세

play.google.com

위 링크에서 25$를 지불하여 개발자 계정을 생성합니다.
개발자 계정 생성 후 우측 상단의 [앱 만들기] 버튼을 클릭하여 앱 세부 정보를 작성합니다.

[성장 > Play 게임즈 서비스 > 설정 및 관리 > 설정]을 선택하고 [아니요, 게임에서 Google API를 사용하지 않습니다]를 선택하여 Google Play Game Service를 생성합니다.

[Google Cloud Platform에서 OAuth 동의 화면 만들기]를 클릭합니다.

[Google Cloud Platform]를 클릭합니다.

User Type을 외부로 설정하고 [만들기] 버튼을 클릭합니다.
모든 필수 입력 사항을 작성하여 동의 화면을 게시합니다.

Google Play Console로 돌아와 [사용자 인증 정보 > 사용자 인증 정보 추가]를 선택합니다.

[게임 서버]를 선택하고 스크롤을 끝까지 내려 [인증 > OAuth 클라이언트 만들기]를 선택합니다.

위 양식에 맞는 OAuth 클라이언트를 만들어야 합니다.

다시 Google Cloud Platform으로 이동하여 [사용자 인증 정보 만들기]를 선택하고 [OAuth 클라이언트 ID]를 선택합니다.

[애플리케이션 유형]으로 웹 애플리케이션를 선택하고 [만들기] 버튼을 클릭합니다.

OAuth 클라이언트가 생성되었습니다.

다시 Google Play Console로 돌아와 [OAuth 클라이언트]를 선택하고 [변경사항 저장]을 클릭합니다.

게임 서버가 생성되었습니다.

Android 사용자 인증 정보 추가를 위해 [사용자 인증 정보 > 사용자 인증 정보 추가]를 선택하고 Android를 선택합니다.

스크롤을 끝까지 내려 [인증 > OAuth 클라이언트 만들기]를 선택합니다.
위와 같은 방법으로 OAuth 클라이언트를 만들어야 합니다.

위와 같이 작성 후 [만들기] 버튼을 누릅니다.

OAuth 클라이언트가 생성되었습니다.

위와 같이 생성된 것을 확인할 수 있습니다.


Package 설치하기

https://github.com/playgameservices/play-games-plugin-for-unity

GitHub - playgameservices/play-games-plugin-for-unity: Google Play Games plugin for Unity

Google Play Games plugin for Unity. Contribute to playgameservices/play-games-plugin-for-unity development by creating an account on GitHub.

github.com

2022.02.07 기준

위 링크에 접속하여 [current-build]를 선택합니다.

2022.02.07 기준

[GooglePlayGamesPlugin-0.10.14.unitypackage]를 선택합니다.

2022.02.07 기준

[Download] 버튼을 클릭하여 unitypackage 파일을 다운로드하고 실행합니다.

GooglePlayGamesPluginImport할때 ExternalDependencyManager 폴더가 이미 존재하는 경우에는 체크를 해제한 후 Import합니다.

( 기존 폴더와 충돌을 일으킬 수 있습니다. )

Import가 완료되면 ExternalDependencyManager, GooglePlayGames, Plugins 폴더가 생성됩니다.


Unity 기본 설정

Google Play Console에 접속하여 [성장 >Play 게임즈 서비스 > 설정 및 관리 > 설정 > 사용자 인증 정보]를 선택하고 [리소스 보기]를 클릭합니다. 위 XML을 모두 복사합니다.

Unity로 돌아와 [Google Play Games > Setup > Android setup]을 선택합니다.

Resources Definition에 복사한 XML을 붙여 넣고 [Setup]을 클릭하여 Android Configure Setup을 완료합니다.

* 오류 메시지가 뜨는 경우 대부분 재실행시 해결됩니다.

[Assets > External Dependency Manager > Android Resolver > Force Resolve]를 선택하여 업데이트를 진행합니다.

* 오류 메세지가 뜨는 경우 Resolve후 Force Resolve를 선택합니다.

Force Resolve가 완료되었습니다.


Google Player Game Service - 업적, 리더보드, 이벤트, 클라우드 서비스 추가

Google Play Console로 이동하여 [성장 > Play 게임즈 서비스 > 업적]을 선택하고 [업적 만들기]를 클릭합니다.

다음과 같이 원하는 만큼 업적을 생성합니다.


이번에는 [이벤트]를 선택하고 [이벤트 만들기]를 클릭합니다.

다음과 같이 원하는 만큼 이벤트를 생성합니다.


이번에는 [리더보드]를 선택하고 [리더보드 생성]을 클릭합니다.

다음과 같이 원하는 만큼 리더보드를 생성합니다.


클라우드 서비스를 이용하기 위해서 [설정 > 속성 수정 > 저장된 게임]에서 사용을 선택합니다.

[Google Platform에서 보기]를 클릭합니다.

[라이브러리]를 선택합니다.

[검색어 입력창]Google Workspace Marketplace SDK를 입력하여 찾습니다.

[사용]을 눌러 해당 API를 사용합니다.
이제 클라우드 서비스 사용이 가능합니다.


Unity - 업적, 리더보드, 이벤트, 클라우드 서비스 추가

Google Play Console에 접속하여 [성장 >Play 게임즈 서비스 > 설정 및 관리 > 설정 > 사용자 인증 정보]를 선택하고 [리소스 보기]를 클릭합니다.

해당 XML을 모두 복사합니다.

Unity로 돌아와 [Google Play Games > Setup > Android setup]을 선택합니다.

Resources Definition에 복사한 XML을 붙여 넣고 [Setup]을 클릭하여 Android Configure Setup을 완료합니다.

AssetsGPGSIds 파일이 생성되었습니다.


GPGSManager.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SocialPlatforms;
using GooglePlayGames;
using GooglePlayGames.BasicApi;
using GooglePlayGames.BasicApi.SavedGame;
using GooglePlayGames.BasicApi.Events;

public class GPGSManager
{
    static GPGSManager instance = new GPGSManager();
    public static GPGSManager Instance { get { return instance; } } // 싱글톤 구현

    public bool IsAuthenticated { get { return Social.localUser.authenticated; } } // 로그인 여부를 확인합니다.

    void Init() {
        var config = new PlayGamesClientConfiguration.Builder()
            .EnableSavedGames() // 클라우드 서비스를 이용하지 않는다면 이 줄을 지웁니다.
            .Build();
        PlayGamesPlatform.InitializeInstance(config);
        PlayGamesPlatform.DebugLogEnabled = true;
        PlayGamesPlatform.Activate();
    }

    public void Login(bool autoLogin = false, Action<bool, ILocalUser> callback = null) { // 로그인을 시도합니다.(autoLogin : 앱 실행시 자동로그인 => true / 사용자가 직접 로그인 => false)
        Init();
        PlayGamesPlatform.Instance.Authenticate(autoLogin ? SignInInteractivity.CanPromptOnce : SignInInteractivity.CanPromptAlways, (result) => {
            callback?.Invoke(result == SignInStatus.Success, Social.localUser);
        });
    }
    public void Logout() => PlayGamesPlatform.Instance.SignOut();  // 로그아웃합니다.

    public void ShowAchievementsUI() => Social.ShowAchievementsUI(); // 모든 업적 목록을 표시합니다.
    public void RevealAchievement(string gpgsID, float progress, Action<bool> callback = null) => Social.ReportProgress(gpgsID, progress, (bool success) => { callback?.Invoke(success); });  // 해당 업적을 진전시킵니다.
    public void UnlockAchievement(string gpgsID, Action<bool> callback = null) => RevealAchievement(gpgsID, 100f, callback); // 해당 업적을 달성시킵니다.

    public void ShowLeaderboardUI() => Social.ShowLeaderboardUI(); // 모든 리더보드 목록을 표시합니다.
    public void ShowLeaderboardUI(string gpgsID) => PlayGamesPlatform.Instance.ShowLeaderboardUI(gpgsID); // 해당 리더보드를 표시합니다.
    public void ReportLeaderboard(string gpgsID, long score, Action<bool> callback = null) => Social.ReportScore(score, gpgsID, (bool success) => { callback?.Invoke(success); }); // 리더보드에 점수를 기록합니다.

    public void FetchEvent(string gpgsID, Action<bool, IEvent> callback = null) { // 해당 이벤트를 표시합니다.
        PlayGamesPlatform.Instance.Events.FetchEvent(
            DataSource.ReadCacheOrNetwork, 
            gpgsID, 
            (status, ievent) => {
                if(status == ResponseStatus.Success) {
                    callback?.Invoke(true, ievent);
                } else {
                    callback?.Invoke(false, null);
                }
            }
        );
    } 
    public void FetchAllEvents(Action<bool, List<IEvent>> callback = null) { // 이벤트 목록을 표시합니다.
        PlayGamesPlatform.Instance.Events.FetchAllEvents(
            DataSource.ReadCacheOrNetwork,
            (status, ievents) => {
                if(status == ResponseStatus.Success) {
                    callback?.Invoke(true, ievents);
                } else {
                    callback?.Invoke(false, null);
                }
            }
        );
    }
    public void IncrementEvent(string gpgsID, uint amount) => PlayGamesPlatform.Instance.Events.IncrementEvent(gpgsID, amount); // 해당 이벤트를 업데이트합니다.

    public void SaveWithCloud(string filename, string serializedFile, Action<bool> callback = null) { // 클라우드 서비스를 이용하여 저장합니다.
        ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;

        savedGameClient.OpenWithAutomaticConflictResolution(
            filename,
            DataSource.ReadCacheOrNetwork,
            ConflictResolutionStrategy.UseLastKnownGood,
            (status, game) => {
                if(status == SavedGameRequestStatus.Success) {
                    var updatedMetadata = new SavedGameMetadataUpdate.Builder().Build();
                    savedGameClient.CommitUpdate(
                        game, 
                        updatedMetadata, 
                        System.Text.Encoding.UTF8.GetBytes(serializedFile), 
                        (ustatus, ugame) => {
                            callback?.Invoke(ustatus == SavedGameRequestStatus.Success);
                        }
                    );
                } else {
                    callback?.Invoke(false);
                }
            }
        );
    }
    public void LoadWithCloud(string filename, Action<bool, string> callback = null) { // 클라우드 서비스를 이용하여 로드합니다.
        ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;

        savedGameClient.OpenWithAutomaticConflictResolution(
            filename, 
            DataSource.ReadCacheOrNetwork, 
            ConflictResolutionStrategy.UseLastKnownGood, 
            (status, game) => {
                if(status == SavedGameRequestStatus.Success) {
                    savedGameClient.ReadBinaryData(game, (lstatus, lserializedFile) => {
                        if(lstatus == SavedGameRequestStatus.Success) {
                            string data_loaded = System.Text.Encoding.UTF8.GetString(lserializedFile);
                            callback?.Invoke(true, data_loaded);
                        } else {
                            callback?.Invoke(false, null);
                        }
                    }
                );
                } else {
                    callback?.Invoke(false, null);
                }
            }
        );
    }
    public void DelectWithCloud(string filename, Action<bool> callback = null) { // 클라우드 서비스에 저장된 데이터를 삭제합니다.
        ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;

        savedGameClient.OpenWithAutomaticConflictResolution(
            filename,
            DataSource.ReadCacheOrNetwork,
            ConflictResolutionStrategy.UseLongestPlaytime,
            (status, game) => {
                if(status == SavedGameRequestStatus.Success) {
                    savedGameClient.Delete(game);
                    callback?.Invoke(true);
                } else {
                    callback?.Invoke(false);
                }
            }
        );
    }
}

위 스크립트를 원하는 곳에 저장하고 아래와 같은 방식으로 사용합니다.


로그인 · 로그아웃

if(GPGSManager.Instance.IsAuthenticated) { // 로그인 여부를 확인합니다.
	// Google Play Game Service 로그인 상태
} else {
	// Google Play Game Service 비로그인 상태
}

 // GPGSManager.Instance.Login(bool autoLogin, Action<bool, ILocalUser> callback = null) 
 // autoLogin : false = 사용자 직접 로그인, true = 자동 로그인
GPGSManager.Instance.Login(false, (success, ilocalUser) => { // 로그인을 시도합니다.
	if(success) {
		// 로그인 성공
        
		//ilocalUser.userName = 플레이어 이름
		//ilocalUser.id = 플레이어 아이디
		//ilocalUser.state = 플레이어 상태
		//ilocalUser.underage = 플레이어 미성년자 여부
	} else {
		// 로그인 실패
	}
});

GPGSManager.Instance.Logout(); // 로그아웃합니다.

도전과제

GPGSManager.Instance.ShowAchievementsUI(); // 모든 도전과제 목록 UI를 표시합니다.

GPGSManager.Instance.RevealAchievement(GPGSIds.ACHIEVEMENTID, 50f, (success) => { // 해당 단계별 도전과제를 업데이트합니다.
	if(success) {
		// 도전과제 업데이트 성공시
	} else {
		// 도전과제 업데이트 실패시
	}
});

GPGSManager.Instance.UnlockAchievement(GPGSIds.ACHIEVEMENTID, (success) => { // 해당 도전과제를 해금시킵니다.
	if(success) {
		// 도전과제 해금 성공시
	} else {
		// 도전과제 해금 실패시
	}
});

리더보드

GPGSManager.Instance.ShowLeaderboardUI(GPGSIds.LEADERBOARDID); // 해당 리더보드 UI를 표시합니다.

GPGSManager.Instance.ReportLeaderboard(GPGSIds.LEADERBOARDID, 123, (success) => { // 해당 리더보드에 점수를 기록합니다.
	if(success) {
		// 리더보드 점수 기록 성공시
	} else {
		// 리더보드 점수 기록 실패시
	}
});

이벤트

GPGSManager.Instance.FetchEvent(GPGSIds.EVENTID, (success, ievent) => { // 해당 이벤트 목록을 표시합니다.
	if(success) {
		// 이벤트 목록 표시 성공시
	} else {
		// 이벤트 목록 표시 실패시
	}
});

GPGSManager.Instance.IncrementEvents((success, ievents) => { // 해당 이벤트를 업데이트합니다.
	if(success) {
		// 이벤트 업데이트 성공시
	} else {
		// 이벤트 업데이트 실패시
	}
});

클라우드 서비스

using Newtonsoft.Json;

//...

public void SaveWithCloud() {
	string serializedData = JsonConvert.SerializeObject(data); // 데이터를 저장하기 전에 직렬화합니다.
	GPGSManager.Instance.SaveWithCloud("FILENAME", serializedData, (success) => { // 데이터를 클라우드에 저장합니다.
		if(success) {
			// 데이터 저장 성공시
		} else {
			// 데이터 저장 실패시
		}
	);
}

public void LoadWithCloud() {
	GPGSManager.Instance.LoadWithCloud("FILENAME", (success, serializedData) => { // 데이터를 클라우드에서 불러옵니다.
		if(success) {
			// 데이터 로드 성공시
			Data data = JsonConvert.DeserializeObject<Data>(serializedData); // 불러온 데이터를 역직렬화합니다.
		} else {
			// 데이터 로드 실패시
		}
	});
}

public void DelectWithCloud() {
	GPGSManager.Instance.DelectWithCloud("FILENAME", (success) => { // 데이터를 클라우드에서 삭제합니다..
		if(success) {
			// 데이터 삭제 성공시
		} else {
			// 데이터 삭제 실패시
		}
	});
}
반응형