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.
Estimated time of SDK implementation: 2.5 hours. (2 hours of reading documentation, 0.5 hours of implementation) 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).
Example of a game powered by GameArter's Lite SDK for Unity: Taxi city.
- 1. Getting started
- 2. SDK Configuration
- 3. Working with SDK
- 4. Ready to use UI
- 5. Testing
- 6. Upload to GameArter
- 7. Game releases
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.
- COMMODITY | commodity for exchange for GRT - game currency / certain event with undefined trend
- PUBLIC_NAME | commodity name visible in the shop.
- ACTION | buy / sell selected commodity for GRT.
- PACKAGE_IMAGE | image for the package offer. (if remains empty, default img will be used)
- VALUE_CHANGE | Value of commodity for certain amount of GRT
- CURRENCY | GRT = shared gamearter currency
- DISCOUNT | Displayes Discount span
Just press "save all events" button, that's all.
3. Working with SDK
This documentation is related to SDK in version 2.0 and above. If you use SDK in older version, switch to Documentation for LITE SDK in ver 1.X.
Example of interaction with Lite SDK mode you can find at GameArter/Examples/LiteSDK_mode. Look for DataManagerExample.cs script.
3.1. SDK initialization
SDK initialization is automatical, made by GameArter_Initialize object (prefab) which must be inserted in a first scene of the game. 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 these data via delegate event "Garter.ExternalListener.SdkInitialized". Listener for this external event must be inserted (installed) in void Awake() of same scene as contain GameArter_Initialize prefab.
Installation of listeners
Garter.I.AddExternalCbListener< A >( B, C );
where:
- A: Structure of returned data (defined for every listener function)
- B: Event the listener is set for
- C: Function into which is sent information once the event occur
Installation of listener for "Garter.ExternalListener.SdkInitialized" event:
public class DataManagerExample : MonoBehaviour {
void Awake(){
Garter.I.AddExternalCbListener< string >(Garter.ExternalListener.SdkInitialized, SdkInitialized);
}
private void SdkInitialized(string sdkError)
{
if (string.IsNullOrEmpty (sdkError)) Debug.Log("GAMEARTER SDK IS INITIALIZED!");
}
}
Once SDK is initialized, their is possible to start interact with SDK.
public class DataManagerExample : MonoBehaviour {
void Awake(){
Garter.I.AddExternalCbListener< string >(Garter.ExternalListener.SdkInitialized, SdkInitialized);
}
private void SdkInitialized(string sdkError)
{
if (string.IsNullOrEmpty (sdkError)) {
Debug.Log("UserNick: " + Garter.I.UserNick());
Debug.Log("UserLanguage: " + Garter.I.UserLang());
Debug.Log("UserCountry: " + Garter.I.UserCountry());
Debug.Log("LoggedUser?: " + Garter.I.IsLoggedUser());
Debug.Log("User Image:" + Garter.I.UserImage());
Debug.Log ("Game progress in game: " + Garter.I.UserProgress ());
Debug.Log ("User's game funds: " + Garter.I.LocalCurrency ());
Garter.I.GetData< dataType >("data-key",(error,value) => {
if(!string.IsNullOrEmpty(error)){
Debug.Log ("myComplexData callback - error: " + error);
} else {
Debug.Log ("myComplexData callback - data: " + value);
}
});
} else {
Debug.LogError("ERR: " + sdkError);
}
}
}
Possible start implementation:
- Screen / box "Loading"
- Wait for "Garter.ExternalListener.SdkInitialized".
- Set game - data, UI...
- Remove "Loading screen (point 1) and let a user play"
Beside "Garter.ExternalListener.SdkInitialized", SDK allow to install listeners for events which occure on background by using GameArter Servics or prefabs. There is ideal to install all the listeners in the same time - in Awake() of the same scene whic contain GameArter_Initialize prefab. Here's list of all events with their descriptions:
public class GameArterSdkListenersExample : MonoBehaviour {
void Awake(){
// All listeners for external events occured in the game.
Garter.I.AddExternalCbListener< string >(Garter.ExternalListener.SdkInitialized, SdkInitialized);
Garter.I.AddExternalCbListener< decimal >(Garter.ExternalListener.CurrencyUpdate, CurrencyUpdate);
Garter.I.AddExternalCbListener< string >(Garter.ExternalListener.EventExternalUpdate, EventUpdateViaShop);
Garter.I.AddExternalCbListener< string >(Garter.ExternalListener.ExternalShopButtonPressed, ShopButtonPressed);
Garter.I.AddExternalCbListener< string >(Garter.ExternalListener.ExternalSettingsButtonPressed, SettingsButtonPressed);
Garter.I.AddExternalCbListener< string[] >(Garter.ExternalListener.ReceivedBadges, BadgeReceived);
Garter.I.AddExternalCbListener< string >(Garter.ExternalListener.PossibleGameExit, PossibleGameExit);
Garter.I.AddExternalCbListener< string >(Garter.ExternalListener.PWAState, ProgressiveWebAppState);
}
private void SdkInitialized(string sdkError)
{
if (string.IsNullOrEmpty (sdkError)) Debug.Log("GAMEARTER SDK INITIALIZED!");
}
private void CurrencyUpdate(decimal currencyValue)
{
// Value of currency was changed out of the game.
// e.g. via currency purchase in exchange
// currency rewards was part of other rreward (badge, leaderboard...)
Debug.Log("SET User's game currency in UI to: " + currencyValue);
}
private void EventUpdateViaShop(string emptyString = null){
// In the external shop/exange, users can use their money
// for changing value of currency (see CurrencyUpdate) as well as events
// with "undefined" trend. These event occurs, when any event with
// undefined trend was changed via in-game shop (by purchase).
Debug.Log ("Update things connected with events with undefined trend");
}
private void ShopButtonPressed(string emptyString = null){
// Called on pressing "Shop" button inserted in "GameArter_Features" prefab;
// visibility of this button is customizable via GameArter_Initialize
}
private void SettingsButtonPressed(string emptyString = null){
// Called on pressing "Settings" button inserted in "GameArter_Features" prefab
// visibility of this button is customizable via GameArter_Initialize
}
private void BadgeReceived(string[] badgeName){
// Badges (Achievements) are distributed automatically in realtime
// on basis of updating defined game Events.
// In that moment, list of received badges is sent to this functions.
// By default, a user see a small notification about received badge
// in top left corner and alert icon on badges button (part of "GameArter_Features" prefab).
// This function can be used if you wish to display a bigger image or any action you want.
for (byte i = 0; i < badgeName.Length; i++) Debug.Log ("Badge received | "+badgeName[i]);
}
private void PossibleGameExit(string emptyString = null){
// SDK detected a potential risk that user will exit the game.
// Right reaction can be to make direct save of data in this moment.
}
private void ProgressiveWebAppState(string state){
// Install as app button visibility (See point 3.15).
Debug.Log ("Progressive Web App State: "+state);
if (state == "enabled") {
// display button "install as app"
buttonInstallAsApp.SetActive(true);
} else if(state == "disabled"){
// hide button "install as app"
buttonInstallAsApp.SetActive(false);
}
}
}
Best practice: Manage all functionality related to listeners from one class - see the example above).
Manual check of SDK initialization state (if needed): bool sdkIsInitialized = Garter.I.IsInitialized();
3.2. 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.3. 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 float gameProgress = Garter.I.UserProgress ()); 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.4. 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.5. Accessing currency
There are more types of currencies in GameArter. The main currency is GameArter currency (GRT). 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 (GRT) 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 GRT 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 by change (RECOMMENDED) | Garter.I.LocalCurrency (currencyChange);
decimal currencyChange = absGameCurrency - Garter.I.LocalCurrency(); Garter.I.LocalCurrency( currencyChange );
Allow to post new absolute value instead of change. Since SDK ver 2.4
Both 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 a user leaves the exchange screen, SDK automatically unmutes the game and returns current value of changed property (currency or event) to a function listening for "Garter.ExternalListener.CurrencyUpdate" (in a case of currency) or "Garter.ExternalListener.EventExternalUpdate" in a case of event. If the scene the exchange was opened from is displaying a value of changed property inside any UI, you need to update value displayed in such UI.
copypublic class GameArterSdkListenersExample { public void CurrencyUpdate(float currencyAbsoluteValue){ // update text of currency counter // If change of currencyValue will affect game story by any kind, // there is good idea to post data on server now } // Update of event value via shop (=event state purchase) public void EventUpdateViaShop(){ // some event with undefined trend has new value now // Update UI, if necessary } }
Behaviour during opened exchange can be set in ServicesAdjustment.cs (optional)
NOTE: If you see an empty space after calling Garter.I.LocalCurrency (currencyChange);, you did not add any packages for your project. Add some for your project id and version via Project panel.
-
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.6 Game storage management
There is no need to care about whether an user is logged in or not. SDK solves data management for both. In general, to offer the best playing experience, all data should be saved in SDK (no directly in playerprefs). If your game uses any services as currency, leaderboards or achievements, playerprefs is something you have to forget.
Data management in SDK v2.0 is backward compatible with SDK v1.X. Data saved via SDK v1 are available in SDK v2 under key "default".
3.6.1 Getting data
SDK keeps all data synchronized in the game (saved is RAM memory) and on server. Thanks to this, there is no limit for getting data from SDK. Data can be returned directly, or via a callback.
public class DataManagerExample : MonoBehaviour {
public void GetDataFromStorage(){
// return data directly
string myKeyData = Garter.I.GetData< string >("my-key");
// return data via callback
Garter.I.GetData< int >("my-num", (error,value) => {
if(!string.IsNullOrEmpty(error)){
Debug.Log ("myNum callback - error: " + error);
} else {
Debug.Log ("myNum callback - data: " + value);
}
});
// You can use both in the same time
string myKeyData = Garter.I.GetData< string >("my-key", (error,value) => {
if(!string.IsNullOrEmpty(error)){
Debug.Log ("myNum callback - error: " + error);
} else {
Debug.Log ("myNum callback - data: " + value); // works
}
});
Debug.Log(myKeyData); // works
// Own data structures
Garter.I.GetData< MyOwnDataStructure >("complexData",(error,value) => {
if(!string.IsNullOrEmpty(error)){
Debug.Log ("myComplexData callback - error: " + error);
} else {
Debug.Log ("myComplexData callback - data: " + value);
}
});
}
}
NOTE: If any error occur, SDK returns default value of requested data type. If callback is attached, the problem is attached under "error" attribute.
3.6.2 Posting data
Events, currency and progress cannot be part of the data structure (they are saved in the SDK data layer directly - see Events schema)
public class DataManagerExample : MonoBehaviour {
public void PostDataToStorage(){
// post data without callback
Garter.I.PostData< string >("my-key", "Hello World");
// post data with callback
Garter.I.PostData< int >("my-num", 6, (error, response) => {
if (!string.IsNullOrEmpty (error)) {
Debug.LogWarning (error);
} else {
Debug.Log (response);
}
});
/**
* Achiless heel
* Avoid direct posting complex data as arrays, list and own structures
* Convert own structurres to string format before posting them
* This will prevend deserialization issues for guests
*/
// Instead of this
MyOwnDataStructure complexData = new MyOwnDataStructure (someStringData, someIntegerData, someFloatData, new MyOwnDataStructure.MyTypeData (someListType, someArrayType, someJaggedArrayType));
Garter.I.PostData< MyOwnDataStructure >("complexData", complexData, (error, response) => {
if (!string.IsNullOrEmpty (error)) {
Debug.LogWarning (error);
} else {
Debug.Log (response);
}
});
// Use this:
// Own data type (defined by Class)
MyOwnDataStructure complexData = new MyOwnDataStructure (someStringData, someIntegerData, someFloatData, new MyOwnDataStructure.MyTypeData (someListType, someArrayType, someJaggedArrayType));
string myComplexData = Garter.I.GetData< string >("complexData",(error,value) => {
Garter.I.PostData< string >("complexData", myComplexData, (error, response) => {
if (!string.IsNullOrEmpty (error)) {
Debug.LogWarning (error);
} else {
Debug.Log (response);
}
});
}
}
SDK contains limit for post data requests. In general, there is enabled 8 post requests every 2 minutes. This frequency can be dynamically managed by SDK on basis of server load. If the limit is exceeded, SDK returns an error informing about that via callback (error attribute).
Requests aggregation: In a case you do more post requests in the same time (as in the case of PostDataToStorage() example where all posts go after each other with minimum delay), SDK automatically aggregates all the post requests and send them in one request. If the request is aggregated, you will get callback response => "aggregated"
There is very usefull to use Own data structures for exchnaging the data between game and storage. Example of such data type is "MyOwnDataStructure" mentioned in "PostDataToStorage()" function example. You can define structure collecting any data types in any size via a class. If you are not familiar with this practice, check smart user data management example.
Test, that all data types used by you are supported. In general, all data types are supported for logged users (saving on server). However, there is often a problem during playing as a guest. More compelx data formats - arrays, lists, own structures can be broken by saving to playerprefs. Verify always, it will not affect your game.
On background, SDK automatically synchronize data in game and server layer to keep active auto-managed services like leaderboard or achievements. If you wish to post your data via this auto-synchronisation (not recommended), you can post the data to SDK layer by following way:
public class DataManagerExample : MonoBehaviour {
public void PostDataToSdkRamLayer(){
// without callback
Garter.I.SetIndividualGameData< string >("key",dataToBeSaved);
// with callback
string postDataError = Garter.I.SetIndividualGameData< string >("key",dataToBeSaved);
if (!string.IsNullOrEmpty (postDataError)) Debug.LogWarning (postDataError);
}
}
3.6.3 Deleting data
-
1
Deleting data of a single key
copypublic class DataManagerExample : MonoBehaviour { public void ClearDataFromKey(){ // without callback Garter.I.ClearDataKey< string >("key"); // with callback Garter.I.ClearDataKey< string >("key", (error,response) => { }); } }
-
2
Deleting all data (user account)
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, with 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 Game Data management
-
1
Downloading static 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("Get static file error: " +www.error); } else { Texture2D image = www.texture; } }
-
2
Assets management
Assets management is a feature via which users can save and manage self-created game content on server. Such self-created content is property of its authors which can decide what permissions other users have regarding this property. On basis of permissions, other users can such property use, modify, duplicate, and rate.
Example of use is for example a game mode, in which players can create game content itself. For example maps. Other users then can rate these maps and help by this action to make the maps more popular. In feature, this concept will be extended about rewards for creators of popular game content.
Due to longer documentation of this feature, this feature is described in separated stream.
3.8 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 (see more in section 4). It is also possible to open all the modules from gameplayer. Inserting call to action buttons directly to a game increases opening these modules.
-
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 Garter.I.OpenSdkWindow ("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 (Optional)
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();
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 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.14 Login during a game
If there is a log-in during a gameplay, SDK automatically re-initialize themselve by new data. Listen for .SdkInitialized event and set the game mechanism so to reinitialize whole the game by new data as well.
3.15 Game as App
Feature available since SDK version 2.2
GameArter SDK allows to installation of web games as Web Apps to user's device. Installation is possible to PC as well as mobile device.
Implementation
- NOTE: this feature is functional after submiting requests for publishing in GameArter.
- Icon of web app (displayed at user's screen of desktop / mobile) must be in .png format and in 2 dimensions - 192x192 & 512x512px. Name them "favicon-192.png" and "favicon-512.png" and attach to folder "_pwa". Upload this folder with other project files in "Files upload" section at GameArter panel.
-
1) External callback listener | Garter.I.AddExternalCbListener("PWAState", targetFunction);
The listener is used for setting visibility of button "installing game as app". Design of the button is up to developer.
copyGarter.I.AddExternalCbListener< string >(Garter.ExternalListener.PWAState, InstallAsAppButton); function InstallAsAppButton(state){ switch(state){ case "enabled": // Display button break; case "disabled": // hide button break; } }
Button must be hidden in default.
- Next option, e.g. when a user comes to menu and there is not known state in the game →
Get current state value | Garter.I.GetStatePWA()
Returns "enabled" / "disabled". See point 1. -
2) Request for instalation
Request for adding game as app to user device is made by user's click at button "installing game as app". Returned state identifies about current state of installation. These states maz be sent to e.g. analytics for tracking click ratio.
copybuttonAddAsApp.onclick = InstallGameAsApp; function InstallGameAsApp(){ Garter.I.InstallAsPWA< string > ((state) => { switch(state){ case "rejected": // request is rejected. Be sure the request is posted only if Garter.I.GetStatePWA() === "enabled". break; case "dismissed": // user cancelled the request break; case "accepted": // user accepted the request break; case "installed": // game was succesfully installed as app break; } }); }
Visibility change of button during these states is driven via listener for "PWAState", see point 1.
4. Ready to use UI
Some ready to use UI which may save you some development time.
4.1 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
}
}
}
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.
All features are functional directly in editor as well as on web. In a case of external-opened window from editor, firstly make an action in the external web window, then press "close" button in the Unity UI informing you that "External window has been opened".
- 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.