乗り物から飛翔体を撃つ方法
むさしは
Cluster Script Advent Calendar 2024
12月21日枠をいただきました
前半戦の記事はこちら
この記事では
先人たちのスクリプトをミックスして
キメラを召喚する方法をまとめます
具体的には
借り物パッチワークの
キメラスクリプトで
『乗り物から飛翔体を撃つ』という
少年の夢を叶えるお話です(笑)
1 キメラスクリプト
1 キメラとは
キメラとは
異なる動物の複数の部位で構成される
妖怪のことです
日本では
頭が猿で足が虎、尻尾は蛇の
『鵺』が有名ですね
2 キメラスクリプト
むさしがつくるアイテムのスクリプトは
自分が編み出したものではなく
先人たちのスクリプトをミックスした
キメラスクリプトです(笑)
2 乗り物と飛翔体
3 乗り物
1 オブジェクト『Small』
・初期表示(表示)
・メッシュのあるオブジェクト構成は
『raisama-s』
『funnel-s』
『kurokumo-s』の3つです
2 オブジェクト『point』
・初期表示(非表示)
・メッシュのあるオブジェクト構成は
『raisama』
『funnel』
『kurokumo』の3つです
3 主なコンポーネント
・『Ridable Item』
・『Item Audio Set List』
・『Humanoid Animation List』
・『Scriptable Item』
4 スクリプト
//cluster公式さん【回転定義】
const speed = 50.0;
const axis = new Vector3(0.0, 0.0, 1.0);
const subNode1 = $.subNode("funnel-s");
const subNode2 = $.subNode("funnel");
//ミッコちゃん【表示非表示定義】
const kawarimi1 = $.subNode("small");
const kawarimi2 = $.subNode("point");
//vinsさん【プロシージャモジュール】
const kawarimiProc = () => {
//ミッコちゃん【表示非表示指令】
let active1 = kawarimi1.getEnabled();
let active2 = kawarimi2.getEnabled();
if (active1) {
active1 = false;
active2 = true;
} else {
active1 = true;
active2 = false;
}
kawarimi1.setEnabled(active1);
kawarimi2.setEnabled(active2);
$.state.active1 = active1;
$.state.active2 = active2;
};
//ニンニン猫さん【アニメ定義】
const timeLength = 0.1;
const timeLengthMax = 3.333;
const animation = $.humanoidAnimation("Anim1");
let rideplayer = null;
//cluster公式さん【効果音定義】
const se = $.audio("Audio1");
const audioPosition = $.subNode("AudioPosition");
//やまちゃん【乗り物スピード定義】
const VER_SPEED = 10; // [m/s]
const HOR_SPEED = 30; // [m/s]
const ANG_SPEED = 90; // [deg/s]
const hor_rot = new Quaternion().setFromAxisAngle(new Vector3(0, 1, 0), 0);
$.onStart(() => {
//cluster公式さん【初期化】
$.state.driver = null;
$.state.steerInput = new Vector2(0, 0);
$.state.steerAdditionalAxisInput = 0;
//きえらさん【初期位置取得&初期化】
$.state.orijinPos = $.getPosition();
$.state.orijinRot = $.getRotation();
$.state.count = 0;
});
$.onRide((isGetOn, player) => {
$.state.isRiding = isGetOn;
$.state.player = isGetOn ? player : null;
$.state.driver = (isGetOn) ? player : null;
if (isGetOn) {
//ニンニン猫さん【アニメ指示】
$.state.clicked = true;
$.state.time = 0.0;
$.state.sumtime = 0.0000;
rideplayer = player;
player.setHumanoidPose(animation.getSample($.state.sumtime));
se.play();
//vinsさん【プロシージャモジュール】
kawarimiProc();
} else {
//vinsさん【プロシージャモジュール】
kawarimiProc();
//ニンニン猫さん【アニメ解除】
$.state.clicked = false;
player.setHumanoidPose(null);
se.play();
//きえらさん【設置時の座標に配置など】
$.setPosition($.state.orijinPos);
$.setRotation($.state.orijinRot);
$.state.count = 0;
}
});
//cluster公式さん【乗り物平面移動トリガー】
$.onSteer((input, player) =>{
$.state.steerInput = input;
});
//cluster公式さん【乗り物垂直移動トリガー】
$.onSteerAdditionalAxis((input,sammon,player) => {
$.state.steerAdditionalAxisInput = input;
//きえらさん【スイッチ】
if (sammon) {
$.state.count++;
switch($.state.count) {
case 1:
//cluster公式さん【クリエイト・召喚呪文(笑)】
const id = new ItemTemplateId("25b1b6db-2296-4e7c-9c0d-fd0429301769");//DM
const position = $.getPosition().clone().add(new Vector3(0, 1, 0));
const rotation = $.getRotation();
$.createItem(id, position, rotation);
break;
default:
$.state.count = 0;
}
}
});
$.onUpdate((deltaTime) => {
//cluster公式さん【回転指示】
subNode1.setRotation(subNode1.getRotation().multiply(new Quaternion().setFromAxisAngle(axis, speed * deltaTime)));
//cluster公式さん【乗車稼働装置】
if (!$.state.driver) {
return;
}
if (!$.state.driver.exists()) {
$.state.driver = null;
return;
}
//cluster公式さん【回転指示】
subNode2.setRotation(subNode2.getRotation().multiply(new Quaternion().setFromAxisAngle(axis, speed * deltaTime)));
//ニンニン猫さん【アニメ稼働】
if ($.state.clicked) {
$.state.time += deltaTime;
$.state.sumtime += deltaTime;
if ($.state.time >= timeLength) {
$.state.time = 0;
if ($.state.sumtime >= timeLengthMax) {
$.log("timeLengthMax");
$.log($.state.sumtime);
$.state.sumtime -= timeLengthMax;
}
rideplayer.setHumanoidPose(animation.getSample($.state.sumtime));
}
}
//やまちゃん【乗り物($) のワールド座標での向きを求めるソースコード】
// note: original script causes error during changing avatar (null returned)
//const direction = $.state.driver.getRotation().createEulerAngles();
// player sit position is horizontally rotated 180 degs from ridable item
const direction = $.getRotation().multiply(hor_rot).createEulerAngles();
//cluster公式さん【乗り物機能】
const forwardRadian = direction.y * Math.PI / 180;
const sideRadian = ((direction.y + 90) % 360) * Math.PI / 180;
//cluster公式さん×やまちゃん【移動量】コラボ
const vectorForwardInput = new Vector3(
Math.sin(forwardRadian) * $.state.steerInput.y * deltaTime * HOR_SPEED,
0,
Math.cos(forwardRadian) * $.state.steerInput.y * deltaTime * HOR_SPEED
);
const vectorSideInput = new Vector3(
Math.sin(sideRadian) * $.state.steerInput.x * deltaTime * HOR_SPEED,
0,
Math.cos(sideRadian) * $.state.steerInput.x * deltaTime * HOR_SPEED
);
const vectorVerticalInput = new Vector3(
0,
$.state.steerAdditionalAxisInput * deltaTime * VER_SPEED,
0
);
const newPosition = $.getPosition()
.add(vectorForwardInput)
//.add(vectorSideInput)
.add(vectorVerticalInput);
$.setPosition(newPosition);
//やまちゃん【旋回反映】
let rotation_side = new Quaternion().setFromAxisAngle(
new Vector3(0, 1, 0), ANG_SPEED * $.state.steerInput.x * deltaTime);
const newRotation = $.getRotation().multiply(rotation_side);
$.setRotation(newRotation);
});
5 乗降時のスケール調整
乗り降りの際の
巨大化と極小化は
ミッコちゃんの表示非表示切り替えの
ソースコードを
vinsさんのプロシージャモジュールで
呼び出しています
ミッコちゃんとvinsさんに感謝です
6 乗降時のニンニンポーズ制御
乗り降りの際の
ニンニンポーズは
ニンニン猫さん(提督)のソースコードを
お借りしています
提督に感謝です
※ソースコードは提督から
直接いただきましたので
アニメの記事ではありませんが
紫電改のnote記事をご紹介します
7 降車時に元の位置に戻る機能
降りた後にの
元の位置に戻る『orijinpos機能』は
きえらさんのソースコードを
お借りしています
きえらさんに感謝です
8 乗り物機能と旋回機能
Cluster公式さんが
ワークラで乗り物を乗れるように
してくれました
そしてその機能を
やまちゃんが
さらに魅力的にしてくれました
Cluster公式さんと
やまちゃんに感謝です
9 召喚呪文【再掲】
後述の飛翔体を作成して
クラフトアイテムのIDを取得したのち
乗り物垂直移動トリガーを
このコードにかえることで
乗り物が上下する際
飛翔体がでるようになります
柱:XXX…XXX = クラフトアイテムのID
const id = new ItemTemplateId("XXX…XXX");//
//cluster公式さん【乗り物垂直移動トリガー】
$.onSteerAdditionalAxis((input,sammon,player) => {
$.state.steerAdditionalAxisInput = input;
//きえらさん【スイッチ】
if (sammon) {
$.state.count++;
switch($.state.count) {
case 1:
//cluster公式さん【クリエイト・召喚呪文(笑)】
const id = new ItemTemplateId("25b1b6db-2296-4e7c-9c0d-fd0429301769");//DM
const position = $.getPosition().clone().add(new Vector3(0, 1, 0));
const rotation = $.getRotation();
$.createItem(id, position, rotation);
break;
default:
$.state.count = 0;
}
}
});
4 飛翔体
1 オブジェクト『point』
・初期表示(表示)
・メッシュのあるオブジェクト構成は
『plasma』
『saucer』の2つです
2 主なコンポーネント
・『Movable Item』
・『Item Audio Set List』
・『Scriptable Item』
3 スクリプト
//きえらさん【時間制御定義】
const obj = $.subNode("point");
const waitTime1 =3.0;
const waitTime2 =6.0;
const v3 = new Vector3(0,0,0);
//vinsさん【飛翔体定義】
const star = $.subNode("point");
const starVec = new Vector3(0,0,5);
const startZ = 0;
const goalZ = 30;
//Cluster公式さん【回転定義】
const subNode0 = $.subNode("saucer");
const subNode1 = $.subNode("p1");
const subNode2 = $.subNode("p2");
const speed = 200.0;
const axis0 = new Vector3(0,0,1);
const axis1 = new Vector3(1,0,0);
const axis2 = new Vector3(1,0,0);
//Cluster公式さん【効果音定義】
const se = $.audio("Audio1");
const audioPosition = $.subNode("AudioPosition");
//Cluster公式さん【効果音トリガー】
$.onStart(() => {
se.attach(audioPosition);
se.play();
});
$.onUpdate((deltaTime) => {
//Cluster公式さん【効果音定義】
subNode0.setRotation(subNode0.getRotation().multiply(new Quaternion().setFromAxisAngle(axis0, speed * deltaTime)));
subNode1.setRotation(subNode1.getRotation().multiply(new Quaternion().setFromAxisAngle(axis1, speed * deltaTime)));
subNode2.setRotation(subNode2.getRotation().multiply(new Quaternion().setFromAxisAngle(axis2, speed * deltaTime)));
//きえらさん【時間制御】
if(!$.state.init) {
$.state.init = true;
}
let time1 = ($.state.time1 ?? 0) + deltaTime;
$.state.time1 = time1;
if (time1 > waitTime1) {
if (!$.state.flg) {
obj.setPosition(v3);
$.state.flg = true;
}
$.state.time1 = 0;
}
let time2 = ($.state.time2 ?? 0) + deltaTime;
$.state.time2 = time2;
if (time2 > waitTime2) {
//Cluster公式さん【消滅呪文】
$.destroy();
$.state.time2 = 0;
}
if (!$.state.flg) {
return;
}
//vinsさん【飛翔制御】
let pos = star.getPosition();
if(pos.z > goalZ) {
star.setPosition(new Vector3(pos.x,pos.y,startZ));
} else {
star.setPosition(pos.add(starVec.clone().multiplyScalar(deltaTime)));
}
});
4 時間差トリガー
飛翔体は
世界に召喚されてから
3秒間その場にとどまり
その後、秒速5mで
前方向に30m飛翔して消滅します
きえらさんの時間制御と
vinsさんの飛翔制御の
4次元時空ソースコードのおかげです
きえらさんとvinsさんに感謝です
5 召喚技
召喚するための
クラフトアイテムIDの設定方法は
こちらの記事が参考になります
6 乗り物の意外な可能性
乗り物機能は
方向キーとスペース・シフトキーの
複数トリガーが魅力で
乗り物以外の表現の可能性も
広げてくれています!
この記事も参考にしてみてください
7 大事にしてること
スクリプトの領域を
・定義系エリアと
・トリガー系エリア
・毎フレーム処理エリアの3つに分け
先人たちのスクリプトを
名刀『鵺斬丸』で
この領域の何処に当てはまるか
切り分けています
頭は猿で足が虎、尻尾は蛇で…
まさにキメラスクリプトですね(笑)
8 むすびに
いかがでしたか?
先人たちが公開してくれている
スクリプトをミックスすれば
子どもの頃の夢をかなえられる
クラフトアイテムをつくれます
皆様もぜひ挑戦してみてください!
これまでの成果を
アドカレとしてまとめる機会をくれた
clusterさんに感謝です
これからも
日々精進してまいります