見出し画像

【ClusterScript】クリエイターズガイドのスクリプトアイテムを作ってみた【エレベーター編】

clusterクリエイターズガイドに記載されているスクリプトアイテムをコードのコピペで作れなかったので自分で作り直すことにしました。
この記事で配布するサンプルアイテムは自由にご利用ください。

▼ 元記事

①オブジェクトを作る

まず、クリエイターズガイド記載のヒエラルキー構成では作成できなかったので別途こちらで用意しました。

こちらからUnityプロジェクトをダウンロードできます。

ヒエラルキー構成をElevator>Container>Door_R, Door_L としました。
※クリエイターズガイドの「Cage」「Collider」は動きのない外枠のため、今回は削除しています。

クリックで拡大

Elevator:Item(Script)のSizeを床タイプ(2,0,2)としました。
Container:上下する床のオブジェクトです。
Door_R, Door_L:ドアです。停止中は開き、移動中は閉じます。

②コード

サンプルコードから以下の2か所を書き換えています。
// エレベーターの移動先の高さや、各部品のサイズを定義する
// ドアの位置を更新する
※解説のためコメントを挿入しています。

// 3つの子オブジェクトを取得する
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.025;
const doorWidth_X = 0.25;
const doorWidth_Y = 19.5;
const doorWidth_Z = 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_X * 2 + doorWidth_X , doorWidth_Y, doorWidth_Z));
  doorRight.setPosition(
    new Vector3(doorPosXRatio(time) * -doorWidth_X * 2 - doorWidth_X , doorWidth_Y, doorWidth_Z));
});

※補足

「エレベーターの移動先の高さや、各部品のサイズを定義する」の箇所ではオブジェクトに合わせて数値を変更してください
この数値をもとに開閉時のドアの位置を決定しています。

// エレベーターの移動先の高さや、各部品のサイズを定義する

// Containerの到達地点の高さ
const targetHeight = 4;

// Containerの初期高さ
const offsetHeight = 0.025; 

// ドアの初期位置(X,Y,Z)
const doorWidth_X = 0.25; 
const doorWidth_Y = 19.5;
const doorWidth_Z = 0.5;

ドアが綺麗に開閉しない場合は最後の行の「 // ドアの位置を更新する」をチェックし、位置を計算してください。
※「doorPosXRatio(time)」は開くと1,閉じると0となります。

解説

最初に、エレベーターの部品を取得します。containerはエレベーターの実際の移動を担当する部品、doorLeftdoorRightは自動ドアを制御する部品です。

次に、エレベーターの移動に必要なパラメータを設定しています。waitTimeSecは停止する時間、transitTimeSecは移動にかかる時間を表します。また、targetHeightはエレベーターが到達する目的の高さ、offsetHeightはエレベーターの位置を微調整するためのオフセットです。doorWidthは自動ドアの幅を表します。

easeInOutQuadはイージング関数で、エレベーターの上下運動の滑らかさを調整するために使われます。upwardsCagePosYRatioは、上向き運動の際のcontainerの位置を計算する関数で、cagePosYRatioはエレベーターの現在位置に応じてcontainerの高さを計算する関数です。doorPosXRatioは、自動ドアの位置を計算する関数です。

最後に、$.onUpdate()メソッドで、エレベーターの移動とドアの開閉を制御します。deltaTimeは前回のonUpdate()呼び出しからの経過時間です。timeはエレベーターの現在の時間を表します。containerと自動ドアの位置は、現在の時間に応じて計算されます。時間の経過は$.state.timeに保存され、次回のonUpdate()呼び出し時に再利用されます。

また、このスクリプトでは以下のような関数が定義されています。easeInOutQuad: イージング関数。引数の値に応じて0から1の範囲で値を返します。ここでは二次曲線のイージング関数が使用されています。
upwardsCagePosYRatio: コンテナが上昇中のときの高さの割合を返します。
cagePosYRatio: コンテナの高さの割合を返します。一定時間上昇した後、一定時間下降し、元の位置に戻るという動きを表現しています。
doorPosXRatio: ドアが開閉しているときにドアの位置の割合を返します。

また、以下の定数や変数が使われています。waitTimeSec:エレベーターが停止している時間(秒)
transitTimeSec:エレベーターが上昇・下降する時間(秒)
period:エレベーターの一周にかかる時間(秒)
targetHeight:エレベーターの到達目標高さ
offsetHeight:エレベーターが止まっているときの高さのオフセット
doorWidth:ドアの幅

onUpdate関数では、現在の時間を取得し、cagePosYRatio関数やdoorPosXRatio関数を使ってコンテナとドアの位置を計算して、それぞれのオブジェクトに設定しています。時間は、stateオブジェクトのtimeプロパティを通じて保存されており、deltaTimeを加算することで更新されています。

https://chat.openai.com

関連記事

ドア編はコチラ↓


この記事が参加している募集

この記事が気に入ったらサポートをしてみませんか?