Create In-Game NFT Loot Boxes In Unity

Create In Game NFT Lootboxes in Unity

In this guide, we'll show you how to use the Pack contract to allow users to open randomly selected NFTs as in-game assets. By the end, you'll:

  • Deploy an Edition; a collection of NFTs representing your in-game items.
  • Deploy the Pack contract; a collection of ERC1155 loot box NFTs.
  • Bundle the in-game item NFTs into the packs/loot crates.
  • Randomly select an NFT to be awarded to the user when they open a pack!

Here's a preview of what we'll be building:

Preview of opening pack NFTs
💡
The assets we use in this guide are created by Gabriel Aguiar Prod.
You can use your own assets, or purchase these assets for $10 USD.

Let's get started!

Creating In-Game NFTs

First, we need to create the NFTs our players can receive when they open their loot boxes! Let's use the Edition contract to achieve this.

Head to the Edition page on the dashboard and click Deploy Now:

Click Deploy Now on the thirdweb Edition page

Populate the metadata of your smart contract, like so:

Setup Edition contract metadata

When you're ready, click the Deploy Now button to deploy your contract! We recommend using a test network before deploying to mainnet.

Click Deploy Now

Nice! Our Edition contract is shipped to the blockchain! 🎉

Minting NFTs

Head to the NFTs tab and click the + Mint button to create your in-game items.

Click Mint from the NFTs Tab

As you mint your NFTs, consider the rarity you want each item to have.

For example, I have created two NFTs in my collection:

  1. Red Gem: A common item, with 400 available supply.
  2. Purple Gem: A rare item, with 100 available supply.
Mint NFTs and consider rarity

Assuming we bundle all the NFTs and release 1 NFT per pack, there will be an 80% chance to open a red gem, and a 20% chance to open a purple gem with 500 available loot boxes.

💡
Each pack NFT can contain more than one token; it can store ERC721, ERC1155, and ERC20 tokens too! We're just keeping it simple here.

Now our NFTs are minted, it's time to bundle them into some pack NFTs!

Creating Loot Box NFTs

The Pack contract lets you bundle ERC20, ERC721, and ERC1155 tokens into new ERC1155 NFTs that act as randomized loot boxes.

The packs themselves are also ERC1155 NFTs, with an additional feature that allows you to "open" them. When they are opened, the user receives randomly selected token(s) from those bundled into the packs.

💡
View the Pack Design Document to learn more about packs.

Deploy the Pack Contract

Head to the Pack page on the dashboard and click Deploy Now.

Pack page on thirdweb dashboard

Populate the metadata for your smart contract like so:

Populate the Pack smart contract metadata

Click Deploy Now, ensuring you select the same network as your Edition contract.

Select network to deploy to

Bundling Items Into Packs

To mint our pack NFTs, we need to use the SDK to bundle our item NFTs into newly created pack NFTs!

To get started, clone our template repository by running the following command:

npx thirdweb@latest create --template pack-creation-script

This will set you up with a script and instructions on bundling your NFTs into packs! We'll quickly cover the key elements in this guide.

First, we configure our smart contract addresses, network and private key.

const EDITION_ADDRESS = "<your-edition-smart-contract-address>";
const PACK_ADDRESS = "<your-pack-smart-contract-address>";
const network: ChainOrRpc = "optimism-goerli";
const PRIVATE_KEY = process.env.PRIVATE_KEY!;
const lootBoxImageFileName = "lootbox.png";

We use these values to instantiate the SDK on behalf of our wallet, and then connect to the edition and pack smart contracts:

// Instantiate the SDK with our private key onto the network
const sdk = ThirdwebSDK.fromPrivateKey(PRIVATE_KEY, network);
const storage = new ThirdwebStorage();
// Connect to the edition and pack contracts
const edition = await sdk.getContract(EDITION_ADDRESS, "edition");
const pack = await sdk.getContract(PACK_ADDRESS, "pack");

Once connected, we grant the pack smart contract the approval to bundle our NFTs from the edition contract:

// Set approval for the pack contract to transfer our edition NFTs (items)
await edition.setApprovalForAll(PACK_ADDRESS, true);

Then we call the create function on our pack contract and specify how we want to bundle our tokens into packs:

await pack.create({
  packMetadata: {
    name: "Loot Box",
    description: "Open this to reveal an in-game item!",
    image: await storage.upload(
      readFileSync(`${__dirname}/${lootBoxImageFileName}`)
    ),
    attributes: {
      artist: "@GabrielAguiarProd",
    },
  },
  erc1155Rewards: [
    // Bundle 400 Red Gem NFTs:
    {
      contractAddress: EDITION_ADDRESS,
      tokenId: 0,
      quantityPerReward: 1,
      totalRewards: 400,
    },
    // Bundle 100 Red Gem NFTs:
    {
      contractAddress: EDITION_ADDRESS,
      tokenId: 1,
      quantityPerReward: 1,
      totalRewards: 100,
    },
  ],
  // We specify 1 reward per pack, and there is 400+100 total rewards, so we will have 500 packs created.
  rewardsPerPack: 1,
});

Finally, we run the script and create our packs by running the following command from our terminal:

npx ts-node src/index.ts

Voila! 🎉 We can now see on the dashboard our packs have been created:

500 loot box packs created on dashboard

Opening Packs

We can open packs directly from the Explorer tab using the openPack function:

Call the openPack function from Explorer

But let's integrate this contract into Unity now to make it more interesting!

We recommend following the guide below to set yourself up with our Unity SDK before continuing:

Get Started With thirdweb’s Unity SDK
Learn how to install thirdweb’s Unity SDK into your project, add connect wallet and web3 functionality in C# scripts and build a web3 game.

First, we import Thirdweb into our script so that we can instantiate the SDK:

using Thirdweb;
// ... other imports

public class LootBox : MonoBehaviour
{
    private ThirdwebSDK sdk;
    
    void Start()
    {
        sdk = new ThirdwebSDK("optimism-goerli");
        animator = GetComponent<Animator>();
    }
}

Now our sdk value is instantiated when the game Starts.

We'll want users to connect their wallets, and switch to the correct network whenever they attempt to open a pack. Let's create a simple function to perform and await both of these:

async Task<string> EnsureCorrectWalletState()
{
    string address = await sdk.wallet.Connect();
    await sdk.wallet.SwitchNetwork(420);
    return address;
}

Let's connect to our pack contract so that we can open the packs:

async Task<Pack> GetPackContract()
{
    await EnsureCorrectWalletState();
    return sdk
        .GetContract("0xd8Bd34726814855fB9cFF58fe5372558e3B411Cb")
        .pack;
}

Finally, call the Open function to open a pack from the connected wallet!

async Task<ERC1155Reward> OpenPack()
{
    // Ensure the user is connected and on the correct network
    await EnsureCorrectWalletState();
    // Connect to the pack contract
    Pack packContract = await GetPackContract();
    // Open 1 quantity of pack ID 0
    var result = await packContract.Open("0", "1");
    // Return the NFT that we opened from the pack!
    return result.erc1155Rewards[0];
}

When the user clicks, we call the OpenPack function and kick off the animation:

if (Input.GetMouseButtonDown(0))
{
    var openedPack = await OpenPack();
    // ... Begin pack open animation now!
}

Wrapping Up

That's it! 🎉 Our packs are ready to be opened!

In this guide, we've successfully:

  1. Created in-game item NFTs
  2. Bundled them into a set of loot box NFTs
  3. Opened those loot box NFTs from within a C# in a Unity game!

If you have any questions, jump into our Discord server to speak with our team directly.