💭

ランダムに動く、蛍の光のようなクラフトアイテムの作り方。【clusterscriptの備忘録】

2024/07/13に公開

ランダムに動く、蛍の光のようなクラフトアイテムの作り方。【clusterscriptの備忘録】

蛍の光のようなクラフトアイテムを作ったので、
そのclusterscriptを記録しておきます。
unityを使用して、クラフトアイテムをclusterにアップしたことがある方向けの記事です。

1、blenderで大きさの違う4つの球を作成します。
大きさは、一番小さな球はmono0で、直径0.1mほど、
一番大きな球はmono2で直径0.3mほどにしました。
名称は、「mono0」「mono1」「mono2」「mono3」です。

FBXでエクスポートして、unityに持っていきます。
出力時のおすすめ設定はこちら。
https://creator.cluster.mu/2022/07/26/blender-unity/

2、unityでアイテムに、Movable ItemとScriptable Itemをつけます。
cckはすでに入っている前提です。

3.Scriptable ItemのSouse Codeに、以下のスクリプトを記載します。

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);
}

■スクリプトの流れ
・光る球体mono0、mono1、mono2、mono3を取得。
・最初の位置を覚えておく。
・次に行く場所をランダムに決める。
・光る球体が動き始める。
・一定時間が経ったら、次の光る球体に切り替える。
・光る球体が目的地に到着したら、新しい目的地を決める。
これを繰り返す。
これで、光る球体が動き回る様子を作り出します。

4、マテリアルを設定し、発光するようにします。
マテリアルのEmissionを有効にすると、発光します。

5、clusterにアップロードし、ワールドクラフトで設置してみましょう。
ワールドの発光の強さを設定することによって、発光します。

Discussion