> ## 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 部分 - 環境設定](/zh-TW/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-environment)
2. [第 2 部分 - 使用 Game Manager](/zh-TW/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-game-manager)

## 步驟 1 - 設定環境設定

開始撰寫程式碼後，我們建議您做的第一件事就是設定環境設定。如此一來，您就可以放心，您所做的每個呼叫都會連結至您的遊戲，並使用您特定的開發人員祕密金鑰。

若要完成此步驟，您可以在程式碼中的任何位置 (最好是您容易找到的地方) 指定 TitleId 和 DeveloperSecretKey 變數，並為其指派您的值。

請新增如下兩行個別的程式碼來執行此動作：

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

## 步驟 2 - 進行驗證

設定好環境、在專案中安裝並設定 PlayFab NuGet 套件，並建立工作室和遊戲之後，我們就可以開始撰寫驗證的程式碼。

<Note>
  使用者有數種方式可以進行驗證。在此範例中，我們將使用 **LoginWithCustomId** 方法。還有其他驗證方式，包括平台特定的方式。如需詳細資訊，請造訪[登入基本概念](/zh-TW/services/playfab/identity/player-identity/login/login-basics-best-practices)。
</Note>

接下來是以 C# 撰寫的範例程式碼，我們在其中使用 **LoginWithCustomID** 來驗證使用者，這被歸類為匿名登入。在呼叫 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>

在此範例中，我們將新增與遊戲對應的物品。這些物品是三個 Stone 執行個體、一個 Cream 執行個體和一個 Gold 執行個體 (這是假設您已建立更多物品，如果沒有，請在繼續之前建立)。但我們不是單純使用 **Add** 作業，而是使用 **Purchase** 作業，並以免費方式購買所需的執行個體。

<Note>
  若要讓此步驟運作，您必須先在 Game Manager 中於您的遊戲內建立物品。
</Note>

下列程式碼片段將示範如何以 C# 和使用 PlayFab 的 API 大量進行這些呼叫。

### C# SDK

在此 C# 範例中，您可以看到我們一開始就將 purchasePrice 設定為所有交易的標準值，這是因為我們會讓所有交易的價格都為 0。

任何一個物品都可以有多個價格，這就是 `purchasePrice` 變數的類型為 `List<PurchasePriceAmount>` 的原因。

您可能會注意到的下一個層面是，除了 `InventoryOperation` 清單之外，要求還需要一個 Entity。為此，我們將使用先前登入時取得的值建立一個新的 Entity。

最後，每個 `InventoryOperation` 都會接受一個 `Purchase` 值，不過這可以是 **ExecuteInventoryOperations** 呼叫下可用的任何一種 (Add、Delete、Purchase、Subtract、Transfer 和 Update)。在此案例中，我們使用 `Purchase` 識別碼，因此需要 `new PurchaseInventoryItemsOperation`。

您也必須清楚指定要購買的物品。您可以使用 `InventoryItemReference` 來執行此動作，它會接受物品的 ID 作為其唯一參數。

在我們的程式碼中，有一個名為 **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](/zh-TW/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-game-manager)，我們在其中詳細說明您應遵循的步驟。

### API

使用下列要求本文呼叫 **ExecuteInventoryOperations** API 端點。請將 ID 取代為對應的 ID。請注意，`Operations` 是陣列，您可以同時填入多種類型的作業。

請務必了解，對於您所做的每個 API 呼叫，都必須設定 `X-EntityToken` 標頭，其中包含您的使用中工作階段或已登入使用者特定的 **EntityToken**。換句話說，在進行任何 API 呼叫之前，您應先執行 **LoginWithCustomID** (在此範例中)，並從傳回訊息中取得 **EntityToken**，以作為所有 API 呼叫中的標頭。

```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 是進行上述呼叫後成功傳回訊息的範例。您會看到傳回三個不同的交易 ID，這是因為 ID 是以每次修改為單位提供，但這並不表示有三個個別的交易。恰恰相反，它是以單一交易的方式處理，但包含三項修改，因此無論修改數量為何，我們都只會針對整個交易傳回單一成功或失敗結果。

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

***

## 步驟 4 - 建立組合

組合可讓您將多個物品分組成單一物品。如需組合的詳細資訊，請透過[此連結](/zh-TW/services/playfab/economy-monetization/economy-v2/catalog/bundles)參閱我們的**組合文件**。

在我們的範例中，我們將使用**組合**來分組 **Kitchen** 傳回的物品，這有助於我們保留 **Icebox** 物品。Icebox 背後的概念是，在購買冰淇淋時它是非消耗性物品，即使 Icebox 是所需材料之一。

以下是此運作方式的高階概觀。假設有一位玩家的庫存中有一個 Cream 和一個 Icebox。存取 Kitchen 商店後，該玩家必須使用這兩個物品來購買/製作一個 Ice Cream。由於 Icebox 是非消耗性物品，預期的結果是庫存中有一個 Ice Cream 和一個 Icebox，只消耗了一個 Cream 物品。

我們在幕後的處理方式是使用一個組合，其價格為一個 Icebox 和一個 Cream，而其傳回的物品為一個 Ice Cream 和一個 Icebox。這表示玩家庫存中的 Icebox 會被消耗，但消耗它的同一筆交易會再傳回一個，讓玩家感覺 Icebox 一直都在庫存中，但實際上 Icebox 執行個體是不同的，只是玩家看不到。

若要建立組合，您必須前往遊戲的 **Economy** 區段，就像建立新物品時一樣。在 **Items**、**Currency** 等索引標籤旁，會有一個名為 **Bundles** 的索引標籤。選取之後，畫面右上角會出現一個顯示 **New bundle** 的藍色按鈕。

接著會顯示一個類似於建立新物品的表單，主要差異在於，如果您向下捲動，會找到一個標題為 **Items** 的區段。您可以在此新增想要讓組合包含的物品，這些物品會在購買時轉移至玩家的庫存。

按一下 **Add** 按鈕之後，會彈出目錄中所有物品的可搜尋清單，您可以在此選取要包含在組合中的物品。選取並新增物品之後，您就可以繼續進行 **Save and publish**，您的組合現在就會處於使用中，並可在商店中選取作為購買價格。

## 步驟 5 - 建立商店

依照我們的製作遊戲範例，我們必須讓玩家從商店購買物品。會有三個不同的商店 (在此案例中為地點)：**Science Machine**、**Alchemy Engine** 和 **Kitchen**。

我們將著重於 **Kitchen**。在這裡，玩家能夠以 **1 個 Cream** 和 **1 個 Icebox** (應建立的新物品) 的價格購買 **Ice Cream** (應建立的新物品)。之所以選擇這個特定案例，是因為它展示了**組合**如何與商店和交易搭配運作。

商店只能從 [Game Manager](https://developer.playfab.com) 建立，方法是前往左側導覽列上的 **Economy** 區段，然後從不同的索引標籤選項中選擇 **Stores**，並選取藍色的 **New store** 按鈕。

這會顯示一個類似於建立新物品時所使用的表單，其中唯一的必要欄位是開始日期以及您想要為商店指定的標題。向下捲動，您將會

## 步驟 6 - 將組合新增至商店

現在您已建立並發佈組合和商店。您可以將組合新增為商店中可傳回的物品。若要這樣做，請進入您的商店，向下捲動直到看到 **Items** 標題，然後選取 **Add** 按鈕。

這會顯示目錄中的物品清單。在搜尋列的左側，會有一個下拉式功能表，其中填入不同類型的物件，例如 **Items**、**UGC Items**、**Bundles** 和 **Subscription**。如果您選擇 **Bundles**，清單會經過篩選而只顯示組合類型的物品，您應該會在這裡看到先前建立的組合。選取組合名稱旁的 **Add** 按鈕，然後選取視窗底部的 **Add** 按鈕之後，該組合就會新增為該特定商店可能的交易物品。

在繼續之前還有最後一個步驟，就是為您的組合設定價格。此價格的運作方式與任何其他物品定價相同，也就是說，在接受購買之前，玩家的庫存中必須有所需的任何價格物品。若要設定價格，您可以選取組合右側的 **Add new price** 按鈕，然後從物品清單中選取您想要作為價格的任何物品。在我們的案例中，我們希望價格為 **1 個 Icebox** 和 **1 個 Cream**。

現在您的組合已新增至商店並已適當定價，我們可以繼續進行下一個步驟。

## 步驟 7 - 購買組合

建立組合和商店，並將組合連結至商店之後，您現在就可以購買該組合，並將產生的物品放入您的庫存中。

若要從玩家的角度購買組合，您可以使用 PlayFab API 的 **PurchaseInventoryItems**。它不僅適用於組合，也適用於單一物品。

### API

在下列案例中，我們要以 **1 個 Icebox** 和 **1 個 Cream** 的價格購買 **1 個組合**。我們將使用 **PriceAmount** 的陣列屬性，將 1 個以上的物品設定為價格。只要確定您已為組合指定 **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 概觀](/zh-TW/services/playfab/economy-monetization/economy-v2/overview)
* [設定](/zh-TW/services/playfab/economy-monetization/economy-v2/settings)
* [Economy v2 商店](/zh-TW/services/playfab/economy-monetization/economy-v2/catalog/stores#creating-a-store)


## Related topics

- [製作遊戲第 1 部分 - 設定](/zh-TW/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-environment.md)
- [製作遊戲第 2 部分 - Game Manager](/zh-TW/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/crafting-game-game-manager.md)
- [製作遊戲 - 背景](/zh-TW/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/game-context.md)
- [原始程式碼和最佳做法 - Winter Starfall](/zh-TW/services/playfab/demo-game/source-code-and-best-practices.md)
- [ACP 概觀](/zh-TW/build/console-features/audio/overviews/acp-overview.md)
