【Cocos Creator】アタッチするだけ!AutoRotator (回転ギミック)の実装方法【TypeScript】

Godot 4ゲーム制作 実践ドリル 100本ノック

新品価格
¥1,250から
(2025/12/13 21:27時点)

Godot4& GDScriptではじめる 2Dゲーム開発レシピ

新品価格
¥590から
(2025/12/13 21:46時点)

Unity 6 C#スクリプト 100本ノック

新品価格
¥1,230から
(2025/12/29 10:28時点)

Cocos Creator100本ノックTypeScriptで書く!

新品価格
¥1,250から
(2025/12/29 10:32時点)

【Cocos Creator 3.8】AutoRotatorの実装:アタッチするだけで足場やオブジェクトを自動回転させる汎用スクリプト

このガイドでは、任意のノード(足場、ギミック、UI、背景オブジェクトなど)にアタッチするだけで、指定した速度・軸・方向で自動回転させ続ける汎用コンポーネント AutoRotator を実装します。外部のゲーム管理クラスやシングルトンには一切依存せず、すべてインスペクタの設定だけで完結するように設計します。


コンポーネントの設計方針

要件整理

  • 任意のノードにアタッチすると、そのノード(=親オブジェクト)を自動で回転させる。
  • 回転速度をインスペクタから調整できる。
  • 回転軸(X / Y / Z)を選択できる。
  • 回転方向(正方向・負方向)を制御できる。
  • ゲームの一時停止などに使える「有効 / 無効」フラグを持つ。
  • 時間依存の回転(deltaTime)で、フレームレートに依存しない動きをする。
  • 他のカスタムスクリプトには一切依存しない。

回転自体は Transform の eulerAngles を更新するだけなので、物理コンポーネントや Sprite などの必須依存はありません。そのため、防御的な実装としては「必須コンポーネントチェック」は不要で、対象ノード(this.node)が有効かどうかだけを確認すれば十分です。

インスペクタで設定可能なプロパティ設計

AutoRotator に持たせるプロパティと役割は次の通りです。

  • enabledRotation: boolean
    • 回転機能のオン / オフ。
    • チェックを外すと、その場で回転を停止できる。
  • speed: number
    • 回転速度(度/秒)。
    • 正の値:direction に従って回転。
    • 0 にすると停止と同じ。
  • axis: number(列挙風:0=X, 1=Y, 2=Z)
    • どの軸を中心に回転させるかを指定。
    • 2Dゲームの足場なら通常は Z 軸(2)を選択。
    • 3Dオブジェクトなら X / Y / Z どれでも利用可能。
  • direction: number(1 または -1)
    • 回転方向。
    • 1:正方向(右ねじの法則に従った回転)。
    • -1:逆方向。
  • useLocalSpace: boolean
    • true:ローカル座標系(this.node.eulerAngles)で回転。
    • false:ワールド座標系(this.node.worldEulerAngles)で回転。
    • 通常は true で問題ないが、親子構造に依存したい場合などに切り替え可能。

この構成により、「2D足場を一定速度でくるくる回す」「3DオブジェクトをY軸にゆっくり回転させる」など、さまざまな用途に再利用しやすくなります。


TypeScriptコードの実装

以下が完成した AutoRotator.ts の全コードです。


import { _decorator, Component, Node, Vec3 } from 'cc';
const { ccclass, property } = _decorator;

/**
 * AutoRotator
 * 任意のノードにアタッチするだけで、自動的に回転させる汎用コンポーネント。
 * - 速度(度/秒)、回転軸、方向をインスペクタから設定可能
 * - ローカル/ワールド座標系を切り替え可能
 */
@ccclass('AutoRotator')
export class AutoRotator extends Component {

    @property({
        tooltip: '回転を有効にするかどうか。\nチェックを外すと回転が停止します。'
    })
    public enabledRotation: boolean = true;

    @property({
        tooltip: '回転速度(度/秒)。\n正の値で速く回転します。0 にすると回転しません。'
    })
    public speed: number = 90;

    @property({
        tooltip: '回転軸を指定します。\n0 = X軸, 1 = Y軸, 2 = Z軸',
        type: Number
    })
    public axis: number = 2; // 0: X, 1: Y, 2: Z

    @property({
        tooltip: '回転方向を指定します。\n1 = 正方向, -1 = 逆方向',
        type: Number
    })
    public direction: number = 1; // 1 or -1

    @property({
        tooltip: 'ローカル座標系で回転するかどうか。\nON: this.node.eulerAngles\nOFF: this.node.worldEulerAngles'
    })
    public useLocalSpace: boolean = true;

    // 内部で使い回す一時ベクトル(GC削減用)
    private _tempEuler: Vec3 = new Vec3();

    onLoad() {
        // direction の値が 1 か -1 以外の場合は自動補正して警告
        if (this.direction !== 1 && this.direction !== -1) {
            console.warn(
                `[AutoRotator] direction が 1 または -1 ではありませんでした。` +
                ` 自動的に 1 に補正します。 (node: ${this.node.name})`
            );
            this.direction = 1;
        }

        // axis の範囲チェック
        if (this.axis < 0 || this.axis > 2) {
            console.warn(
                `[AutoRotator] axis が 0〜2 の範囲外でした。` +
                ` 自動的に 2 (Z軸) に補正します。 (node: ${this.node.name})`
            );
            this.axis = 2;
        }
    }

    start() {
        // 特に必須コンポーネントはないが、node の有効性をチェック
        if (!this.node) {
            console.error('[AutoRotator] this.node が無効です。コンポーネントのアタッチ先を確認してください。');
            this.enabled = false;
            return;
        }
    }

    update(deltaTime: number) {
        if (!this.enabledRotation) {
            return;
        }

        if (this.speed === 0) {
            return;
        }

        // 1秒あたり speed 度回転するように、フレームごとの回転角を計算
        const deltaAngle = this.speed * this.direction * deltaTime;

        // 現在の回転角を取得
        if (this.useLocalSpace) {
            this.node.getRotation().getEulerAngles(this._tempEuler);
        } else {
            this.node.getWorldRotation().getEulerAngles(this._tempEuler);
        }

        // 指定した軸に回転を加算
        switch (this.axis) {
            case 0: // X
                this._tempEuler.x += deltaAngle;
                break;
            case 1: // Y
                this._tempEuler.y += deltaAngle;
                break;
            case 2: // Z
            default:
                this._tempEuler.z += deltaAngle;
                break;
        }

        // 更新した角度を適用
        if (this.useLocalSpace) {
            this.node.setRotationFromEuler(this._tempEuler.x, this._tempEuler.y, this._tempEuler.z);
        } else {
            this.node.setWorldRotationFromEuler(this._tempEuler.x, this._tempEuler.y, this._tempEuler.z);
        }
    }
}

主要メソッドの解説

  • onLoad()
    • direction が 1 / -1 以外だった場合に自動補正し、警告ログを出します。
    • axis が 0〜2 以外だった場合に Z軸(2)に補正し、警告ログを出します。
    • インスペクタの誤設定による意図しない挙動を防ぐための、防御的な初期化です。
  • start()
    • this.node の有効性を簡単にチェックします。
    • 通常は問題になりませんが、万一アタッチ先が不正な場合はエラーを出してコンポーネント自体を無効化します。
  • update(deltaTime: number)
    • enabledRotationfalse の場合は何もせずにリターン。
    • speed が 0 の場合も回転しないため、早期リターンします。
    • deltaAngle = speed × direction × deltaTime で、フレームごとの回転角を計算。
    • 現在の回転(ローカル or ワールド)を _tempEuler に取得。
    • 指定軸(X/Y/Z)に deltaAngle を加算。
    • 更新したオイラー角を setRotationFromEuler または setWorldRotationFromEuler で適用。
    • _tempEuler を使い回すことで、毎フレームの GC(メモリ確保・解放)を抑えています。

使用手順と動作確認

1. スクリプトファイルの作成

  1. エディタ上部メニューまたは Assets パネルで、スクリプトを置きたいフォルダを選択します(例: assets/scripts)。
  2. そのフォルダ上で右クリックし、Create → TypeScript を選択します。
  3. 新規スクリプトの名前を AutoRotator.ts に変更します。
  4. 作成された AutoRotator.ts をダブルクリックし、エディタ(VS Code など)で開きます。
  5. 中身をすべて削除し、前述の AutoRotator のコードをそのまま貼り付けて保存します。

2. テスト用ノードの作成

ここでは 2D の足場スプライトを回転させる例で説明します。

  1. Hierarchy パネルで、2D シーンなら Canvas の子として、3D シーンならルート直下など、回転させたい位置を選びます。
  2. 右クリックして Create → 2D Object → Sprite を選択します(3D オブジェクトなら Create → 3D Object → Box など)。
  3. 作成されたノードに分かりやすい名前を付けます(例: RotatingPlatform)。
  4. 2D の場合は Sprite コンポーネントに適当な画像を設定して、足場のように見えるようにしておきます。

3. AutoRotator コンポーネントのアタッチ

  1. Hierarchy で、先ほど作成した RotatingPlatform ノードを選択します。
  2. Inspector パネルの下部にある Add Component ボタンをクリックします。
  3. Custom カテゴリを開き、その中から AutoRotator を選択します。
    • もし表示されない場合は、スクリプトの保存漏れやクラス名(@ccclass('AutoRotator'))のスペルミスがないか確認し、エディタをリロードしてください。

4. インスペクタでプロパティを設定

InspectorAutoRotator が追加されていることを確認し、各プロパティを次のように設定してみます。

  • Enabled Rotation(enabledRotation)
    • チェック ON(デフォルトのまま)。
  • Speed(speed)
    • 例1: 45(ゆっくり回転)。
    • 例2: 180(速く回転)。
  • Axis(axis)
    • 2D足場の場合:2(Z軸)を指定。
    • 3Dで縦回転させたい場合:1(Y軸)などに変更。
  • Direction(direction)
    • 1:時計回りまたは右ねじ方向。
    • -1:逆回転。
    • 試しに 1-1 を切り替えて挙動を確認してください。
  • Use Local Space(useLocalSpace)
    • 通常は true のままで問題ありません。
    • 親ノードの回転に影響されない絶対的な回転をさせたい場合は false に変更してみてください。

5. シーン再生で動作確認

  1. エディタ上部の Play ボタンをクリックしてシーンを再生します。
  2. 先ほど AutoRotator をアタッチしたノードが、設定した軸と速度で回転していることを確認します。
  3. 回転が速すぎる / 遅すぎる場合は、Speed を調整して再度再生してみてください。
  4. 再生中に Inspector から Enabled Rotation のチェックを外すと、その場で回転が止まることも確認できます(エディタのリアルタイム編集が有効な場合)。

6. よくある調整パターン例

  • ゆっくり回転する背景ギミック
    • Speed: 15
    • Axis: 2 (Z軸)
    • Direction: 1
    • Use Local Space: true
  • プレイヤーが乗る高速回転足場
    • Speed: 120
    • Axis: 2 (Z軸)
    • Direction: -1
    • Use Local Space: true
  • 3DタイトルロゴのゆっくりY軸回転
    • Speed: 30
    • Axis: 1 (Y軸)
    • Direction: 1
    • Use Local Space: false(ワールド基準で回転させたい場合)

まとめ

この AutoRotator コンポーネントは、

  • 任意のノードにアタッチするだけで回転ギミックを実現できる。
  • 回転速度・軸・方向・座標系をインスペクタから柔軟に調整できる。
  • 他のカスタムスクリプトやシングルトンに依存せず、このスクリプト単体で完結する。

という特徴を持っています。

足場・トラップ・背景オブジェクト・UIアイコン・タイトルロゴなど、「とりあえずクルクルさせたい」場面はゲーム中に非常に多くあります。そのたびに都度スクリプトを書くのではなく、このような汎用コンポーネントとして切り出しておくことで、

  • アセットを配置して AutoRotator をアタッチするだけで即座に動かせる。
  • パラメータ調整もインスペクタ上で完結し、プログラムを触らずにゲームデザイナーも調整できる。
  • 同じスクリプトを複数シーン・複数プロジェクトで再利用できる。

といったメリットが得られ、開発効率が大きく向上します。

この AutoRotator をベースに、「一定時間ごとに回転方向を切り替える」「角度制限を付けて往復運動にする」など、機能を拡張したバリエーションコンポーネントを作るのも容易です。まずは本記事のコードをそのままプロジェクトに組み込んで、さまざまなオブジェクトを回転させてみてください。

Godot 4ゲーム制作 実践ドリル 100本ノック

新品価格
¥1,250から
(2025/12/13 21:27時点)

Godot4& GDScriptではじめる 2Dゲーム開発レシピ

新品価格
¥590から
(2025/12/13 21:46時点)

Unity 6 C#スクリプト 100本ノック

新品価格
¥1,230から
(2025/12/29 10:28時点)

Cocos Creator100本ノックTypeScriptで書く!

新品価格
¥1,250から
(2025/12/29 10:32時点)

URLをコピーしました!