💭
ランダムに動く、蛍の光のようなクラフトアイテムの作り方。【clusterscriptの備忘録】
ランダムに動く、蛍の光のようなクラフトアイテムの作り方。【clusterscriptの備忘録】
蛍の光のようなクラフトアイテムを作ったので、
そのclusterscriptを記録しておきます。
unityを使用して、クラフトアイテムをclusterにアップしたことがある方向けの記事です。
1、blenderで大きさの違う4つの球を作成します。
大きさは、一番小さな球はmono0で、直径0.1mほど、
一番大きな球はmono2で直径0.3mほどにしました。
名称は、「mono0」「mono1」「mono2」「mono3」です。
FBXでエクスポートして、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