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

# クラフト ゲーム パート 3 - コーディング

> PlayFab Economy V2 クラフト ゲーム チュートリアルのパート 3: Economy V2 API を呼び出してインベントリ、レシピ、クラフト アイテムを管理する C# コードを記述します。

# パート 3 - コーディング + 例

環境が準備でき、Game Manager に慣れたので、ゲームのコーディングを開始できます。

## 前提条件

1. [パート 1 - 環境のセットアップ](/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-environment)
2. [パート 2 - Game Manager の使用](/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-game-manager)

## ステップ 1 - 環境設定を構成する

コーディングを開始する際に最初にお勧めするのは、環境設定を構成することです。これにより、行うすべての呼び出しに、タイトルへのリンクと特定の Developer Secret Key が使用されることが保証されます。

このステップを済ませるには、コード内のどこか (見つけやすい場所が望ましい) で TitleId と DeveloperSecretKey 変数を指定し、そこに値を割り当てます。

これを行うには、次のように 2 行のコードを別々に追加します。

```csharp theme={null}
PlayFabSettings.staticSettings.TitleId = "{Your Title ID}";
PlayFabSettings.staticSettings.DeveloperSecretKey = "{Your Developer Secret Key}";
```

## ステップ 2 - 認証を受ける

環境がセットアップされ、PlayFab NuGet パッケージがプロジェクトにインストールされて構成され、スタジオとタイトルの両方が作成されたら、認証のコーディングを開始できます。

<Note>
  ユーザーが認証を受ける方法はいくつかあります。この例では、**LoginWithCustomId** メソッドを使用します。プラットフォーム固有のものを含む、他の認証方法もあります。詳細については、[ログインの基本](/services/playfab/identity/player-identity/login/login-basics-best-practices) を参照してください。
</Note>

以下は、匿名サインインとして分類される **LoginWithCustomID** を使用してユーザーを認証する C# のサンプル コードです。認証のために API を呼び出す前に、サインイン プロセスの一部として生成される **EntityKey** を格納するグローバル変数を宣言する必要があります。

**EntityKey** は API へのあらゆる呼び出しに使用され、ログインしているユーザーにすべてのリクエストとレスポンスをリンクするものです。

グローバル EntityKey 変数の宣言は次のとおりです。

```csharp theme={null}
private static PlayFab.ClientModels.EntityKey entityKey;
```

***

次に、ユーザーを認証するためのロジックは次のとおりです。

### C# SDK

```csharp theme={null}
var request = new LoginWithCustomIDRequest { CustomId = username };
var loginTask = PlayFabClientAPI.LoginWithCustomIDAsync(request);
entityKey = loginTask.Result.Result.EntityToken.Entity;
```

### API

```json theme={null}
{
  "CustomId": "{{Username}}",
  "CreateAccount": false,
  "TitleId": "{{TitleId}}"
}
```

***

上記のコードは、ゲーム タイトルにリンクされた既存のプレイヤーを検索します。ただし、一致するユーザー名を持つユーザーがいない場合は失敗します。これを回避するには、リクエストのボディに "CreateAccount = true" パラメーターを追加できます。これにより、ユーザー名として送信された値に一致するプレイヤーがいない場合、PlayFab は新しいプレイヤーを作成します。これにより、コードは次のようになります。

### C# SDK

```csharp theme={null}
var request = new LoginWithCustomIDRequest { CustomId = username, CreateAccount = true };
var loginTask = PlayFabClientAPI.LoginWithCustomIDAsync(request);
entityKey = loginTask.Result.Result.EntityToken.Entity;
```

### API

```json theme={null}
{
  "CustomId": "{{Username}}",
  "CreateAccount": true,
  "TitleId": "{{TitleId}}"
}
```

***

サインインが成功すると、API は **SessionTicket**、ユーザーの **PlayFab ID**、**EntityToken** など、いくつかのデータ セットを返します。これらは、以下に詳しく示す API からの直接のレスポンスで確認できます。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "SessionTicket": "{{SessionTicket}}",
        "PlayFabId": "{{PlayFabID}}",
        "NewlyCreated": false,
        "SettingsForUser": {
            "NeedsAttribution": false,
            "GatherDeviceInfo": true,
            "GatherFocusInfo": true
        },
        "LastLoginTime": "2023-08-01T17:09:54.508Z",
        "EntityToken": {
            "EntityToken": "{{EntityToken}}",
            "TokenExpiration": "2023-08-04T21:20:35Z",
            "Entity": {
                "Id": "{{Player ID}}",
                "Type": "title_player_account",
                "TypeString": "title_player_account"
            }
        },
        "TreatmentAssignment": {
            "Variants": [],
            "Variables": []
        }
    }
}
```

***

API から `"code":200` が返されるか、上記の C# の例の `loginTask` に情報が含まれるようになったら、認証されて次のステップに進む準備ができています。

## ステップ 3 - 開始インベントリをセットアップする

有効なプレイヤーでログインしたら (または新しいプレイヤーを作成したら)、最初のステップはそのプレイヤーの開始インベントリを設定することです。これには、[ExecuteInventoryOperations](https://learn.microsoft.com/en-us/rest/api/playfab/economy/inventory/execute-inventory-operations) API 呼び出しを使用します。

<Note>
  ExecuteInventoryOperations 呼び出しでは、プレイヤーのインベントリに対して複数/バッチの [InventoryOperations](https://learn.microsoft.com/en-us/rest/api/playfab/economy/inventory/execute-inventory-operations) を実行できます。サポートされる操作のタイプは次のとおりです: - Add - Delete - Purchase - Subtract - Transfer - Update
</Note>

この例では、ゲームに対応するアイテムを追加します。3 個の Stone、1 個の Cream、1 個の Gold です (これは他のアイテムを作成していることが前提です。まだの場合は、続行する前に作成してください)。ただし、単に **Add** 操作を使用するのではなく、**Purchase** 操作を使用し、必要なインスタンスを無料で購入します。

<Note>
  このステップが機能するには、まず Game Manager でタイトル内にアイテムを作成しておく必要があります。
</Note>

以下のスニペットは、C# と PlayFab の API の両方でこれらの呼び出しをまとめて行う方法を示しています。

### C# SDK

この C# の例では、purchasePrice をすべての取引の標準値として設定していることがわかります。これは、すべてが 0 の価格を持つようにするためです。

1 つのアイテムに複数の価格を設定できるため、`purchasePrice` 変数は `List<PurchasePriceAmount>` 型です。

次に気付くのは、リクエストは `InventoryOperation` のリストに加えて Entity を受け取ることです。これには、先ほどのサインインから取得した値を使って新しいエンティティを作成します。

最後に、各 `InventoryOperation` は `Purchase` 値を取ります。ただし、これは **ExecuteInventoryOperations** 呼び出しで利用可能な各 (Add、Delete、Purchase、Subtract、Transfer、Update) にすることもできます。この場合は `Purchase` 識別子を使用するため、`new PurchaseInventoryItemsOperation` が必要です。

購入したいアイテムが何であるかを明確にする必要もあります。これは、アイテムの ID を唯一のパラメーターとして受け取る `InventoryItemReference` を使って行います。

私たちのコードには **SearchItem({itemName})** というメソッドがありますが、これはアイテムの ID を表す文字列に簡単に置き換えることができます。各アイテムの名前 (または ID) を対応する数量と一致させることを確認してください。

```csharp theme={null}
var purchasePrice = new List<PurchasePriceAmount> { new PurchasePriceAmount { ItemId = freeItemId, Amount = 0 } };
var request = new ExecuteInventoryOperationsRequest 
{ 
    Entity = new PlayFab.EconomyModels.EntityKey { Id = entityKey.Id, Type = entityKey.Type },
    Operations = new List<InventoryOperation> {
        new InventoryOperation
        {
            Purchase = new PurchaseInventoryItemsOperation { 
                Item = new InventoryItemReference {AlternateId = new AlternateId { Type = "FriendlyId", Value = "Stone" } }, 
                Amount = 3, 
                PriceAmounts = purchasePrice
            }
        },
        new InventoryOperation
        {
            Purchase = new PurchaseInventoryItemsOperation {
                Item = new InventoryItemReference { AlternateId = new AlternateId { Type = "FriendlyId", Value = "Gold" } },
                Amount = 1,
                PriceAmounts = purchasePrice
            }
        },``
        new InventoryOperation
        {
            Purchase = new PurchaseInventoryItemsOperation {
                Item = new InventoryItemReference {AlternateId = new AlternateId { Type = "FriendlyId", Value = "Cream" }},
                Amount = 1,
                PriceAmounts = purchasePrice
            }
        }
    }
};
await PlayFabEconomyAPI.ExecuteInventoryOperationsAsync(request);
```

上記のコードで `AlternateId` と `FriendlyId` を正常に使用するには、アイテムに Game Manager でそれらの値が構成されている必要があります。これを行うには、詳細な手順を説明している [パート 2 - Game Manager の使用](/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-game-manager) を確認することをお勧めします。

### API

以下に示すリクエスト本文で **ExecuteInventoryOperations** API エンドポイントを呼び出します。ID を対応するものに置き換えてください。`Operations` は配列であり、複数のタイプの操作を同時に含めることができます。

行う各 API 呼び出しに対して、アクティブなセッションまたはログインしているユーザーに固有の **EntityToken** を含む `X-EntityToken` ヘッダーを設定する必要があることを理解することが重要です。つまり、API 呼び出しを行う前に、まず (この例では) **LoginWithCustomID** を呼び出し、戻りメッセージからすべての API 呼び出しでヘッダーとして使用する **EntityToken** を取得します。

```json theme={null}
{
  "Operations": [
    {
      "Purchase": {
            "Item": {
                "Id": {Stone ID}
            },
            "Amount": 3,
            "PriceAmounts": [
                {
                "ItemId": {Free Item ID},
                "Amount": 0
                }
            ]
        }
    },
    {
      "Purchase": {
            "Item": {
                "Id": {Gold ID}
            },
            "Amount": 1,
            "PriceAmounts": [
                {
                "ItemId": {Free Item ID},
                "Amount": 0
                }
            ]
        }
    },
    {
      "Purchase": {
            "Item": {
                "Id": {Cream ID}
            },
            "Amount": 1,
            "PriceAmounts": [
                {
                "ItemId": {Free Item ID},
                "Amount": 0
                }
            ]
        }
    }
  ]
}
```

次の JSON は、上記の呼び出しを行った後の成功戻りメッセージの例です。3 つの異なる取引 ID が返されるのがわかります。ID は変更ごとに与えられるためですが、これは 3 つの別々の取引があるという意味ではありません。むしろその逆で、1 つの取引ですが 3 つの変更があるものとして扱われます。したがって、変更の数に関係なく、取引全体に対して 1 回の成功または失敗のみを返します。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "IdempotencyId": {Idempotency ID},
        "TransactionIds": [
            "200",
            "201",
            "202"
        ],
        "ETag": "1/MjAy"
    }
}
```

***

## ステップ 4 - バンドルを作成する

バンドルを使用すると、複数のアイテムを 1 つのアイテムにグループ化できます。バンドルの詳細については、[このリンク](/services/playfab/economy-monetization/economy-v2/catalog/bundles) に従って **バンドルのドキュメント** を参照してください。

例では、**Kitchen** によって返されるアイテムをグループ化するために **バンドル** を使用します。これは **Icebox** アイテムを維持するのに役立ちます。アイス ボックスの考え方は、必要な材料の 1 つであっても、アイスクリームを購入する際に非消費アイテムとするというものです。

これがどのように機能するかの高レベルの概要は次のとおりです。プレイヤーがインベントリに 1 個の Cream と 1 個の Icebox を持っているとします。Kitchen ストアにアクセスすると、そのプレイヤーはそれら両方のアイテムを使って 1 個の Ice Cream を購入/作成する必要があります。Icebox は非消費なので、期待される機能は 1 個の Ice Cream と 1 個の Icebox がインベントリに残り、1 個の Cream アイテムのみが消費されることです。

私たちが裏で処理する方法は、1 個の Icebox と 1 個の Cream の価格を持ち、返品アイテムが 1 個の Ice Cream と 1 個の Icebox であるバンドルを使用することです。つまり、プレイヤーのインベントリの Icebox は消費されますが、消費する同じ取引で別の Icebox が返され、プレイヤーには Icebox が常にインベントリにあるように見えます。実際には、Icebox のインスタンスは異なりますが、プレイヤーには見えません。

バンドルを作成するには、新しいアイテムを作成した時と同様に、タイトルの **Economy** セクションに移動する必要があります。**Items**、**Currency** などと並んで **Bundles** というタブがあります。選択すると、画面の右上に **New bundle** という青いボタンが表示されます。

すると、新しいアイテムを作成する時と似たフォームが表示されますが、重要な違いは、下にスクロールすると **Items** というセクションがあります。ここでは、バンドルに含めたいアイテムを追加でき、購入時にプレイヤーのインベントリに転送されます。

**Add** ボタンをクリックすると、カタログ内のすべてのアイテムの検索可能なリストが表示されます。ここで、バンドルに含めたいアイテムを選択できます。アイテムを選択して追加したら、**Save and publish** に進むと、バンドルがアクティブになり、ストアから購入価格として選択できるようになります。

## ステップ 5 - ストアを作成する

クラフト ゲームの例に従うと、プレイヤーがストアからアイテムを購入する必要があります。3 つの異なるストア (この場合は場所) があります: **Science Machine**、**Alchemy Engine**、**Kitchen** です。

**Kitchen** に焦点を当てます。ここで、プレイヤーは **1 Cream** と **1 Icebox** (作成する必要のある新しいアイテム) の価格で **Ice Cream** (作成する必要のある新しいアイテム) を購入できます。この特定のケースは、**バンドル** がストアや取引と共にどのように機能するかを示すために選ばれました。

ストアは [Game Manager](https://developer.playfab.com) からのみ作成でき、左側のナビゲーション バーの **Economy** セクションに移動し、次に異なるタブ オプションから **Stores** を選択して、青い **New store** ボタンを選択します。

これにより、新しいアイテムを作成する時に使用したものと似たフォームが表示されます。ここでは、Start Date とストアに与えたい Title のみが必須フィールドです。下にスクロールすると

## ステップ 6 - ストアにバンドルを追加する

バンドルとストアが作成されて公開されたので、ストアで返品可能なアイテムとしてバンドルを追加できます。これを行うには、ストアに移動し、**Items** タイトルが表示されるまで下にスクロールして、**Add** ボタンを選択します。

これによりカタログ内のアイテムのリストが表示されます。検索バーの左側には、**Items**、**UGC Items**、**Bundles**、**Subscription** など、さまざまなタイプのオブジェクトが表示されたドロップダウン メニューがあります。**Bundles** を選択すると、リストがバンドル タイプのアイテムのみを反映するようにフィルタリングされます。ここでは、以前に作成したバンドルが表示されるはずです。バンドルの名前の横にある **Add** ボタン、次にウィンドウの末尾にある **Add** ボタンを選択すると、そのバンドルがその特定のストアの取引可能なアイテムとして追加されます。

続行する前にもう 1 ステップ、バンドルの価格を設定します。この価格は他のアイテムの価格設定と同様に機能し、プレイヤーが購入を受け入れる前にインベントリに必要な価格アイテムを持っている必要があります。価格を設定するには、バンドルの右側にある **Add new price** ボタンを選択し、アイテム リストから価格にしたいアイテムを選択します。この場合、価格を **1 Icebox** と **1 Cream** にしたいと思います。

バンドルがストアに追加され、それに応じて価格設定されたので、次のステップに進むことができます。

## ステップ 7 - バンドルを購入する

バンドルとストアが作成され、バンドルがストアにリンクされたら、そのバンドルを購入して結果のアイテムをインベントリに取得できるようになります。

プレイヤーの視点からバンドルを購入するには、PlayFab API の **PurchaseInventoryItems** を使用できます。これはバンドルだけでなく、単一のアイテムでも機能します。

### API

次のケースでは、**1 Icebox** と **1 Cream** の価格で **1 Bundle** を購入しようとしています。1 つ以上のアイテムを価格として設定するために、**PriceAmount** の配列プロパティを使用します。バンドルに **FriendlyId** を与えたことを確認してください。

```json theme={null}
{
  "Item": {
    "AlternateId": {
        "Type": "FriendlyId",
        "Value": "Ice Cream and Ice Box"
    }
  },
  "Amount": 1,
  "PriceAmounts": [
    {
        "ItemId": "0d2ab329-2fc5-4ae1-9e3c-19f9fc9bbf86",
        "Amount": 1
    },
    {
        "ItemId": "e5276289-f839-4bde-acce-309ea7959e45",
        "Amount": 1
    }
  ],
  "DeleteEmptyStacks": true,
  "StoreId": "f116f1d4-64f9-4be7-9660-a3c1f021100b"
}
```

次のスニペットは、API 呼び出しが成功した後に予想される戻り値です。

```json theme={null}
{
    "code": 200,
    "status": "OK",
    "data": {
        "ETag": "1/MjEz",
        "IdempotencyId": "d710508f-defc-4382-bbd1-a3576417b3f7",
        "TransactionIds": [
            "212",
            "213"
        ]
    }
}
```

<Note>
  レスポンスでは、2 つの異なる `TransactionIds` が返されることに気付くでしょう。これは、`DeleteEmptyStacks` プロパティが追加の取引として処理されるためです。前の例では、取引 212 はバンドルの購入に対応し、取引 213 は空の Cream スタックの削除に対応します (インベントリに 1 個の Cream しか持っていなかった場合)。
</Note>

### C# SDK

C# のコードがどのように見えるべきかについては、以下に例のスニペットを示します。

```csharp theme={null}
var purchaseRequest = new PurchaseInventoryItemsRequest
{
    Entity = new PlayFab.EconomyModels.EntityKey { Id = entityKey.Id, Type = entityKey.Type },
    Item = new InventoryItemReference { Id = "34167d9f-c8d7-4e17-9a87-b6af1fc389b2" }, //bundle id
    Amount = 1,
    PriceAmounts = new List<PurchasePriceAmount>() { 
        new PurchasePriceAmount { 
            ItemId = "e5276289-f839-4bde-acce-309ea7959e45", 
            Amount = 1 
        }, //cream id and quantity
        new PurchasePriceAmount { 
            ItemId =  "0d2ab329-2fc5-4ae1-9e3c-19f9fc9bbf86", 
            Amount = 1 
        } //icebox id and quantity
    }, 
    StoreId = "f116f1d4-64f9-4be7-9660-a3c1f021100b",
    DeleteEmptyStacks = true
};

var result = await PlayFabEconomyAPI.PurchaseInventoryItemsAsync(purchaseRequest);
```

***

## 関連項目

* [Economy v2 の概要](/services/playfab/economy-monetization/economy-v2/overview)
* [設定](/services/playfab/economy-monetization/economy-v2/settings)
* [Economy v2 ストア](/services/playfab/economy-monetization/economy-v2/catalog/stores#creating-a-store)


## Related topics

- [クラフト ゲーム パート 2 - Game Manager](/ja-jp/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-game-manager.md)
- [クラフト ゲーム パート 1 - セットアップ](/ja-jp/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-environment.md)
- [アクセスと公開のための XBOX パートナー オンボーディング](/ja-jp/home/onboarding.md)
- [クラフト ゲーム - コンテキスト](/ja-jp/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/game-context.md)
- [XAG 105: オーディオ アクセシビリティ](/ja-jp/build/game-principles/accessibility/xag-deep-dives/xag-105-audio-accessibility.md)
