Before you start
- GameArter supports exports from Unity version 5.6 (Release date 31 Mar, 2017) and above.
Every GameArter SDK mode is designed for specific user-cases. Lite SDK is an ideal choice for developers who develop complete games.
- Continue only if following points are true:
- You want to connect the game with GameArter services (server saving, rewards, badges ...)
- Your game is complete. It does not need any web services like a shop etc.
Brief overview above the system
Estimated time of SDK implementation: 3,5 hours. Please, follow the guide carefully. It will save your time and many future problems. Many Unity functionalities must be made via SDK (outgoing links, fullscreen to work properly with GameArter services).
1. Getting started
- Few points you need to have in mind during setting of SDK:
- User Accounts | User accounts are connected via SDK. You do not need to solve whether a user is logged in or not, or whether you have to display login box or not. This is done by SDK in background. You use same functions and calls for every user. SDK gets and saves data for logged players as well as for guests.
- Working with data | All important data must be saved in SDK. Do not use PlayerPrefs and other local storages for saving important game data which may affect running of the game. These storages can be blocked or may crash. If data are not saved on GameArter server, there is no possibility to provide support for users in a case of any problem.
- SDK GUI displayed in the editor | SDK displays simple boxes simulating real more-complex windows displayed on the website. No box you see in the editor is actually displayed on the website, but functionality is similar. See the login example below.
1.1. Create a project
Create new game project in projects section of GameArter system.
This is way you will get your project Id for inserting to GameArter SDK. Once you will make first configuration export (see further), you will get access to the system.
1.2. Download SDK package
Download latest version of GameArter SDK Unity package from GameArter SDK Unity Package section.
1.3. Import GameArter SDK package to the game project
Path: Assets → Import Package → Custom Package [HELP]
If your project contains old version of sdk (sdk-pure), remove it. If your project contains current SDK, update changed files (except scripts you have adjusted (=GarterCallbacks) if possible).
- Expand all
- Collapse all
-
Core folder -
SDK core. Do not modify any file there.
- _scripts -
Scripts required for correct function of all GameArter features. Do not modify.
- Garter.cs - SDK core module.
- GarterWWW - GameArter server connection module.
- HGarterBranding.cs - GameArter branding connection module.
- HgarterBrowserServices.cs - GameArter browser services module.
- HGarterClickListener.cs - GameArter click-listener module.
- HGarterGui.cs: - GameArter GUI module.
- HGarterInit.cs: - GameArter init conf module.
- HGarterPlayerPrefs.cs: - GameArter PlayerPrefs module.
- HGarterScreenShot.cs - GameArter screenshots module.
- Editor -
GameArter Editor workers & customization. Do not modify.
- HGarterBrandingEditor.cs - GUI customization
- HGarterEditor.cs - GUI customization
- HGarterInitEditor - GUI customization
- Plugins -
Plugins required for correct running of SDK. Do not modify.
- GarterBrowserManager - Browser connection
- GarterProtection - Steal & data protection
- link.xml - Assembly config file
- Newtonsoft.Json - Data management
- Newtonsoft.Json.dll - Library for data management
- Resources -
Resources required for correct running SDK. Do not modify.
- GameArter_LoadingScreen - Prefab for loading screen
- Garter_Notification - Prefab for notifications
- Garter_sdk - Prefab for accessing core functions.
- sdkgui - Textures for GameArter SDK.
- LiteSDK -
Contain a prefab usable in LiteSDK mode only
- GarterLite - Prefab which keeps lite data available in all scenes
- GameArter_Branding - Prefab containing brand logos. Logos are presented by white elements. Their real images and links are downloaded on the base of currently using brand. Also designed for placing own open web-window requests.
- GameArter_DashBoard - A box containing user profile informations and indicator of a progress in the game.
- GameArter_Features - A box, via which a user can open features connected with a game. It may be leaderboard, badges, shop, sharing, login and settings.
- BasicSDK_interaction -
Callback catcher for Basic SDK
- GarterBasicCallbacks - Class for listening callbacks for BasicSDK
- LiteSDK_interaction - scripts for interaction with SDK running in lite mode
Classes (examples) for communication with GameArterSDK
- DataManagerExample.cs - Class for working with data
- ExampleObjectForSdkInteraction prefab - Example object for placing to hiearchy window for working with data
- FullSDK_interaction -
Callback catcher for Full SDK
- GarterFullCallbacks.cs - Class for listening callbacks for FullSDK
- ServicesAdjustment.cs - Script via which you can individualize the behavior of your muted game.
- GameArter_Initialize prefab - Pre-created prefab for placing to project. Consists from an empty object with associated HGarter_init.cs script.
- readme.txt - Basic informations about the SDK.
- copyright.txt - Copyright - all rights reserved.
Prefabs Folder Prefabs you can place to your scene.
Folders with scriptes designed for SDK modes
1.4. Switching to WebGL project
Path: File → Build Settings → WebGL → press "Switch Platform button" [HELP]
If WebGL is not on the list of platforms, there is need to install it first.
1.5. Fixing possible errors
- Duplicity of Newtonsoft.Json library | More newtonsoft.json libraries is available in the project. Solution: Let one and remove all remaining. Usually, this occures when you have Photon sdk in your project. Photon uses newtonsoft for some operations in the editor. You can fix duplicity by unchecking option "Editor" in Assets/Photon Unity Networking/Editor/Newtonsoft.Json.
- Missing plugin | Check what platforms are selected in plugins setting. [HELP]
- You should place no SDK scripts to hiearchy manually. All scripts are loaded automatically. If you insert some there, SDK will not work properly.
- Missing Prefab | Some OS do not load prefabs to example scenes. In such case you see GameObjects "Missing prefab".
The prefabs are not necessary for right function of the SDK, however, there is recommended to add them to the example scenes manually to see the benefit of using them. These prefabs ara available at Assets/GameArter/Prefabs folder. Drop prefabs GameArter_Features and GameArter_DashBoard and move them into scene's hiearchy window. - Info about missing prefabs in Hiearchy window inside example projects. There may happen during Unity upgdares, that there is lost link to a prefab. If this happen, simply go to GameArter/Prefabs folder and move prefabs GameArter_DashBoard and GameArter_Features back to hiearchy. In a case that also GameArter_Initialize object is reseted (projectId = 0), there is better to reimport SDK to the project again to see example scenes in functional state.
- Need a help?GameArter Slack: @adm_vladimir / email - [email protected] /
2. SDK configuration
SDK configuration will be connected on two places. Initial configuration is set on the game side (point 2.1). Game-side configuration sets basic informations like type of a game, required GameArter services and important events in a game. Server side (point 2.2) is designed for setting / adjusting services (adding badges, leaderboards, shops).
2.1. Game side configuration
Follow the guide:
- Open first scene of your project
- Find GameArter_Initialize prefab in Assets/GameArter (Project window)
- Move the prefab (or create an equivalent object containing HGarterInit.cs script) to Hiearchy window
- Select GameArter_Initialize object in hiearchy of your project
- Fill all options on a basis of documentation below. Use button apply for saving your changes.
-
1
Documentation
A button opening knowledge base you are currently at. -
2
Active?
A switcher via which you can enable / disable run of the SDK. -
3
Enable theft protection
Disable only if you need it for testing on your local machine. With active protection, the game is protected from illegal running. Whitelisted servers: localhost, gamearter.com, pacogames.com and all their subdomains. -
4
4.1 Project ID
Every project must have own unique ID. Project ID is a signature needed for communication with GameArter services. You got this id during creating your project in projects section of GameArter system. (point 1.1)
Note: Do you have a problem that your filled project id is reseted to default on going to play mode?
This is something what many developers may experience after removal of "apply" button on prefabs by Unity. To eliminate it, use one of following
- 1) You can use your own game object instead of teh use of prefab (see notes of this section - Option 2 - own object)
- Check whether you work with the prefab correctly. There is a reason between changing projectId and other values in the prefab placed in hiearchy and in the prefab placed in the project window.
4.2 Project Version
For possibility of testing, GameArter provides to run up to 5 game versions. Every version has separated configuration and databases.
-
5
Multiplayer game
Select, whether your game contains multiplayer mode (it can be played as a network multiplayer game)
If yes, select, whether the game will use GameArter photon ID or your own.
Price of using GameArter Photon ID: 10% of income share.
If you set wrong game type (singleplayer / multiplayer), GameArter services (ads, modules) will not work properly and you will have to rebuild the game. -
6
SDK
The mode, under which the SDK will run. Select Lite. -
7
In-game Currency
Select whether your game contains an in-game currency. If so, this currency will be used for GameArter currency exchange and in-game purchases.
-
8
Smart Events
Smart events - Achievements, Leaderboards, IAP and more easily
Before implementation, please read and try to understand Events purpose - In-game currency distribution. According to the event specification, make a plan, which game data will be saved as events and which as a different type of data.
Event explanation
Examples:
Event is an important variable connected with a feature (leaderboard) or a reward (achievements, currency reward), or with a shop for direct in-app purchases. Event example: kills in a shooter game , lap time in a racing game, number of gints in a logic game... Value of event can be increasing, decreasing or without defined trend. Events with defined trend can have attached unlimited number of badges on every event. There can be active also leaderboard above these events. Events with undefined trend are designed for direct connection with in-game shop. There is a possibility to work with events in many ways, events are written generally to allow anything a developer may need.-
"kills" event = total number of kills in a game
Initial value is 0 (new player). The number of kills can only grow in a time (= event with increasing trend). There will be a leaderboard connected with the event (most kills in the game). There will be badges - 1st kill, 10th kill, 100th kill... Leaderboard and badges are made and distributed by SDK. Developer only needs to keep best "kills" value in events = update the event with every kill. Required "kills" value for events is set on server (point 2.2). Then, once the value of the event will achieve the value of a badge, SDK will reward the badge to a user automatically. If a user sends a request to see a leaderboard, the SDK will create the leaderboard by comparing "kills" values of all users in the game. -
"bestLapTime" event = the lowset time achieved in a lap
Initial value is any not-null number. E.g. 120 (secs). Lower time is mostly better (= event with decreasing trend). There is a leaderboard for the time in the lap (made by SDK on basis of the best time of all users who completed the lap). There are 3 badges for the lap - gold / silver / bronze time. At the end of every lap, the developer checks time saved in the event "bestLapTime" and if current time is better (lower), he updates best achieved time in the lap. -
"maxAchievedMoney" event = a special help event allowing give own badge
This is a special event allowing to give a badge on basis of a dynamic variable. E.g. there is a need to add badges "Earned 1st dollar" and "Millionaire". The badges are connected with a currency which has dynamic value changeable in both directions. Then, if currency value will achieve a specific milestone, you can update event "maxAchievedMoney" and a user will be rewarded by a badge. -
"hints" event = number of available hints for a player.
Let's say a logic game will not contain any in-game currency, badges or leaderboards. All required functionality is implementation of in-game purchases. A user has certain number of hints to use (either one-time only, or every day) and in a case of need, he can buy more for GRT currency via native GameArter shop system.
Another possible event use-caseInitial values of events are changeable in web environment as well. Thanks to this option, events can be used also for game testing - If you set e.g. items to be unlocked on basis of some event value, you can unlock them directly from server without need of game rebuilding.
size | set number of groups in which you want to have events divided (better clarity)Group name - name of a group of eventsGroup events - number of events in the group- NameId | ID name of the event. Name in lowercase letters, without spaces. this is string ID over which you will get and set values for the events.
- Initial value | initial value of the events. (probably 0 for increasing trend, any number > 0 for decreasing trend, any number >= 0 for undefined trend)
- Trend | select, whether the event has increasing trend (value number is better (kills), or decreasing (lower number is better (best time of the lap), or undefined trend - this event is intended for monetisation - e.g. option to buy XY hints.
-
"kills" event = total number of kills in a game
-
9
GameArter features
- Notifications | set, whether you want to allow SDK to display notifications (badge received, saving data and so on).
- Go to Assets/GameArter/core/Resources
- Select Garter_Notification_Box (child of Garter_Notification object)
- Adjust Pos Y parameter.
Notification box position
SDK automatically displayes notification in a fixed place. This place may be in a conflict with a game GUI. If needed, adjusting of notification is possible by following way:
NOTE: There is a good way to check your adjustment. To do so, you can move Garter_Notification object to Hiearchy of your project. After this, the notification box is visible and you can find its ideal new Y position. Once you know the number, remove the object from hiearchy and set your height in Assets/GameArter/core/Resources/Garter_Notification/Garter_Notification_Box
-
10
Advanced features
These options are managed by prefab called "GameArter_Features". Placement of this prefab is optional, but useful, because of its hotkeys - "Leaderboard", "Badges", "Shop", "Login", "Settings", and "Share". Most of the buttons are displayed / hidden automatically on basis of active features in the game. "Settings" and "Shop" button are customizable and in order to press them, you must open own windows, if you want to let them be visible = you can use them for your own screens. Once a button is pressed, you will receive an information about that.
- Settings button | button for opening game-settings screen. When pressed, you will receive the information to GarterLiteCallbacks class. From there you have to open own settings screen. If you do not want to work with the button, hide it.
- Shop button | Like "Settings" button, only for Shop. You can open your own shop or GameArter exchange module by its pressing.
-
11
Progress mode
SDK allows three types of counting user's game progress. Value of user's progress must be always saved in the SDK. This information is needed for displaying game info (progress, badges...) in the user's profile.
Current progress state can be displayed also in the game. If the game does not contain GUI for this value, there is possible to display user's progress with other user's data over GameArter_DashBoard prefab. If you want to use GameArter_DashBoard prefab, but without progress bar, switch its visibility to state "hidden".- SDK | progress is being counted on a basis of received badges. (2 badges of 10 = progress 20%). You can display the progress in your own GUI, or via GameArter prefab GameArter_DashBoard prefab. If you want to use GameArter_DashBoard, but without the progress bar at the bottom, you can switch options of SDK Progress bar.
- Individual | SDK does not count progress, only holds its value. There is always need to send changes of user's progress into the SDK. Progress can be displayed in your own GUI, or via GameArter_DashBoard, see the point above.
- None | A game does not contain progress feature.
-
12
Minimum timescale
When an ad is being displayed, sdk automatically will set minimum timestamp to keep low requirements for performance. Set this to 0 if your game is not sensitive for 0 timescale value. In a case of games using networkning (multiplayer), set 1 for sure. -
13
Auto Saving
If enabled, SDK automatically synchronizes data between game and server side at the background. Number of synchronized data depends on real data changes. Events / gameData. Currency is always saved in a package with other data, never alone. -
14
Analytics mode
Analytics mode selection. Analytics may run under three modes. Find out more about individual options at: ... and select the right for your purpose.- Automatic | SDK automatically detects scene changes and sends them to analytics. Beside this automatic mechanism, you can also send own events.
- Manual | Only your own requests go to analytics.
- OFF | No in-game data are in analytics. Analytics displays only standard data.
Note: Beside this analytics, a developer has access also to users' all saved game data on server in csv format. These data can be imported to e.g. Microsoft Excel. By this way a developer has overview about current user's progress and behavior. SDK adds another interesting metrics like returning visits automatically.
-
15
Save the configuration.
- Save the filled data to prefab by pressing "Apply" button
- Press "play" button in the editor (Play mode) and export the configuration to server by pressing Export on server button.
After pressing export button, there is need to approve the request (rewriting previously exported data)
-
16
Clear user's data button
Via this button, there is a possibility to clear saved data. This is very useful for testing of correct implemenation of the SDK.
- Process of clearing:
- 1) Go to play mode
- 2) Log as a user you want to clear his data (Guest / Logged)
- 3) Press clear user's data button
-
17
Advanced configuration
Opens server-side configuration environment. It is available after exporting game-side configuration via button "Export to server".
2.2 Game configuration exports
Exports can be made via Export button available at GameArter_initialize object. With every export, configuration made at a game side is exported to server side (set events, currency option, network option ...)
2.2.1 First game configuration export
First game export is a proof of start of SDK implementation. Once first export is made, you will get an access to server configuration of your project (available in projects section).
2.2.2 Next game configuration exports
You can adjust settings made at game side (in the unity) dynamically during your development. You can add new events as well as remove old. With every export, new data are exported to server and you can manage them in the project section. Every export offers various options - you can clear previous exported data or update them about new data. On basis of mode you will select, you will, or will not lose previously fileld data (badges, packages, rewards...).
2.3 Server side configuration
Server configuration is for adjusting data filled in the game (in production mode, without need of rebuilding a game) and for adding additinal SDK features as badges, leaderboards and in-game purchases. Configuration is manageable via the project panel.
- Rows / Buttons explanation:
- Version | exported project version (filled in Garter_Initialize object inside unity)
- Version State | project mode - testnet / production
- Interpreter | interpreter under which the project version runs
- Config status | Status of data state - concept / pending (= waiting for authorization by admins) / live (= in production)
- Events button | Opens events configuraion (= rewards, badges, leaderboards)
- Packages button | Opens packages configuraion (= ingame purchases)
- More button | Opens configuraion of additional features
- Saved data button | Opens environment for reading / changing data of logged (developer) account in the game
- Files upload button | Opens environment for uploading game files
- Test the game button | Opens game in a new tab
- Remove button | Removes project version
-
1
Events configuration
- Server-side contains all exported events. If not, contact support.
EventDetail- Event ID | non-changeable string ID. All data you will fill for the event are associated with this ID. If you change its name / remove the ID, all associated badges and leaderboards will be lost. Do not change this, if it is not necessary. If so, contact support for possibility to convert users' data below the new event ID.
- Leaderboard | Checkbox for activation of leaderboards for the event. SDK automatically creates leaderboards for the event. There are leadeabords created with filters 1 day / 1 week / 1 month / all-time. Trend of leaderboards is intended by event trend.
- Trend | Trend of event. From safety reasons, there is no possibility to manipulate with events in both directions. An event can only grow (increasing trend) or fall (decreasing trend). Usage: increasing trend - total number of kills, number of opened maps. Decreasing trend - best time of a lap.
- Initial Value | Initial value of event. By this, you can overwrite initial value set in the game. This value is returned to all new players. Default value for events with increasing trend = 0. Default value for events with decreasing trend - none, need to be set.
If availability of some item depends on a state of event value, this is way you can set the item property for new users without need of rebuilding game, directly on one click from server. - Reward Cx | Reward for occured event in a currency depending on a native game currency. (Full SDK = GRT, Lite SDK = GRT/local game coins on basis of local game coins existence). Reward is for a change about one unit. Examples:
- kill event - a coins reward for 1 kill
- lap of a round - better time lap about 0.2sec → reward per 1 unit (=1sec) = 1coin → 0.2*1 = 0.2 coin reward.
- Reward Exp | available for Full SDK mode only. Works same as Reward cx, only the reward is in game experience. On basis of achieved experience in the game by users, there is possible to automatically manage items - unlock them for using (see more in items configuration). This feature allows to create basic game design.
Add badge- Badge name | Name of a badge you want to add (e.g. 100 kills)
- Event value | Event value on achieving which the badge will be received (= 100)
- Coin reward | Received coin reward for received badge.
- Exp reward | Received coin reward for received badge. (full SDK only)
- Dx reward | Received diamonds for received badge. (rewards disabled currently)
- img url | image of a badge. Fill name of image file. If you do not have an image for the badge, let it be.
Event Badges List | list of created badges. You can adjust already defined badges here. If your game is already released and badges are rewarded, and you want to change value for a received badge, please contact support. Badges of all players will have to be recounted.
Badge Collections | Group more badges to a defined collection. Max number of collections is three. E.g. Character, car, others. Badge collections do badge listing in GUI clearer.
Saving events configurationFilled events must be saved. There are 2 options of saving. "Save as concept" saves the changes as a concept only - these saves are not visible from game. If you want to save the data and have access to them from a game, save them via "Save to production" button. If you do bigger changes for a project in production state "live", there is a need of approval by administrator. It is to prevent clashes which would lead to possible game crashes after changing values for badges, eventIDs and so on.
-
2
Packages configuration
Setting of packages for exchanges between game currency and GameArter currency.
- Shop enabled | Activation / deactivation of exchange
- type | type of conversion. Buying vs selling in-game currency for GameArter currency.
- img_thumbnail | image for the package offer. (if remains empty, default img will be used)
- amount of in-game coins | Amount of in-game coins a user will get by buying the package
- price, currency, discount | will be set on a basis of price optimization (By GameArter)
Just press "save all events" button, that's all.
3. Working with SDK
- There is a folder "LiteSDK_interaction" which contains:
- GarterLiteCallbacks.cs script | SDK uses 2 types of callbacks. Classic callbacks made via a parameter in function calls, and callbacks which are evoked by external events. Just these callbacks (requests) you will receive to GarterLiteCallbacks.cs script.
- Example_of_use folder | Example script and its prefab (script attached in an object) displaying possible interaction with SDK. You will find there a way you can work with game data. Due to next SDK updates, the best practice is to do not use this example scenes, but inspire by them to create your own.
3.1. SDK initialization
SDK initialization is automatical, powered by GameArter_Initialize object (prefab) which must be inserted in a first scene. On background, SDK loads all user's data, If a user is not logged in, SDK gives him a possibility to select an account he wants to play on. Once user's data are available, SDK sends user's saved data to function SdkInitialized() located in the class GarterLiteCallbacks () (Assets/GameArter/LiteSDK_interaction/GarterLiteCallbacks.cs). From this function, you should forward the data to your function for data management. If the returned data are null, the user launched the game for first time - set default data for a new user in this case.
Possible implementation is to create initial screen e.g. "Waiting for data" and once you will receive the callback, remove the screen and launch your game.
NOTE: There is no need to check whether a user is logged in or not. You work with all users the same way - via SDK function.
public class GarterLiteCallbacks { // this class must exist in the project. DO not change the name of this class
GameObject objectWithScript = null;
string nameOfGameObjectContainingScriptForDataManagement = "ExampleObjectForSdkInteraction"; // REPLACE *ObjectWithGarterLiteScript* FOR YOUR GAME OBJECT WITH DATA MANAGER SCRIPT
private DataManagerExample GameSdkManagerExample(){ // REPLACE ALL *DataManagerExample* FOR YOUR OWN SCRIPT (PUBLIC CLASS NAME)
DataManagerExample scriptElm = null;
if (objectWithScript != null) {
objectWithScript.GetComponent< DataManagerExample > ();
scriptElm = (DataManagerExample)objectWithScript.GetComponent(typeof(DataManagerExample));
} else {
Debug.LogError ("GARTER | GameObject was not found. Set right path to the required function");
}
return scriptElm;
}
/// SDK Initialized. There is known used identity and his game data. www contains progress data to load.
public void Initialized(GarterWWW www){
objectWithScript = GameObject.Find (nameOfGameObjectContainingScriptForDataManagement);
if (GameSdkManagerExample() != null) GameSdkManagerExample().DataInitialized (www); // REPLACE .DataInitialized () FOR YOUR FUNCTION FOR DATA INITIALIZATION
}
}
By this action, you will receive www data into function DataInitialized() availabe in DataManagerExample.cs file
public class DataManagerExample : MonoBehaviour { // Example script for working with data
public void DataInitialized(GarterWWW www){
if (!string.IsNullOrEmpty(www.error)) {
Debug.LogError ("ERR " + www.error);
new HGarterGui ().IlustrateBrowserBox ("error","Ops, something went wrong. We apologize");
} else {
// 1) User informations - nick, country, language, logged...
Debug.Log ("UserNick: " + Garter.I.UserNick()); // returns usernick or random Guest name
Debug.Log ("UserLanguage: " + Garter.I.UserLang());
Debug.Log ("UserCountry: " + Garter.I.UserCountry());
Debug.Log ("User Image:" + Garter.I.UserImage ());
Debug.Log ("data: " + www.text);
// 2) Save current data to game variables
if (!string.IsNullOrEmpty(www.text)) {
SaveToVariables (www.text); // overwrite default data by returned data
} else {
Debug.Log ("Overwrite values by default data");
// kills = 0; and so on
}
//3) if your game is multiplayer, since now photon id and ver is available
// see section 3.5/1 for more informations
}
// Dont destroy on load - variables and functions will be available in every scene
DontDestroyOnLoad(transform.gameObject);
}
}
By actions mentioned above, you know all data releated to user and its progress in the game.
3.2. Creating data structure
Function DataInitialized(GarterWWW www) in point 3.1 contains function SaveToVariables (www.text); This function saves received variables to game variables and looks like following:
public class DataManagerExample : MonoBehaviour {
private void SaveToVariables(string json){ // Function being called in 3.1
// parse json data
JsonStructure dataClass = Garter.I.FromJson< JsonStructure >(json);
someStringData = dataClass.someStringData;
someIntegerData = dataClass.someIntegerData;
someFloatData = dataClass.someFloatData;
someListType = dataClass.someOwnTypeData.someListType;
someArrayType = dataClass.someOwnTypeData.someArrayType;
someJaggedArrayType = dataClass.someOwnTypeData.someJaggedArrayType;
}
}
The important part of the function is call JsonStructure dataClass = Garter.I.FromJson< JsonStructure >(json);
This function uses a class JsonStructure. This class defines a data structure under which data are transmitted between game and server. You can define any structure you want. All data types are supported. Example data structure containing various data types is displayed below.
public class JsonStructure { // create your own data structure for posting / geting data.
public string someStringData;
public int someIntegerData;
public float someFloatData;
public MyTypeData someOwnTypeData; // own data type
public JsonStructure(string stringData, int integerData, float floatData, MyTypeData ownTypeData){
this.someStringData = stringData;
this.someIntegerData = integerData;
this.someFloatData = floatData;
this.someOwnTypeData = ownTypeData;
}
[System.Serializable]
internal class MyTypeData {
public List< byte > someListType;
public bool[] someArrayType;
public ulong[][] someJaggedArrayType;
public MyTypeData(List< byte > list, bool[] array, ulong[][] jaggedArray){
this.someListType = list;
this.someArrayType = array;
this.someJaggedArrayType = jaggedArray;
}
}
}
NOTE: In the unity package, this class is solved as internal class directly in DataManagerExample.cs.
Create data class with all user data you want to save by SDK for your game. Events, currency and progress cannot be part of the data structure (they are saved in the SDK data layer directly)
3.3. Server connection
SDK keeps data in two layers. Game layer is a data layer keeping data in RAM momory of user's computer. Accessing these data is a matter of a moment. You can communicate with this layer via SDK anytime you want.
Server data layer is a layer which keeps user data on server. Server layer and game layer are being synchronized automatically by the SDK.
Data are mirrored from server layer to the game layer automatically during SDK initialization (DataInitialized function is being called - see point 3.2 - SDK Initialization). Further repeating of getting data from server is not necessary. For direct connections from SDK to server, there are certain limitations protecting server from above-limit number of requests. Default limit is 5 requests per 2 minutes.
-
1
Posting data to the server
SDK allows to do only limited number of manual connections with server per certain time (usually 5 requests per 2 minutes). For efective work with this limitation, there are two types of "posting data to server":
-
1) Posting directly
This is effective way to save data immediatelly in a time of request. E.g. in some important time, when you think a user will close a game, or you want to be sure that the current state will be saved, because it costs much time to achieve it. For these cases, there is a direct connection with server:
copypublic class DataManagerExample : MonoBehaviour { public void PostData(){ // function which takes data from local variable, convert them to JSON and posting to server string dataToBeSaved = Garter.I.ToJson ( new JsonStructure(someStringData,someIntegerData,someFloatData,new JsonStructure.MyTypeData(someListType,someArrayType,someJaggedArrayType)) ); Garter.I.PostData(dataToBeSaved, callback => PostDataCallback(callback)); // callback from server } private void PostDataCallback(GarterWWW www){ if (www.error != null) { Debug.LogWarning (www.error); } else { Debug.Log (www.text); // → ok } } }
-
2) Posting via middle-man
SDK automatically tracks changes in events values, currency values and own game-data values. When a change occurs, SDK synchronizes data in RAM memory with data located on server. Data are synchronized also during every received badge. If there is no need to have the data saved on server instantly in a second, you can post them only to the game data layer and the data will be posted to server automatically in a time of soonest data synchronization. Automatical data synchronization is in dynamic time period. That means that users will never lose more than few minutes (e.g. 2) of playing time.
copypublic class DataManagerExample : MonoBehaviour { public void PostDataOverMidleMan(){ // function which takes data from local variable, convert them to JSON and posting to middle-man which sends them to server in the nearest connection string dataToBeSaved = Garter.I.ToJson ( new JsonStructure(someStringData,someIntegerData,someFloatData,new JsonStructure.MyTypeData(someListType,someArrayType,someJaggedArrayType)) ); Garter.I.SetIndividualGameData(dataToBeSaved); } }
-
1) Posting directly
-
2
Getting data from the server
All server data are downloaded and saved in a RAM memory during SDK initialization. You can ask for their values in any frequency you need. There is no reason for repeated downloading of the data from server during the game. However, this opportunity exists in the SDK. There is possibility to download data from server by following way:
copypublic class DataManagerExample : MonoBehaviour { public void GetData(){ // get data from server and return them to function DataInitialized() Garter.I.GetData (data => DataInitialized (data)); } public void DataInitialized(GarterWWW www){ if (!string.IsNullOrEmpty(www.error)) { Debug.LogError ("ERR " + www.error); } else { if (!string.IsNullOrEmpty(www.text)) { // parse and save data JsonStructure dataClass = Garter.I.FromJson< JsonStructure >(www.text); } else { // use default data for new user } } } }
-
3
Downloading data files
SDK allows to download any data files from servers. These reqests are out of limitations. You can do any number of requests you want from the game.
This function might be used for downloading images, videos, bundles, fonts...
copy// example of dowloading an image Garter.I.DownloadDataFile(string url, result => DownloadedImage(result)); // callback function of DownloadDataFile() call private void DownloadedImage(WWW www){ if (!string.IsNullOrEmpty(www.error)) { Debug.LogWarning("UserPhoto ERR " +www.error); } else { Texture2D image = www.texture; } }
3.4. Post-data preparation
For right function of auto-synchronisations, there is need to create (define) a function via which SDK can take current game data and post them to server. This function should be the same as function postData() mentioned in point 3.3 Server Connection / 1 Posting data to the server.
public class GarterLiteCallbacks {
public void DataSynchronistationRequired(){ // request for exchange - need to sync data between game and server
if (GameSdkManagerExample() != null) GameSdkManagerExample().PostData (); // REPLACE .PostData () FOR YOUR FUNCTION POSTING DATA
}
}
public class DataManagerExample : MonoBehaviour {
public void PostData(){ // function which takes data from local variable, convert them to JSON and posting to server
string dataToBeSaved = Garter.I.ToJson (
new JsonStructure(someStringData,someIntegerData,someFloatData,new JsonStructure.MyTypeData(someListType,someArrayType,someJaggedArrayType))
);
Garter.I.PostData(dataToBeSaved, callback => PostDataCallback(callback)); // callback from server
}
private void PostDataCallback(GarterWWW www){
if (!string.IsNullOrEmpty(www.error)) {
Debug.LogWarning (www.error);
} else {
Debug.Log (www.text); // → ok
}
}
}
Having only one function (PostData()) for posting all data to Server is a good practice. Then, developer, as well as SDK, can use the same function for posting all current data. Define a post function with access to all data in GarterLiteCallabcks calls, function DataSynchronistationRequired().
This function is called from SDK in the cases of need to have latest gaming data. Usually, when working with currency and other data with an emphasis on high security.
3.5. Accessing SDK data
SDK data are available after SDK initialization. There is a possibility to access them from any script and in every scene.
-
1
Network
If your game is multiplayer, using GameArter Photon subscription, you need to insert following SDK calls to PhotonSDK to places designed for inserting Photon ID and Photon Version. Load the data via the calls directly into Photon scripts.
copyGarter.I.GetMultiplayerNetwork () [0]; // photon Id Garter.I.GetMultiplayerNetwork () [1]; // photon ver
Server Authentication
For possibility to connect to photon, you must authenticate the game. This will be done by PhotonNetwork.AuthValues.AuthType = CustomAuthenticationType.Custom;. See the example below.
Users identification in photon
Photon works with general UTF formats. By this way, unique nicknames at the beginning may become a non unique nickanames after removing some special signs. Eg. nickname "I♥GameArter" == "IGameArter" after photon compilation. Similar with chinesse signs. If 2 players with same nickname are in the same room, it will cause a problem. From that reason, SDK offers a special unique id identificator you can use for identifying players in a photon (instead of using nicknames for that). See more info.. Call Garter.I.NetworkUniqueUserId () for getting an unique identificator.
Photon Authentication example
PUN 2
For Photon's example of connection to network, check Photon's script ConnectAndJoinRandom.cs. This class connects to network via "ConnectNow" function.
For usage with GameArter, we will have to modify and move this function into our script (this is example, you do not need to use the photon's function).
How to connect to Photon PUN2
- you must disabled auto connection of the photon, if you used their example file ConnectAndJoinRandom. This can be done by removing content of "ConnectNow" function
- for removing alert message of no filled AppId, fill AppIdRealtime of PhotonServerSettings plugin by some fake id - e.g. space " ".
- Wait till gamearter SDK is initialized (see point 3 - Working with SDK)
From this moment there is known App Id and version for your application. Once needed, you can connect to photon network by following way:- Inside script you want to connect to photon, link Photon libraries
copy
using Photon.Pun; using Photon.Realtime;
-
Create a function for connecting photon
copy
private void ConnectPhotonNow(){ // set user data (nickname etc) and load game // Server authentication PhotonNetwork.AuthValues = new AuthenticationValues(); PhotonNetwork.AuthValues.AuthType = CustomAuthenticationType.Custom; PhotonNetwork.AuthValues.AddAuthParameter("u", Garter.I.NetworkAuthentication()); PhotonNetwork.AuthValues.AddAuthParameter("g", Garter.I.GameId().ToString()); // Set unique userId for photon PhotonNetwork.AuthValues.UserId = Garter.I.NetworkUniqueUserId(); // Set dynamic photonID - (must! be set for possibility to switch from test to production mode on release) Debug.Log("PhotonId: " + Garter.I.GetMultiplayerNetwork()[0]); PhotonNetwork.PhotonServerSettings.AppSettings.AppIdRealtime = Garter.I.GetMultiplayerNetwork()[0]; Debug.Log("SetId: "+PhotonNetwork.PhotonServerSettings.AppSettings.AppIdRealtime); // Connecting photon with right game version string photonGameVersion = Garter.I.GetMultiplayerNetwork()[1]; PhotonNetwork.ConnectUsingSettings(); PhotonNetwork.GameVersion = photonGameVersion + "." + SceneManagerHelper.ActiveSceneBuildIndex; }
- Inside script you want to connect to photon, link Photon libraries
PUN 1
copy// Server authentication PhotonNetwork.AuthValues = new AuthenticationValues (); PhotonNetwork.AuthValues.AuthType = CustomAuthenticationType.Custom; PhotonNetwork.AuthValues.AddAuthParameter("u", Garter.I.NetworkAuthentication()); PhotonNetwork.AuthValues.AddAuthParameter("g", Garter.I.GameId().ToString()); // Set unique userId for photon PhotonNetwork.AuthValues.UserId = Garter.I.NetworkUniqueUserId(); // Set dynamic photonID - (must! be set for possibility to switch from test to production mode on release) // Photon Pun 1 and 2 has different API and this api. // Photon Pun 1 PhotonNetwork.PhotonServerSettings.AppID = Garter.I.GetMultiplayerNetwork () [0]; // Photon Pun 2 PhotonNetwork.PhotonServerSettings.AppID = Garter.I.GetMultiplayerNetwork () [0]; // Connecting photon with right game version string photonGameVersion = Garter.I.GetMultiplayerNetwork () [1]; PhotonNetwork.ConnectUsingSettings(photonGameVersion + "." + SceneManagerHelper.ActiveSceneBuildIndex);
-
2
Individual Game Mode
There's a possibility you require to run the game in individual game modes on certain websites or e.g. for testing. By using individual game mode features, you can set individual mode the game will run in for every website the game is published on. SDK will return you after its initialization number of modes which you will assign to a certain website. Then, you can simply set data with which the game should run according the mode number.
Get mode number under which the game should run:
byte individualGameModeNumber = Garter.I.IndividualGameMode(); -
3
Browser name
WebGL games have often different performance in various browsers. With knowledge of a browser a game is running in, there is a possibility for optimization of disabling features for certain browsers. E.g. car destructions for Chrome.
string browserName = Garter.I.GetBrowserName();
3.6. User data
Requests for interaction with user's data.
-
1
Accessing user data
Folowing calls will return information about the user. It is read-only data.
copystring userNick = Garter.I.UserNick(); // user's nickname or Guest#randomNumber string userLang = Garter.I.UserLang(); // default language a user has set on pacogames // ar, cs, de, en, es, fr, pl, pt, ru, tr string userCountry = Garter.I.UserCountry(); // country shortcut the user is connected from bool loggedUser = Garter.I.IsLoggedUser(); // returns true, if user is logged in Texture2d userImage = Garter.I.UserImage (); // returns user's profile img as a texture () [1]); string userRankName = Garter.I.UserRankName(); // returns profile rank of a user // server data in a string format. See 3.3 Server connection - posting via middle-men. string usersSaveData = Garter.I.GetIndividualGameData(); // returns user data in json string format. Need to parse them via JsonStructure
-
2
User's game progress
SDK allows three types of counting game progress. Their configuration was in game-side configuration (section 2.1). No matter what type you have selected (if your game contains a tracker of progress), the progress value must be saved in SDK. Only this way, a user can see all games he is active in at his profile.
Game progress is in number set < 0, 100 > (in percentages). Do not use values 0-1 from a reason of float accuracy.- Getting user's game progress | float userPgrogress = Garter.I.UserProgress();
Returns value of progress as float.
If you do not have own GUI for displaying user's progress, you can use default prefab GameArter_DashBoard.
If your progress mode is "SDK", the progress is counted automatically on basis of achieved badges. (2 badges of 10 = progress 20%). - Setting user's game progress | Garter.I.UserProgress(float absProgress);
If the game uses individual progress mode, you must inform SDK about current user's progress.
- Getting user's game progress | float userPgrogress = Garter.I.UserProgress();
-
3
Clearing user's game data
Clearing data might be used in one case only - restarting game. Game restart is possible in two cases:
-
User's request | Garter.I.ClearDataUserReq();
Send this request on basis of user's interaction. (A user requires to clear all his game data and start the game from beginning). After the call, there will be displayed a confirmation box by the SDK where the user will have to confirm his request.
-
End of a game | Garter.I.ClearDataUserConfirm();
Send this request, when a game must be restarted because of a game design reason (=end of the game - negative money, death...)
Clearing data restarts game automatically. In editor, function Initialized() (point 3.2) is called and data are rewritten by default data. (www.text == null). In a browser, whole page is reloaded.
NOTE: Currently, wit clearing data, a user loses also all badges he got in the game. New SDK update will bring a possibility to select which badges should be removed and which not.
-
User's request | Garter.I.ClearDataUserReq();
3.7. Accessing events
Events keep values in secure way (encrypted state) while they are optimized for maximum possible performance in the same time. There is possible to think about events like about helper functions - Event feature is simple automated way to protect important data from manipulation (cheat engine), use achievements (badges), leaderboards or IAP.
- Events with defined trend (increasing / decreasing) - keep best achieved value and automatically manage configured achievements and leaderboards
- Events with undefined trend - keep current value and allow connection with in-game purchases (if configured)
-
Get | Garter.I.Event (eventNameId);
returns (decimal)value of required event
-
Update by change | Garter.I.Event (eventNameId, change);
The function updates value of the event based on trend. Examples:
- Garter.I.Event ("kills", 1); where "kills" are defined as event with increasing trend → Increase value of kills about 1
- Garter.I.Event ("lapTime", -1); where "lapTime" is defined as event with decreasing trend → Decreases value of lapTime about 1
- Garter.I.Event ("freeHints", 3); where "freeHints" is defined as event with undefined trend → Decreases value of lapTime about 3
Events with defined trend do not allow to use negative change - such values are ignored
Update events value always by sending a difference (change to better. Example: when kills value goes from 11 to 12, you sends 1 (= the difference). When time of the best lap goes from 121.3 secs to 118.4 secs, send 2.9). Pay attention to correctness of these values.
-
Post absolute even value | Garter.I.EventAbs (eventNameId, absEventValue);
Sometimes it may be simpler to send absolute value instead of relative value (size of value change). For this case SDK has helper function "EventAbs". All this helper function does, it is counting the difference between sent absolute value and saved previous value, and forrwarding this difference (change) into "Even" function described 1 point above
This function is available since SDK ver 2.4
Important: How and in what frequency events data are posted on the server
As mentioned, events are designed to work for any requests frequency (calmly 100s per second) while they are also managers of all events-related features. For this reason, events are not posted to server storage on every event request, instead only if one of following is conditions becomes true:
- During every event update, there is a check for achievement (badges). If a certain value for a badge(s) is achieved, SDK automatically sync data (posts event values), and release the badge(s) and associated rewards (game money, if configured) for the user. Developer is informed about released achievements and rewards via callback trigger ("ReceivedBadges"), see Event listeners section in SDK initialization.
- On every update change, SDK checks time of the last update data. If there is reached certain maximum time from the last update, SDK automatically post the data to server to keep them synchronized between game and server. This time is usually 2 minutes, but may vary based on current server capacity.
- Saved data in events are automatically attached to every Post request to server made by developer (use of Garter.I.PostData function)
Best practice for saving event values on server
The rules described above are simple to understand, but complicated to work with. Fortunately, there is a simple best practice that comes from the bullet 3. Everytime you think, that the reached value is importnat (not because of achievement), post data on server (see how in point 3.6.2).
NOTE: If all you need to save are event values, and you do not use any other data which must be saved on the server, then you can use a request with general key (e.g. "key") and fake data (e.g. empty string). It would look like Garter.I.PostData< string >("key", "")
If there would happen, that more conditions are filled in the same time, all the requests will be aggregated into one and functionality remain same - data will be posted on server.
Posting data to leaderboard
Since SDK in ver 3.1, there is possible to quick push of data into leaderboard via helper function Garter.I.PostToLeaderboard (eventNameId, absEventValue);. By calling the function, value of specified event is being updated and posted to leaderboard. This function is handy e.g. at the end of a brain game.
If you update a game with older SDK, see Best practice section described above.
_________________NOTE to decimal data type: decimal data type is used despite its size requirements due to requirement for high accuracy of saved data. Beside it, high accuracy is also required by protection mechanisms for data manipulation over tools adjusting values in RAM memory.
3.8. Accessing currency
There are more types of currencies in GameArter. The main currency is GameArter currency (GRC). This currency is available in all games running in FullSDK mode. Games running under LiteSDK mode have own local currency available in the game only. This local currency is convertible to GameArter currency (GRC) and vise versa under specific conversion ratios. This is mechanism protecting games in LiteSDK from affecting whole ecosystem by distributing and consuming too much of GRC currency. Exchange of the currencies is in a user-friendly form.
If you have own currency you want to use further in the game, you must make a mechanism which will guarantee parity of these two currencies. Only by this way, the currency can work properly. If you are not working on creating any mechanisms for currencies parity, you must use GameArter local currency as a default currency.
-
Get | Garter.I.LocalCurrency ();
returns amount of currency
-
Update | Garter.I.LocalCurrency (currencyChange);
decimal currencyChange = absGameCurrency - Garter.I.LocalCurrency(); Garter.I.LocalCurrency( currencyChange );
returns new amount of currency
-
(Currency) Exchange Module
Currency exchange is made via exchange module provided by SDK. The exchange can be opened by user's action from gameplayer, or by a call from the game. For opening exchange, call Garter.I.OpenSdkWindow ("exchange");. Currency exchange is designed for currency exchange and increasing value of events with undefined trend.
Once SDK recieves a request for opening an exchange, SDK requires data synchronization for safety reasons. This data synchronization is direct, outside of server request limitations. This synchronization is made over DataSynchronistationRequired() function located in GarterLiteCallbacks.cs (Assets/GameArter/LiteSDK_interaction/GarterLiteCallbacks.cs) file.
copypublic class GarterLiteCallbacks { public void DataSynchronistationRequired(){ // request for exchange - need to sync data between game and server if (GameSdkManagerExample() != null) GameSdkManagerExample().PostData (); // REPLACE .PostData () FOR YOUR FUNCTION POSTING DATA } }
The purpose of this function is to call a game function working with data. It is such function, which has access to current game's data. This function takes the data and sends them to server. (= it might be the same function which is being used for posting data)
copypublic class DataManagerExample : MonoBehaviour { public void PostData(){ string dataToBeSaved = Garter.I.ToJson (new JsonStructure(someStringData,someIntegerData,someFloatData,new JsonStructure.MyTypeData(someListType,someArrayType,someJaggedArrayType))); Garter.I.PostData(dataToBeSaved, callback => PostDataCallback(callback)); } private void PostDataCallback(GarterWWW www){ if (www.error != null) { Debug.LogWarning (www.error); } else { Debug.Log (www.text); // respons - ok = data have been saved succesfully } } }
Once data are succesfully posted, SDK automatically mutes the game and opens currency exchange. Once a user leaves the exchange screen, SDK automatically unmutes the game and returns current currency value to CurrencyUpdate() located in GarterLiteCallbacks.cs file. If the scene the exchange was opened from is displaying a currency value, you need to update the text.
copypublic class GarterLiteCallbacks { public void CurrencyUpdate(float currencyValue){ // update text on currency counter if (GameSdkManagerExample() != null) GameSdkManagerExample().CurrencyUpdate (currencyValue); // REPLACE .CurrencyUpdate() FOR YOUR OWN FUNCTION UPDATING GUI DISPLAYING CURRENT FUNDS } // Update of event value via shop (=event state purchase) public void EventUpdateViaShop(){ // some event with undefined trend has new value now } }
Behaviour during opened exchange can be set in ServicesAdjustment.cs (optional)
-
Saving currency
Local currency is not synchronized during every change of its state. It is because of currency is connected with event values, progress and bought items. Therefore, local currency is synchronized together with all the other data. This prevents user from losing an individual unit from the mentioned units. If a user loses latest progress, he will lose currency, bought items, as well as progress made from the time of the last save.
3.9. Ads
Ad types
- Interstitial ads = fullscreen ads (Available on Web, Android)
- Rewarded ads = interstitial ads with a reward for watching (Available on Web, Android)
- Banner ads = ad banner unit in certain place on the screen (Available on Android)
Ad types can be combined in a game (One game can use all 3 types of ads)
Fullscreen (Interstitial) ad
Request:
Garter.I.RequestAd(adUnitId, (optional)callback);
Rules for displaying Interstitial ads
- Request ads only in suitable places. Ads cannot affect best user experience (UX) from playing games
- Request ads in any suitable place for ad
- Game sounds MUST be muted during an ad
- Any exhortation or rewards for interacting with ads is prohibited
Best practices for interstitial ads
- First ad call from the start of the game. An ad at the beginning of the game does most of the income (the highest number of views). GameArter ad manager works with 2 types of preroll ads. In a case, that a website does not have own preroll, GameArter ad manager displayes an preroll ad on a load of gameplayer. In such case, first ad call from game is ignored. If no preroll on load of gameplayer is displayed (because it is not possible or is disabled), an ad on first ad call is displayed (= replacement of the preroll ad). From that reason, insert first ad call always at the beginning of the game.
- Call ads in every suitable place. GameArter's ad manager contains a layer which filtrates ad requests to achieve the best ratio between number of displayed ads and user experience.
How ad requests work
- ad request is received in GameArter Ad manager.
- GameArter Ad manager checks availability of ads and processes ad-frequency-check.
- If suitable ad was found, GameArter Ads manager displayes an ad.
Adblock ads behaviour
In a case of active ad blocking in user's browser, GameArter runs affiliate ads instead of classic ads.
Ad configuration for individual websites
Ad configuration for individual websites where the game is published is visible in Reports section after release of the game. There you can find out preroll ad type, frequency of ads, maximum length of ads, ad providers and so on. GameArter uses a mix of ad providers including own ads due to cover all websites restrictions (mainly policies for displaying Google Ads and ads.txt standard) and for achieving the best possible CPM. If you would like to make a change in default settings for a certain website or your game, contact GameArter support.
Implementation
Ads can be implemented either with or without callback, preferred way is up to a developer
- With callback - SDK provides callback about current state of an ad
- Without callback - SDK manages game behaviour during ads automatically based on configuration in "ServicesAdjustments.cs file" file.
Implementation without a callback
If no callback in ad request is found, GameArter mutes a game (on displayed ad) and unmutes (on completed ad) game automatically. This behaviour is set and may be adjusted (if default solution does not work properly in the game) via ServicesAdjustments.cs file (mentioned below).
public class AdCallExample : MonoBehaviour {
Garter.I.RequestAd (adUnitId); // request an ad.
}
Where adUnitId is unit id defined in step 2.1.12 - ads definition
Issues prevention
- Do not call ads in a time game sounds is being initialized. If you do not want adjust ad configuration for muting / unmuting game in ServicesAdjustments.cs, be sure you do not call ads before or during a time when game sounds is being initialized. If any sound loads after the ad request, ad manager is not able to mute it. In this case, ad implementation is not valid. Always verify in the editor, that all sounds are muted during a box illustrating an ad.
Configuration of game behaviour during ads
Adjust it only if it does not work in your game (something is wrong while you see UI "Ad is being displayed"), or you can improve it. Make the change inside Assets/GameArter/ServicesAdjustment.cs. On end of an ad, function "AdClosed()" (located in the same class) returns the game back to the state before changes made by "AdOpened()" (CacheCurrentSettings ();). If you adjust function AdOpened(), you must adjust function "AdClosed()" as well.
SDK works with sound, timescale and pointer by following way:
// ServicesAdjustments.cs file
public void AdOpened(){
CacheCurrentSettings (); // cache current state - game will be returned to this state after clossing an ad (=mute game)
// mute the game sound
AudioListener.volume = 0f;
//set minimum timescale to improve ad performance
float minimumTimeScale = Garter.I.GetMinimumTimeScale ();
Time.timeScale = minimumTimeScale;
if (minimumTimeScale == 0) {
AudioListener.pause = true;
}
// display mouse pointer (unlock cursor)
if (Cursor.lockState != CursorLockMode.None) {
Cursor.lockState = CursorLockMode.None;
}
if (!Cursor.visible) {
Cursor.visible = true;
}
}
Implementation with a callback
If a developer prefer setting game behaviour during ads on his own, he can deal with it via used callback function.
Callback states
- ignored = ad request has been ignored. Probably due to not enough interval from the previous interstitial ad
- pending = GameArter is checking availability of an ad
- loaded = An ad has been loaded. Game sounts must be muted
- running = An ad is running
- completed = An ad has been completed Game sounts must be unmuted
- failed = something went wrong Game sounts must be unmuted
public class AdCallExample : MonoBehaviour {
Garter.I.RequestAd (adUnitId, (state) => {
if(state == "loaded"){
// MUTE GAME
} else if(state == "completed" || state == "failed"){
// UNMUTE GAME
} else {
// ... do nothing
}
});
}
where adUnitId is unit id defined in step 2.1.12 - ads definition. Be sure that game behaviour is in accordance with the terms for displaying ads.
----------------------------Note (if you need...)
Ads may be set differently or updated dynamically for every website / platform. Especially minimum time interval for displaying ads. This value, together with minimum time to next ad (both in seconds) you can get from SDK by the way mentioned below. Possible use case is e.g. for setting own ads in a loop.
public class AdCallExample : MonoBehaviour {
Garter.I.GetAdConf ((conf) => {
SdkDebugger("Garter.I.GetAdConf ((conf) => {})", ("Next ad in "+conf.nextAdM.ToString()+"s. Minimum time between ads "+conf.meantimeM.ToString()+"s."), "returns ads configuration.");
});
}
Note, that getting ad configuration must be tested. On basis of internal tests, unity does not return callback function of this type immediatelly, but after a user interaction (click) -> (Unity gets focus). This says, that working with Garter.I.GetAdConf() may be very hard e.g. in driving games where users do not do any clicks during gameplay.
Rewarded ad
Availability of a rewarded ad is individual based on user's behaviour. Display button / option to launch rewarded ad only if the rewarded ad is available.
Rewarded ad can be called only with defined callback function
Callback states
- ignored = ad request has been ignored. Probably due to no ad (be sure you check ad availability before requests!)
- pending = GameArter is processing the request
- loaded = Rewarded ad has been loaded. Game sounts must be muted
- running = The ad is running
- completed = An ad has been succesfully completed. Release reward + unmute sounds
- failed = something went wrong - user canceled the ad unmute sounds without reward
Implementation
public class AdCallExample : MonoBehaviour {
if(Garter.I.RewardedAdAvailability()){
// display button / UI for requesting rewarded ad
}
// On rewarded ad request from user (e.g. pressing rewarded ad button)
Garter.I.RequestAd(adUnitId, (state) =>
{
if(state == "loaded"){
// MUTE GAME
} else if(state == "completed"){
// UNMUTE GAME, RELEASE REWARD
// HIDE BUTTON FOR REWARDED AD
} else if(state == "failed"){
// UNMUTE GAME
// HIDE BUTTON FOR REWARDED AD
} else {
// ... do nothing
}
});
}
where adUnitId is unit id defined in step 2.1.12 - ads definition. Be sure that game behaviour is in accordance with the terms for displaying ads.
Note: rewarded ad availability is driven by ad network. Because editor is not connected with any ad network, returned rewarded ad availability state is always false.
Banner ad
where adUnitId is unit id defined in step 2.1.12 - ads definition
3.10. Analytics
You can use any tool for tracking you want. Do not you know any? Here's example of few of them.
By default, GameArter has implemented and supports Google Analytics for websites with a bridge of caching game-side data events. All you need to do to activate it, is to insert your own Google Analytics tracking id to "Basic settings" tab of your project. This analytics tracks all gameplayer-based data as players, source of visits, time of playing and so on. These data can be extended by data in a form of events sent from a game, see Google analytics guide page. Some basic events as scene change and so on can be send to analytics automatically on basis of analytics configuration made in point "Game side SDK configuration".
Send any information you want to analytics by call:
Garter.I.AnalyticsEvent(string action, string category, string label, int value);
/*
where:
category, label, value are optional parameters
See more at: https://developers.google.com/analytics/devguides/collection/analyticsjs/events
*/
3.11. Fullscreen
Because of other services around a game, fullscreen mode must be called over GameArterSDK. Attach following call to fullscreen button in your game (if your game has such button). If a game is already in fullscreen mode, fullscreen is cancelled by the call.
Garter.I.Fullcreen();
Fullscreen must be initialized on Pointer down event.(Event trigger).
3.12. Redirects / Branding
SDK contains a solution for working with brands and making redirects (opening new tabs / windows). Branding and redirects must be made via SDK for two reasons:
-
Displaying right brand
SDK contains a multi-brand solution. In short, this feature allows to display all in-game logos on basis of a website the game is displayed on. Changes of outgoing links are also included. This feature is active for websites which promote games from GameArter system. With gameater promotion, there should be more gameplayes and higher incomes. Logos are downloaded at the beginning of the game.
-
Opening pages from a game
A browser pop-up blocker blocks all requests which are not initialized in a certain time from user's action. This applies for all JavaScript requests called from games. SDK contains a solution, which reduces the time between clicks and opens new tabs without hit of the pop-up blocker.
-
Tracking redirects
With our solution you will know about every made redirect. - From what logo, on what website, and how oftenly is being used.
2 Ways of implementation:
- Implementation via prefab
Prefab Individual_logo in Prefabs folder (Assets/GameArter/Prefabs) - A solution for placing own logos containing redirect links into your game. Option Individual requires placing own 2d texture as a button image and a link the logo will redirect. All redirects are opened as a new tab. 1) this does not destroy user's experience and 2) sites like app store or google play do not support opening in iframes.
If you want to have more individual logos in the scene, simply duplicate the object and change logos and links.
- Implementation via code:
Use function Garter.I.OpenWebPage (string targetURL);
This callmust be initialized on POINTER DOWN event. You can listen for this event via EVENT TRIGGER or via following code:copy// where gameObject is your target object for listening EventTrigger et = gameObject.AddComponent< EventTrigger > (); EventTrigger.Entry entry = new EventTrigger.Entry (); entry.eventID = EventTriggerType.PointerDown; entry.callback.AddListener((data) => { OnPointerDownDelegate((PointerEventData)data); }); et.triggers.Add(entry);
3.13. SDK loading screen
SDK contains pre-created loading screen asset in GamePlayer design. Its purpose is to save time, if your game does not contain such screen yet. This screen can be used e.g. during loading maps and other assets.
Using of loading screen:-
1) Creating loading screen |
Garter.I.CreateLoadingScreen (string assetName, texture assetImg, bool activeProgressBar);set activeProgressBar to false, if you do not want to send current time of progress to the loading screen. The bar will be hidden.
-
2) Updating loading screen | Garter.I.UpdateLoadingScreen (float progress);
If you set activeProgressBar to "true" during creating the loading screen, this is a way you can send update to the progress bar by current state of progress. 0 = 0%, 100 = 100%
-
3) Removing loading screen | Garter.I.RemoveLoadingScreen ();
Once the asset is loaded, remove loading screen by this call.
// insert this script to an object placed in scene Hiearchy
public class LoadingScreenExample : MonoBehaviour {
public Texture mapTexture = null; // public var for attaching texture
int updateLimit = 1001; // for test
public void LoadAssetScreen(){
Garter.I.CreateLoadingScreen ("Loading map: Office", mapTexture, true); // create loading screen
updateLimit = 0; // set progress of loading screen to 0
}
void Update(){
updateLimit ++;
if (updateLimit < 1000) {
Garter.I.UpdateLoadingScreen (updateLimit / 10); // set current progress of loading
} else if (updateLimit == 1000){
Garter.I.RemoveLoadingScreen (); // asset loaded - remove loading screen
}
}
}
3.14. SDK cutscenes module
Every game contains many data-weight cutscenes, stories and animations which are displayed calmly only one time for the whole game. GSDK helps to reduce game filesizes by providing a story module — an option for downloading these stories from external storage only in a time when it’s required. Dynamic loading of game stories might be done via asset bundles or this SDK feature when the story is displayed in gameplayer above the game (like an ad).
-
1) Calling browser stories | Garter.I.RunStoryAnimation (int animationNumber);
By calling this, the game is automatically muted (via ServicesAdjustment.cs) and the animation (story) launched. Be sure that animation of such number is available for your game.
-
2) Callback in the end of animation
Once animation ends, there is a callback to ServicesAdjustment.cs file. By default, the game is unmuted via the class. You can find more about this class and its features in point 4 - Advanced features. If you customize behavior during opened modules from default behavior, be sure that sounds are muted for during story module (moduleName == "storywindow").
- 3) Setting / switching of stories
Is being made in "More" section of configuration of the project
3.15. Login during a game
If there is a log-in during a gameplay, SDK automatically calls function Initialized() inside Class GarterLiteCallbacks. The purpose of the function is to forward the received data to developer's function via which he sets default user's data for the game. It means that once these data are received, old data are rewritten by the new incoming data. Be sure, this functionality remains preserved (See 3.2 SDK Initialization).
4. Advanced features
Additional features are features which are not necessary for running of a game in the system. These features are for customization of the game behavior. With information from this section, you can rewrite default behavior of the SDK.
Do not work with this, if you do not understand them.
4.1. Working with GameArter modules
WebGL games are running in a GamePlayer supported by modules. These modules might be opened by user's direct action or by a call from a game. There is also possibility to customize game-behavior during the time modules are being opened. It is also possible to open all the modules from gameplayer, so inserting them to a game is purely optional.
-
1
Opening GameArter web modules
GameArter modules can be opened from a game by calling Garter.I.OpenSdkWindow (moduleName);
List of GameArter modules- Login Garter.I.OpenSdkWindow ("login");
Opens login window. Login window is automatically called by the SDK at the beginning of a game (if a user is not logged in already). SDK opens login window also after pressing log in button in GameArter_Features prefab. Use this call only if a user is not logged in (check via .IsLoggedUser()) and by your own environment.
- Badges Garter.I.OpenSdkWindow ("badge");
Opens viewer of all badges available in the game. Received badges are visibly separated from other badges.
- Leaderboard Garter.I.OpenSdkWindow ("leaderboard");
Viewer of leaderboard state is being in progress, but you can add these calls already now. A user will be informed, that it will come soon. Once leaderboards viewer will be ready, it will begin work automatically.
- User's web profile Garter.I.OpenSdkWindow ("profile");
Opens user's web profile. This is the place a user can change his nick, image, or log out.
- Share Garter.I.OpenSdkWindow ("share");
Opens sharing window via which a user can share the game.
- Exchange
Opens an exchange. See more in point 3.7 - Currency exchange.
- Discussion Garter.I.OpenSdkWindow ("discussion");
Opens a discussion.
- Bug reporting Garter.I.OpenSdkWindow ("report");
Opens box for reporting bugs or any other feedback.
- Development Info Garter.I.OpenSdkWindow ("development");
Opens module with information about development. This is place with information about game updates. Such a small blog. There can be polls and so on.
- Video Garter.I.OpenSdkWindow ("video");
Opens box with a video. Videos to the module might be added via GameArter.com website.
- Game infobox Garter.I.OpenSdkWindow ("gameinfo");
Opens a window displaying game controls and Developer information.
- More games | Garter.I.OpenSdkWindow ("moregames");
Opens window with other recommended games to play.
- Login Garter.I.OpenSdkWindow ("login");
-
2
Customization of game behavior during opened modules
By default, a game is muted during opened modules. If you want to individualize behavior of your game during opened modules, it has to be done over ServicesAdjustment.cs (Assets/GameArterServicesAdjustment.cs) script. This script contains function "ModuleWindowOpened()" and "ModuleWindowClosed()".
copypublic class ServicesAdjustment { public void ModuleWindowOpened(string moduleName){ // module was opened - cancel mouse lock, make pointer visible, set low timescale, run a music ... // this is called also during every change of a module. // Therefore, if you waok with "caching" of current game state, there is need to // save the values on first module only float minimumTimeScale = Garter.I.GetMinimumTimeScale (); if(Time.timeScale != minimumTimeScale){ // set your own value instead of 0 CacheCurrentSettings (); // save this for first opened module only Time.timeScale = minimumTimeScale; // set minimum timescale (better performance) } // on basis of moduleName, every module can have different config - e.g. different ambient music. } public void ModuleWindowClosed(string moduleName){ // return game to the initial state (from CacheCurrentSettings()); } }
If you need to know, whether the game is active or not, there's req Garter.I.IsGameMuted();
4.2. Customization of game behavior during ads
During anactive ad, game sounds must be muted. This is made automatically by SDK. SDK works with sound, timescale and pointer by following way:
public void AdOpened(){
CacheCurrentSettings (); // cache current state - game will be returned to this state after clossing an ad (=mute game)
// by this way, the game is muted
AudioListener.volume = 0f;
float minimumTimeScale = Garter.I.GetMinimumTimeScale ();
Time.timeScale = minimumTimeScale;
if (minimumTimeScale == 0) {
AudioListener.pause = true;
}
// mouse pointer
if (Cursor.lockState != CursorLockMode.None) {
Cursor.lockState = CursorLockMode.None;
}
if (!Cursor.visible) {
Cursor.visible = true;
}
}
Adjust it only if it does not work in your game, or you can improve it. Make the change inside Assets/GameArter/ServicesAdjustment.cs. On end of an ad, function "AdClosed()" (located in the same class) returns the game back to the state before changes made by "AdOpened()" (CacheCurrentSettings ();). If you adjust function AdOpened(), you must adjust function "AdClosed()" as well.
5. Testing
Start your game. Most SDK services are also available in Unity editor. Before an upload, you must check:
- Functional communication with server.
The game has an access to server and can post and get data. If you need to clear all posted data, you can make it via button "Clear user's game data" in GameArter_Initialize object.
- Events, currency etc. are set and working properly
You do not have a mistake in working with events. Events contain correct values. Badges are returned in the right time.
- When a module is opened, the game has corect behavior on background. Game must be muted with visible pointer during ads.
- All works as expected
6. Upload to GameArter
6.1. Uploading files
- Two ways to upload files
-
Zip package.
This way is supported in all browsers. Simply wrap all your build files to .zip format. A program allowing creating .zip files is in most systems by default. If you do not have any in your pc, you can look e.g. for WinRar.
-
Direct files.
If you sue Google Chrome, you can upload individual files by a drop and move schema. Just take file you want to upload and move it into the grey area.
-
Zip package.
- Files intended to be dynamically loaded during gameplay
There's always huge benefit to keep basic filesize as small as possible (see the importance of loading time). There is collection of files which do not need be loaded in significant percentage of game launched, or e.g. directlz from the beginning. For such file, tehre is recommended to use dynamical load in a time when they are needed.
Dynamical load may be applicated for any type of assets - cars, maps, sounds, textures.
- Assets must be uploaded to GameArter, directly inside or in any sub-folder inserted in Build folder. E.g. Build/Textures/...
- Loading this assets is then possible via relative path "Build/...", e.g. "Build/Textures/...". Relative path guarantee that the game will be alsoways load all the files from right place in right version.
- In a case of any problem or required consultation, contact Vladimir.
6.2. Adding game on GameArter
Log in to you account at GameArter - https://www.gamearter.com/. At gamearter, go to the game project and press "upload game files" button. Fill boxes and attach game .zip file. By "test now" button, you can look whether the game runs properly. If you think that your game is ready, change its status to "Published". Once this is done, save the game.
6.3. Setting GamePlayer
In a tab GamePlayer you can customize gameplayer. You can fill there game description, controls, links to social sites, add images for game loading time and so on.
7. Game releases
Managed by "Publication" section of a project.
Be sure that you enabled caching option in build settings.
7.1 First release
Once the game is ready to release, you can get a public link for free spreading in the "Publish" section of the project after pressing "Publish now button". In this case, game is automatically fully set and you can start share the game with players. In one working day since release, GameARter also will make additional check of the game and its functionality. Once the game is checked, you will be informed about result on Slack or email. If all is ok, the game will be sent to hundreds of webmasters in the system. Next day after release, the game will be displayed in reports sections of GameArter dashboard.
Important note: Once you press publish now button, the game passess from "testnet" to "release" state. In a case that your game is connected with GRT currency, any updates of events / items / packages will be visible in the game after confirmation from a side of administrators. This is a protection from manipulation with prices and affecting value of GRT token. Therefore be sure you are requesting release state when you are sure you will not update your released version of game. For testing next updates before release, you can use testnets where you can still edit all the items without any limitation.
7.2 Game updates
Game updates are fully managed by developers via Publication tab in project environment. (Project section at GameArter). After pressing "Publish now" button, previous game version is replaced for a new game version automatically. By every update, GameArter changes files location to prevent running old versions from cache. GameArter also keeps 1 old version for option to return back in a case of any found issue.
Updates are instant, there is no approval by GameArter. By this action, developer takes full responsibility for the update so be sure the new version works well.
All updates are tracked by GameArter. GameArter's staff check all updates in few hours after update to prevent potential problems.