【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 の速度をゼロにするか。
true:linearVelocity/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に応じてsetPositionかsetWorldPositionを使い分け。resetVelocityOnRespawnが true の場合は_resetVelocity()で速度をゼロにします。
- _resetVelocity
- 3D物理(RigidBody)と2D物理(RigidBody2D)の両方に対応。
- 存在するほうだけ速度をゼロにし、どちらもなければ警告を出します。
使用手順と動作確認
1. スクリプトファイルの作成
- エディタ上部メニューまたは Assets パネル内で、任意のフォルダを選択します(例:
assets/scripts)。 - Assets パネルで右クリック → Create → TypeScript を選択します。
- 新しく作成されたスクリプトの名前を KillZ.ts に変更します。
- KillZ.ts をダブルクリックしてエディタ(VS Codeなど)で開き、既存の中身をすべて削除して、前章のコードを丸ごと貼り付けて保存します。
2. テスト用ノードの作成(2Dの例)
- Hierarchy パネルで右クリック → Create → 2D Object → Canvas を作成(まだなければ)。
- Canvas を選択し、右クリック → Create → 2D Object → Sprite でプレイヤー用の Sprite ノードを作成します。
- Sprite ノードを
Playerなど分かりやすい名前に変更します。 - 必要であれば、Rigidbody2D や Collider2D などを追加して、重力で落ちるように設定します。
- Player を選択 → Inspector の Add Component → Physics 2D → RigidBody2D を追加。
- Body Type を Dynamic に設定し、Gravity Scale を 1 にします。
3. KillZ コンポーネントをアタッチ
- Hierarchy で Player ノードを選択します。
- Inspector の下部にある Add Component ボタンをクリックします。
- Custom カテゴリの中から KillZ を選択して追加します。
- もし Custom の中に見つからない場合は、一度保存してエディタを再読み込みしてください。
4. プロパティの設定例(基本編)
まずは「落ちたら消える」シンプルな挙動から試します。
- Player ノードの Inspector で、追加した KillZ コンポーネントを確認します。
- プロパティを次のように設定します:
- killY:
-10(ステージの下の方に合わせて調整) - actionOnKill: Destroy
- useLocalPosition:
false(Destroy なのでどちらでも影響なし) - customRespawnPosition: そのままでOK(Destroy では未使用)
- resetVelocityOnRespawn:
true(Destroy では未使用) - logOnKill:
true(挙動確認のためON推奨)
- killY:
- シーンビューで Player を少し高い位置(Y=5 など)に配置します。
- 再生ボタン(▶)を押してゲームを実行します。
- Player が重力で落下し、Y座標が -10 より下に到達した瞬間に ノードが消える ことを確認します。
- Console パネルに
[KillZ] Node "Player" fell below killY=-10. Action=Destroyのようなログが出ていれば成功です。
- Console パネルに
5. リスポーン動作の確認(RespawnAtStart)
次に、「落ちたらスタート位置に戻る」パターンを試します。
- Player ノードの KillZ コンポーネント設定を次のように変更します:
- killY:
-10(そのままでもOK) - actionOnKill: RespawnAtStart
- useLocalPosition:
true(Canvas 内のローカル座標で扱う想定) - resetVelocityOnRespawn:
true(落下速度をリセットしたいのでON) - logOnKill:
true
- killY:
- シーンを一度停止してから、Player の初期位置(スタート地点)をシーンビューで調整します(例:Y=200)。
- 再生ボタンを押して実行し、Player が落下して killY を下回ったときに、初期位置にワープして戻る ことを確認します。
- Rigidbody2D を付けている場合、リスポーン直後に落下速度がゼロになっている(その場から再び落ち始める)ことも確認してください。
6. 任意位置リスポーン(RespawnAtCustom)
最後に、「特定のチェックポイント位置に戻す」ような使い方を確認します。
- Player ノードの KillZ 設定を次のように変更します:
- actionOnKill: RespawnAtCustom
- useLocalPosition: 2D Canvas 内なら
true推奨。 - customRespawnPosition:
- 例えば (x: 0, y: 250, z: 0) など、チェックポイントの位置を入力します。
- resetVelocityOnRespawn:
true
- ゲームを実行し、Player が落下して killY を下回ると、毎回 customRespawnPosition で指定した座標に戻ることを確認します。
7. 3D シーンでの利用
3D でも基本的な使い方は同じです。
- Hierarchy で任意の 3D キャラクターノード(例:
Player3D)を作成します。 - 必要であれば RigidBody と Collider を追加して、重力で落ちるようにします。
- Add Component → Custom → KillZ を追加します。
- プロパティを設定します:
- killY: 3D ステージの高さに合わせて(例:
-5)。 - actionOnKill:
RespawnAtStartなど。 - useLocalPosition: 通常は
false(ワールド座標で扱うことが多い)。
- killY: 3D ステージの高さに合わせて(例:
- 実行して、3D キャラクターが足場から落ちたときに Destroy / Respawn されることを確認します。
まとめ
本記事では、Cocos Creator 3.8 で使える汎用落下死コンポーネント KillZ を実装しました。
- Y座標が一定以下になったら即死 というよくある挙動を、アタッチするだけ で簡単に導入できる。
- 「破棄」「開始位置にリスポーン」「任意位置にリスポーン」を
@propertyで切り替え可能。 - Rigidbody / RigidBody2D があれば、リスポーン時の速度リセットにも対応。
- 外部の GameManager やシングルトンには一切依存せず、このスクリプト単体で完結 する設計。
- 2D / 3D 共通で使え、ノードごとに killY や挙動を変えられるため、プレイヤー・敵・アイテムなど幅広く再利用できる。
この KillZ をベースに、
- リスポーン回数の制限(3回までなど)
- 落下死時にエフェクトやSEを再生する
- UIに「残機」や「リトライメッセージ」を表示する
といった拡張も簡単に行えます。まずは本記事のコードをそのままプロジェクトに取り込んで、シーン内のノードにアタッチしながら、自分のゲームに合う設定値を探ってみてください。




