> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sequence.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Jelly Forest 入門 - Unity ゲームガイド

> Jelly Forest 入門 - Unity ゲームガイドでは、ソーシャルサインインやアップグレード、コスメティックアイテムなどのブロックチェーン機能を備え、これらのアイテムがすべてスマートコントラクトウォレットに保存される2Dランナーゲームを紹介します。

Jelly Forest はブロックチェーン対応の2Dランナーゲームです。ゲームにはソーシャルサインイン、複数段階のアップグレード（上位のアップグレードには下位のアップグレードを材料として使用）、コスメティックアップグレードがあり、すべてが組み込み型のノンカストディアルスマートコントラクトウォレットに保存されます。プレイヤーに対してトランザクション署名のポップアップやガス代の支払いは発生しません。

<Frame>
  <video controls className="w-full aspect-video" src="https://pub-f048362b915448c9b012a2e03c189024.r2.dev/JellyForest.mp4" />
</Frame>

Google Play から[こちら](https://play.google.com/store/apps/details?id=app.sequence.jelly_forest)でダウンロードできます！

[スマートコントラクトウォレットについてはこちら](/solutions/technical-references/smart-contract-wallets) をご覧ください。

[埋め込み型ウォレットについてはこちら](/solutions/wallets/developers/embedded-wallet/overview) をご参照ください。

このガイドでは、Jelly Forest をどのように開発したか、そして[Sequence の Unity SDK](/sdk/unity/overview/)を使ってご自身の web3 ゲームを作る方法を解説します！

## 1. ゲームループを作成する

最初のステップは基本的なゲームループの構築です。まずはマネタイズ戦略や、どのように web3 要素を活用するかも考えておきましょう！

ゲームループには、Unity Asset Store で [Infinite Runner Engine](https://assetstore.unity.com/packages/templates/systems/2d-3d-infinite-runner-engine-51328) を購入しました。このアセット内のデモシーン `JellyForest` を少し調整することで、iOS と Android で動作するビルドを作成できました。

## 2. ソーシャルサインインと Sequence の Embedded Wallet ソリューションを統合する

### 設定

1. [Package Manager を使って Sequence の Unity SDK をインストールする](/sdk/unity/installation#package-manager---recommended)
2. [Sequence Builder Console にサインインする](/solutions/builder/getting-started)
3. [Builder Consoleでゲーム用プロジェクトを作成する](/solutions/builder/project-management)
4. [Builder Console で Embedded Wallet をセットアップする](/solutions/builder/embedded-wallet#embedded-wallet-in-builder)
5. `SequenceConfig` [スクリプタブルオブジェクト](https://docs.unity3d.com/Manual/class-ScriptableObject.html)（インストール時に Package Manager の Samples メニューからインポート）に、Builder で追加した Google および Apple のクライアントIDと、`WaaSConfigKey` に設定キーを入力してください。
   * Android と iOS のクライアントIDは、それぞれのプラットフォームに正しく設定するのを忘れずに！
6. [Builder Console から取得した Builder API キー](/solutions/builder/getting-started#claim-an-api-access-key) を `Settings > API Access Keys` の `prod` キーに入力してください。

### ソーシャルサインイン

1. プレイヤーがログインするための基本的なシーンを作成しましょう。
   * 私たちは[新しいシーンを作成](https://docs.unity3d.com/Manual/scenes-working-with.html#creating-a-new-scene)し、背景画像を追加しました。
2. `Canvas` を作成し、`Canvas Scaler` コンポーネントを追加して「Scale with Screen Size」UIスケールモードを使用します。これにより、LoginPanel や他の UI 要素がビルドターゲットを切り替えても自動的にスケーリングされます。
3. `LoginPanel` プレハブを Canvas の下にシーン階層へドラッグします。これは Project ウィンドウの `Packages > Sequence Embedded Wallet SDK > SequenceFrontend > Prefabs` にあります。
4. UI マネージャーを作成し、`LoginPanel` の `Open` を呼び出せるようにします。[実装例はこちら](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/UI/LoginScreenUIManager.cs)：

```csharp theme={null}
private void Start()
{
    LoginPanel loginPanel = GetComponentInChildren<LoginPanel>();
    if (loginPanel == null)
    {
        Debug.LogError("LoginPanel not found!");
    }
    loginPanel.Open();
}
```

5. 階層内で `LoginPanel` プレハブとの参照を切り離し、シーンビューで自由に編集できるようにします。
   1. 階層内で `LoginPanel` ゲームオブジェクトを選択します。
   2. 階層内で `LoginPanel` ゲームオブジェクトを右クリックします。
   3. `Prefab > Unpack Completely` を選択します。
6. LoginPanel をゲームのテーマに合わせてカスタマイズしましょう。

LoginPanelは、すべてのソーシャルサインインのロジックを自動で処理します。実装方法に興味がある場合は、`LoginPage`や`OpenIdAuthenticator`の実装を確認できます。
認証は[Open ID Connect Implicit Flow](https://auth0.com/docs/authenticate/login/oidc-conformant-authentication/oidc-adoption-implicit-flow)を利用しています。

### Sequence API でセッションを登録する

ソーシャルサインインが完了すると、自動的に Sequence WaaS（Wallet as a Service）API へセッション登録リクエストが送信されます。仕組みは以下の通りです：

ソーシャルサインインが完了すると、`OpenIdAuthenticator.SignedIn` イベントが発火します。これにより `SequenceLogin.ConnectToWaaS` で認可プロセスが始まります。

### ユーザーのウォレットを取得する

ウォレットを取得するには、`SequenceWallet.OnWalletCreated` イベントに購読する必要があります。

```csharp theme={null}
SequenceWallet.OnWalletCreated += OnWalletCreatedHandler;
public void OnWalletCreatedHandler(SequenceWallet wallet) {
  // Do something
}
```

「Sequence Embedded Wallet SDK」の Package Manager ページの Samples から「Useful Scripts」経由で `SequenceConnector` をインポートすることを強くおすすめします。[初期コードが多数含まれており](https://github.com/0xsequence/sequence-unity/blob/master/Packages/Sequence-Unity/Sequence/Samples~/Scripts/SequenceConnector.cs)、SDK とのやりとりに便利なインターフェースとして機能します。JellyForest でも[このコードを多用しました](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/SequenceConnector.cs)。

JellyForest では、`SequenceWallet.OnWalletCreated` イベントが発火した際に次のシーンを読み込む [LevelLoader](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/LevelLoader.cs) MonoBehaviour も作成しました。

```csharp theme={null}
private void Awake()
{
    SequenceWallet.OnWalletCreated += OnWalletCreated;
}

private void OnWalletCreated(SequenceWallet wallet)
{
    SceneManager.LoadScene("MenuScene");
}
```

Sequence Embedded Wallet ソリューションの認証の仕組みについては、[ドキュメント](/solutions/wallets/developers/embedded-wallet/overview) および [ブログ記事](https://sequence.xyz/blog/sequence-embedded-wallets) をご覧ください。

## 3. コレクティブルコントラクトをデプロイする

プレイヤーがサインインしてウォレットを持てるようになったので、コレクティブルを追加しましょう！

[ERC1155](https://eips.ethereum.org/EIPS/eip-1155) コントラクトの利用を強くおすすめします。ゲームに最適な柔軟なトークン規格です。Builder Console から監査済みの ERC1155 実装を簡単にデプロイできます：

<Frame>
  <video controls className="w-full aspect-video" src="https://mintcdn.com/sequence-0fb8d9e6/lxUnT9Alj4nXyzbb/video/builder/03_Contracts.mp4?fit=max&auto=format&n=lxUnT9Alj4nXyzbb&q=85&s=b6bffdeb6c09ea73f11d60ff9457b1e6" data-path="video/builder/03_Contracts.mp4" />
</Frame>

Jelly Forest でもこの方法を採用しました。

スマートコントラクトをデプロイしたら、忘れずにBuilder Consoleの[「Gas Sponsoring」ページ](/solutions/builder/gas-sponsorship#gas-sponsorship-in-builder)で、コントラクトアドレスをSponsored Addressとして追加してください。これにより、ユーザーがゲームのスマートコントラクトとやり取りする際、あなたのコンピュートクレジットを使って自動的にガス代がスポンサーされます。

## 4. リモートミンターをデプロイする

Builder Console でデプロイした ERC1155 コントラクトは、デフォルトでトークンをミントするための権限が必要です。一見面倒に思えるかもしれませんが、これはとても重要です！これがなければ、誰でもコントラクトの mint メソッドを呼び出して無限にゲーム内アイテムを手に入れることができてしまいます。

Sequence ウォレット（または他のウォレット）を持つサーバーをデプロイし、Builder でミント権限を付与しましょう。

### Jelly Forest での実装例

Jelly Forest では、ゲームプレイ中に集めたコインがすべて ERC1155 トークンとしてミントされます。実装方法は以下の通りです：

1. [Cloudflare](https://www.cloudflare.com/) に登録します（ミントサービスのコードをホストするためですが、他の方法でも構いません）
2. ターミナルやコマンドラインを開きます
3. `git clone https://github.com/0xsequence-demos/cloudflare-worker-sequence-relayer.git` を実行し、続いて `cd cloudflare-worker-sequence-relayer`
4. `git checkout permissionedMinter`
5. `pnpm install` で依存関係をインストールします
6. wrangler をインストールします

```
pnpm install wrangler --save-dev
alias wrangler='./node_modules/.bin/wrangler'
```

そしてログインします

```
wrangler login
```

7. `wrangler.toml` を開きます
   1. `name` の文字列を変更してサーバー名を設定します
   2. 新しい[EOAウォレット](https://ethereum.stackexchange.com/questions/5828/what-is-an-eoa-account)を作成し、秘密鍵をエクスポートします。どのEOAウォレットでも構いません。Metamaskを使えば簡単に[ウォレットのセットアップ](https://support.metamask.io/hc/en-us/articles/360015489531-Getting-started-with-MetaMask)や[秘密鍵のエクスポート](https://support.metamask.io/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key)ができます。秘密鍵の取り扱いには十分ご注意ください。パソコンに平文で保存したり、バージョン管理にコミットしたりしないでください！この秘密鍵を`PKEY`に設定します。
   3. `CONTRACT_ADDRESS`を設定します。
   4. `PROJECT_ACCESS_KEY`を設定します。これは、先ほどBuilder Consoleで`SequenceConfig`スクリプタブルオブジェクトをセットアップした際に取得した本番用APIキーです。
   5. `CHAIN_HANDLE`を設定します。これが何かわからない場合は、Builder ConsoleのNode Gatewayページで各ネットワークの`CHAIN_HANDLE`を確認できます。
8. `pnpm dev` - これでサーバーがローカルにデプロイされます。どのlocalhostでデプロイされたかはコマンドラインに表示されます。
9. 別のコマンドラインウィンドウを開きます。
10. `curl http://localhost:8787` - 表示されたlocalhostに置き換えてください。これでサーバーにリクエストを送ります。
11. ローカルサーバーが動作しているコマンドライン上で、ミンターのウォレットアドレスがログに表示されるはずです。
12. このアドレスにBuilder Consoleでミント権限を付与します。
    1. `Contracts`から該当するコントラクトを探し、クリックして開きます。
    2. `Write Contract`をクリックします。
    3. `grantRole`を展開します。
    4. `role`には`0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6`を入力します。これは`MINTER_ROLE`のKeccak-256ハッシュ値です。
    5. `account`にはミンターのウォレットアドレスを貼り付けます。
13. `wrangler deploy` - これで[Cloudflare Worker](https://developers.cloudflare.com/workers/)にコードがデプロイされ、ミント用のURLが発行されます。

これで準備完了です！サーバーにPOSTリクエストを送るときは、[C#で定義された](https://github.com/0xsequence/sequence-unity/blob/master/Packages/Sequence-Unity/Sequence/SequenceSDK/Relayer/MintingRequestProver.cs#L103)ボディを使います。`proof`はミントリクエストを送るクライアント側で生成されます。Unity SDKでは、[MintingRequestProver](https://github.com/0xsequence/sequence-unity/blob/master/Packages/Sequence-Unity/Sequence/SequenceSDK/Relayer/MintingRequestProver.cs#L27)によって実装されています。

## 5. ゲーム内トークンをプレイヤーのインベントリにミントする

パーミッション付きミンターサーバーのセットアップが完了したので、クライアント側（Made With Unityアプリ）を連携させ、プレイヤーにゲームプレイを通じてトークンを付与できるようにします。Unity SDKの`PermissionedMinter.MintToken`メソッドを呼び出すことで、パーミッション付きミンターにリクエストを送信できます。

Jelly Forestでは、プレイヤーがレベルを進むごとに多くのコインを集めます。これらはすべてERC1155トークンです。プレイヤーに快適なUXを提供するために、まだ解決すべき課題がいくつかあります。

1. ユーザーのインベントリにどのトークンや権利があるかを、どのようにチェーンから読み取るのでしょうか？
2. ブロックチェーンのトランザクションは、Arbitrumのような一部のチェーンでは高速ですが、即時ではありません。コイン（または他のアイテム）を集めてから、ゲーム内のインベントリに反映されるまで数秒待つ必要があるのは、一般的に良いユーザー体験とは言えません。
3. 一見すると、ユーザーがゲーム内でトークンを獲得するたびにトランザクションを送信したくなるかもしれません。しかし、特にJelly Forestのように大量のコイン（トークン）を集めるゲームでは、膨大な数のトランザクションが発生し、[ガス代](https://ethereum.org/en/developers/docs/gas/)が非常に高額になってしまいます！

それでは、Jelly ForestでUnity SDKを使ってこれらの課題をどのように解決したか見ていきましょう！

### 1. チェーンの読み取り

特定ユーザーのウォレット内のトークンを読み取る処理は複雑ですが、[Sequenceのインデクサー](/api-references/indexer/overview)を利用することで大幅に簡単になります。これは[Unity SDKでも実装されています](/sdk/unity/indexer/read-from-blockchain)。

こちらはJelly Forestで、Indexerを使ってプレイヤーのウォレットからゲームのERC1155コントラクト内の全トークンを読み取るコード例です。

```csharp theme={null}
private Dictionary<BigInteger, TokenBalance> _tokenBalances = new Dictionary<BigInteger, TokenBalance>();
private async Task GetTokenBalances(Page page = null)
{
    if (page == null)
    {
        page = new Page();
    }
    GetTokenBalancesReturn balances = await _indexer.GetTokenBalances(new GetTokenBalancesArgs(_userAddress, SequenceConnector.ContractAddress, false, page));
    int uniqueTokens = balances.balances.Length;
    for (int i = 0; i < uniqueTokens; i++)
    {
        _tokenBalances[balances.balances[i].tokenID] = balances.balances[i];
    }
    if (balances.page.more)
    {
        await GetTokenBalances(balances.page);
    }
}
```

### 2. キャッシュの構築

ブロックチェーンのトランザクションは即時反映されませんが、ユーザーには即時のフィードバックを提供したいので、シンプルなインメモリキャッシュを活用します。

Jelly Forestで最初に`SequenceWallet`を受け取った際、[SequenceConnector](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/SequenceConnector.cs)（ゲーム内でSequence SDKとやり取りする主なインターフェース）が`Inventory`を作成します。

```csharp theme={null}
private void OnWalletCreated(SequenceWallet wallet)
{
    Wallet = wallet;
    Wallet.OnSendTransactionComplete += OnSendTransactionCompleteHandler;
    Wallet.OnSendTransactionFailed += OnSendTransactionFailedHandler;
    Wallet.OnSignMessageComplete += OnSignMessageCompleteHandler;
    Wallet.OnDeployContractComplete += OnDeployContractCompleteHandler;
    Wallet.OnDeployContractFailed += OnDeployContractFailedHandler;
    Wallet.OnDropSessionComplete += OnDropSessionCompleteHandler;
    Wallet.OnSessionsFound += OnSessionsFoundHandler;

    Inventory = new Inventory(Indexer, Wallet.GetWalletAddress(), ItemCatalogue); // [!code focus]

    _transactionQueuer.Setup(Wallet, Chain);
    _permissionedMinterTransactionQueuer.Setup(Wallet, Chain, "https://sequence-relayer-jelly-forest2.0xsequence.workers.dev/", ContractAddress);
}
```

この`Inventory`は、ゲーム内でシンプルなキャッシュとして使われます。作成時や必要に応じて、Indexerを使ってユーザーのウォレット内トークンを取得します。その後、ユーザーがトークンを獲得するたびにキャッシュ（`Inventory`）とオンチェーンデータを更新します。

`Inventory`の全実装は[こちらでご覧いただけます](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/Inventory.cs)

### 3. トランザクションキューの活用

SequenceのUnity SDKには、とても柔軟な[トランザクションキューイングシステム](https://github.com/0xsequence/sequence-unity/blob/master/Packages/Sequence-Unity/Sequence/SequenceSDK/Relayer/TransactionQueuer.cs)が用意されています。

Jelly Forestでは、[PermissionedMinterTransactionQueuer](https://github.com/0xsequence/sequence-unity/blob/master/Packages/Sequence-Unity/Sequence/SequenceSDK/Relayer/PermissionedMinterTransactionQueuer.cs)のMonoBehaviourを`SequenceConnector`のGameObjectにアタッチし、[Awakeで参照を取得しています](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/SequenceConnector.cs#L59)。

<img src="https://mintcdn.com/sequence-0fb8d9e6/EO81tWzeFuHvYzqy/images/guides/making-of-jelly-forest/TransactionQueuer.png?fit=max&auto=format&n=EO81tWzeFuHvYzqy&q=85&s=592fc54a17b51a2d3169b0b7d1a5517e" alt="PermissionedMinterTransactionQueuer" width="1038" height="667" data-path="images/guides/making-of-jelly-forest/TransactionQueuer.png" />

[この設定が完了したら](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/SequenceConnector.cs#L78)、トークンを集めたときに「ミントトークン」を呼び出すだけです。

```csharp theme={null}
public class CollectibleToken : Coin
{
    protected override void ObjectPicked()
    {
        base.ObjectPicked();
        if (SequenceConnector.Instance == null || SequenceConnector.Instance.Wallet == null)
        {
            Debug.LogWarning("No minting will happen. Make sure SequenceConnector is in the scene and user is logged in.");
            return;
        }
        SequenceConnector.Instance.MintFungibleToken(); // [!code focus]
    }
}
```

これにより`Inventory`が更新され、ミントトランザクションが`PermissionedMinterTransactionQueuer`のキューに追加されます。`PermissionedMinterTransactionQueuer`は、可能な限りトランザクションを自動的にまとめて、ガス代を最小限に抑えます。

Jelly Forestでは、プレイヤーがゲームオーバーになるたび、ただし、30秒未満の間隔では送信されないように設定しています。

#### どのくらいの頻度でトランザクションを送信するべきでしょうか？

Unity SDKを使えば、これは技術的な問題というよりゲームデザインの問題になります。

`TransactionQueuers`は、X秒ごとに自動で送信、関数呼び出しで促されたときに送信（ただしY秒未満では送信しない）、または促されたときに最小間隔（Y秒）を無視して即時送信、など柔軟に設定できます。

トランザクションキューアの設定を決める際に考慮すべきポイントをいくつか挙げます：

* トランザクション送信頻度が高いほど、ガス代も多くかかります。もちろん、選択するEVM互換ブロックチェーンによって、コストが許容範囲かどうかや送信できるトランザクション数・複雑さは大きく変わります。
* トランザクション送信頻度が低いほど、ゲーム内の状態（キャッシュ）とオンチェーン情報のズレが大きくなります。もしトランザクションが失敗した場合、プレイヤー体験を損なわずに復旧する方法が必要です。

Jelly Forestの例では、ショップでのトランザクションはユーザーにとって非常に重要だと考えました。ユーザーがアップグレードや帽子を手に入れたと思っても、トランザクションが失敗して取り消す必要が出たり、正当に獲得していないアイテムを余分にミントする事態は避けたいと考えました。そのため、ショップページでは購入トランザクション（およびTransactionQueuers内の全トランザクション）が完了するまでユーザーに待ってもらう仕様にしました。

```csharp theme={null}
public async Task Buy()
{
    if (Status != ItemStatus.Available)
    {
        return;
    }

    if (SequenceConnector.Instance == null)
    {
        string error = "SequenceConnector not found. User has not logged in";
        Debug.LogError($"Failed to purchase shop item: {error}");
        OnFailedToPurchaseShopItem?.Invoke($"Failed to purchase shop item: {error}");
        return;

    SequenceConnector.Instance.AddToTransactionQueue(new PurchaseShopItemQueueableTransaction(this));
    TransactionReturn result = await SequenceConnector.Instance.SubmitQueuedTransactions(true, false); // [!code hl]
    if (result is SuccessfulTransactionReturn successfulTransactionReturn)
    {
        BurnTokensFromInventory();
        MintTokenInInventory()
        if (string.IsNullOrWhiteSpace(successfulTransactionReturn.txHash))
        {
            GetTransactionReceipt(successfulTransactionReturn);
        }
    }
    else if (result is FailedTransactionReturn failed)
    {
        string error = $"Transaction failed: {failed.error}";
        Debug.LogError(error);
        OnFailedToPurchaseShopItem?.Invoke($"Failed to purchase shop item: {error}");
    }
    else
    {
        throw new Exception("Unexpected transaction result type");
    }
}
```

## 6. ゲーム内トークンを他のトークンと交換してバーンする

Jelly Forestでは、コインや（場合によっては）下位のパワーアップをバーンすることで、パワーアップやコスメティックアイテムを購入できます。

この仕組みを有効化し、強制するために、シンプルな[BurnToMintスマートコントラクト](https://polygonscan.com/address/0x80329e7f4F006E3178Db369425329759157B5a2a#code)をデプロイしました。このコントラクトでは、特定のトークンIDに対してミント要件（必要なトークンIDとその数量）を指定できます。ERC1155トークンのバッチを受け取り、送信者が`data`パラメータでミントしたいトークンIDを指定すると、コントラクトは各トークンIDの必要数を受け取ったかどうかを確認します。条件を満たしていれば、コントラクトはトークンをバーンし、指定されたトークンIDを送信者（ユーザー）にミントします。条件を満たさない場合は、トランザクションが失敗し、ロールバックされます。

このコントラクトには、Builder Consoleでゲームコントラクトのミント権限を付与しています。

1. `Contracts`から該当するコントラクトを探し、クリックして開きます。
2. `Write Contract`をクリックします。
3. `grantRole`を展開します。
4. `role`には`0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6`を入力します。これは`MINTER_ROLE`のKeccak-256ハッシュ値です。
5. `account`にはミンターのウォレットアドレスを貼り付けます。

:::danger
警告：上記で紹介した`BurnToMint`スマートコントラクトは、第三者による監査を受けていません。再利用の際は十分ご注意ください。
:::

ユーザーがショップでアップグレードやコスメティックアイテムを購入すると、[PurchaseShopItemQueueableTransaction](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/Items/ShopItem.cs#L109)を`SequenceConnector`内の[SequenceWalletTransactionQueuer](https://github.com/0xsequence/sequence-unity/blob/master/Packages/Sequence-Unity/Sequence/SequenceSDK/Relayer/SequenceWalletTransactionQueuer.cs)に追加し、`BurnToMint`スマートコントラクトへトランザクションを送信します。

```csharp theme={null}
SequenceConnector.Instance.AddToTransactionQueue(new PurchaseShopItemQueueableTransaction(this));
```

## 7. ショップページの構築とミント要件の設定

Jelly Forestのショップページを作成し、各アップグレードや帽子の価格・ミント要件を設定する際、[Scriptable Objects](https://docs.unity3d.com/Manual/class-ScriptableObject.html)を使って[ShopItems](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/Items/ShopItem.cs)を定義することにしました。これにより、Inspectorでシリアライズできるため、調整や可視化が簡単です。また、これらのScriptable Objectを使って、各[Item](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/Items/Item.cs)の内容やトークンIDとの紐付けも行っています。

しかし、Scriptable Objectで定義したミント要件と、オンチェーンの`BurnToMint`コントラクトで定義したミント要件を同期させるのは手間がかかり、バグの原因にもなりやすいことが分かりました。

そこで、`ShopItem`のScriptable Object用に[エディタ拡張](https://learn.unity.com/tutorial/editor-scripting)を作成し、ボタンを追加しました。このボタンを押すと、オンチェーンで定義されているミント要件とScriptable Objectの内容が一致しているかを確認し、異なっていればScriptable Objectに合わせて`BurnToMint`コントラクトのミント要件を更新するトランザクションを送信します。トランザクションは、開発者のマシンに環境変数として保存された秘密鍵から作成されたEOAウォレットを使って送信されます。このEOAウォレットは、このコントラクトの[オーナー](https://docs.openzeppelin.com/contracts/2.x/access-control#ownership-and-ownable)です。

実際、ショップページは60秒ごと（およびページを開くたび）にスマートコントラクトへミント要件の変更を問い合わせ、UIを自動で更新しています。これにより、ゲームの経済バランスをアップデートなしでリアルタイムに調整できます！

下の動画をクリックしてください

<Frame>
  <video controls className="w-full aspect-video" src="https://pub-f048362b915448c9b012a2e03c189024.r2.dev/ShopItemExtension.mp4" />
</Frame>

[ShopItemEditorExtensionの実装はこちら](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/Editor/ShopItemEditorExtension.cs)をご覧ください。

# 8. 購入したアイテムをゲーム内で活用する

これで、プレイヤーはログインしてウォレットを取得し、トークンを獲得し、そのトークンでアイテムを購入できるようになりました。あとは、プレイヤーがアイテムを欲しくなる理由を作るだけです。つまり、ここからはゲーム開発者としての腕の見せ所です。魅力的なパワーアップやコスメティックを作りましょう！

ゲーム内でトークンを活用するには、ユーザーが指定したトークンIDを十分に所有しているかを確認し、そのトークンの効果を適用するだけです。

Jelly Forestでは、いくつかの[PowerUpTypes](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/Items/ItemCatalogue.cs#L13)を定義し、各`Item`に`PowerUpType`とティアを割り当てています。そして、[プレイヤーが所有する各タイプの最強パワーアップを`Inventory`から検索](https://github.com/0xsequence/sequence-unity-demo/blob/JellyForest/Scripts/Inventory.cs#L138)する仕組みを作っています。
