動くクラフトアイテムがつくれるようになりました!
いつも cluster をご利用いただきありがとうございます、プロダクトマネージャーのいかりです。
10/20 に開催の「Cluster Conference 2022」の中で発表された新機能「スクリプト(JavaScript)」について、会場で展示したサンプルコードと配布したクラフトアイテムの動き方をこちらでも紹介させていただきます。
サンプルコードを使うことで、ワールドクラフトで下記のような動きがつくれるようになります!
動くクラフトアイテムのつくり方
動くクラフトアイテムをつくるにはアイテム作成時に「Scriptable Item」をつけ、スクリプトを書いて、アップロードする必要があります。
また、PC版ワールドクラフトでは、cluster内でスクリプトの編集をすることもできます!
ワールドクラフト内でのスクリプトの使い方
ワールドクラフトでスクリプトを編集するためには設定を行う必要があります。下記にその手順を示すので、参考にしてみてください!
また、Creators GuideではCluster Creator Kitでのスクリプトの活用法を紹介した記事も公開しています。こちらもぜひご覧ください。
コピペ・改変することで使えるサンプルコードを配布します!
「とりあえず試してみたい!」という方向けに「Cluster Conference 2022」で紹介したサンプルコードを配布します!
先ほどの手順をもとに、ぜひ触ってみてください(使用するには少し改変が必要なので、そちらもチェックを忘れずに!)
ドア
const door = $.subNode("Model");
const axis = new Vector3(0, 1, 0);
$.onInteract(() => {
let isOpen = $.state.isOpen;
isOpen = !isOpen;
$.state.isOpen = isOpen;
const rot = new Quaternion()
.setFromAxisAngle(axis, isOpen ? -90 : 0);
door.setRotation(rot);
});
△インタラクションのシンプルなサンプルです。間の動きはないので、 onInteract 内で処理しています。
移動する床
const tile = $.subNode("Tile");
const period = 3;
const width = 4;
const trapezoidalWave = (t) => {
if (t < 0.25) {
return t * 4;
} else
if (t < 0.5) {
return 1;
} else
if (t < 0.75) {
return 3 - t * 4;
} else {
return 0;
}
};
$.onUpdate(deltaTime => {
let time = $.state.time ?? 0;
time += deltaTime;
$.state.time = time;
const pos = new Vector3(
trapezoidalWave(time % period / period) * width - width / 2,
0,
0);
tile.setPosition(pos);
});
△ループの動きのサンプルです。onUpdate内で毎フレームの位置を更新しています。
エレベーター
const container = $.subNode("Container");
const doorLeft = $.subNode("Door_L");
const doorRight = $.subNode("Door_R");
const waitTimeSec = 10;
const transitTimeSec = 10;
const period = (waitTimeSec + transitTimeSec) * 2;
const targetHeight = 4;
const offsetHeight = 0.275;
const doorWidth = 0.5;
const easeInOutQuad = (t) => {
return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
};
const upwardsCagePosYRatio = (time) => {
if (time <= waitTimeSec) {
return 0;
} else {
return easeInOutQuad((time - waitTimeSec) / transitTimeSec);
}
};
const cagePosYRatio = (time) => {
time = time % period;
if (time < period / 2) {
return upwardsCagePosYRatio(time);
} else {
return 1 - upwardsCagePosYRatio(time - period / 2);
}
};
const doorPosXRatio = (time) => {
time = time % (period / 2);
if (time <= waitTimeSec) {
return 1;
} else {
return 0;
}
};
$.onUpdate(deltaTime => {
let time = $.state.time ?? 0;
time += deltaTime;
$.state.time = time;
container.setPosition(
new Vector3(
0,
cagePosYRatio(time) * targetHeight + offsetHeight,
0));
doorLeft.setPosition(
new Vector3(doorPosXRatio(time) * doorWidth, 0, 0));
doorRight.setPosition(
new Vector3(doorPosXRatio(time) * -doorWidth, 0, 0));
});
△ループの動きを少し発展させたサンプルです。easing をかけると動きがそれっぽくなります。
倒れる壁
const container = $.subNode("Container");
const minAngle = 0.0;
const maxAngle = 90.0;
const openTimeSec = 0.8;
const closeTimeSec = 2;
const lerp = (a, b, t) => {
if (b == a) return a;
t = Math.min(Math.max(t, 0), 1);
return a + t * (b - a);
};
const easeInQuart = (t) => {
return t * t * t * t;
};
const easeOutBounce = (t) => {
const n1 = 7.5625;
const d1 = 2.75;
if (t < 1 / d1) {
return n1 * t * t;
} else if (t < 2 / d1) {
return n1 * (t -= 1.5 / d1) * t + 0.75;
} else if (t < 2.5 / d1) {
return n1 * (t -= 2.25 / d1) * t + 0.9375;
} else {
return n1 * (t -= 2.625 / d1) * t + 0.984375;
}
};
const easeInBounce = (t) => {
t = Math.min(t, 1);
return 1 - easeOutBounce(1 - t);
};
$.onUpdate(deltaTime => {
let time = $.state.time ?? 0;
time += deltaTime;
$.state.time = time;
let angle = minAngle;
if ($.state.open) {
angle = lerp(minAngle, maxAngle, easeInQuart(time / openTimeSec));
if (time > 5) {
$.state.time = 0;
$.state.open = false;
}
} else {
angle = lerp(maxAngle, minAngle, easeInBounce(time / closeTimeSec));
}
const rot = new Quaternion()
.setFromEulerAngles(new Vector3(angle, 0, 0));
container.setRotation(rot);
});
$.onInteract(() => {
if (!$.state.open && $.state.time > closeTimeSec) {
$.state.time = 0;
$.state.open = true;
}
});
△ドアをさらに発展させたようなイメージです。こちらも easing をかけて動きに緩急をつけています。
ぜひご活用ください!
Cluster Creator Kitを使うにあたって便利な機能がまたひとつ増えたかなと考えております。またJavaScriptに触れたことがある方はもちろん、これまで触れてこなかった方にも今後ご活用いただけると非常にうれしく思います。
この機能はさらに拡張をする予定ですので今後のアップデートもお楽しみにしていただければと思います。