ClusterScript - 商品の購入状況をPlayerStorageに保存する
クラスター Advent Calendar 2024の8日目の枠が空いていたので、その日の記事ということにします。
概要
clusterのワールドに以下のようなものをつくります。
- 商品を購入すると、購入したプレイヤーにチケットが1枚付与される
- プレイヤーごとのチケット所持数は、プレイヤーがスペースを退室しても保存される
- 手に入れたチケットはスペース内でプレイヤーが任意のタイミングで消費することができる
なお、この記事は既にある程度ClusterScriptに触れている方が読むことを想定して書いています。
Unitypackageの配布については追って検討します。
プレイヤーがスペースを退室してもプレイ状況を保存する方法はいくつかありますが、この記事ではPlayerStorageを使用します。PlayerStorageに保存する内容は、「持っているチケットの枚数」と、「チケットを付与した回数」の2つの情報です。
「商品を購入した回数」はPlayerStorageを使用しなくても OwnProduct.plusAmount
から取得することができます。それを取得した上で、PlayerScriptで「商品を購入した回数」と「チケットを付与した回数」を比較して、「チケットを付与した回数」のほうが少なければ、「持っているチケットの枚数」を1枚増やします。
PlayerScriptをプレイヤーに適用する
PlayerStorageにアクセスするために、下記のPlayerScriptをプレイヤーにセットします。
// PlayerStorageを読み込む
let storageData = _.getPlayerStorageData();
// paidTicketAmount : プレイヤーが持っている有料チケットの枚数
let paidTicketAmount = storageData.paidTicketAmount ?? 0;
// addPaidTicketCount : プレイヤーに有料チケットを付与した回数
let addPaidTicketCount = storageData.addPaidTicketCount ?? 0;
// "OwnTicket"という名前がついたGameObjectのTextコンポーネントを取得する
const textObject = _.playerLocalObject("PaidTicketAmountDisplay");
const textComponent = textObject.getUnityComponent("Text");
// プレイヤーが持っている有料チケットの枚数を表示する
textComponent.unityProp.text = String(paidTicketAmount);
_.onReceive((messageType, arg, sender) => {
// messageType "CheckTicket" を受け取った時
if (messageType === "CheckTicket") {
// 受け取ったargから、purchaseCount(商品を購入した回数)を取り出す
let purchaseCount = arg.purchaseCount;
// 商品を購入した回数が、チケットを追加した回数より多ければ、チケットを追加する
if(purchaseCount > addPaidTicketCount){
// 差分を計算する
let diff = purchaseCount - addPaidTicketCount;
// プレイヤーが持っている有料チケットの枚数を1増やす
paidTicketAmount += diff;
_.log("paidTicketAmount: " + paidTicketAmount);
// プレイヤーに有料チケットを付与した回数を1増やす
addPaidTicketCount += diff;
_.log("addPaidTicketCount: " + addPaidTicketCount);
// PlayerStorageに保存する
_.setPlayerStorageData({ paidTicketAmount, addPaidTicketCount });
}
// プレイヤーが持っている有料チケットの枚数を表示する
textComponent.unityProp.text = String(paidTicketAmount);
}
});
PlayerScriptをプレイヤーにセットする方法はこちらの記事をご覧ください。
商品を購入してもらうためのアイテム
商品を購入するための、ボタンのようなアイテムをつくります。
ColliderのついたCubeなどを設置して、Scriptable Itemコンポーネントを追加し、以下のコードを割り当てます。
const productId = "cluster公式Webサイトのワールド編集ページで設定した商品のID";
$.onStart(() => {
// 購入通知を購読する
$.subscribePurchase(productId);
});
$.onInteract(player => {
player.requestPurchase(productId, "");
});
$.onPurchaseUpdated((player, productId) => {
// 商品が購入された場合、購入したプレイヤーの購入状況を確認する
$.getOwnProducts(productId, player, "");
});
$.onGetOwnProducts((ownProducts, meta, errorReason) => {
// 商品の所持状況を取得したとき
for (let ownProduct of ownProducts) {
// 商品を購入した回数から返品した回数を引いて、商品の所持数を取得する
let purchaseCount = ownProduct.plusAmount - ownProduct.minusAmount;
// send用のobjectに商品idと所持数を格納する
let obj = {
productId: productId,
purchaseCount: purchaseCount,
}
// 購入したプレイヤーにsendして、PlayerScriptで購入状況を反映する
ownProduct.player.send("CheckTicket", obj);
}
});
Player Local UIの設定
Player Local UIの中にGameObjectを配置し、Textコンポーネントを追加しましょう。
画像ではPaidTicketAmountDisplayObject
という名前にしています。
Scene内の適当なGameObjectに、Player Local Objecr Reference List
コンポーネントを追加して、Idに PaidTicketAmountDisplay
と設定しましょう。TargetObjectには、先ほど作成したPaidTicketAmountDisplayObject
をドラッグ&ドロップしましょう。
メモ
「チケットを付与した回数」を保存することで、以下のような状況に対応しています。
- ワールド内でチケットを消費することができる
- PlayerScriptに記述を追加する必要がある(そのうち記事にしたい)
- 通信切断などによってチケット付与に失敗した場合に、追って付与し直すことができる
- 商品を購入してもらうためのアイテムとは別に、購入状況を確認するためのアイテムをつくるとよさそう(そのうち記事にしたい)
- スペースでのクラフトを許可している場合は、sendおよびonReceiveのmessageTypeである
CheckTicket
を任意の文字列に変更しておくことをオススメします- スペースに
PlayerHandle.send("CheckTicket", {purchaseCount: 100});
を実行するクラフトアイテムを設置すれば、特定のplayerが100回購入したことにできてしまう(はず)
- スペースに
Discussion