プレイヤーのインベントリ

要件

プレイヤーのインベントリを使用するには、タイトル用に定義されたカタログが必要です。 詳細については、カタログ をご覧ください。

注意

必要に応じて、カタログのストアを定義することもできます。

カタログにはゲームで使用可能なアイテムすべての一覧が表示されている一方、ストアにあるのはカタログ内で一意の価格設定であるオプションのサブセットです。

カタログごとに定義されている複数のストアがあるため、ユーザーのセグメント化やその他の理由でプレイヤーに提示するアイテムのセットが明らかです。

ゲーム マネージャー、管理の SetCatalogItemsUpdateCatalogItems の API 呼び出しでカタログを定義すると、クライアントとサーバーの幅広いインベントリ API 呼び出しを使用できます。

API 概要

すべてのインベントリ API 呼び出しは、サーバー側に権限 があり、保護されるように設計されています。 適切に使用すると、顧客は不正行為や獲得していないアイテムの取得ができなくなります。

クライアント:

サーバー:

次に挙げる例では、これらの API メソッドを呼び出すコード ブロックを示し、プレイヤーのインベントリにとって基本的なユースケースを設定します。

注意

参考として、これらの例は Unicorn Battle を元に作成しています。PlayFab の機能を紹介する例として作成したゲームです。

以下で使用する仮想通過 AUゴールド です。モンスターと闘って獲得した通貨です (通貨 チュートリアルをご覧ください)。

開始前に、いくつかの有用な機能を定義し、このガイドで使用する多くの例で使用できるようにします。

// **** Shared example utility functions ****

// This is typically NOT how you handle success
// You will want to receive a specific result-type for your API, and utilize the result parameters
void LogSuccess(PlayFabResultCommon result) {
    var requestName = result.Request.GetType().Name;
    Debug.Log(requestName + " successful");
}

// Error handling can be very advanced, such as retry mechanisms, logging, or other options
// The simplest possible choice is just to log it
void LogFailure(PlayFabError error) {
    Debug.LogError(error.GenerateErrorReport());
}

クライアントのみでの使用例: ヘルス ポーションの購入と利用

クライアント API 呼び出しの順序: PurchaseItemgetuserinventoryconsumeitem

まず、カタログ内のアイテムを定義する必要があります。

PlayFab - エコノミー - カタログ アイテムの編集

ヘルス ポーションCatalogItem 要求を示します。

  • PurchaseItem には、明確なアイテム価格が必要です (5 AU)。
  • ConsumeItem には、Consumable であるアイテムが必要です。アイテム数 (3) を指定します。
  • 購入するプレイヤーは、使用できる仮想通貨を 5 AU 持っている必要があります。

各呼び出しのコードを以下に示します。

void MakePurchase() {
    PlayFabClientAPI.PurchaseItem(new PurchaseItemRequest {
        // In your game, this should just be a constant matching your primary catalog
        CatalogVersion = "CharacterClasses",
        ItemId = "MediumHealthPotion",
        Price = 5,
        VirtualCurrency = "AU"
    }, LogSuccess, LogFailure);
}

void GetInventory() {
    PlayFabClientAPI.GetUserInventory(new GetUserInventoryRequest(), LogSuccess, LogFailure);
}

void ConsumePotion() {
    PlayFabClientAPI.ConsumeItem(new ConsumeItemRequest {
        ConsumeCount = 1,
        // This is a hex-string value from the GetUserInventory result
        ItemInstanceId = "potionInstanceId"
    }, LogSuccess, LogFailure);
}

例: プレイヤーは許可され、コンテナーを開きます

API は次の順で呼び出します。

最初に、カタログで定義されているコンテナーを使用する必要があります。 この例のコンテナーでは、CrystalContainer を選択しました。

また、この例ではキーを使用してコンテナーを開きます。オプションのアイテムが、正常な UnlockContainerInstance の呼び出し用のプレイヤーのインベントリにある必要もあります。

PlayFab - エコノミー - カタログ コンテナーの編集

CatalogItem 要求 (この例の CrystalContainer 向け) には次のものが含まれます。

  • CrystalContainerコンテナー として定義されていること。

  • コンテナー は、オプションとして キー アイテム を定義できること。この場合、コンテナー のロックを解除する必要があります。CrystalKey のことです。

  • コンテナーキー両方Consumable にすることを強くお勧めします。数値を正しく使うと、使用後にプレイヤーのインベントリから削除されます。

サーバー コード

void GrantItem() {
    PlayFabServerAPI.GrantItemsToUser(new GrantItemsToUserRequest {
        // In your game, this should just be a constant
        CatalogVersion = "CharacterClasses",
        // Servers must define which character they're modifying in every API call
        PlayFabId = "playFabId",
        ItemIds = new List<string> { "CrystalContainer" }
    }, LogSuccess, LogFailure);
}

クライアント コード

void OpenContainer() {
    PlayFabClientAPI.UnlockContainerInstance(new UnlockContainerInstanceRequest {
        // In your game, this should just be a constant matching your primary catalog
        CatalogVersion = "CharacterClasses",
        ContainerItemInstanceId = "containerInstanceId",
        KeyItemInstanceId = "keyInstanceId"
    }, LogSuccess, LogFailure);
}

キーとコンテナーの消費

キーやコンテナーには Consumable が推奨されますが、前の例では、これが唯一のお勧めです。

コンテナーとそのキー (ある場合) が 消耗品アイテムでない 場合、コンテナーを 無限に 開き、毎回プレイヤーにその中身を付与できます。

プレイヤーのインベントリの容量は無限では ない ため、このパターンはほとんどお勧めしません。 消耗品アイテムであるコンテナーがロックされていない場合、コンテナーと消耗品アイテムであるキーの両方を使うと、自動的にその使用可能回数が 減り、使用可能回数が 0 になると、プレイヤーのインベントリから削除されます。

各種オプション

消耗品アイテムのコンテナー のみで、キー がない: 最も基本的なパターンで、コンテナーを開くと消費され、キーはありません。

消耗品アイテムのコンテナーとキー: 単純にコンテナーをロックする場合で、プレイヤーはキーでコンテナーを開けます。 両方 とも消費されると、プレイヤーは残っている使用回数分だけ、キーでコンテナーを開けます。

永続的なアイテムのコンテナーと消耗品アイテムのキー: この場合は、プレイヤーがキーを見つけた時ににコンテナーを開けられます。 キーは消耗し、キーに使用回数が残っている間にのみ、コンテナーを開けます。

消耗品アイテムのコンテナー、永続的なアイテムのキー: この場合、プレイヤーはキーを使用するアイテムであるコンテナーを すべて 開けられるキーを持つことになります。 コンテナーは消費されますが、プレイヤーがあとでキーを使用してコンテナーを開くすることができる能力を保持します。

例: プレイヤーからのインベントリー アイテムの購入

ゲーム特有の手順である、プレイヤーからインベントリ アイテムを買い戻す組み込み API はありません。 ただし、既存 の API メソッドを使用して、次のように独自の SellItem エクスペリエンスを作成できます。

  • PlayFab サーバー API RevokeInventoryItem** を使用して、インベントリ アイテムを削除できます。

  • PlayFab サーバー API AddUserVirtualCurrency** を使用して、仮想通貨の適切な金額を返せます。 現在、PlayFab API メソッドを使って実際のお金を返すことはできません。

注意

アイテムと仮想通貨は密接な関係にあります。 詳細については、WebUIBackgroundTaskInstance.current チュートリアルをご覧ください。

次の CloudScript 機能を使用して、説明した 2 つのサーバー呼び出しを 1 つのクライアントでアクセス可能な呼び出しにします。

var SELL_PRICE_RATIO = 0.75;
function SellItem_internal(soldItemInstanceId, requestedVcType) {
    var inventory = server.GetUserInventory({ PlayFabId: currentPlayerId });
    var itemInstance = null;
    for (var i = 0; i < inventory.Inventory.length; i++) {
        if (inventory.Inventory[i].ItemInstanceId === soldItemInstanceId)
            itemInstance = inventory.Inventory[i];
    }
    if (!itemInstance)
        throw "Item instance not found"; // Protection against client providing incorrect data
    var catalog = server.GetCatalogItems({ CatalogVersion: itemInstance.CatalogVersion });
    var catalogItem = null;
    for (var c = 0; c < catalog.Catalog.length; c++) {
        if (itemInstance.ItemId === catalog.Catalog[c].ItemId)
            catalogItem = catalog.Catalog[c];
    }
    if (!catalogItem)
        throw "Catalog Item not found"; // Title catalog consistency check (You should never remove a catalog/catalogItem if any player owns that item
    var buyPrice = 0;
    if (catalogItem.VirtualCurrencyPrices.hasOwnProperty(requestedVcType))
        buyPrice = catalogItem.VirtualCurrencyPrices[requestedVcType];
    if (buyPrice <= 0)
        throw "Cannot redeem this item for: " + requestedVcType; // The client requested a virtual currency which doesn't apply to this item
    // Once we get here all safety checks are passed - Perform the sell
    var sellPrice = Math.floor(buyPrice * SELL_PRICE_RATIO);
    server.AddUserVirtualCurrency({ PlayFabId: currentPlayerId, Amount: sellPrice, VirtualCurrency: requestedVcType });
    server.RevokeInventoryItem({ PlayFabId: currentPlayerId, ItemInstanceId: soldItemInstanceId });
}

handlers.SellItem = function (args) {
    if (!args || !args.soldItemInstanceId || !args.requestedVcType)
        throw "Invalid input parameters, expected soldItemInstanceId and requestedVcType";
    SellItem_internal(args.soldItemInstanceId, args.requestedVcType);
};

ベスト プラクティス

  • 変更を加える前に、有効 としたクライアントの入力した情報をすべて確認します。

  • CloudScript はアトミックではないため発生する呼び出し順に関する問題: AddUserVirtualCurrency が成功し、RevokeInventoryItem が失敗する場合があります。

ヒント

通常は、代替品 なしで 奪うのではなく、この過程でプレイヤーが獲得 しなかった 物を与えます。

この CloudScript 機能には、クライアントからアクセスできます。

void SellItem()
{
    PlayFabClientAPI.ExecuteCloudScript(new ExecuteCloudScriptRequest
    {
        // This must match "SellItem" from the "handlers.SellItem = ..." line in the CloudScript file
        FunctionName = "SellItem",
        FunctionParameter = new Dictionary<string, string>{
            // This is a hex-string value from the GetUserInventory result
            { "soldItemInstanceId", "sellItemInstanceId" },
            // Which redeemable virtual currency should be used in your game
            { "requestedVcType", "AU" },
        }
    }, LogSuccess, LogFailure);
}