- Home /
How to save/load with Google Play Services
Hi all! I-m trying yo implement the Google Play Services in my Android game.
https://github.com/playgameservices/play-games-plugin-for-unity
I have been able to implement achievments without problems and are working good, but I have been some days trying to get the Saved Services working and I can´t.
The main problem is the code of the plugin page, I don´t understand how it works, only I have been able to showUI with a button but I dont pass from that point.
I need the new Saved Service, not the old one Cloud Services, thats the main problem, for the old Cloud Service are a lot of tutorial, but for the new one I can´t fine anything.
I have enable Saved Games in Google Developers Console and it is publishied more than 24 hours ago (2 days exactly).
I have enabled Saved Games in the code:
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder()
// enables saving game progress.
.EnableSavedGames()
.Build();
PlayGamesPlatform.InitializeInstance(config);
This is the code provided with the plugin:
To show the default UI:
void ShowSelectUI() {
int maxNumToDisplay = 5;
bool allowCreateNew = false;
bool allowDelete = true;
ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;
savedGameClient.ShowSelectSavedGameUI("Select saved game",
maxNumToDisplay,
allowCreateNew,
allowDelete,
OnSavedGameSelected);
}
public void OnSavedGameSelected (SelectUIStatus status, ISavedGameMetadata game) {
if (status == SelectUIStatus.SavedGameSelected) {
// handle selected game save
} else {
// handle cancel or error
}
}
To open save game:
void OpenSavedGame(string filename) {
ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;
savedGameClient.OpenWithAutomaticConflictResolution(filename, DataSource.ReadCacheOrNetwork,
ConflictResolutionStrategy.UseLongestPlaytime, OnSavedGameOpened);
}
public void OnSavedGameOpened(SavedGameRequestStatus status, ISavedGameMetadata game) {
if (status == SavedGameRequestStatus.Success) {
// handle reading or writing of saved game.
} else {
// handle error
}
}
Writing save game:
void SaveGame (ISavedGameMetadata game, byte[] savedData, TimeSpan totalPlaytime) {
ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;
SavedGameMetadataUpdate.Builder builder = new SavedGameMetadataUpdate.Builder();
builder = builder
.WithUpdatedPlayedTime(totalPlaytime)
.WithUpdatedDescription("Saved game at " + DateTime.Now());
if (savedImage != null) {
// This assumes that savedImage is an instance of Texture2D
// and that you have already called a function equivalent to
// getScreenshot() to set savedImage
// NOTE: see sample definition of getScreenshot() method below
byte[] pngData = savedImage.EncodeToPNG();
builder = builder.WithUpdatedPngCoverImage(pngData);
}
SavedGameMetadataUpdate updatedMetadata = builder.Build();
savedGameClient.CommitUpdate(game, updatedMetadata, savedData, OnSavedGameWritten);
}
public void OnSavedGameWritten (SavedGameRequestStatus status, ISavedGameMetadata game) {
if (status == SavedGameRequestStatus.Success) {
// handle reading or writing of saved game.
} else {
// handle error
}
}
public Texture2D getScreenshot() {
// Create a 2D texture that is 1024x700 pixels from which the PNG will be
// extracted
Texture2D screenShot = new Texture2D(1024, 700);
// Takes the screenshot from top left hand corner of screen and maps to top
// left hand corner of screenShot texture
screenShot.ReadPixels(
new Rect(0, 0, Screen.width, (Screen.width/1024)*700), 0, 0);
return screenShot;
}
Reading save game:
void LoadGameData (ISavedGameMetadata game) {
ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;
savedGameClient.ReadBinaryData(game, OnSavedGameDataRead);
}
public void OnSavedGameDataRead (SavedGameRequestStatus status, byte[] data) {
if (status == SavedGameRequestStatus.Success) {
// handle processing the byte array data
} else {
// handle error
}
}
Thanks for your time!
I only need a simple code example of how to save and load with the official plugin, the code provided from Google is a piece of crap and incomplete code.
This plugin is really frustrating, I´m moving to a backend server service for my games, the support and tutorials of Google are shit.
Any one hace used GameSparks or Gamedonia?
Thanks!
Have you looked at the samples folder? The CubicPilot sample should be a full project ($$anonymous$$us the actual Play Games Plugin, but that's irrelevant since you can easily add it yourself) demonstrating exactly how to get Google Saved Games working.
Answer by C4nDiM4n · Aug 25, 2016 at 04:54 PM
For people who finds this thread in the future and have problems setting up GPG cloud save, like I had.
I've made the most barebones setup I can. Hopefully this will help people get started with GPG cloud save. Since this is a very light setup once it works you should tailor it to your own setup.
IMPORTANT This is Save/Load without using GPG UI. Also GPG needs to be initialized before you can use this. GPG Cloud Save needs to be turned on in Dev console and .EnableSavedGames() needs to exist in PlayGamesClientConfiguration.
This only saves a simpel string (in our case a json string with save progress) to a GPG cloud save. It overwrites the save every time so if you want multiple saves you need to implement that yourself. Comments in code should explain most.
Look at https://github.com/playgameservices/play-games-plugin-for-unity/tree/master/samples/CubicPilot/Source/Assets/CubicPilot/GameLogic for a more full setup.
This https://github.com/playgameservices/play-games-plugin-for-unity/issues/384 thread helped me a bit. Cred to iqbalmineraltown's answer. I used it in this implementation.
Also cred to @peteradamondy with the above answer. Used his his implementation for reference aswell.
#if UNITY_ANDROID
using UnityEngine;
using System;
using System.Collections.Generic;
//gpg
using GooglePlayGames;
using GooglePlayGames.BasicApi;
using GooglePlayGames.BasicApi.SavedGame;
//for encoding
using System.Text;
//for extra save ui
using UnityEngine.SocialPlatforms;
//for text, remove
using UnityEngine.UI;
public class GPG_CloudSaveSystem {
private static GPG_CloudSaveSystem _instance;
public static GPG_CloudSaveSystem Instance{
get{
if (_instance == null) {
_instance = new GPG_CloudSaveSystem();
}
return _instance;
}
}
//keep track of saving or loading during callbacks.
private bool m_saving;
//save name. This name will work, change it if you like.
private static string m_saveName = "game_save_name";
//This is the saved file. Put this in seperate class with other variables for more advanced setup. Remember to change merging, toBytes and fromBytes for more advanced setup.
private string saveString = "";
//check with GPG (or other*) if user is authenticated. *e.g. GameCenter
private bool Authenticated {
get {
return Social.Active.localUser.authenticated;
}
}
//merges loaded bytearray with old save
private void ProcessCloudData(byte[] cloudData) {
if (cloudData == null) {
Debug.Log("No data saved to the cloud yet...");
return;
}
Debug.Log("Decoding cloud data from bytes.");
string progress = FromBytes(cloudData);
Debug.Log("Merging with existing game progress.");
MergeWith(progress);
}
//load save from cloud
public void LoadFromCloud(){
Debug.Log("Loading game progress from the cloud.");
m_saving = false;
((PlayGamesPlatform)Social.Active).SavedGame.OpenWithAutomaticConflictResolution(
m_saveName, //name of file.
DataSource.ReadCacheOrNetwork,
ConflictResolutionStrategy.UseLongestPlaytime,
SavedGameOpened);
}
//overwrites old file or saves a new one
public void SaveToCloud() {
if (Authenticated) {
Debug.Log("Saving progress to the cloud... filename: " + m_saveName);
m_saving = true;
//save to named file
((PlayGamesPlatform)Social.Active).SavedGame.OpenWithAutomaticConflictResolution(
m_saveName, //name of file. If save doesn't exist it will be created with this name
DataSource.ReadCacheOrNetwork,
ConflictResolutionStrategy.UseLongestPlaytime,
SavedGameOpened);
} else {
Debug.Log("Not authenticated!");
}
}
//save is opened, either save or load it.
private void SavedGameOpened(SavedGameRequestStatus status, ISavedGameMetadata game) {
//check success
if (status == SavedGameRequestStatus.Success){
//saving
if (m_saving){
//read bytes from save
byte[] data = ToBytes();
//create builder. here you can add play time, time created etc for UI.
SavedGameMetadataUpdate.Builder builder = new SavedGameMetadataUpdate.Builder();
SavedGameMetadataUpdate updatedMetadata = builder.Build();
//saving to cloud
((PlayGamesPlatform)Social.Active).SavedGame.CommitUpdate(game, updatedMetadata, data, SavedGameWritten);
//loading
} else {
((PlayGamesPlatform)Social.Active).SavedGame.ReadBinaryData(game, SavedGameLoaded);
}
//error
} else {
Debug.LogWarning("Error opening game: " + status);
}
}
//callback from SavedGameOpened. Check if loading result was successful or not.
private void SavedGameLoaded(SavedGameRequestStatus status, byte[] data) {
if (status == SavedGameRequestStatus.Success){
Debug.Log("SaveGameLoaded, success=" + status);
ProcessCloudData(data);
} else {
Debug.LogWarning("Error reading game: " + status);
}
}
//callback from SavedGameOpened. Check if saving result was successful or not.
private void SavedGameWritten(SavedGameRequestStatus status, ISavedGameMetadata game) {
if (status == SavedGameRequestStatus.Success){
Debug.Log("Game " + game.Description + " written");
} else {
Debug.LogWarning("Error saving game: " + status);
}
}
//merge local save with cloud save. Here is where you change the merging betweeen cloud and local save for your setup.
private void MergeWith(string other) {
if (other != "") {
saveString = other;
} else {
Debug.Log("Loaded save string doesn't have any content");
}
}
//return saveString as bytes
private byte[] ToBytes() {
byte[] bytes = Encoding.UTF8.GetBytes(saveString);
return bytes;
}
//take bytes as arg and return string
private string FromBytes(byte[] bytes) {
string decodedString = Encoding.UTF8.GetString(bytes);
return decodedString;
}
// -------------------- ### Extra UI for testing ### --------------------
//call this with Unity button to view all saves on GPG. Bug: Can't close GPG window for some reason without restarting.
public void showUI() {
// user is ILocalUser from Social.LocalUser - will work when authenticated
ShowSaveSystemUI(Social.localUser, (SelectUIStatus status, ISavedGameMetadata game) => {
// do whatever you need with save bundle
});
}
//displays savefiles in the cloud. This will only include one savefile if the m_saveName hasn't been changed
private void ShowSaveSystemUI(ILocalUser user, Action<SelectUIStatus, ISavedGameMetadata> callback) {
uint maxNumToDisplay = 3;
bool allowCreateNew = true;
bool allowDelete = true;
ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;
if (savedGameClient != null) {
savedGameClient.ShowSelectSavedGameUI(user.userName + "\u0027s saves",
maxNumToDisplay,
allowCreateNew,
allowDelete,
(SelectUIStatus status, ISavedGameMetadata saveGame) => {
// some error occured, just show window again
if (status != SelectUIStatus.SavedGameSelected) {
ShowSaveSystemUI(user, callback);
return;
}
if (callback != null)
callback.Invoke(status, saveGame);
});
} else {
// this is usually due to incorrect APP ID
Debug.LogError("Save Game client is null...");
}
}
}
#endif
Hi! Thanks for this code.
I just tried it, but logcat shows error:
"09-04 21:00:00.998: I/Unity(12896): NotImplementedException: You must enable saved games before it can be used. See PlayGamesClientConfiguration.Builder.EnableSavedGames."
and i have no callbacks on OpenWithAutomaticConflictResolution
"Save games" is activated in Dev console and .EnableSavedGames() is enabled in PlayGamesPlatform config
Can you please tell me, why this problem may occure?
SOLVED! Looks like problem was with calling PlayGamesPlatform.Activate(); AFTER logging in. That line must be before logging in.
Ah nice, good catch. I didn't include code for login to keep it small.
Hi!
While I was already halfway there myself, your code definitely helped me make more sense of everything and figure out what I can customize and play around with. This kind of stripped down code with some simple explanation was exactly what I needed. I cannot thank you enough!
Thanks, I was looking for this as well.
One question though, what should I do if I want to save mutiple variables without using json? I'm using playerprefs for my save, (obviously) I have many variables to save for my game, and I don't know how to convert it to json.
UPVOTE!! You rock dude!!! I have been googling for hours trying to just find a way to save a simple value to GPG. Thanks.
I hope that some one is still viewing this thread cause I have a question.
How secure is the values written? I mean, can the user go in and edit it since it's technically a save on his account?
You mean standard user/player? No. Although it is technically saved to his account. That part is not directly accessible by user. Also, he would need class (or at least marshalling structure) you are using for serialization.
With that being said, however it is possible to "hack/reverse eng. your apk" and have access to saves, scores and leaderboards. How to prevent that to happen is whole another topic.
Answer by peteradamondy · Feb 18, 2015 at 08:43 PM
I've been struggling with GPG in unity too. Today, I finally figured things out. SaveDataBundle should be your "save file" implementation with custom serialization/deserialization. Hope this helps :)
using UnityEngine;
using System.Collections;
using GooglePlayGames;
using GooglePlayGames.BasicApi.SavedGame;
using UnityEngine.SocialPlatforms;
using System;
using System.Collections.Generic;
public class AndroidSaveSystem {
public static Action OnSaveGameSelected;
public static Action<SaveDataBundle> OnSaveLoaded;
private static SaveDataBundle m_currentSaveBundle;
private static ISavedGameMetadata m_saveBundleMetadata;
/// <summary>
/// Static reference to current save data. Automatically refreshed by save system.
/// </summary>
/// <value>The current save.</value>
public SaveDataBundle CurrentSave
{
get
{
return m_currentSaveBundle;
}
}
/// <summary>
/// Shows the default save system UI. This allows user to select/delete saves as required.
/// </summary>
/// <param name="user">User.</param>
/// <param name="callback">Invokes, when save game has been selected. Check for status for errors, or </param>
public void ShowSaveSystemUI(ILocalUser user, Action<SelectUIStatus,ISavedGameMetadata> callback)
{
uint maxNumToDisplay = 3;
bool allowCreateNew = true;
bool allowDelete = true;
ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;
if(savedGameClient != null)
{
savedGameClient.ShowSelectSavedGameUI(user.userName + "\u0027s saves",
maxNumToDisplay,
allowCreateNew,
allowDelete,
(SelectUIStatus status, ISavedGameMetadata saveGame) =>
{
// some error occured, just show window again
if(status != SelectUIStatus.SavedGameSelected)
{
ShowSaveSystemUI(user,callback);
return;
}
if(callback != null)
callback.Invoke(status,saveGame);
if(OnSaveGameSelected != null && status == SelectUIStatus.SavedGameSelected)
OnSaveGameSelected.Invoke();
});
}else{
// this is usually due to incorrect APP ID
Debug.LogError("Save Game client is null...");
}
}
/// <summary>
/// Creates the new save. Save returned in callback is closed!. Open it before use.
/// </summary>
/// <param name="save">Save.</param>
/// <param name="saveCreatedCallback">Invoked when save has been created.</param>
private static void CreateNewSave(ISavedGameMetadata save, Action<ISavedGameMetadata> saveCreatedCallback)
{
ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;
SavedGameMetadataUpdate.Builder builder = new SavedGameMetadataUpdate.Builder ();
builder = builder
.WithUpdatedPlayedTime (save.TotalTimePlayed.Add (new TimeSpan (0, 0, (int)Time.realtimeSinceStartup)))
.WithUpdatedDescription ("Saved at " + DateTime.Now);
SavedGameMetadataUpdate updatedMetadata = builder.Build ();
SaveDataBundle newBundle = new SaveDataBundle();
newBundle.RegenerateSaveData(50);
savedGameClient.CommitUpdate ( save,
updatedMetadata,
SaveDataBundle.ToByteArray (newBundle),
(SavedGameRequestStatus status,ISavedGameMetadata game)=>
{
if(status == SavedGameRequestStatus.Success)
{
m_saveBundleMetadata = game;
if(saveCreatedCallback != null)
saveCreatedCallback(game);
}
Debug.Log("Creating new save finished with status :" + status.ToString());
});
}
/// <summary>
/// Opens the saved game.
/// </summary>
/// <param name="savedGame">Saved game.</param>
/// <param name="callback">Invoked when game has been opened</param>
private static void OpenSavedGame(ISavedGameMetadata savedGame, Action<ISavedGameMetadata> callback)
{
if(savedGame == null)
return;
if(!savedGame.IsOpen)
{
ISavedGameClient saveGameClient = PlayGamesPlatform.Instance.SavedGame;
// save name is generated only when save has not been commited yet
saveGameClient.OpenWithAutomaticConflictResolution(
savedGame.Filename == string.Empty ? "Save" + UnityEngine.Random.Range(1000000,9999999).ToString() : savedGame.Filename,
DataSource.ReadCacheOrNetwork,
ConflictResolutionStrategy.UseLongestPlaytime,
(SavedGameRequestStatus reqStatus, ISavedGameMetadata openedGame) =>
{
if(reqStatus == SavedGameRequestStatus.Success)
{
m_saveBundleMetadata = openedGame;
if(callback != null)
callback.Invoke(m_saveBundleMetadata);
}
});
}else{
if(callback != null)
callback.Invoke(savedGame);
}
}
/// <summary>
/// Loads the saved game. This should be a starting point for loading data.
/// </summary>
/// <param name="user">User.</param>
/// <param name="onSaveLoadedCallback">On save loaded callback.</param>
public void LoadSavedGame (ILocalUser user, Action<SaveDataBundle> onSaveLoadedCallback)
{
if(onSaveLoadedCallback != null)
OnSaveLoaded += onSaveLoadedCallback;
if(m_saveBundleMetadata == null)
{
ShowSaveSystemUI (user, LoadGame);
}else
{
LoadGame(SelectUIStatus.SavedGameSelected, m_saveBundleMetadata);
}
}
static void LoadGame (SelectUIStatus status, ISavedGameMetadata game)
{
if (status == SelectUIStatus.SavedGameSelected){
OpenSavedGame (game, (ISavedGameMetadata openedGame) =>
{
if(game.Description == null || game.Description == string.Empty)
{
// game has not been saved on cloud before, create new file
CreateNewSave(openedGame, (ISavedGameMetadata newlySavedGame) =>
{
LoadGame(SelectUIStatus.SavedGameSelected, newlySavedGame);
});
return;
}
// save should be opened now
Debug.Log ("Loading save from: " + openedGame.Filename + "\n" + openedGame.Description + "\nOpened = " + openedGame.IsOpen.ToString ());
m_saveBundleMetadata = openedGame;
ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;
savedGameClient.ReadBinaryData (openedGame, (SavedGameRequestStatus reqStatus, byte[] data) =>
{
Debug.Log("Reading save finished with status: " + reqStatus.ToString());
if (reqStatus == SavedGameRequestStatus.Success){
SaveDataBundle bundle = SaveDataBundle.FromByteArray (data);
m_currentSaveBundle = bundle;
if (OnSaveLoaded != null)
{
OnSaveLoaded.Invoke (bundle);
OnSaveLoaded = null;
}
}
});
});
}
}
public void SaveGame (SaveDataBundle file, Action<bool> callback)
{
CommitSaveToCloud(file,"undefined",callback);
}
/// <summary>
/// Commits the save to cloud.
/// </summary>
/// <param name="file">Actual save file. This will replace static reference to current save file</param>
/// <param name="fileName">File name. Used only when saving for first time</param>
/// <param name="callback">Invoked after commit (true = success)</param>
private static void CommitSaveToCloud (SaveDataBundle file, string fileName, System.Action<bool> callback)
{
ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;
savedGameClient.OpenWithAutomaticConflictResolution(
m_saveBundleMetadata.Filename == string.Empty ? fileName : m_saveBundleMetadata.Filename,
DataSource.ReadCacheOrNetwork,
ConflictResolutionStrategy.UseLongestPlaytime,
(SavedGameRequestStatus reqStatus, ISavedGameMetadata openedGame) =>
{
if(reqStatus == SavedGameRequestStatus.Success)
{
// adding real time since startup so we can determine longes playtime and resolve future conflicts easilly
m_saveBundleMetadata = openedGame;
SavedGameMetadataUpdate.Builder builder = new SavedGameMetadataUpdate.Builder ();
builder = builder
.WithUpdatedPlayedTime (m_saveBundleMetadata.TotalTimePlayed.Add (new TimeSpan (0, 0, (int)Time.realtimeSinceStartup)))
.WithUpdatedDescription ("Saved game at " + DateTime.Now);
SavedGameMetadataUpdate updatedMetadata = builder.Build ();
savedGameClient.CommitUpdate ( m_saveBundleMetadata,
updatedMetadata,
SaveDataBundle.ToByteArray (file),
(SavedGameRequestStatus status,ISavedGameMetadata game)=>
{
if(status == SavedGameRequestStatus.Success)
{
m_saveBundleMetadata = game;
m_currentSaveBundle = file;
}
if(callback != null)
callback.Invoke(status == SavedGameRequestStatus.Success);
});
}
});
}
}
Great Help! I have a few questions:
If I understand right, SaveDataBundle is another Script (SaveDataBundle.cs) with the functions ToByteArray(), FromByteArray() and RegenerateSaveData() (for what is this one??).
Something like this:
public class SaveDataBunndle
{
public void RegenerateSaveData () {}
public byte[] ToByteArray() {
return System.Text.ASCIIEncoding.Default.GetBytes(ToString());
}
public static GameData FromByteArray (byte[] bytes) {
return FromString(System.Text.ASCIIEncoding.Default.GetString(bytes));
}
}
Imagine I have a public float Coins, where I have to put that float (that one is the one I want to save in the cloud).
Thanks for your time!
You don't have to use RegenerateSaveData. This is just method I use to populate save structure. You can use simple code like this:
[Serializable]
public class SaveDataBundle
{
// public members are serialized automatically
// for private members use [SerializeField] attribute
public float m_coins;
public SaveDataBundle(float initialCoinAmount)
{
m_coins = initialCoinAmount;
}
public static SaveDataBundle FromByteArray(Byte[] array)
{
if(array == null || array.Length == 0)
{
Debug.LogWarning("Serialization of zero sized array!");
return null;
}
using(var stream = new System.IO.$$anonymous$$emoryStream(array))
{
try{
var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
SaveDataBundle bundle = (SaveDataBundle)formatter.Deserialize(stream);
return bundle;
}catch(Exception e)
{
Debug.LogError("Error when reading stream: "+ e.$$anonymous$$essage);
}
}
return null;
}
public static byte[] ToByteArray( SaveDataBundle bundle)
{
var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using(var stream = new System.IO.$$anonymous$$emoryStream())
{
formatter.Serialize(stream, bundle );
return stream.ToArray();
}
}
}
Thanks for your time!
From the first code that you provides me, how can I use a button to display save o load game?
The problem is that the functions have arguments and that is imcompatible with UI buttons of Unity 4.6.
You can simply wrap functionality like this:
// reference to save system instance
private static AndroidSaveSystem m_saveSystem;
public void Start()
{
// create new instance of save system - it is static, so only one instance will be created in entire game
if(m_saveSystem == null)
m_saveSystem = new AndroidSaveSystem();
}
// call this method form load button
public void LoadGame()
{
// user is ILocalUser from Social.LocalUser - will work when authenticated
m_saveSystem.LoadSavedGame(user, (SaveDataBundle saveBundle) =>
{
// do whatever you need with save bundle
} );
}
// call this method from save button
public void Save()
{
if(m_saveSystem != null && m_saveSystem.CurrentSave != null)
m_saveSystem.SaveGame(m_saveSystem.CurrentSave,OnLevelSaved);
}
private void OnLevelSaved(bool success)
{
// do whatever you need when game has been successfully saved
}
This plugin is really frustrating, I´m moving to a backend server service for my games, the support and tutorials of Google are shit.
Any one hace used GameSparks or Gamedonia?
Thanks!
Answer by google_play_service_dev · Oct 03, 2016 at 02:10 PM
You can try another Play game service Unity plugin
Login Google Play Game
Login Game is required before call other API.Play Game Unity Plugin support google account ,not support google plus api now.
GoogleGame.Instance().login (true, false);
GoogleGame.Instance().gameEventHandler += onGameEvent;
void onGameEvent(int result_code,string eventName,string data){
Debug.Log (eventName + "-----------" + data);
if(result_code==-1&&eventName==GameEvent.onConnectSuccess){
//login success,you can do other now
}
}
You can get player infomation after login,the data is json format string
string json=GoogleGame.Instance().getCurrentUserInfo();
If you exit your game,you can login Out and disconnect
GoogleGame.Instance().loginOut();
Play Game Leaderboard
Display Leaderboard with default UI is very easy
GoogleGame.Instance().showLeaderboards();
Submit a leaderboard score,the first param is leaderboard id,the second param is score value.
GoogleGame.Instance().submitLeaderboardScore("CgkItJ_UzNUHEAIQCQ", 1000L);
if you want to define a ui for leaderboard,you can load data,and you will get data in event GameEvent.onLeaderboardMetadataResult
GoogleGame.Instance().loadLeaderboardsMetadata(false);
Play Game Achieve
Display Achievements with default UI is easy too
GoogleGame.Instance().showAchievements();
Unlock Achievement,the param is Achievement ID
GoogleGame.Instance().unlockAchievement("CgkItJ_UzNUHEAIQBA");
If you want to define ui for Achievement,you can load data ,and handle event GameEvent.onLoadAchievementsResult
GoogleGame.Instance().loadAchievements();
Game Event and Quest
Load Game Event List,and handle Event GameEvent.onLoadEventsResult
GoogleGame.Instance().loadEvents();
Change Event Data
GoogleGame.Instance().incrementEvent("eventID",102);
Load Quest ,and handle Event GameEvent.onLoadQuestsResult.selector is in GameConst such as SELECT_COMPLETED,sortOrder is SORT_ORDER_MOST_RECENT_FIRST or SORT_ORDER_SOCIAL_AGGREGATION
GoogleGame.Instance().loadQuests(int[] questSelectors, int sortOrder, bool forceReload);
accept Quest
GoogleGame.Instance().acceptQuest(string questid);
you can listener the state change of quest by handle event GameEvent.onQuestCompleted
Game Snapshot
Display saved snapshot with default ui
GoogleGame.Instance().showSnapshots("saved games", true, true, 10);
Save Game State with google play snapshot api.open snapshot first
GoogleGame.Instance().openSnapshot("firstgamesnap", true, GameConst.RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED);
and then write snapshot after event onOpenSnapshotResult,snapshotfilePath is a image path,the second param is your game data
GoogleGame.Instance().writeSnapshot(snapshotfilePath, System.Text.Encoding.UTF8.GetBytes("{'score':20}"));
open a snapshot first and then get you saved data
GoogleGame.Instance().openSnapshot("firstgamesnap", true, GameConst.RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED);
after open success
byte[] gamedata=GoogleGame.Instance().readSnapshot();
RealTime Multiplayer Game
Create a multiplayer game room,and show waiting Room Panel
GoogleGame.Instance().createAutoMatchRoom(mincount,maxcount,mask);
GoogleGame.Instance().showRoomWaitingPanel(minParticipantsToStart);
you can accept invite to enter a room too
GoogleGame.Instance().acceptInviteToRoom(inviteid);
if the player want to leave the room
GoogleGame.Instance().leaveRoom();
There are many Event when play multiplayer game,such as onRoomCreated,onJoinedRoom,and you can handle event to play game when GameEvent.onRoomWaitingChange fired. google game support realtime message reliable or unreliable.if recipientParticipantId is null,then message will been sent to all player except sender.
GoogleGame.Instance().sendReliableMessage(byte[] messageData, string roomId, string recipientParticipantId);
//GoogleGame.Instance().sendUnreliableMessage(byte[] messageData, string roomId, string[] recipientParticipantIds);
Turnbased Multiplayer Game
Create a turnbased game room
GoogleGame.Instance().createTurnBasedMatch(minplayer, maxplayer, mask);
or you can accept a Invitation
GoogleGame.Instance().acceptTurnBasedInvitation(invitationId);
Show All turn based Matches with default UI
GoogleGame.Instance().showTurnBasedMatches();
Show TurnBased Invitations
GoogleGame.Instance().showTurnBasedInvitations( minPlayers, maxPlayers, exclusiveBitMask, allowAutomatch);
There are many event you can handle such as onInitiateMatchResult,onUpdateMatchResult,when onTurnBasedMatchReceived received you can do game logic
when play game,you will call taketurnbasedturn to notify the next player
GoogleGame.Instance().takeTurnBasedTurn( matchId, matchData, pendingParticipantId);
GoogleGame source
google realtimeMultiplayer api
Your answer
Follow this Question
Related Questions
How Do I See My RayCast? 1 Answer
Change material when an event occurs 2 Answers