PlayerStorageを使ってワールドのプレイ数をカウントしてみよう

Cluster Creator Kit(以下、CCK)で使えるスクリプトには、PlayerStorageというプレイヤーごとに状態を保存しておける仕組みがあります。
これを利用して、今回は各プレイヤーがワールドをプレイした回数をカウントし、それによって何かが起きるようなギミックについて、解説していきます。

ここからは、サンプルスクリプトと、その中身を解説していきます。
まず最初に今回のギミックの基礎となる、プレイヤーがワールドをプレイした数をカウントするギミックをつくります。ローカルに表示され、プレイヤーごとにそのワールドへの訪問回数が表示されます。

Player Local UIを設定する

Player Local UIの作成

まずは、表示するためのPlayer Local UIを作成します。
今回は Text コンポーネントを設定します。

  • Hierarchyを右クリック、または上部メニューのGameObjectを選択して「UI>PlayerLocalUI – cluster」を新規作成します。
  • Hierarchy上のSafeAreaオブジェクトを右クリックして、UI>Legacy>Textを作成します。

Player Local Object Reference ListにPlayer Local UIを登録する

制作したPlayer Local UIをスクリプト側から参照するためには、Player Local Object Reference Listコンポーネントを使用する必要があります。

  • GameObjectを新しく作成して、Player Local Object Reference Listコンポーネントを追加してください。
    • Player Local Object Referenceの右にある数字を「1」にするか下部にある「+」を押して登録欄を表示させてください。
      • 先ほど制作したTextをTarget Objectにドラッグ&ドロップしてください。
        • Target Objectに設定するGameObjectは後ほどスクリプトから参照する「Text」コンポーネントが追加されているGameObjectを追加してください。
        • idは「label」にしてください(後ほど、このidでスクリプト側から参照します)。

Cluster ScriptとPlayer Scriptを設定する

先ほど、Player Local Object Reference Listコンポーネントを追加したGameObjectにScriptable ItemコンポーネントPlayer Scriptコンポーネントを追加して、以下のスクリプトを設定してください。

サンプルスクリプト

次に掲載するサンプルスクリプトの内、counter.jsをScriptable Itemコンポーネントに、player.jsをPlayer Scriptコンポーネントに設定してください。
player.jsのスクリプトはPlayer Local Object Referenceのidと同じキーワードを設定してください。

counter.js

$.onUpdate(deltaTime => {
  // 既知のプレイヤー一覧を取得(なければ空配列)
  const knownPlayers = $.state.knownPlayers ?? [];

  // 現在のプレイヤーを取得
  const currentPlayers = $.getPlayersNear(new Vector3(0, 0, 0), Infinity);

  // 既存プレイヤー一覧と比較して、新しく見つかったプレイヤーだけに処理を適用
  for (const player of currentPlayers) {
    if (!knownPlayers.some(p => p.id === player.id) && player.exists()){
      $.log(`${player.userDisplayName}が見つかりました`);
      $.setPlayerScript(player);
      knownPlayers.push(player);
    }
  }

  // まだ存在しているプレイヤーだけを保持
  $.state.knownPlayers = knownPlayers.filter(p => p.exists());
});

player.js

// MEMO: ここの"PlayerStorageSample"の部分は、他と被らないような文字に書き換えて使用してください
const STORAGE_KEY = "PlayerStorageSample";

// PlayerStorageのデータを取得(無ければ空のobjectを返す)
const playerStorage = _.getPlayerStorageData() ?? {};

// 今回のスクリプト用の保存領域を作成
playerStorage[STORAGE_KEY] ??= {};

// プレイ回数をカウントするためのプロパティを取得
const saveObject = playerStorage[STORAGE_KEY];

// プレイ回数をカウントするためのプロパティが無ければ0を取得し、1を加算してセット
saveObject.playCount = (saveObject.playCount ?? 0) + 1;

// PlayerStorageに保存
_.setPlayerStorageData(playerStorage);

// プレイ回数を表示するために、UnityのTextコンポーネントを取得
const textComponent = _.playerLocalObject("label").getUnityComponent("Text");

// Textコンポーネントにプレイ回数を表示
textComponent.unityProp.text = `${saveObject.playCount}回目のプレイです`;

ここではcounter.jsのスクリプト内で新しく入ったプレイヤーを検知し、PlayerScript(player.js)をセットしています。
プレイ回数をカウントするコア部分はplayer.jsの中にあり、ワールドに入るごとに1が加算されるようになっています。

最初のスクリプトでは入る度にカウントしていましたが、「1日に1回カウントする」といったことも実現できます。

その場合はスクリプトのうちplayer.jsをこのように変更します。

// MEMO: ここの"PlayerStorageSample"の部分は、他と被らないような文字に書き換えて使用してください
const STORAGE_KEY = "PlayerStorageSample";

// PlayerStorageのデータを取得(無ければ空のobjectを返す)
const playerStorage = _.getPlayerStorageData() ?? {};

// 今回のスクリプト用の保存領域を作成
playerStorage[STORAGE_KEY] ??= {};

// プレイ回数をカウントするためのプロパティを取得
const saveObject = playerStorage[STORAGE_KEY];

// 現在の日付を取得
const today = new Date();

// 日本時間へ変換 (時差+9時間)
today.setTime(today.getTime() + 3600000 * 9);

// YYYY-MM-DD形式の文字列を作成
const todayString = `${today.getFullYear()}-${today.getMonth() + 1}-${today.getDate()}`;

// 最終プレイ日をチェックして、今日と異なる日であればカウントする
if (saveObject.lastPlayedDate !== todayString) {
  // プレイ回数をカウントするためのプロパティが無ければ0を取得し、1を加算してセット
  saveObject.playCount = (saveObject.playCount ?? 0) + 1;

  // 最終プレイ日を更新
  saveObject.lastPlayedDate = todayString;

  // PlayerStorageに保存
  _.setPlayerStorageData(playerStorage);
}

// プレイ回数を表示するために、UnityのTextコンポーネントを取得
const textComponent = _.playerLocalObject("label").getUnityComponent("Text");

// Textコンポーネントにプレイ回数を表示
textComponent.unityProp.text = `${saveObject.playCount}日目のプレイです`;

前のスクリプトと大きく変わったのは、現在の日付を取得する部分からです。
ここで取得した日付と、保存されている最終プレイ日を比較し、同じであればカウントしない仕組みを新たに導入しています。
これによって1日に1回しかカウントされないような処理となっています。

これまでに書いてきたカウントするスクリプトを応用して、一定数プレイしてくれた方に向けて特別な処理を行うことも可能です。
今回のサンプルでは、特定回数プレイしてくれた方に向けて特別なメッセージを表示するスクリプトを書いてみます。

player.jsを以下のように変更してください。

// MEMO: ここの"PlayerStorageSample"の部分は、他と被らないような文字に書き換えて使用してください
const STORAGE_KEY = "PlayerStorageSample";

// PlayerStorageのデータを取得(無ければ空のobjectを返す)
const playerStorage = _.getPlayerStorageData() ?? {};

// 今回のスクリプト用の保存領域を作成
playerStorage[STORAGE_KEY] ??= {};

// プレイ回数をカウントするためのプロパティを取得
const saveObject = playerStorage[STORAGE_KEY];

// 現在の日付を取得
const today = new Date();

// 日本時間へ変換 (時差+9時間)
today.setTime(today.getTime() + 3600000 * 9);

// YYYY-MM-DD形式の文字列を作成
const todayString = `${today.getFullYear()}-${today.getMonth() + 1}-${today.getDate()}`;

// 最終プレイ日をチェックして、今日ならカウントしない
if (saveObject.lastPlayedDate !== todayString) {
  // プレイ回数をカウントするためのプロパティが無ければ0を取得し、1を加算してセット
  saveObject.playCount = (saveObject.playCount ?? 0) + 1;

  // 最終プレイ日を更新
  saveObject.lastPlayedDate = todayString;

  // PlayerStorageに保存
  _.setPlayerStorageData(playerStorage);
}

// プレイ回数を表示するために、UnityのTextコンポーネントを取得
const textComponent = _.playerLocalObject("label").getUnityComponent("Text");

switch (saveObject.playCount) {
  case 1:
    // 初回プレイ時のメッセージ
    textComponent.unityProp.text = "ようこそ!ゆっくりしていってね";
    break;
  case 5:
    // 5回目プレイ時のメッセージ
    textComponent.unityProp.text = "今日で訪問5日目!ありがとうございます!";
    break;
  default:
    // それ以外のプレイ回数のメッセージ
    textComponent.unityProp.text = `${saveObject.playCount}日目です`;
}

このコードではswitchによって回数ごとに異なる処理を行うようにしています。
今回のサンプルでは表示するメッセージを変更しているだけですが、PlayerLocalObject.setEnabled()UnityComponent.onClick()を使用して、特定回数以上になったら画面上にボタンを表示し、それを押すと特別な場所に行ける…なんてことも可能です。

今回はPlayerStorageを使ってワールドのプレイ数を管理できるようにしましたが、PlayerStorageの使い道は広く、プレイ数以外にもさまざまな応用が考えられます。ぜひ皆さんも思いついたギミックがあれば試してみてください!

PlayerStorageにプレイ数を記録するスクリプトですが、こんなシンプルな書き方でも実は動きます。

// objectではなく直接数値を保存するコード
const count = 1;
_.setPlayerStorageData(count);

// objectだけど直下にcountを入れているコード
const obj = {
  count: 1;
};
_.setPlayerStorageData(obj);

ではなぜ紹介してきたギミックでは一段深いところに保存していたかというと、PlayerStorageは自分だけが使うとは限らないからです。
誰かがブログで紹介していたスクリプトや、BOOTHで購入したギミックなど、それらにPlayerStorageを使うスクリプトが入っていた場合に、自分の書いたスクリプトと競合してしまう可能性があります。その時に誤動作しないようにみんなが同じルールでPlayerStorageを使うことで、複数のスクリプトが混在した状態で使っても問題なく動作するようになります。

記事をシェアしてワールド制作を盛り上げよう!

Cluster Creators Guide|バーチャル空間での創作を学ぶならをもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む