Cluster Creator Kit Script Reference

[ 日本語 / English (US) ]

cluster-script-types

Cluster Creator Kitを活用し、多彩なアイテムやワールドの作成が可能です。 これらにJavaScriptを使うことで高度なインタラクションを実装できます。

本ドキュメントでは、JavaScriptからアクセス可能なAPIについて詳細に説明します。 Creator Kitで使用するコンポーネントについては、Creator Kit ドキュメントをご覧ください。

JavaScriptから利用できるJavaScriptの標準組み込みオブジェクトについては説明を省略します。 JavaScriptの使い方を調べる際は、 MDNのJavaScript リファレンス などを参照してください。

ドキュメントで用いられる記法

Beta

型やメソッドがベータ版で提供される機能が許容された環境でのみ使用可能であることを示します。
(許可されていない場合、ClusterScriptErrorが発生します。)

Item

型やメソッドが Scriptable Itemコンポーネント のスクリプト内でのみ使用可能であることを示します。

Player

型やメソッドが Player Scriptコンポーネント のスクリプト内でのみ使用可能であることを示します。

基本概念

全てのスクリプトは個々のアイテム(item)で実行され、アイテムの外側で動作するスクリプトは存在しません。 各アイテムのスクリプトは独自のステート($.state)を保有し、空間内に存在する間は並列実行されます。

アイテムはAPIやコンポーネントを通じて、自身の見た目を変える能力を有します。 また、各アイテムは自己のステートに対して自由に操作を行うことができます。 他のアイテムのステートを読み書きすることはできず、特定のAPIを通じた情報交換や空間内での物理的な相互作用に限定されます。

clusterの空間は、アイテム間の独立性とプレイヤー体験を保護するために、各アイテムのCPU時間やメモリを制限します。 これにより、制限を超えたアイテムがあっても、他のアイテムの動作やフレームレートが維持されます。 ただし、制限を超過すると例外が発生するか、一時的に実行が停止する可能性があります。

APIの制限

APIは使い方に制限がある場合があります。

  • 頻度の制限: アイテムが一定時間内にAPIを呼び出せる回数は制限を持つことがあります。
  • 容量の制限: APIに引数として渡される文字列の長さやSendableのデータサイズは制限を持つことがあります。

これらの制限を超えた場合、ClusterScriptErrorが発生し操作は失敗します。 個々の制限値については各APIのドキュメントを参照してください。

制限値はワールドがCreator Kit製ワールドかワールドクラフトかによって異なる場合があります。 また、制限値は事前告知の上で変更されることがあります。

ベータAPI

ベータ機能を許容する設定がされた空間でのみ有効になるAPIです。 正式リリース前に使用感に対してフィードバックをいただき開発を促進させる目的で提供されています。

ベータ機能について詳細は Creator Kit ドキュメント の ベータ機能の項目 をご覧ください。

ScriptableItemのトップレベルとコールバック

ScriptableItemから利用できるAPIは以下の3つに分類されます。

  • トップレベルのみで利用できるもの。
    • コールバックを設定するAPIが該当します。
    • 例: $.onStart$.onUpdate など。
  • コールバックのみで利用できるもの。
    • 空間の状態を読み書きするAPIが該当します。
    • 例: $.state$.getPositionItemHandle.send など。
  • トップレベルとコールバックのどちらでも利用できるもの。
    • 空間の状態に関わらずアイテムごとに決まった値を返すAPIが該当します。
    • 例: $.subNodenew Vector3 など。

コールバックのみで利用できるAPIは、トップレベルで呼び出した場合はサポートされません。 そのような場合、警告ログがコンソールに表示されます。

Cluster Creator Kitから提供されないJavaScript標準のAPIはトップレベルで利用できます。 ただし、 Math.random() や、 new Date() など、呼び出すたびに異なる値を返すJavaScriptのAPIをトップレベルで利用することは推奨されません。 代わりに、コールバックの設定と SubNode などの取得のみをトップレベルで行い、それらを除くアイテムの初期化処理は $.onStart 内に記述してください。

PlayerScriptのトップレベルとコールバック

PlayerScriptから利用できる全てのAPIは、PlayerScriptのトップレベルとコールバックの両方で利用できます。

ハンドル

ClusterScriptでは空間インスタンスに存在する他の物体を指し示すスクリプトから扱える参照値をハンドルと呼び、ItemHandlePlayerHandleがそれにあたります。

(MaterialHandleCameraHandleなど、名前にHandleを含む型が他にも存在します。 これらはアイテムやプレイヤーの一部であるという意味でここで述べるハンドルとは異なります。)

以下のAPIは、ItemHandleまたはPlayerHandleのいずれかの型の値を返します。

ItemHandle.typePlayerHandle.type を利用して、ItemHandleとPlayerHandleを区別できます。 この場合、RaycastResult.handleなどの値はnullである場合もあることに気をつけてください。

$.onReceive((messageType, arg, sender) => {
if (sender.type === "item") {
$.log(`message from item: ${messageType}`);
} else if (sender.type === "player") {
$.log(`message from player: ${messageType}`);
}
}, { player: true });

または、JavaScriptのinstanceof演算子を利用して、ItemHandleとPlayerHandleを区別できます。

$.onReceive((messageType, arg, sender) => {
if (sender instanceof ItemHandle) {
$.log(`message from item: ${messageType}`);
} else if (sender instanceof PlayerHandle) {
$.log(`message from player: ${messageType}`);
}
}, { player: true });

PlayerScriptのItemIdPlayerIdも同様の方法で区別できます。

ハンドルに対する操作

ハンドルに対するset...,add...,reset...など、状態の変更を伴うメソッドの呼び出しを「ハンドルに対する操作」と呼びます。

ひとつのアイテムから、他のハンドルに対する操作の合計は最大で10回/秒に制限されています。 瞬間的にこの制限を超えることはできますが、平均回数はこの制限を下回るようにしてください。 この制限を超えた場合、ClusterScriptErrorが発生します。

ItemHandle.sendには「ハンドルに対する操作」とは独立した制限が適用されます。 つまり、「ハンドルに対する操作」とItemHandle.sendそれぞれで最大10回/秒の呼び出しを行うことが可能です。

ワールドクラフトでのスクリプトの動作

ワールドクラフト内のアイテムで、 スクリプトが実行されるタイミングとステートについて解説します。

実行タイミング

空間中に存在している間は常にスクリプトが実行されます。 誰もいない空間のスクリプトは実行されません。 (将来的に、負荷軽減のため遠方などのアイテムのスクリプト動作を一時停止する可能性はあります)

  • 「クラフトモード」でのアイテム操作中、有料アイテムを「試す」している最中、どちらの場合もスクリプトは実行されます

実行時間制限

Scriptの初期化及び各コールバック関数の実行時間には最大値が設定されています。

また、実行時間が最大値以下であっても、一定のしきい値を超える実行時間を検出した際には警告ログがコンソールに表示されます。 アイテムの作者には警告ログが出ないようにスクリプトを軽量に作ることが推奨されています。

警告ログが出るしきい値は50msです。 実行時間の最大値及び推奨値は今後変更される可能性があります。

ステート

以下の場合、空のステートで開始されます。

  • アイテムが新たに空間に現れたとき
    • createItemでアイテムが生成されたとき
    • 「クラフトモード」でアイテムを設置しようとしたとき

以下の場合、ステートは維持されます。

  • 「クラフトモード」でアイテムを移動・回転するとき

「クラフトモード」におけるアイテムのコピーはステートをコピーしません。 新規設置と同様にアイテムは空のステートから開始します。

onStartの呼び出しルールについて

ワールドクラフトとCreator Kit製ワールドでonStartの呼び出される条件が異なります。

  • ワールドクラフト

    • アイテムが新たに空間に現れたときに一度だけ実行されます。
      • アイテムをコピーしたとき、コピーによって新たに作られたアイテムのonStartが実行されます。
      • これは、アイテムを複製したときにステートは複製されないためです。
    • アイテムがonStartを実行したかどうかはステートの一部として保存されるため、再入室時にonStartが再度実行されることはありません。
  • 投稿されたワールドクラフト製ワールド

    • ワールドクラフト製ワールド上でスペースが新規に始まるとき、空間の状態は「投稿した時点でのワールドクラフトの状態」で始まります。
    • そのため、元のワールドクラフトでonStartが実行されているアイテムに対しては、ワールドクラフト製ワールド上で実行されることはありません。
    • スペース開始後に新規に作成されたアイテムに対してはワールドクラフトと同様にonStartが実行されます。
  • Creator Kit製ワールド

    • ワールドに置かれているアイテムに対しては、新しくスペースが始まったときにonStartが実行されます。
    • スペース開始後に新規に作成されたアイテムに対しては、作成されたタイミングでonStartが実行されます。

衝突と重なり

  • 衝突:物理的な衝突を意味します。Collisionオブジェクトで表現されます。Unityではトリガーでないコライダー同士の衝突に対応します。
  • 重なり:非物理的な接触を意味します。Overlapオブジェクトで表現されます。Unityではトリガーコライダーへの重なりに対応します。

「クラフトモード」でアイテムを移動する間はアイテムは衝突も重なりも発生しません。これは新規に作成しているアイテムも既に空間に設置されたアイテムを移動するときも含まれます。

時刻の取得とタイムゾーンに関する注意点

空間のスクリプトは世界中で実行される可能性があります。 実行環境に依存した時刻を扱うスクリプトを書くと、スクリプトが予期しない動作をすることがありますのでご注意ください。

時刻を取得する際に次のように書くと予期しない挙動になることがあります。

const date = new Date();
$.log(`${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`);

次のようにタイムゾーンを明示的に指定したスクリプトを書きましょう。

// スクリプトを実行する環境によらずUTCを取得する関数
function getUTCDate() {
const date = new Date();

return {
timezone: "Etc/UTC",
hours: date.getUTCHours(),
minutes: date.getUTCMinutes(),
seconds: date.getUTCSeconds(),
};
}

// スクリプトを実行する環境によらず日本時刻を取得する関数
function getJSTDate() {
const date = new Date();

// Etc/GMT-9の時刻へ変換 (時差+9時間)
date.setTime(date.getTime() + 3600000 * 9);

return {
timezone: "Etc/GMT-9",
hours: date.getUTCHours(),
minutes: date.getUTCMinutes(),
seconds: date.getUTCSeconds(),
};
}

// スクリプトを実行する環境によらず米国東部標準時を取得する関数
function getESTDate() {
const date = new Date();

// Etc/GMT+5の時刻へ変換 (時差-5時間)
date.setTime(date.getTime() + 3600000 * -5);

return {
timezone: "Etc/GMT+5",
hours: date.getUTCHours(),
minutes: date.getUTCMinutes(),
seconds: date.getUTCSeconds(),
};
}

function logDate(date) {
const hours = date.hours.toString().padStart(2, "0");
const minutes = date.minutes.toString().padStart(2, "0");
const seconds = date.seconds.toString().padStart(2, "0");
$.log(`${date.timezone}: ${hours}:${minutes}:${seconds}`);
}

$.onInteract((player) => {
const dateUTC = getUTCDate();
logDate(dateUTC);

const dateJST = getJSTDate();
logDate(dateJST);

const dateEST = getESTDate();
logDate(dateEST);

// 下記は実行される環境によって結果が異なるので使わない
// const date = new Date();
// $.log(`local: ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`);
});

PostProcessEffectsのエフェクトの優先順位について

プレイヤーに設定されたポストエフェクトは、UnityのPostProcessingのGlobalなVolumeとして表現されます。 そのVolumeのPriorityは100であり、ワールドに設定されているPriorityが100より小さいPostProcessVolumeを上書きします。 PostProcessEffectsの各設定がsetValue()されていない、もしくはclear()が呼ばれている場合、ワールドに配置されているPostProcessVolumeの値が使用されます。

PlayerHandleに対して設定したPostProcessEffectsのDepthOfFieldSettingsのエフェクト設定は、カメラ機能の被写界深度に上書きされます。

PlayerHandleに対して設定したPostProcessEffectsのBloomSettingsやColorGradingSettingsのエフェクト設定は、それぞれワールドクラフトの光の強さやカラーエフェクトに上書きされます。

$.setPlayerScriptで付与したPlayerScriptの有効期間について

$.setPlayerScriptで付与したPlayerScriptは、その$.setPlayerScriptを呼び出したアイテムが空間に存在する間のみ有効です。 アイテムが削除されると、そのアイテムが付与したPlayerScriptも削除されます。

また、$.setPlayerScriptが複数回呼ばれると、先に呼ばれた$.setPlayerScriptで付与されたPlayerScriptは削除されて、あとから呼ばれた$.setPlayerScriptのスクリプトで上書きされます。

PlayerScriptが削除された場合、そのPlayerScript内部で設定したカメラの設定やボタン表示の設定はリセットされます。

PlayerScriptはベータの機能であるため、PlayerScriptが削除された場合の挙動などは将来的に変更される場合があります。

型定義ファイル

エディタの入力補完を使いたい方向けに、npmでTypeScript型定義ファイルを公開しています。

https://www.npmjs.com/package/@clustervr/cluster-script-types

Generated using TypeDoc