Stores - Code

Allow players to purchase items from in-game stores [ECON-Stores-03]

Beamable offers various APIs to allow the game maker to set up purchasing with various configurations. Virtual Currency or real money can be used to purchase items, as well as support for Unity IAP or a variety of third-party or custom purchasers (see Custom Purchaser).

📘

Prerequisites

Before items can be purchased be the user, you must set up at least one valid currency, a store item, and store listing.

Step 1. Initialize Beamable

Before we can perform any transactions, the current player must be logged in and Beamable must be initialized.

private BeamContext _beamContext;
    
private async void Start()
{
    _beamContext = BeamContext.Default;
    await _beamContext.OnReady;
    Debug.Log($"User Id: {_beamContext.PlayerId}");
}

Step 2. Make Purchase

The function to purchase an item is in the CommerceService. The function call requires a Store ID and an Item ID. For ease of use, it is recommended to create a StoreRef and ListingRef, which will create a drop-down in the Inspector to select a valid store and item.

[SerializeField] private StoreRef storeRef;
[SerializeField] private ListingRef listingRef;

private async Task<bool> MakePurchase()
{
    var success = true;
        
  	//Errors are simply logged to the console here,
 	  //but the user should also be notified in the UI or otherwise.
    await _beamContext.Api.CommerceService.Purchase(storeRef.Id, listingRef.Id)
        .Error((error)=>
        {
            Debug.LogError(error);
            success = false;
        });
        
    return success;
}

To validate if the purchase was successful, we can also use the InventoryService to print out the inventory before and after the purchase. See the Inventory feature for more details.

private async Task PurchaseItem()
{
    await PrintInventory();
    var success = await MakePurchase();
    if (success)
    {
        Debug.Log("Purchase was successful!");
    }
    await PrintInventory();
}

private async Task PrintInventory()
{
    var inventory = await _beamContext.Api.InventoryService.GetCurrent();

    foreach (var kvp in inventory.items)
    {
        var inventoryItemName = $"{kvp.Key} x {kvp.Value.Count}";
        Debug.Log(inventoryItemName);
    }
}

Step 3. Run & Test

After creating these functions, assign a store and item.

472

Call the PurchaseItem() function from above and inspect the logs. If necessary, the Portal can be used to grant your user more virtual currency (see Portal - Inventory guide for more details). Here is the console output for a successful purchase:

834

Below is the full script that will attempt a purchase when the MonoBehaviour is enabled.

using System.Threading.Tasks;
using Beamable;
using Beamable.Common.Shop;
using UnityEngine;

public class StoreTest : MonoBehaviour
{
    [SerializeField]
    private StoreRef storeRef;

    [SerializeField]
    private ListingRef listingRef;

    private BeamContext _beamContext;

    private async void Start()
    {
        _beamContext = BeamContext.Default;
        await _beamContext.OnReady;

        Debug.Log($"User Id: {_beamContext.PlayerId}");

        await PurchaseItem();
    }

    private async Task PurchaseItem()
    {
        await PrintInventory();
        var success = await MakePurchase();
        if (success)
        {
            Debug.Log("Purchase was successful!");
        }
        await PrintInventory();
    }

    private async Task<bool> MakePurchase()
    {
        var success = true;
        
        await _beamContext.Api.CommerceService.Purchase(storeRef.Id, listingRef.Id)
            .Error((error)=>
            {
                Debug.LogError(error);
                success = false;
            });
        
        return success;
    }

    private async Task PrintInventory()
    {
        var inventory = await _beamContext.Api.InventoryService.GetCurrent();

        foreach (var kvp in inventory.items)
        {
            var inventoryItemName = $"{kvp.Key} x {kvp.Value.Count}";
            Debug.Log(inventoryItemName);
        }
    }
}