【Cocos Creator】アタッチするだけ!KillZ (落下死ライン)の実装方法【TypeScript】

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

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

脱・初心者!Godot 4 ゲーム開発の「2歩目」

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

Godot4ローグライク入門 ~ダンジョン自動生成~

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

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

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

【Cocos Creator 3.8】KillZ(落下死ライン)の実装:アタッチするだけで「一定Y座標以下で即死&リスポーン」を実現する汎用スクリプト

本記事では、2D/3Dどちらのゲームでも使える「落下死ライン」用コンポーネント KillZ を実装します。
プレイヤーや敵など「落ちたら即アウト」にしたいノードにアタッチするだけで、Y座標が指定値より下に落ちた瞬間に自動で即死処理(消滅 or リスポーン) を行えるようになります。

HP管理用のGameManagerやシングルトンには一切依存せず、このコンポーネント単体で完結する設計です。
「とりあえず落ちたら消えてほしい」「簡易的なリスポーンを付けたい」といったシーンで、そのままコピペして使えるように解説します。


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

要件整理

  • 対象ノード(プレイヤー・敵・アイテムなど)の Y座標 を毎フレーム監視する。
  • Y座標が指定した閾値(killY)より小さくなったら「即死」とみなす。
  • 即死時の挙動は、用途に応じて選べるようにする:
    • ノードを削除する(destroy)
    • 指定位置にリスポーンする(位置だけ戻す)
    • リスポーン時に速度もゼロにリセットする(Rigidbody / RigidBody2D があれば)
  • 外部のカスタムスクリプトには一切依存せず、すべてを @property で設定できる。
  • 2D/3Dどちらでも使えるよう、ワールド座標のY値 だけを見て判定する。
  • 必須コンポーネントは特にないが、リスポーン時に速度リセットを行う場合のみ、Rigidbody / RigidBody2D があれば利用する(なければログを出してスキップ)。

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

KillZ コンポーネントに用意する @property は以下の通りです。

  • killY: number
    • 「このY座標より下に落ちたら即死」とみなす閾値。
    • ワールド座標系のY値で指定。
    • 例:-10, -100 など。ステージの高さに応じて調整。
  • actionOnKill: KillAction(enum)
    • 落下死時に行うアクションの種類。
    • Destroy: ノードを破棄する(完全に消える)。
    • RespawnAtStart: ゲーム開始時の位置(start時に記録)に戻す。
    • RespawnAtCustom: 任意のリスポーン位置を指定してそこに戻す。
  • useLocalPosition: boolean
    • リスポーン位置を「ローカル座標」として扱うかどうか。
    • true:親ノードからの相対位置(setPosition)。
    • false:ワールド座標として扱う(setWorldPosition)。
    • 2Dゲームでプレイヤーが親ノードの中にいる場合など、ローカル座標でのリスポーンが便利。
  • customRespawnPosition: Vec3
    • actionOnKill = RespawnAtCustom のときに使うリスポーン先座標。
    • 2DでもVec3で指定(Zは通常0でOK)。
    • useLocalPosition が true ならローカル座標、false ならワールド座標として解釈。
  • resetVelocityOnRespawn: boolean
    • リスポーン時に Rigidbody / RigidBody2D の速度をゼロにするか。
    • truelinearVelocity / linearVelocity を (0,0) にリセット。
    • false:速度はそのまま(物理挙動を自前で制御している場合など)。
  • logOnKill: boolean
    • 落下死が発生したときにコンソールにログを出すか。
    • デバッグ時は true、本番では false にしてもよい。

この設計により、

  • プレイヤー:RespawnAtStart でスタート地点に戻す。
  • 敵:Destroy で画面外に落ちたら消す。
  • アイテム:RespawnAtCustom で特定位置に戻して再出現させる。

といった使い分けが、同じ KillZ コンポーネントをアタッチするだけ で可能になります。


TypeScriptコードの実装


import { _decorator, Component, Node, Vec3, v3, math, RigidBody, RigidBody2D, log, warn } from 'cc';
const { ccclass, property } = _decorator;

/**
 * KillZ
 * Y座標が指定値より下に落ちたときに即死(Destroy or Respawn)させる汎用コンポーネント。
 */
enum KillAction {
    Destroy = 0,
    RespawnAtStart = 1,
    RespawnAtCustom = 2,
}

@ccclass('KillZ')
export class KillZ extends Component {

    @property({
        tooltip: 'このワールドY座標より下に落ちたら即死させます。\n例: -10, -100 など。',
    })
    public killY: number = -10;

    @property({
        type: KillAction,
        tooltip: '落下死が発生したときに行うアクションの種類です。\n' +
                 'Destroy: ノードを破棄します。\n' +
                 'RespawnAtStart: ゲーム開始時の位置に戻します。\n' +
                 'RespawnAtCustom: customRespawnPosition で指定した位置に戻します。',
    })
    public actionOnKill: KillAction = KillAction.Destroy;

    @property({
        tooltip: 'リスポーン位置をローカル座標として扱うかどうか。\n' +
                 'ON: 親ノードからの相対位置として respawnPosition を適用します。\n' +
                 'OFF: ワールド座標として respawnPosition を適用します。',
    })
    public useLocalPosition: boolean = false;

    @property({
        tooltip: 'RespawnAtCustom のときに使用するリスポーン位置です。\n' +
                 '2DでもVec3で指定します(通常 Z=0 のままで問題ありません)。',
    })
    public customRespawnPosition: Vec3 = v3(0, 0, 0);

    @property({
        tooltip: 'リスポーン時に Rigidbody / RigidBody2D の速度をゼロにリセットするかどうか。\n' +
                 'ON: 速度を (0,0) にします。\n' +
                 'OFF: 速度は変更しません。',
    })
    public resetVelocityOnRespawn: boolean = true;

    @property({
        tooltip: '落下死が発生したときにログを出力するかどうか。',
    })
    public logOnKill: boolean = true;

    // 開始時の位置(RespawnAtStart 用)
    private _startLocalPosition: Vec3 | null = null;
    private _startWorldPosition: Vec3 | null = null;

    // キャッシュ用
    private _rigidbody3D: RigidBody | null = null;
    private _rigidbody2D: RigidBody2D | null = null;

    onLoad() {
        // Rigidbody / RigidBody2D を取得(あればキャッシュ)
        this._rigidbody3D = this.getComponent(RigidBody);
        this._rigidbody2D = this.getComponent(RigidBody2D);

        if (!this._rigidbody3D && !this._rigidbody2D && this.resetVelocityOnRespawn) {
            // 速度リセットをONにしているのにRigidbodyがない場合は警告
            warn('[KillZ] resetVelocityOnRespawn が有効ですが、Rigidbody / RigidBody2D が見つかりません。速度リセットはスキップされます。');
        }
    }

    start() {
        // 開始時の位置を記録(RespawnAtStart 用)
        const node = this.node;
        this._startLocalPosition = node.position.clone();
        this._startWorldPosition = node.worldPosition.clone();
    }

    update(deltaTime: number) {
        // ノードがすでに破棄されている場合は何もしない
        if (!this.node || !this.node.isValid) {
            return;
        }

        // 現在のワールドY座標を取得
        const currentWorldY = this.node.worldPosition.y;

        // 閾値より下に落ちたか判定
        if (currentWorldY < this.killY) {
            this._handleKill();
        }
    }

    /**
     * 落下死時の処理をまとめたメソッド。
     */
    private _handleKill() {
        if (this.logOnKill) {
            log(`[KillZ] Node "${this.node.name}" fell below killY=${this.killY}. Action=${KillAction[this.actionOnKill]}`);
        }

        switch (this.actionOnKill) {
            case KillAction.Destroy:
                this._destroyNode();
                break;
            case KillAction.RespawnAtStart:
                this._respawnAtStart();
                break;
            case KillAction.RespawnAtCustom:
                this._respawnAtCustom();
                break;
            default:
                warn('[KillZ] 未知の KillAction が指定されています。何も行いません。');
                break;
        }
    }

    /**
     * ノードを破棄する。
     */
    private _destroyNode() {
        if (!this.node.isValid) {
            return;
        }
        this.node.destroy();
    }

    /**
     * start() 時点の位置にリスポーンさせる。
     */
    private _respawnAtStart() {
        if (!this.node.isValid) {
            return;
        }

        const node = this.node;

        if (this.useLocalPosition) {
            if (this._startLocalPosition) {
                node.setPosition(this._startLocalPosition);
            } else {
                warn('[KillZ] _startLocalPosition が未初期化です。RespawnAtStart に失敗しました。');
            }
        } else {
            if (this._startWorldPosition) {
                node.setWorldPosition(this._startWorldPosition);
            } else {
                warn('[KillZ] _startWorldPosition が未初期化です。RespawnAtStart に失敗しました。');
            }
        }

        if (this.resetVelocityOnRespawn) {
            this._resetVelocity();
        }
    }

    /**
     * customRespawnPosition で指定した位置にリスポーンさせる。
     */
    private _respawnAtCustom() {
        if (!this.node.isValid) {
            return;
        }

        const node = this.node;

        if (this.useLocalPosition) {
            node.setPosition(this.customRespawnPosition);
        } else {
            node.setWorldPosition(this.customRespawnPosition);
        }

        if (this.resetVelocityOnRespawn) {
            this._resetVelocity();
        }
    }

    /**
     * Rigidbody / RigidBody2D の速度をゼロにする。
     */
    private _resetVelocity() {
        if (this._rigidbody3D) {
            // 3D物理
            this._rigidbody3D.linearVelocity = new math.Vec3(0, 0, 0);
            this._rigidbody3D.angularVelocity = new math.Vec3(0, 0, 0);
        }

        if (this._rigidbody2D) {
            // 2D物理
            this._rigidbody2D.linearVelocity = v3(0, 0, 0);
            this._rigidbody2D.angularVelocity = 0;
        }

        if (!this._rigidbody3D && !this._rigidbody2D) {
            // 速度リセットが有効だがRigidbodyがない場合は警告
            warn('[KillZ] 速度リセットを試みましたが、Rigidbody / RigidBody2D が見つかりませんでした。');
        }
    }
}

コードの要点解説

  • onLoad
    • Rigidbody / RigidBody2D を取得してキャッシュ。
    • resetVelocityOnRespawn が true なのにどちらも見つからない場合、警告ログを出して開発者に気付かせます。
  • start
    • ゲーム開始時の ローカル座標ワールド座標 を両方記録。
    • RespawnAtStart のとき、useLocalPosition の設定に応じてどちらかを使います。
  • update
    • 毎フレーム、this.node.worldPosition.y を監視。
    • Yが killY より小さくなったら _handleKill() を呼び出します。
  • _handleKill
    • 設定された actionOnKill に応じて、Destroy / Respawn を振り分け。
    • logOnKill が true の場合、どのノードに何が起きたかログを出します。
  • _respawnAtStart / _respawnAtCustom
    • useLocalPosition のON/OFFに応じて setPositionsetWorldPosition を使い分け。
    • resetVelocityOnRespawn が true の場合は _resetVelocity() で速度をゼロにします。
  • _resetVelocity
    • 3D物理(RigidBody)と2D物理(RigidBody2D)の両方に対応。
    • 存在するほうだけ速度をゼロにし、どちらもなければ警告を出します。

使用手順と動作確認

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

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

2. テスト用ノードの作成(2Dの例)

  1. Hierarchy パネルで右クリック → Create → 2D Object → Canvas を作成(まだなければ)。
  2. Canvas を選択し、右クリック → Create → 2D Object → Sprite でプレイヤー用の Sprite ノードを作成します。
  3. Sprite ノードを Player など分かりやすい名前に変更します。
  4. 必要であれば、Rigidbody2DCollider2D などを追加して、重力で落ちるように設定します。
    • Player を選択 → Inspector の Add ComponentPhysics 2D → RigidBody2D を追加。
    • Body Type を Dynamic に設定し、Gravity Scale を 1 にします。

3. KillZ コンポーネントをアタッチ

  1. Hierarchy で Player ノードを選択します。
  2. Inspector の下部にある Add Component ボタンをクリックします。
  3. Custom カテゴリの中から KillZ を選択して追加します。
    • もし Custom の中に見つからない場合は、一度保存してエディタを再読み込みしてください。

4. プロパティの設定例(基本編)

まずは「落ちたら消える」シンプルな挙動から試します。

  1. Player ノードの Inspector で、追加した KillZ コンポーネントを確認します。
  2. プロパティを次のように設定します:
    • killY: -10(ステージの下の方に合わせて調整)
    • actionOnKill: Destroy
    • useLocalPosition: false(Destroy なのでどちらでも影響なし)
    • customRespawnPosition: そのままでOK(Destroy では未使用)
    • resetVelocityOnRespawn: true(Destroy では未使用)
    • logOnKill: true(挙動確認のためON推奨)
  3. シーンビューで Player を少し高い位置(Y=5 など)に配置します。
  4. 再生ボタン(▶)を押してゲームを実行します。
  5. Player が重力で落下し、Y座標が -10 より下に到達した瞬間に ノードが消える ことを確認します。
    • Console パネルに [KillZ] Node "Player" fell below killY=-10. Action=Destroy のようなログが出ていれば成功です。

5. リスポーン動作の確認(RespawnAtStart)

次に、「落ちたらスタート位置に戻る」パターンを試します。

  1. Player ノードの KillZ コンポーネント設定を次のように変更します:
    • killY: -10(そのままでもOK)
    • actionOnKill: RespawnAtStart
    • useLocalPosition: true(Canvas 内のローカル座標で扱う想定)
    • resetVelocityOnRespawn: true(落下速度をリセットしたいのでON)
    • logOnKill: true
  2. シーンを一度停止してから、Player の初期位置(スタート地点)をシーンビューで調整します(例:Y=200)。
  3. 再生ボタンを押して実行し、Player が落下して killY を下回ったときに、初期位置にワープして戻る ことを確認します。
  4. Rigidbody2D を付けている場合、リスポーン直後に落下速度がゼロになっている(その場から再び落ち始める)ことも確認してください。

6. 任意位置リスポーン(RespawnAtCustom)

最後に、「特定のチェックポイント位置に戻す」ような使い方を確認します。

  1. Player ノードの KillZ 設定を次のように変更します:
    • actionOnKill: RespawnAtCustom
    • useLocalPosition: 2D Canvas 内なら true 推奨。
    • customRespawnPosition:
      • 例えば (x: 0, y: 250, z: 0) など、チェックポイントの位置を入力します。
    • resetVelocityOnRespawn: true
  2. ゲームを実行し、Player が落下して killY を下回ると、毎回 customRespawnPosition で指定した座標に戻ることを確認します。

7. 3D シーンでの利用

3D でも基本的な使い方は同じです。

  1. Hierarchy で任意の 3D キャラクターノード(例:Player3D)を作成します。
  2. 必要であれば RigidBodyCollider を追加して、重力で落ちるようにします。
  3. Add Component → Custom → KillZ を追加します。
  4. プロパティを設定します:
    • killY: 3D ステージの高さに合わせて(例:-5)。
    • actionOnKill: RespawnAtStart など。
    • useLocalPosition: 通常は false(ワールド座標で扱うことが多い)。
  5. 実行して、3D キャラクターが足場から落ちたときに Destroy / Respawn されることを確認します。

まとめ

本記事では、Cocos Creator 3.8 で使える汎用落下死コンポーネント KillZ を実装しました。

  • Y座標が一定以下になったら即死 というよくある挙動を、アタッチするだけ で簡単に導入できる。
  • 「破棄」「開始位置にリスポーン」「任意位置にリスポーン」を @property で切り替え可能。
  • Rigidbody / RigidBody2D があれば、リスポーン時の速度リセットにも対応。
  • 外部の GameManager やシングルトンには一切依存せず、このスクリプト単体で完結 する設計。
  • 2D / 3D 共通で使え、ノードごとに killY や挙動を変えられるため、プレイヤー・敵・アイテムなど幅広く再利用できる。

この KillZ をベースに、

  • リスポーン回数の制限(3回までなど)
  • 落下死時にエフェクトやSEを再生する
  • UIに「残機」や「リトライメッセージ」を表示する

といった拡張も簡単に行えます。まずは本記事のコードをそのままプロジェクトに取り込んで、シーン内のノードにアタッチしながら、自分のゲームに合う設定値を探ってみてください。

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

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

脱・初心者!Godot 4 ゲーム開発の「2歩目」

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

Godot4ローグライク入門 ~ダンジョン自動生成~

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

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

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

URLをコピーしました!