まえがき
第1章 ドロップテーブルを使おう
第2章 タイトルニュースを使おう
第3章 メールを送信しよう
第4章 フレンド機能を使おう
第5章 キャラクターを使おう
第6章 エンティティを使おう
第7章 エンティティグループを使おう
あとがき
本書を手に取っていただき、ありがとうございます。本書の中では、エンティティの使い方について触れています。エンティティは、PlayFabにおけるデータ管理の新しい考え方で、実際に試している人は見つけられず、情報がほとんどありませんでした。そんな中でも諦めず、試行錯誤を繰り返して、何とか本書の完成にまでたどり着くことができました。本書には、検索しても簡単に見つからない情報を惜しみなく載せています。誰かが作成したもののコピーコンテンツではありません。私が独自に調べ、試して、本書にまとめています。私と同じことを調べようとすると、みなさんも何十時間もかけてしまうことになります。その時間は本当にもったいないです。なぜなら、本書を読むことでその分の時間を開発に回すことができるからです。本書の値段分は、1日もかからずに元が取れる内容だと確信しています。日本では誰も発信していない内容なので、値段の10倍くらいの価値があると自負しています。PlayFabを採用するからには、実装コストを下げたいと考えていることでしょう。本書をお読みになって、どんどん開発を加速させてください。あなたがやりたいことは、PlayFabの使い方を時間をかけて調べることではなく、ゲームをできるだけ早く完成させることです。私は、そのお手伝いができます。
いろいろとつまづきながら学習した経験から、つまずくポイントもわかっています。つまずく点を先回りして解決できるよう、画像も多めに使用し、わかりやすさと見やすさにこだわって書きました。この本を読むことで、PlayFabにかける勉強時間を少なくして、ゲーム開発の部分に時間を割くことができます。この本が、少しでもみなさんのためになれば幸いです。
PlayFabのことを教えてくださった方々、普段の発信をシェアしたりコメントしてくださる方々、応援してくださる方々のおかげで、本書の執筆にいたることができました。深く感謝いたします。
ねこじょーかー
本書の目的は、PlayFabの基礎とサーバー処理の実装方法を理解している人が、ドロップテーブルやフレンドなど、ソーシャル機能を中心に、ひと通り使えるようになることです。特に、エンティティまわりについては情報が少なく、ゼロから調べるのは大変ですが、本書でわかりやすく解説しているので、迷うことなく進められると思います。PlayFabの基本機能をひと通り網羅したい人にとって、この本はぴったりです。
・ドロップテーブルの知識
・タイトルニュースの知識
・メール送信の知識
・フレンドの知識
・キャラクターの知識
・エンティティの知識
・エンティティグループの知識
・PlayFabの基礎学習、サーバー処理の勉強が終わっている人
・ソーシャルまわりの機能に興味がある人
・普段からPlayFabを使っているが、復習も兼ねて学びたい人
本書は、以下の知識がある前提とします。UnityやC#の説明は省き、PlayFabに特化した説明をしています。
・PlayFabの基礎知識(入門編の内容が理解できていること)
・サーバー処理の基礎知識(自動化編の内容が理解できていること)
本書では、以下のバージョンを使用しています。PlayFabSDKは最新のバージョンを使用して構いません。Unityのバージョンも、特に揃える必要はありません。
・Unity 2019.4.1f1
・PlayFab SDK 2.89.200629
・PlayFabAllSDK 1.77.200730
PlayFabでは、アイテムごとに確率を付けて、その確率ごとにドロップすることができる「ドロップテーブル」の機能が提供されています。本章では、ドロップテーブルの概要と使い方について解説します。
ドロップテーブルとは、アイテムごとに確率をもたせてひとつのテーブルとして管理することで、その確率に応じてランダムにアイテムを取得できる機能のことです。ひとつの使い方の例としては、ガチャの機能を実現できます。たとえば、プレイヤーがゲーム内通貨を消費することでガチャを引き、確率に応じてモンスターを手に入れることができるという機能ですね(図1.1)。また、クエストのクリア報酬として付与するアイテムも、8割は通常アイテムをドロップして、2割はレアアイテムをドロップする、という使い方も可能です。
ドロップテーブルを使用するには、まずアイテムが必要になります。私は、図1.2の内容で登録しました。ここは、何でも好きなアイテムで構いません。
アイテムが登録できたら、ドロップテーブルを登録します。「エコノミー > カタログ > ドロップテーブル」と進み、「新しいドロップテーブル」を選択してください(図1.3)。
テーブルIDを入力した後、「ドロップテーブルを追加」を選択しましょう(図1.4)。図1.5が表示されるので、そこから先ほど登録したアイテムを選択すると、図1.6の状態になります。
加重というのは、そのアイテムが全体のどれだけの比率でドロップするかを表す数値のことです。加重が大きければ大きいほど、ドロップ率が上がります。隣に表示されている「オッズ」というのが、ドロップ率のことです。好きな加重を入力した後は、「ドロップテーブルを保存」を選択してください。これで、ドロップテーブルの保存が完了しました。
「アイテムをひとつドロップする」というケースを見てみましょう。ドロップテーブルに従ってアイテムをひとつドロップするには、EvaluateRandomResultTable1を使用します。TableIdとCatalogVersionが必要になるので、クライアント側から引数で渡してあげましょう。結果は、ResultItemIdというプロパティで取得できます。アイテムのドロップができたので、GrantItemsToUser2を使用して、プレイヤーにアイテムを付与します。最後に、付与結果をクライアント側に返して、ひと通りの処理が完了です。
[FunctionName("DropItem")]
public static async Task<dynamic> DropItem(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
string body = await req.ReadAsStringAsync();
log.LogInformation($"Body : {body}");
var context = JsonConvert
.DeserializeObject<FunctionExecutionContext<dynamic>>(body);
var args = context.FunctionArgument;
string playFabId = context.CallerEntityProfile.Lineage.MasterPlayerAccountId;
var serverApi = GetServerInstance(context.TitleAuthenticationContext);
var evaluateResult = await serverApi.EvaluateRandomResultTableAsync(new EvaluateRandomResultTableRequest
{
TableId = args["TableId"],
CatalogVersion = args["CatalogVersion"]
});
var grantResult = await serverApi.GrantItemsToUserAsync(new GrantItemsToUserRequest
{
PlayFabId = playFabId,
CatalogVersion = args["CatalogVersion"],
ItemIds = new List<string> { evaluateResult.Result.ResultItemId }
});
return new
{
error = PlayFabSimpleJson.SerializeObject(grantResult.Error),
result = PlayFabSimpleJson
.SerializeObject(grantResult.Result.ItemGrantResults)
};
}
クライアントから呼び出すときは、TableIdとCatalogVersionを引数で渡します。サーバー側の返り値としてはList<GrantedItemInstance>を指定しているのですが、クライアント側では指定することができません。そこで、List<ItemInstance>を代わりに指定しています。問題なく実行できると、リスト1.4の結果が返ってきます。今回は、みどりの魔物がドロップされたことが確認できました。
private void DropItem()
{
CallAzureFunctions<List<ItemInstance>>(
"DropItem",
new
{
CatalogVersion = "Main",
TableId = "dt_normal"
},
funcResult =>
{
Debug.Log("アイテムドロップ成功!");
Debug.Log(PlayFabSimpleJson.SerializeObject(funcResult));
}, funcError =>
{
Debug.Log("実行時にエラーが発生しました。");
Debug.Log(funcError.GenerateErrorReport());
});
}
/// <summary>
/// Azure Functions の呼び出し
/// </summary>
/// <typeparam name="T">取得結果の型</typeparam>
/// <param name="funcName">呼び出す関数名</param>
/// <param name="funcParam">サーバーに渡すパラメータ</param>
/// <param name="onSuccess">成功時コールバック</param>
/// <param name="onError">失敗時コールバック</param>
public void CallAzureFunctions<T>(
string funcName,
object funcParam,
Action<T> onSuccess = null,
Action<PlayFabError> onError = null)
{
PlayFabCloudScriptAPI.ExecuteFunction(new
PlayFab.CloudScriptModels.ExecuteFunctionRequest()
{
Entity = new PlayFab.CloudScriptModels.EntityKey()
{
Id = PlayFabSettings.staticPlayer.EntityId,
Type = PlayFabSettings.staticPlayer.EntityType
},
FunctionName = funcName,
FunctionParameter = funcParam,
GeneratePlayStreamEvent = true,
}, result =>
{
Debug.Log("Azure Functions 実行成功!");
// 返り値の取り出し
var jsonResult = (JsonObject)result.FunctionResult;
var funcSuccess = PlayFabSimpleJson.DeserializeObject<T>
(jsonResult["result"].ToString());
var funcError = PlayFabSimpleJson.DeserializeObject<PlayFabError>
(jsonResult["error"].ToString());
if (result.FunctionResultTooLarge != null
&& (bool)result.FunctionResultTooLarge)
{
onError?.Invoke(funcError);
return;
}
if (funcError == null)
onSuccess?.Invoke(funcSuccess);
else
onError?.Invoke(funcError);
}, error =>
{
onError.Invoke(error);
});
}
[
{
"Annotation": null,
"BundleContents": null,
"BundleParent": null,
"CatalogVersion": "Main",
"CustomData": null,
"DisplayName": "みどりの魔物",
"Expiration": null,
"ItemClass": "Monster",
"ItemId": "monster_green",
"ItemInstanceId": "A4D0364CEB3E28F9",
"PurchaseDate": "2020-09-14T12:51:36.219Z",
"RemainingUses": 3,
"UnitCurrency": null,
"UnitPrice": 0,
"UsesIncrementedBy": 1
}
]