📌

Clusterクラフトアイテム作成

に公開

はじめに

概要

ワールド作っていると、小物アイテムを作りたくなります。スクリプトでちょっと挙動が変わるクラフトアイテムの作り方を記載しておきます。

きっかけ

https://x.com/YoiyamiLuna/status/1894870056846217408
この投稿をみて、かわいいなぁと思いました。

開発環境(ワールド作り)

  • Unity 2021.3.4f1
  • Windows10
  • Cluster Creator Kit 2.31.0

関連記事

方針

  • 基本的にアイテムを使ったら見た目が変わるようにするだけの機能を作ります。
    • onUseで使うたびに状態を変えます
    • 状態によってSubNodeのsetEnabledで表示・非表示を切り替えます

実装(dango)

  • 団子を使うと、球(Sphere)を上から順に非表示にし、全て非表示の状態で使うと一括で表示します。
    • dangoノードの下にSphere0,Sphere1,Sphere2を用意して、それぞれ表示・非表示するようにします。
      • ※SphereよりNodeとか命名にすると汎用的かもしれないですね。。。
dango
const subNodes = [
    $.subNode("Sphere0"),
    $.subNode("Sphere1"),
    $.subNode("Sphere2"),
]
const subNodesSize = subNodes.length;
let nodeIndex = 0;
let toggleMode = true;
$.onUse((isDown, player) => {
    // $.log(`colorIndex=${colorIndex}`);
    if (!isDown) { return; }
    if ($.getGrabbingPlayer() === null) { return; }

    if (toggleMode) {
        const node = subNodes[nodeIndex];
        let enabled = node.getEnabled();
        node.setEnabled(!enabled);

        nodeIndex = (nodeIndex + 1) % subNodesSize; // 0 -> 1 -> 2 ...
        if (nodeIndex === 0) {
            toggleMode = false;
        }
    } else {
        subNodes.forEach(n => n.setEnabled(true));
        toggleMode = true;
    }
});

実装(sensu)

  • dangoより簡単です
    • 扇子を閉じたモデルと開いたモデル二つ用意します。(クラフトアイテムとしてアップロードするときマテリアルが2つまでという制約があります。そのため各モデルでマテリアル一つまでになります。まぁ二つのモデルで一つのマテリアル参照できると思いますが)
  • 扇子のオブジェクト
    • Scriptable Item
      • サブノードNodeのEnabledフラグを切り替えています
sensu
const node0 = $.subNode("Node0");
const node1 = $.subNode("Node1");
$.onStart = () => {
    $.state.toggleMode = true;
}
$.onUse((isDown, player) => {
    if (!isDown) { return; }
    if ($.getGrabbingPlayer() === null) { return; }
    let toggleMode = $.state.toggleMode;
    toggleMode = !toggleMode;
    $.state.toggleMode = toggleMode ;
;
    node0.setEnabled(toggleMode);
    node1.setEnabled(!toggleMode);
});
  • ゲームオブジェクト
    • 同名のゲームオブジェクトはクラフトアイテムに設定できないらしいので、接尾辞をつけています。
    • Visibleには用意した扇子fbxを配置しています
    • Coliderには、アイテムをつかむためにColiderをつけておきます

実装(mekure)

  • インターアクトしたら名前が表示されるアイテムを作ります
    • サブノードTextにはTextViewを用意、インターアクトするためにButtonにColiderをつけておきます。
    • 選択したプレイヤーのDisplayNameを取得し、各文字ずつ改行して縦に一列に表示するようにしています。
mekure
const subNodeText = $.subNode("Text");
$.onInteract((player) => {
    // $.log(`onInteract`);
    let displayName = player.userDisplayName;
    let formattedDisplayName = displayName.split('').join('\n');
    let formattedText = `${formattedDisplayName}`;
    subNodeText.setText(formattedText);
    $.log(formattedText);
});

実装(throw zabuton)

  • 投げられる座布団をつくりました。
    • リリースするとき、持っているプレイヤーの方向に衝撃を与えるようにしています
    • つかんだときにプレイヤーの情報をもって、放すときにアイテムに衝撃を与えています。与える方向はプレイヤーの向きにしています。
    • AddForceでそのままそっちの方向にぶっ飛んでほしいんですが、たぶんプレハブアイテムには効かないのかもしれません。。
  • 背景
  • Unity
    • シュートができるバスケットボールをつくってみよう【cluster用アイテム】の設定を参考にしました。クラフトアイテムアップロード時にエラーになるコンポーネントを削除してスクリプト側で再実装した感じです。
throw zabuton
$.onGrab((isGrab, isLeftHand, player) => {
    if (isGrab) {
        // $.log("isGrabbing");
        $.state.grabbingPlayer = player;
    } else {
        // $.log("releasing");
        $.state.throwUp = true;
    }
});

$.onPhysicsUpdate(deltaTime => {
    let throwUp = $.state.throwUp ?? false;
    if (throwUp) {
        // $.log("relonPhysicsUpdateeasing");
        // $.log("throwUp: " + throwUp);
        let grabbingPlayer = $.state.grabbingPlayer;
        // $.log("grabbingPlayer: " + grabbingPlayer);
        if (grabbingPlayer === null || !grabbingPlayer.exists()) {
            $.state.throwUp = false;
            $.state.grabbingPlayer = null;
            return;
        }
        let playerRotation = grabbingPlayer.getRotation();
        const dir = new Vector3(0, 1, 1);
        const intensity = 4;
        // $.log("playerRotation: " + playerRotation);
        const velocity = dir.applyQuaternion(playerRotation).multiplyScalar(intensity);
        // $.log("velocity: " + velocity);
        $.addImpulsiveForce(velocity);
        $.state.throwUp = false;
    }
});

Discussion