Skip to main content

Unity SDK - Adventure Game Integration

Welcome to our Unity SDK Guide. This is a step-by-step guide on how to integrate your Unity game with the ZEBEDEE SDK. Once integrated you will be able to follow similar development flows to introduce the ability to pay, receive, and withdraw Bitcoin through your game.

Video Guide

If you're more of a visual learner, we've also created an in-depth step-by-step video walkthrough of the written guide below.

Requirements

  • You have the latest Unity Editor installed.
  • You have a Unity User Account (This is required to download assets from Unity Store).
  • You have Visual Studio installed. This is required to edit C# code seamlessly with Unity.
  • You have a ZEBEDEE Developer Dashboard account with an API Key (See our Registering Account guide).
  • You have ZEBEDEE Mobile Wallet or an equivalent Bitcoin Lightning Wallet to read/pay invoices.

Game Setup

Importing Unity Project

Fire up the Unity Editor and create a new 3D Project following the steps in the wizard.

Unity | Create new project wizard

Unity | Create new project wizard

Once you have started your new project, and you see the project information/details in the main Unity Editor view, head over to the top menu and select the Asset Store, by clicking on Window > Asset Store.

Unity | Asset Store selector

Unity | Asset Store selector

The Unity Asset Store is a great place to find ready-made items/graphics/vectors for your games. For this tutorial we are going to use one of Unity's core demo games as a base for our integration with ZEBEDEE and Bitcoin.

Search for the keyword "Adventure Sample Game" and you should see a cover like the one below. Go ahead and choose to download and import the game.

If you cannot perform this action, ensure you are logged into your Unity User Account. If not, create one to proceed.

Unity | Adventure Sample Game

Unity | Adventure Sample Game

Once you choose to import this new Unity game, you will see a list of items to select. These are the many files available in this Unity demo game and it includes Animator objects, Animations, Environments and Player details and much more. Make sure to select All and choose Import.

Unity | Importing Adventure Sample Game

Unity | Importing Adventure Sample Game

All done! You have successfully imported a Unity demo game to your local Unity Editor. This means you can run, edit, and play this game locally on your computer.

Playing Unity Project

Now that we've imported the demo game, let's make sure it runs smooth and everything works as its intended. To fire up the demo game choose Scenes folder in the Project Pane, and inside it click the Persistent Scene file, like it is shown below.

Unity | Persistent Scene file location

Unity | Persistent Scene file location

Now hit the Play button.

Once started, you will be able to move your character by clicking on the destination path. The goal of this demo game is to get the security gate open. To make things easy, we'll tell you how to beat it (just this once, we promise). You can get out of the security room from the side of the corridor heading to the Market scene. To do so, simply disguise your character with glasses and head on over to open the gate. Go ahead, try it yourself!

How to win the game

  • Get the coin from the vending machine
  • Buy a coffee from the robot
  • Disturb the bird, which will drop the glasses
  • Pick the glasses up, and walk through security again
Unity | Adventure demo gameplay

Unity | Adventure demo gameplay

ZEBEDEE SDK

Downloading the SDK

In order to use ZEBEDEE's services to allow for Bitcoin transactions in your game, you must either use the ZEBEDEE API directly, or leverage one of our Software Development Kits (SDKs). For the purpose of this tutorial, we are going to make use of the official ZEBEDEE Unity SDK.

To download the SDK, head on over to ZEBEDEE's GitHub page and click on the Releases tab of the Unity SDK project. Pick the latest version of the SDK and download the ZEBEDEE_SDK_vX.X.X.unitypackage file.

Link: https://github.com/zebedeeio/unity-sdk/releases

GitHub | ZEBEDEE SDK releases page

GitHub | ZEBEDEE SDK releases page

Importing the SDK

Now that we've downloaded the SDK Unity package, we need to import it into the Unity Editor. To do that head on over to the top menu and choose Assets >> Import Package >> Custom Package.

Select the ZEBEDEE_SDK_vX.X.X.unitypackage file you just downloaded, and when prompted make sure to select All to import all of the files from the SDK to your Unity project.

Unity | Importing Custom Package

Unity | Importing Custom Package

Adding QR Code Capabilities

Currently, in order to effect Bitcoin Lightning payments in your game from any mobile and desktop wallet, you must display the invoice request as a QR Code for the player to scan.

For this integration demo, we are going to create a simple paywall inside of the game, where a Player needs to make a payment in order to proceed. This is just a simple integration, it is entirely up to you as the creator of the game to decide what cool interactions can be built around micropayments in your game.

So let's start of by creating the game interface for displaying a QR Code.

Make sure you are in the Persistent Scene file from the Project (Inside Assets/Scenes folder).

Under the PersistentCanvas panel, in the Hierarchy section choose to create a UI element (UI >> Panel). Let's call this new Panel QRPanel. In the Inspector view on the right side, in the Rect Transform section, select the anchor presets to middle-center. Let's also change the width and height of our QRPanel to be 500 for both.

Unity | Panel Inspector

Unity | Panel Inspector

Great, now we've got a brand new blank panel. Let's fill it with our QR Code.

Following the same approach as before, in the Hierarchy section, choose to add a new UI element, but this time let's add an image (UI >> Image). Place this new UI element under the QRPanel and rename it to QRImage.

In the Inspector view, under Rect Transform set the position of X to 0, position of Y to -30, and position Z to 0. Let's also set the height and width to be 350 each, as seen in the image below.

Unity | QRImage positioning

Unity | QRImage positioning

The last bit we'll add to our QR Code UI is a string of text above the QRImage. Similarly, under Hierarchy, choose to add a new UI Element, this time a text element (UI >> Text). And just like last time, let's place that new UI element under the QRPanel, and let's rename it to QRText.

In the inspector view, under Rect Transform, set the position of X to 0, the position of Y to 160, the position of Z to 0, and set the height to 100 and width to 500. We are also going to select Text >> Font Size to be 40, alignment set to center, and white color. Your inspector view should look something like the image below.

Unity | QRText information

Unity | QRText information

ZEBEDEE Integration in C#

Now that we have successfully created the necessary interface for displaying QR Codes in the demo game, we can add/edit the code itself to integrate the ZEBEDEE SDK.

To begin this process let's open the *SceneController game object, in the inspector view double click the script SceneController. This should open up Visual Studio (or equivalent code editor) with the C# code for the controller file.

Unity | SceneController Panel

Unity | SceneController Panel

Let's start by adding the necessary public variables we will be reusing through this integration. We need to provide a set of variables, detailed below:

  • apiKey: this is the API Key you have retrieved from your ZEBEDEE Developer Dashboard
  • zebedeeBaseUrl: this is the URL for the ZEBEDEE API
  • QRCodePanel: this is the panel/wrapper/container element for the QR code
  • QRCodeImage: this is the image element for the QR code
  • QRCodeText: this is the text element for the QR code
  • logger: a logging utility
  • zbdClient: the ZEBEDEE SDK client
  • totalSats: total amount of satoshis to be charged
  • gameplayFeeSats: total amount of fees to charge to play the game

You can see a sample source code below:

public string apiKey;
public string zebedeeBaseUrl;
public Image QRcodeImage;
public GameObject QRCodePanel;
public Text QRcodeText;

private IZdbLogger logger = LoggerFactory.GetLogger();
private ZebedeeClient zbdClient = null;
private int totalSats = 10;
public int gamePlayFeeSats;

Now let's add some logic to the main Start() method.

First we instantiate a new ZEBEDEE SDK client through the zbdClient variable, and subsequently add a simple text to the QR code to let users know that this is a paywalled experience and that a payment is required.

We then await for a payment, and if one is received, we disable the QR code and proceed with the gameplay.

Find a demo source code below:

private async void Start()
{
// Set the initial alpha to start off with a black screen.
faderCanvasGroup.alpha = 1f;

// Write the initial starting position to the playerSaveData so it can be loaded by the player when the first scene is loaded.
playerSaveData.Save(PlayerMovement.startingPositionKey, initialStartingPositionName);

QRcodeText.text = "Play Game for " + gamePlayFeeSats + " sats";

zbdClient = new ZebedeeClient(zebedeeBaseUrl, apiKey);

PayForAGamePlay();
}

The PayForAGamePlay() method helps in preparing the Invoice details (description and amount), and then sends that data to the zbdClient SDK client to create a Charge.

You can see that being done in this line: ChargeDetail chargeDetail = await zbdClient.CreateInvoiceAsync(invoiceReq);

We also introduce an invoice handling logic to check whether the Invoice was paid (API returns with status of completed), which allows for changing the UI of the QR code panel once the payment is received.

private async void PayForAGamePlay()
{
Charge charge = new Charge();
charge.Description = gamePlayFeeSats + " sats for ZEBEDEE SDK DEMO GAME";
charge.AmountInSatoshi = int.Parse(gamePlayFeeSats + "");
Debug.Log(zebedeeBaseUrl + " " + apiKey + " " + gamePlayFeeSats);

await zbdClient.CreateChargeAsync(charge, handleInvoice);
}

private async void handleInvoice(ChargeResponse invoice)
{
// 3.Lightning BOLT invoice string
string boltInvoice = invoice.Data.Invoice.Request;
string chargeId = invoice.Data.Id;

if (string.IsNullOrEmpty(boltInvoice))
{
Debug.Log("bolt Invoice is not set in Invoice in reponse.Check the BTCpay server's lightning setup");
return;
}

Texture2D texs = GenerateQR(boltInvoice);//Generate QR code image

// 4.Set the QR code Image to image Gameobject
QRcodeImage.GetComponent<Image>().sprite = Sprite.Create(texs, new Rect(0.0f, 0.0f, texs.width, texs.height), new Vector2(0.5f, 0.5f), 100.0f);

// 5.Subscribe the get notified about payment status
string status = await zbdClient.SubscribeChargeAsync(chargeId);

if ("completed".Equals(status))
{
// Change the image from QR to Paid
QRcodeImage.GetComponent<Image>().sprite = Resources.Load<Sprite>("image/paid");
logger.Debug("payment is complete");
await Task.Delay(2000);
QRCodePanel.SetActive(false);
totalSats += gamePlayFeeSats;
StartCoroutine(LoadSceneAndSetActive(startingSceneName));

// Once the scene is finished loading, start fading in.
StartCoroutine(Fade(0f));
}
else
{
// For example, if the amount paid is not full, do something.the line below just print the status.
logger.Error("payment is not completed:" + status);
}
}

In order to perform a Withdrawal, you will need a similar set of lines of codes but instead of requesting the ZEBEDEE SDK create a payable Charge, you now request for an asynchronous Withdrawal.

public async void DoWithdrawal()
{
QRCodePanel.SetActive(true);

// 1.New Withdrawal Preparation
Withdraw withdraw = new Withdraw();
withdraw.Description = "ZEBEDEE SDK DEMO GAME";
withdraw.AmountInSatoshi = totalSats;

// 2.Create Invoice with initial data and get the full invoice
await zbdClient.WithDrawAsync(withdraw, handleWithdrawal);
}

private async void handleWithdrawal(WithdrawResponse withdraw)
{
string lnURL = withdraw.Data.Invoice.Request;

if (string.IsNullOrEmpty(lnURL))
{
logger.Debug("lnURL is not set in withdrawal response.");
logger.Debug(withdraw.Data.Invoice.Request);
return;
}

QRcodeText.text = "Congrats! Withdraw " + gamePlayFeeSats + " sats";

Texture2D texs = GenerateQR(lnURL);//Generate QR code image

// 4.Set the QR code image to image Gameobject
QRcodeImage.GetComponent<Image>().sprite = Sprite.Create(texs, new Rect(0.0f, 0.0f, texs.width, texs.height), new Vector2(0.5f, 0.5f), 100.0f);

// 5.Subscribe to a callback method with ID to be monitored
string status = await zbdClient.SubscribeWithDrawAsync(withdraw.Data.Id);

if ("completed".Equals(status))
{
// Change the image from QR to Paid
QRcodeImage.GetComponent<Image>().sprite = Resources.Load<Sprite>("image/withdrawn");
logger.Debug("withdraw is success");
}
else
{
// For example, if the amount paid is not full, do something.the line below just print the status.
logger.Error("withdraw is not success:" + status);
}
}

Last but not least, let's make sure our Unity game is able to render the QR code itself. For that we need to create a BarCodeWriter object and let that handle the Invoice/Withdrawal data returned from the ZEBEDEE SDK.

private Texture2D GenerateQR(string text)
{
logger.Debug("generateQR():generating Qr for text: " + text);

var encoded = new Texture2D(350, 350);
var color32 = Encode(text, encoded.width, encoded.height);
encoded.SetPixels32(color32);
encoded.Apply();
return encoded;
}

private static Color32[] Encode(string textForEncoding, int width, int height)
{
var writer = new BarcodeWriter
{
Format = BarcodeFormat.QR_CODE,
Options = new QrCodeEncodingOptions
{
Height = height,
Width = width
}
};

return writer.Write(textForEncoding);
}

Once that's all done let's save the file and return to the main Unity inspector. If you are using the Inspector on the SceneController file, you should now see lots of new fields (familiar public properties we just created).

ItemDetails
API KeyYour API key from Developer Dashboard
ZEBEDEE URLAPI URL for ZEBEDEE Environment
QR Code ImageDrag and drop the QRImage object in Hierarchy
QR Code PanelDrag and drop the QRPanel object in Hierarchy
QR Code TextDrag and drop QRText object in Hierarchy
Gameplay Fee SatsPaywall amount (in satoshis) to play game
Unity Editor | Inspector

Unity Editor | Inspector

alt

Unity Editor | Inspector

Once you have filled in all the values as needed, we can now test your Bitcoin-enabled game.

Testing Paywall Integration

Now that everything's ready to go, let's test the new Paywall integration. Go ahead and press the Play button on the Unity Editor.

It should now show a container with the corresponding Text and QR Codes we created in the code a few steps ago.

Use any of your Bitcoin Lightning Wallets to pay for the Invoice. Once the payment is successful, you will be able to start playing the game.

Job well done! You've now added a very easy and simple monetization aspect to your game.

tip

If for whatever reason you cannot see the QR Code, make sure to check the Unity Editor's Console as you'll find some clues about what's happening.

alt

Testing

Withdrawal Capabilities

Now that we have successfully integrated a Charge, let's go ahead and introduce the Withdrawing mechanism. The ZEBEDEE API and SDK have native support for allowing players to withdraw satoshis directly from the game. Let's go ahead and implement it.

Create a new C# file called LnurlReaction under Asset/Scripts/ScriptableObjects/Interaction/Reactions/ImmediateReactions and use the source code below.

alt

Visual Studio | Withdrawal Code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LnurlReaction : Reaction
{
private SceneController sceneController; // Reference to the SceneController to actually do the loading and unloading of scenes.

protected override void SpecificInit()
{
sceneController = FindObjectOfType<SceneController>();

}

protected override void ImmediateReaction()
{
sceneController.DoWithdrawal();
}
}

The idea is when the player opens the gate, this script will get triggered and the Withdrawal code above will be executed.

After that let's create another C# file called LnurlReactionEditor in /Asset/Scripts/Editor/Interaction/ReactionEditors and let's paste the source code available below:

alt

Visual Studio | Withdrawal Code

using UnityEditor;

[CustomEditor(typeof(LnurlReaction))]
public class LnurlReactionEditor : ReactionEditor
{
protected override string GetFoldoutLabel()
{
return "LNURL Reaction";
}
}

Now let's move onto the SecurityRoom scene. In order to do that choose Hierarchy on the inspector panel and then select BeamsOffReaction under LaserGridInteractable

alt

Visual Studio | Withdrawal Code

On the inspector, select LnurlReaction in the dropdown and click Add Selected Reaction like in the image below.

alt

Visual Studio | Withdrawal Code

You should now be all good to go! Test your new Withdrawal functionality by opening up the Security gate again, and you should see a QR code allowing you to withdraw satoshis.

tip

Remember to select the Persistent Scene first and then hit the Play button

Appendix

The appendix mentioned can be found here: https://gist.github.com/mandelmonkey/72185b076b49097e5def783cb07564a5.

Final Code

And the full source code of the tutorial and any other files for this Unity project can be found here: https://github.com/zebedeeio/unity-sdk-adventure-game-tutorial.