Skip to main content

Brick Breaker Example Project

About

The brick breaker Example project is included with the Skillz Unity package. The following document explains how to run the example project as well as how the example project Implements the Skillz SDK and features including match parameters, progression, fairness, anti-cheat measures, and other best practices.

NOTE: All the pertinent files are under Assets/Skillz/Examples/Brick Break.

Running the Example Project

Running in the Unity Editor

The brick breaker example project can be run in the Unity editor using the Skillz SIDEkick. It is recommended to run the example project in this way as the setup process is much simpler.

  1. Go to File > Build Settings.

  2. Add the following scenes into the 'Scenes in Build' in the build settings:
    (The following can be found in the Assets/Skillz/Examples/Brick Break/Scenes folder)
    BB_StartMenu
    BB_Game
    BB_ProgressionRoom

2a. Make sure the BB_StartMenu scene is at index 0

  1. Open the BB_StartMenu scene. You will be prompted to import TMP Essentials. Click Import TMP Essentials. If this does not appear, go to Window > TextMeshPro > Import TMP Pro Essential Resources.

  2. Go to Skillz > Settings from the menu bar.

  3. Under the SIDEkick section add the following SIDEkick templates:
    (The following can be found in the Assets/Skillz/Examples/Brick Break/SIDEkick folder)
    BB Match Types
    BB Match Parameters
    BB Players
    BB Progression Responses
    BB Seasons

  4. Click the Launch Game button.

Running on a Mobile Device

It is recommended to run the example project in the Unity editor using SIDEkick as it is quicker to set up. To run the brick breaker example on a mobile device, more setup is required. Instructions on how to run on a mobile device can be found at the end of this document in the Running the Example Project on a Mobile Device section.

Launching Skillz From the Start Menu

The BB_Start menu scene in the Skillz/Examples/Brick Break/Scenes folder makes use of the Skillz Manager prefab to launch Skillz. When the start button is clicked the Skillz UI is launched. When a user in the Skillz UI starts a match, returns to the start menu, or enters the progression room, the corresponding scene is launched.

NOTE: The chosen scenes needs to be in the Build Settings under the Scenes in Build section.

The Skillz Manager in the example project also includes references to a Skillz Example Manager Logic script. This script currently only has log statements, but this script can be used to add additional logic to these scene transitions.

Submitting the Score

The brick breaker example project handles score submission in the BB_SkillzMatchManager script (Assets/Skillz/Examples/Brick Break/Scripts/BB_SkillzMatchManager). The score is submitted with SkillzCrossPlatform.SubmitScore() method. If the score is submitted successfully then the SkillzCrossPlatform.ReturnToSkillz() method is called on the next update. This will return the user to the Skillz UI. If the Score submission is unsuccessful then the SkillzCrossPlatfrom.DisplayTournamentResultsWithScore() fallback method is called. This will ensure the user’s score is not lost. More information on score submission can be found here.

BB_SkillzMatchManager.cs
// ...
private void Update()
{
if (hasSubmittedScore)
{
MatchComplete();
}
}

public void SubmitScore()
{
SkillzCrossPlatform.SubmitScore(GetScore(), OnScoreSubmitSuccess, OnScoreSubmitFailure);
}

private void OnScoreSubmitSuccess()
{
Debug.Log("Score Submit - Success");
hasSubmittedScore = true;
}

//If the submit score fails then call fallback score submission
private void OnScoreSubmitFailure(string reason)
{
Debug.Log("Score Submit - Failure: " + reason);
SkillzCrossPlatform.DisplayTournamentResultsWithScore(GetScore());
}

public void MatchComplete()
{
Debug.Log("Returning to Skillz UI");
SkillzCrossPlatform.ReturnToSkillz();
}

private int GetScore()
{
return BB_Managers.matchManager.GetTotalScore();
}
// ...

Using Match Parameters to Support Multiple Game Modes

The Skillz brick breaker example uses match parameters to alter the rules of the match based on the type of match the user selects. These parameters are:

  • game_mode Sets the mode as either a delux match (mulitpliers added to bricks) or practice match.

  • time The time given for the player to complete the match.

  • multi_ball Whether the game spawns extra balls at set time intervals.

Setting up Match Parameters in SIDEkick

When running your game within the Unity editor, the match parameters are set up in the Sidekick settings. Select Skillz > settings, go to the SIDEkick section, then double click on the selected Match Parameter Templates. The templates will then appear in the inspector where they can be edited as needed.

When after launching the game the templates will be available under the match parameters dropdown in the simulated Skillz UI. Select the desired template and enter the match.

Setting up Match Parameters on the Developer Console

When you run the game on a mobile device, the match parameters need to be set up along with the tournament types in the developer console (https://developers.skillz.com). To modify the match parameters click on your game then click the Optimize tab. Under the Customize Gameplay section, select Tournament. The instructions to run this project on a mobile device can be found here.

Querying Match Parameters in the Game Scene

Match parameters can be accessed in the game code by calling the SkillzCrossPlatform.GetMatchRules() method. This will return a Hashtable with key-value pairs corresponding to the match parameters set up in the developer console or SIDEkick settings. The values of these parameters are then used to drive changes in the rules of the match. This is done in the BB_MatchManager script (Assets/Skillz/Examples/Brick Break/Scripts/BB_MatchManager).

BB_SkillzMatchManager.cs
// ...
private Hashtable matchParameters;
private float matchTime = 60;
private bool isMultiBall = false;

private void SetMatchParameters()
{
matchParameters = SkillzCrossPlatform.GetMatchRules();

if (matchParameters.ContainsKey("game_mode"))
{
gameMode = (string)matchParameters["game_mode"];
}

if (matchParameters.ContainsKey("time"))
{
timeRemaining = int.Parse(((string)matchParameters["time"]));
matchTime = timeRemaining;
}

if (matchParameters.ContainsKey("multi_ball"))
{
if ((string)matchParameters["multi_ball"] == "true")
{
isMultiBall = true;
}
}
}
// ...

Ensuring Fairness

On the Skillz platform it is critical that the games be fair. Both players must be presented with the same opportunity to achieve a score. Care must be taken to ensure one player does not have an advantage over the other.

This means that any kind of randomness in the game that affects gameplay must be calculated the same for each player. The Skillz SDK provides a set of SkillzCrossPlatform.Random methods to achieve this. If these calls are made in the same order for each player, they will return the exact same result.

In the Skillz Brick Breaker example, a fairness Script (Skillz/Examples/Brick Breaker/Scripts/BB_Fairness) is used to ensure the game is set up in the same way for each player. The fairness script has a GenerateFairGame() function as seen below:

BB_Fairness.cs
// ...
public static BB_GameBoard GenerateFairGame(List<BB_GameBoard> possibleGameBoards, bool isDeluxMatch, Transform gameBoardParent)
{
//Choose Game Board
int gameBoardIndex = SkillzCrossPlatform.Random.Range(0,possibleGameBoards.Count);
BB_GameBoard chosenGameBoard = possibleGameBoards[gameBoardIndex];

//Create the game board
BB_GameBoard gameBoard = GameObject.Instantiate(chosenGameBoard, gameBoardParent);

//Choose Brick Multiplier Locations
if (isDeluxMatch)
{
for (int i = 0; i < 6; i++)
{
int brickChoice = SkillzCrossPlatform.Random.Range(0, gameBoard.NumberOfBricks());
gameBoard.GetBrick(brickChoice).SetMultiplier(2);
}
}

//Generate List of ball perturbations
randomBallPerturbations = new List<Vector2>();
for (int i = 0; i < 50; i++)
{
Vector2 randomPerturbation = SkillzCrossPlatform.Random.InsideUnitCircle() * .1f;
randomBallPerturbations.Add(randomPerturbation);
}

return gameBoard;
}
// ...

A random integer is generated using SkillzCrossPlatform.Random.Range() and this is used to pick one of the possible game boards. This will ensure the amount, positions, and type of bricks are the same for both players.

If the game is a delux match, SkillzCrossPlatform.Random.Range() is used to pick which bricks will have a score multiplier (eg. X2). This ensures the locations of the multipliers are the same for each player in the match.

And lastly a list of ball perturbations is generated using SkillzCrossPlatform.Random.InsideUnitCircle() these. These are used to set the initial velocity for balls that spawn during the match.

It is important to note how the fairness setup has been consolidated into one script. There are no other calls to SkillzCrossPlatform.Random anywhere else in the game code. This ensures that the SkillzCrossPlatform.Random calls happen deterministically (in the same order and therefore with some result) for each player in the match.

Anti-Cheat Measures

When integrating with Skillz it becomes extremely important to take precautions against potential cheating in a game. To maintain a fair and competitive gameplay experience, we recommend that developers take anti-cheating measures before going live with Skillz. More Information on anti-cheat measures can be found here.

The Brick Breaker example app duplicates and obfuscates important game data to prevent cheaters from modifying the data through memory modification. This is accomplished by using the BB_AntiCheatVault class (Assets/Skillz/Examples/Brick Break/Scripts/BB_AntiCheatVault).

BB_AntiCheatVault.cs
// ...
public class BB_AntiCheatVault
{
private int xorCode1;
private int xorCode2;
private int value;
private int valueCheck;

public BB_AntiCheatVault()
{
xorCode1 = Random.Range(0, int.MaxValue);
xorCode2 = Random.Range(0, int.MaxValue);
value = 0 ^ xorCode1;
valueCheck = 0 ^ xorCode2;
}

public void Set(int newValue)
{
value = newValue ^ xorCode1;
valueCheck = newValue ^ xorCode2;
}

public int Get()
{
return value ^ xorCode1;
}

public bool IsValid()
{
return (value ^ xorCode1) == (valueCheck ^ xorCode2);
}
}
// ...

Instead of storing an important variable like score in a regular variable it is stored in a BB_AntiCheatVault. This can be seen in the BB_MatchManager script (Assets/Skillz/Examples/Brick Break/Scripts/BB_MatchManager).

BB_MatchManager.cs
// ...
private BB_AntiCheatVault score;

public void AddScore(int deltaScore)
{
score.Set(score.Get() + deltaScore);
BB_Managers.matchUIManager.SetScore(GetScore());
}
// ...

When the score is queried it is then checked for validity to make sure it has not been altered during the game.

BB_MatchManager.cs
// ...
public int GetScore()
{
if (!score.IsValid())
{
return 0;
}
return score.Get();
}
// ...

Pausing the Game

When Pausing the game it is important to not display the game board in the background. The Player could then cheat by continually pausing and planning their next move. For this reason, the brick breaker pause menu displays on top of the game board and completely obscures the current state of the game.

Creating a Progression System

Progression adds a critical component to help drive the success of your game. The Progression methods allow you to store, recall, and update player data at any time within the game, unlocking personalized player experiences.

Progression Room

The Skillz brick breaker example includes an example of a simple progression system. Various user statistics are tracked over many matches. Earned achievements are displayed in a dedicated progression room (Assets/Skillz/Examples/Brick Break/Scenes/BB_ProgressionRoom).

First we will take a look at the progression room and how the progression data is queried. The BB_ProgressionManager script (Assets/Skillz/Examples/Brick Break/Scripts/BB_ProgressionManager.cs) is used to interact with the Skillz progression API.

BB_ProgressionManager.cs
// ...
private void Start()
{
defualtDataKeys = new List<string>();
defualtDataKeys.Add("games_played");
defualtDataKeys.Add("cash_games_played");
defualtDataKeys.Add("games_won");
defualtDataKeys.Add("cash_games_won");
defualtDataKeys.Add("best_score_lifetime");
defualtDataKeys.Add("average_score");
defualtDataKeys.Add("player_level");
defualtDataKeys.Add("skillz_level");
defualtDataKeys.Add("install_date");

customDataKeys = new List<string>();
customDataKeys.Add("bricks_broken");
customDataKeys.Add("bricks_cleared");
customDataKeys.Add("only_bronze_remaining");
customDataKeys.Add("15_time_remaining");
customDataKeys.Add("no_ball_lost");

//Retrieve the progression data from Skillz
GetProgressionData();
}

private void GetProgressionData()
{
SkillzCrossPlatform.GetProgressionUserData(ProgressionNamespace.DEFAULT_PLAYER_DATA,
defualtDataKeys,
OnSuccessDefault,
OnFailure);
SkillzCrossPlatform.GetProgressionUserData(ProgressionNamespace.PLAYER_DATA,
customDataKeys,
OnSuccessCustom,
OnFailure);
}
// ...

On Start(), the data keys lists are created and SkillzCrossPlatfrom.GetProgressionUserData() is called twice. Once to get the default progression data and Once to get the custom progression data. Notice that the data keys in the defaultDataKeys list and customDataKeys list match the data keys in the progression responses section of the SIDEkick settings and the data keys setup in the developer console. When the call returns successfully, the OnSuccessDefault and OnSuccessCustom methods are called and the defaultProgressionData and customProgressionData are updated respectively.

BB_ProgressionManager.cs
// ...
private Dictionary<string, SkillzSDK.ProgressionValue> defaultProgressionData;
private Dictionary<string, SkillzSDK.ProgressionValue> customProgressionData;
// ...
//Store the default progression data locally
private void OnSuccessDefault(Dictionary<string, ProgressionValue> data)
{
foreach (string key in data.Keys)
{
defaultProgressionData.Add(key, data[key]);
}
hasRevievedDefaultData = true;
}

//Store the custom progression data locally
private void OnSuccessCustom(Dictionary<string, ProgressionValue> data)
{
foreach (string key in data.Keys)
{
customProgressionData.Add(key, data[key]);
}
hasRecievedCustomData = true;
}
// ...

Now that the progression values are stored locally, they can be utilized by the progression room controller (Assets/Skillz/Examples/Brick Break/Scripts/BB_ProgressionRoomController) to display data in the progression room.

Updating Progression Data

When a player completes a match in the Brick Breaker example, the progression data is updated to reflect the player's performance. This is accomplished using the same Progression Manager (Assets/Skillz/Examples/Brick Break/Scripts/BB_ProgressionManager.cs) as is in the progression room scene. The progression data is queried on Start() and stored locally as seen above. Retrieving the progression data is necessary because the new progression data values is based upon the old values added to the new values (eg. bricks_broken goes from 100 to 120 if 20 bricks are broken).

A list of progression data updates is then tracked locally. Updates are added to the list using the SetData() method. The updates are stored locally to reduce the amount of calls to SkillzCrossPlatform.UpdateProgressionData(), as only one call is needed at the end of the match to update the data.

BB_ProgressionManager.cs
// ...
private Dictionary<string, object> customProgressionUpdates;
// ...
public void SetData(string dataKey, object value)
{
if (customProgressionUpdates.ContainsKey(dataKey))
{
customProgressionUpdates[dataKey] = value;
}
else
{
customProgressionUpdates.Add(dataKey, value);
}
}
// ...

When the match is completed the updates are pushed to Skillz using the SkillzCrossPlatfrom.UpdateProgressionData() method.

BB_ProgressionManager.cs
// ...
//Save the progression data to Skillz
public void UpdateProgressionData()
{

SkillzCrossPlatform.UpdateProgressionUserData(ProgressionNamespace.PLAYER_DATA,
customProgressionUpdates,
OnSuccessUpdate,
OnFailure);
}
// ...

NOTE: Only the custom progression data is updated. The default progression data is automatically updated by Skillz and cannot be updated manually using Skillz API calls.

Running the Example Project on a Mobile Device

  1. Go to https://developers.skillz.com/your_games

  2. Select ‘Add new game’

  3. Fill in name and description, select cross-platform > unity. Then select Start Integration.

  1. Choose the game options as seen below then click Next.

  1. When on the Now let's set up the SDK’ screen, follow the instructions then click Next`.

  2. When on the Let’s integrate the SDK into your game screen. Instead of following the instructions in the documentations, the Brick Breaker example will need to be setup.

  3. Open Unity go to File > Build Settings.

  4. Add the following scenes into the 'Scenes in Build' in the build settings:
    (The following can be found in the Assets/Skillz/Examples/Brick Break/Scenes folder)
    BB_StartMenu
    BB_Game
    BB_ProgressionRoom

  5. Make sure the BB_StartMenu scene is at index 0.

  6. Go to Skill > Settings.

  7. Set the Skillz Orientation to Portrait, Set the Game ID to the id generated in the developer console.

  8. Follow the build instructions for your SDK version and desired platform at: https://docs.skillz.com/docs/installing-skillz-unity

  9. Follow the steps below to finish the setup process in the developer console.

Configuring Developer Console for the Example Project

Setting Up Tournaments with Game Parameters

  1. In the developer console, select your game then go to Optimize > Tournament.

  2. Select Edit on the sandbox tournament templates.

  3. Fill out the tournament templates with desired values. The brick breaker example supports the game parameters below:

Setting Up Progression

  1. In the developer console, select your game then go to Progression > Entry Points > Edit

  2. Click New Entry Point and create an entry point.

  3. In the developer console go to Progression > Player Data > Edit.

  4. Turn on the Sandbox flag, then click Add Custom Data.

  5. Add the custom data keys seen below: