本記事はCluster Creator Kitの「ベータ機能」を利用した解説になります。
ベータ機能では正式リリース前の機能を使うことができます。正式リリース前のため、不安定な挙動をしたり将来的に挙動が変わる可能性があります。
利用にはCluster Creator Kitでベータ機能を設定した状態でアップロードを行う必要があります。ワールドクラフトで利用する場合は、ワールドクラフトのワールドを新規作成する際にベータ機能の設定を行う必要があります。設定方法はこちらをご覧ください。
今回は「直線上にあるオブジェクトを取得する『レイキャスト』」機能を使ったアイテムの作成方法を紹介します。
この機能を使うと、例えば目に見えない速度で当たる銃や、その銃の着弾地点を示すマーカーなどをつくることができます。今回は、こちらの記事の機能に加えて、銃の着弾地点を示すマーカーをつくります。

サンプルコード
的のアイテム
まずは、ダメージを受けて消える的を用意します。
新しい空のGameObjectにScriptable Itemコンポーネントを追加し、以下のスクリプトを設定します。
子オブジェクトにモデルやコライダーも配置しておきましょう。
$.onReceive((requestName, arg, sender) => {
// 初期化
if (!$.state.initialized) {
$.state.initialized = true;
$.state.hp = 30;
}
// 特定のrequestNameのときだけ処理
if (requestName == "damage") {
// 引数の値の分だけHPを減らす
let damage = arg.value;
let hp = $.state.hp - damage;
// HPが0以下になると破壊
if (hp <= 0) {
$.destroy();
}
$.state.hp = hp;
}
});
銃のアイテム
新規GameObjectにGrabbable ItemおよびScriptable Itemコンポーネント、またモデルやコライダーなどを設定し、Scriptable Itemに以下のスクリプトを設定してください。
const maxDistance = 30;
$.onUse(isDown => {
// ボタンを離したときには発動しない
if (!isDown) return;
// アイテムの現在位置からZ軸の向いている方向を見る
let position = $.getPosition();
let direction = new Vector3(0, 0, 1).applyQuaternion($.getRotation());
let raycastResult = $.raycast(position, direction, maxDistance);
// 直線上に何も見つからなかった場合
if (raycastResult == null) return;
// 直線上にあるオブジェクトがアイテムであるかどうか確認
let itemHandle = raycastResult.object.itemHandle;
if (itemHandle == null) return;
// 対象アイテムにメッセージ送信
itemHandle.send("damage", { value: 50 });
});
それぞれのアイテムが設定できたら、ベータ機能を有効にしたアイテムとしてアップロードし、確認してみましょう。
的を狙って銃を使うと、ダメージを与えて消すことができます。
今回のサンプルは現時点ではUnityでアップロードしたワールドでは正しく動作しないことがあります(詳細はこちらの記事を参照)。クラフトアイテムとしてアップロード後、ワールドクラフト上で設置して確認してみてください。

サンプルコードの解説
新しい機能を利用している部分を中心に、サンプルコードを解説します。
let raycastResult = $.raycast(position, direction, maxDistance);
$.raycast()
メソッドは、ある点から特定の方向に向かう「レイ」が最初に衝突するオブジェクトを取得します。
戻り値のRaycastResult型には対象のオブジェクトの情報と、レイが衝突する点の座標や法線の情報が含まれます。
let itemHandle = raycastResult.object.itemHandle;
レイが衝突するオブジェクトがアイテムであった場合、itemHandleでそのアイテムのハンドルを取得できます。対象がアイテムでない場合はnullになります。
ターゲットマーカーを表示する
レイキャストを利用すると、オブジェクトの情報だけでなく、レイが衝突した点についての情報も取得することができます。
これを利用して、銃が狙っている点を示すターゲットマーカーをつくってみましょう。
銃のアイテムの子に「Marker」という子オブジェクトを作成し、Markerの子にマーカーの見た目となるQuadなどを追加します。
Markerやその子などにコライダーを含めないよう注意してください。

銃のスクリプトを、以下のものに差し替えます。
const maxDistance = 30;
const marker = $.subNode("Marker");
$.onUpdate(deltaTime => {
// アイテムの現在位置からZ軸の向いている方向を見る
let position = $.getPosition();
let direction = new Vector3(0, 0, 1).applyQuaternion($.getRotation());
let raycastResult = $.raycast(position, direction, maxDistance);
// 直線上に何も見つからなかった場合
if (raycastResult == null) {
$.state.targetItem = null;
marker.setEnabled(false);
return;
}
// マーカーの位置を更新
let raycastPoint = raycastResult.hit.point;
let markerPosition = raycastPoint.clone().sub(position).applyQuaternion($.getRotation().clone().invert());
marker.setPosition(markerPosition);
marker.setEnabled(true);
// アイテム情報を取得・保存
let itemHandle = raycastResult.object.itemHandle;
$.state.targetItem = itemHandle;
});
$.onUse(isDown => {
// ボタンを離したときには発動しない
if (!isDown) return;
// 狙っているアイテムを取得
itemHandle = $.state.targetItem;
// itemHandleが有効かどうか確認
if (itemHandle == null || !itemHandle.exists()) return;
// 対象アイテムにメッセージ送信
itemHandle.send("damage", { value: 50 });
});

解説
let raycastPoint = raycastResult.hit.point;
let markerPosition = raycastPoint.clone().sub(position).applyQuaternion($.getRotation().clone().invert());
marker.setPosition(markerPosition);
raycastResult.hit
でレイが衝突した点のグローバル座標や法線情報を取得できます。
ここでは衝突した点の座標を取得し、アイテムのローカル座標に変換してマーカーの位置に設定しています。
if (itemHandle == null || !itemHandle.exists()) return;
itemHandleが示しているアイテムが現時点で存在するかどうかをitemHandle.exists()で確認することができます。
今回はハンドルの取得と参照を別の箇所でおこなっており、実行時点でアイテムが破棄されている可能性もあるためこのチェックをしています。