Unityを触り始めた頃にありがちなのが、プレイヤーの移動、カメラ制御、ギミックの回転、UI更新…とにかく全部をひとつの Update() に書いてしまうパターンですね。
動けば最初は嬉しいのですが、時間が経つにつれて「どこを直せばいいかわからない」「別シーンでも使いたいのにコピペ地獄」という状態になりがちです。
そこで役立つのが、小さな責務ごとに分けたコンポーネント指向の設計です。
この記事では「指定したオブジェクト(多くは足場やギミック)を、一定の速度で回転させ続ける」だけに責務を絞ったコンポーネント 「AutoRotator」 を作っていきます。
回転ギミックを使い回したいときに、プレイヤー制御スクリプトに手を入れる必要はありません。
回したいオブジェクトにこのコンポーネントをポンと付けるだけで、どのシーンでも同じ動きを再利用できるようにしていきましょう。
【Unity】回転ギミックを量産しよう!「AutoRotator」コンポーネント
フルコード(C# / MonoBehaviour)
using UnityEngine;
/// <summary>
/// 指定したTransformを、指定した軸・速度で回転させ続けるコンポーネント。
/// - 足場、トラップ、オブジェクトの飾り回転などに利用可能。
/// - 自分自身を回すことも、親オブジェクトなど別のTransformを回すことも可能。
/// </summary>
public class AutoRotator : MonoBehaviour
{
// 回転させる対象。未指定の場合はこのコンポーネントが付いているGameObject自身を回す
[SerializeField]
private Transform targetTransform;
// 1秒あたりの回転量(度)。XYZそれぞれの軸ごとに設定可能
[SerializeField]
private Vector3 rotationSpeed = new Vector3(0f, 90f, 0f);
// ワールド座標系で回転させるかどうか。falseならローカル座標系で回転
[SerializeField]
private bool useWorldSpace = false;
// ゲーム開始時に自動で回転を有効にするか
[SerializeField]
private bool autoStart = true;
// 一時停止用フラグ(外部スクリプトやインスペクタから制御可能)
[SerializeField]
private bool isRotating = true;
// --- プロパティ(読み取り専用) ---
public bool IsRotating => isRotating;
private void Reset()
{
// コンポーネントを追加したときに、自身のTransformを自動セット
targetTransform = transform;
rotationSpeed = new Vector3(0f, 90f, 0f);
useWorldSpace = false;
autoStart = true;
isRotating = true;
}
private void Awake()
{
// targetTransform が未設定なら自分自身を対象にする
if (targetTransform == null)
{
targetTransform = transform;
}
}
private void Start()
{
// autoStart が false の場合は開始時に停止状態にしておく
if (!autoStart)
{
isRotating = false;
}
}
private void Update()
{
// 回転が無効なときは何もしない
if (!isRotating || targetTransform == null)
{
return;
}
// 経過時間を考慮して、フレームレートに依存しない回転量を計算
Vector3 deltaRotation = rotationSpeed * Time.deltaTime;
// ローカル回転かワールド回転かを選択
if (useWorldSpace)
{
// ワールド座標系での回転
targetTransform.Rotate(deltaRotation, Space.World);
}
else
{
// ローカル座標系での回転
targetTransform.Rotate(deltaRotation, Space.Self);
}
}
/// <summary>
/// 回転を開始(再開)する。
/// 外部スクリプトやUIボタンから呼び出せるようにpublicにしている。
/// </summary>
public void StartRotation()
{
isRotating = true;
}
/// <summary>
/// 回転を一時停止する。
/// </summary>
public void StopRotation()
{
isRotating = false;
}
/// <summary>
/// 回転速度を変更する。
/// 例: ギミックの難易度を上げたいときに呼び出す。
/// </summary>
/// <param name="newSpeed">新しい回転速度(度/秒)</param>
public void SetRotationSpeed(Vector3 newSpeed)
{
rotationSpeed = newSpeed;
}
/// <summary>
/// 回転対象のTransformを動的に差し替える。
/// 例: ゲーム中に別の足場を回すように変更したい場合など。
/// </summary>
public void SetTarget(Transform newTarget)
{
targetTransform = newTarget != null ? newTarget : transform;
}
}
使い方の手順
ここでは具体的な例として、
- プレイヤーが乗る「回転足場」
- 当たるとダメージを受ける「回転トゲ付きポール」
- ただの見た目用「回転コイン」
といったオブジェクトに適用するケースを想定して説明します。
手順①:回転させたいオブジェクトを用意する
- Hierarchy で
Right Click > 3D Object > Cubeなどを作成し、「RotatingPlatform」など分かりやすい名前にします。 - プレイヤーが乗る足場にしたい場合は、サイズを調整して床っぽい形にしておきます。
- ポールやコインなど別のオブジェクトでも同様です。Prefab にしておくと後で量産しやすいです。
手順②:「AutoRotator」コンポーネントを追加する
- 回転させたいオブジェクトを選択します(例:
RotatingPlatform)。 - Inspector の
Add Componentボタンを押し、「AutoRotator」と検索して追加します。 Reset()により、targetTransformには自動で自分自身がセットされます。
この状態でプレイすると、デフォルト設定では「ローカルY軸を毎秒90度」で回転し続けます。
床オブジェクトなら、ぐるぐる回転する足場の完成です。
手順③:回転の向き・速度を調整する
Inspector 上で、以下のパラメータを調整してギミックの性格を変えられます。
- Target Transform
デフォルトでは自分自身(このコンポーネントが付いているオブジェクト)。
親の足場だけを回しつつ、子オブジェクト(エフェクトなど)は別制御にしたい場合などは、明示的に別のTransformをドラッグ&ドロップで指定しましょう。 - Rotation Speed
(x, y, z)それぞれの軸の回転速度(度/秒)。
例:- 回転足場:
(0, 45, 0) - 横方向に倒れ続ける棒:
(0, 0, 60) - 3軸同時にグルグル回るトゲ:
(30, 60, 90)
- 回転足場:
- Use World Space
- OFF(デフォルト): ローカル軸で回転。オブジェクトの向きに沿って回転します。
- ON: ワールド軸で回転。例えば常に「世界のY軸」を中心に回したい場合はこちら。
- Auto Start
- ON: ゲーム開始と同時に回転開始。
- OFF: 最初は止まった状態。トリガーやボタンで
StartRotation()を呼ぶまで静止させたい場合に便利。
- Is Rotating
実行中でもチェックを外したり付けたりすることで、一時停止/再開を確認できます。
スクリプトからはStartRotation()/StopRotation()を呼び出すのが基本です。
手順④:ゲーム進行に応じて回転を制御する(発展)
少し踏み込んだ使い方として、例えば「スイッチを押したら足場が回転し始める」ギミックを作ることもできます。
using UnityEngine;
public class RotationSwitch : MonoBehaviour
{
[SerializeField]
private AutoRotator targetRotator;
private void OnTriggerEnter(Collider other)
{
// プレイヤーがスイッチに触れたら回転開始
if (other.CompareTag("Player") && targetRotator != null)
{
targetRotator.StartRotation();
}
}
private void OnTriggerExit(Collider other)
{
// 離れたら止める例(必要なければ削除してOK)
if (other.CompareTag("Player") && targetRotator != null)
{
targetRotator.StopRotation();
}
}
}
このように、回転そのもののロジックは AutoRotator に閉じ込めておき、
「いつ回すか」「どのくらいの速度にするか」といった制御だけを別コンポーネントに任せると、責務がきれいに分離できます。
メリットと応用
AutoRotator を導入するメリットは、単に「回転する」以上に、プロジェクト全体の設計がスッキリする点にあります。
- プレハブ化が簡単
回転足場、回転トゲ、回転コインなどをそれぞれ Prefab にしておけば、
シーン上にドラッグ&ドロップするだけで同じ挙動を使い回せます。
速度や軸を変えたいときも、Prefab のインスタンス側でパラメータを変えるだけでOKです。 - レベルデザインの試行錯誤がしやすい
「この足場はもう少しゆっくり」「このトゲはもっと速く」など、
デザイナーや自分自身がシーンビュー上でパラメータをいじるだけで調整できます。
スクリプトを開いて書き換える必要がないので、試行錯誤が高速になります。 - 責務が明確でテストしやすい
「回転の挙動」だけをこのコンポーネントが担当しているので、
バグが出たときもAutoRotatorだけを確認すればよく、原因の切り分けがしやすくなります。 - 他のコンポーネントと組み合わせやすい
ダメージ判定、サウンド再生、エフェクトなどは別コンポーネントとして付け足すだけでOKです。
「回転ロジック」と「ゲームルールロジック」が混ざらないので、Godクラス化を防げます。
改造案:ゆっくり加速しながら回転させる
例えば「ゲーム開始直後はゆっくり、数秒かけて最大速度まで加速する」ようなギミックを作りたい場合、
以下のようなメソッドを AutoRotator に追加して、外部からコルーチンを呼び出す形にしても面白いです。
/// <summary>
/// 一定時間かけて回転速度を変化させる(線形補間)。
/// 例: StartCoroutine(autoRotator.LerpSpeed(new Vector3(0, 180, 0), 3f));
/// </summary>
public System.Collections.IEnumerator LerpSpeed(Vector3 targetSpeed, float duration)
{
Vector3 startSpeed = rotationSpeed;
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
// 線形補間で速度をなめらかに変化させる
rotationSpeed = Vector3.Lerp(startSpeed, targetSpeed, t);
yield return null;
}
// 最終的に目標速度で固定
rotationSpeed = targetSpeed;
}
ゲーム開始時に StartCoroutine(autoRotator.LerpSpeed(...)) を呼び出せば、
じわじわ難易度が上がっていく回転足場なども簡単に作れます。
このように、小さなコンポーネントをベースに「ちょい足し」していくスタイルで、柔軟なギミックを量産していきましょう。
