🔖

【clusterscriptの備忘録】お魚のクラフトアイテムを動かすclusterscript(難易度3)

2024/07/24に公開

https://zenn.dev/toko1219/articles/634c1e487b35a3
上記にお魚のクラフトアイテムを動かすclusterscript(難易度2)を書きました。
今回は、難易度3のスクリプトを記載します。
blenderを使用したことがあり、unityを使ってクラフトアイテムをclusterにアップしたことがある方向けの記事です。
難易度3とこれまでで一番難しい難易度ですが、難易度2のお魚のスクリプトと設定をちょっと変えるだけなので、難易度2を実施した方は、そこまで時間はかからないと思います。

難易度3:★★★

■お魚をピチピチさせながらランダムに泳がす。

1.unityを開きます。難易度2で使用したお魚のアイテムをそのまま使用します。

名称をお好きなように変更してください。

2.Scriptable ItemのSouse Codeに入っているスクリプトを消し、以下のスクリプトを記載します。

これは、以前「ランダムに動く、蛍の光のようなクラフトアイテムの作り方。【clusterscriptの備忘録】」のページでも紹介したclusterscriptです。
https://zenn.dev/toko1219/articles/6463610e4ec424

const monoAr = [];
const monoNum = 4;
const speed = 0.3; // 移動速度
const radius = 3; // 半径3m
const axis = new Vector3(0.0, 1.0, 0.0);
const changeSpeed = 2.0;

for (let monoNo = 0; monoNo < monoNum; monoNo++) {
	monoAr.push($.subNode("mono" + monoNo));
}

$.onStart(() => {
    $.state.initialPosition = $.getPosition(); // 初期位置を保存
    $.state.targetPosition = getRandomPositionWithinRadius(); // 最初のターゲット位置を設定
});

$.onUpdate(deltaTime => {
    if (!$.state.isInitialized) {
        $.state.isInitialized = true;
        $.state.tick = 0;
        $.state.firstPos = $.getPosition();
    }

    const currentPosition = $.getPosition();
    const targetPosition = $.state.targetPosition;

    // ターゲット位置に向かう方向ベクトルを計算
    const direction = targetPosition.clone().sub(currentPosition).normalize();
    const distance = calculateDistance(currentPosition, targetPosition);

    // ターゲット位置に向かって移動
    if (distance > speed * deltaTime) {
        const newPosition = currentPosition.clone().add(direction.multiplyScalar(speed * deltaTime));
        $.setPosition(newPosition);

        // ターゲット位置に向くように回転
        const targetDirection = new Vector3(direction.x, 0, direction.z).normalize(); // Y軸方向の回転のみ
        if (!targetDirection.equals(new Vector3(0, 0, 0))) {
            const up = new Vector3(0, 1, 0);
            const forward = new Vector3(1, 0, 0);
            const currentRotation = $.getRotation();
            const currentForward = forward.applyQuaternion(currentRotation).normalize();
            const rotationAxis = currentForward.clone().cross(targetDirection).normalize();

            // 回転軸が有効であることを確認
            if (rotationAxis.length() > 0) {
                const dot = currentForward.dot(targetDirection);
                // Ensure the dot product is within the valid range for acos
                if (dot >= -1 && dot <= 1) {
                    const angle = Math.acos(dot);
                    const quaternion = new Quaternion().setFromAxisAngle(rotationAxis, angle);
                    $.setRotation(currentRotation.multiply(quaternion));
                }
            }
        }
    } else {
        // ターゲット位置に到達したら新しいターゲット位置を設定
        $.state.targetPosition = getRandomPositionWithinRadius();
    }

    if (!$.state.initialized) {
        $.state.tick = 0;
        $.state.currentNo = 0;
        $.state.initialized = true;
    }

    $.state.tick += deltaTime * changeSpeed;
    if ($.state.tick >= 1.0) {
        $.state.tick -= 1.0;
        monoAr[$.state.currentNo].setEnabled(false);
        $.state.currentNo = ($.state.currentNo + 1) % monoNum;
        monoAr[$.state.currentNo].setEnabled(true);
    }
});

// 半径3mの範囲内でランダムな位置を生成する関数
function getRandomPositionWithinRadius() {
    const angle = Math.random() * 2 * Math.PI;
    const distance = Math.random() * radius;
    const offsetX = distance * Math.cos(angle);
    const offsetY = Math.random() * 1.0; // 0~1mの範囲で上下ランダムな値。上下には動かないようにする場合は、const offsetY = 0;
    const offsetZ = distance * Math.sin(angle);
    return new Vector3($.state.initialPosition.x + offsetX, $.state.initialPosition.y + offsetY, $.state.initialPosition.z + offsetZ);
}

// 2つのベクトル間の距離を計算する関数
function calculateDistance(vector1, vector2) {
    const dx = vector1.x - vector2.x;
    const dy = vector1.y - vector2.y;
    const dz = vector1.z - vector2.z;
    return Math.sqrt(dx * dx + dy * dy + dz * dz);
}

3.子アイテムの「mono0」「mono1」「mono2」「mono3」のPositionをZ:0に変更します。

4.お魚のアイテムをclusterにアップロードします。

5.ワールドクラフトでお魚のアイテムを置いてみてください。

※設置する際、中心位置を決定するため、コピーで配置(PCであれば、マウス右クリック)するようにしてください。

ピチピチする速度を速めたい場合は、以下の数値を上げてください。2.0~6.0ぐらいがおすすめです。

const changeSpeed = 2.0;

以下は、移動範囲を指定しています。
半径3m、つまり、前後左右6mx6mの範囲を移動するようになります。

const radius = 3; // 半径3m

以下は、次の位置をランダムに生成する関数です。
const offsetY = Math.random() * 1.0;
の部分は0~1mの範囲で上下ランダムな値を生成します。
今回お魚の子アイテムをy:1にしているので、高さ1m~2mの間で動きます。上下には動かしたくない場合は、const offsetY = 0;と記載してください。

// 半径3mの範囲内でランダムな位置を生成する関数
function getRandomPositionWithinRadius() {
    const angle = Math.random() * 2 * Math.PI;
    const distance = Math.random() * radius;
    const offsetX = distance * Math.cos(angle);
    const offsetY = Math.random() * 1.0; // 0~1mの範囲で上下ランダムな値。上下には動かないようにする場合は、const offsetY = 0;
    const offsetZ = distance * Math.sin(angle);
    return new Vector3($.state.initialPosition.x + offsetX, $.state.initialPosition.y + offsetY, $.state.initialPosition.z + offsetZ);
}

※ここまで読んでくださってありがとうございます。以下は宣伝です。※

今回難易度1~3までのclusterscirptを紹介しました。
難易度2、難易度3のclusterscriptを使用して作成したお魚のクラフトアイテムを販売しております、その中のいくつかを宣伝します。

■難易度2のスクリプトを使用したクラフトアイテム
「海の生き物セット」に入っている一部のアイテム、「ミニフグ」「フグ」「ナンヨウハギ」「クマノミ」などがそうです。
https://cluster.mu/store/packages/4abb081f-21ad-427e-bb93-57a5b75c23f8

■難易度3のスクリプトを使用したクラフトアイテム
「ランダムに泳ぐ錦鯉セット」は、前後左右2m(4mx4m)の範囲をランダムに移動するように設定してあります。
https://cluster.mu/store/packages/1eb844f0-6e17-4b25-a926-ca7b95edfc38

「虹色_フナ1」アイテムも難易度3のスクリプトを使用しています。
https://cluster.mu/store/items/673e806e-14eb-4bc0-ba0b-f5257aa64175

※以上宣伝でした。※

Discussion