【Cocos Creator 3.8】RespawnAnchor(復活地点)の実装:アタッチするだけで「触れた位置をセーブ&そこから復活」を実現する汎用スクリプト
このコンポーネントは、プレイヤーなどのキャラクターにアタッチするだけで、「最後に触れた復活地点(アンカー)」から自動的にリスポーンできるようにする汎用スクリプトです。
復活地点側には特別なスクリプトを用意せず、任意のノードを「RespawnAnchor」として認識させるだけで機能します。
- プレイヤーがチェックポイント(復活地点)に触れたら、その位置を記録
- 死亡条件を満たしたとき、自動で最後の復活地点にテレポート
- 外部のGameManagerやシングルトン不要。これ1本で完結
コンポーネントの設計方針
1. 全体コンセプト
このコンポーネントは「復活される側(プレイヤー等)」にアタッチして使います。
- プレイヤーノードに
RespawnAnchorを付ける。 - シーン上の任意のノードを「復活地点」として扱う。
- 復活地点ノードの判定は、タグ的に ノード名 or ノードに付けた特定コンポーネント を使うのではなく、インスペクタで登録したノード配列を使う(外部依存を避けるため)。
- 「触れた」ことの判定は、Collider2D のトリガーイベントまたは、距離ベースの簡易チェックで行えるようにする。
- 死亡判定は、Y座標が一定以下になったら死亡扱いにする(よくある「奈落に落ちたら復活」)。
外部のGameManagerやシングルトンに依存せず、このコンポーネント単体で「チェックポイント+復活」まで完結させます。
2. インスペクタで設定可能なプロパティ
RespawnAnchor コンポーネントに用意する @property を整理します。
- respawnPoints :
Node[]
– 復活地点として扱うノードの配列。
– シーン上の任意のノード(Empty Node / Sprite / Tilemap など)をドラッグ&ドロップで登録。
– プレイヤーがこれらのノードに「触れた」と判定されたとき、そのノードの位置を最新の復活地点として記録。 - useTriggerCollider :
boolean
–true:Collider2DのonTriggerEnterを使って「触れた」ことを検出。
–false:毎フレーム、距離ベースで「近づいたら触れた」とみなす簡易モード。 - triggerTargetIsRespawnPoint :
boolean
–true:トリガーに入った「相手ノード」がrespawnPointsのいずれかと一致した場合にのみ、復活地点として採用。
–false:トリガーに入った「相手ノードの親(parent)」を復活地点候補とみなし、respawnPointsに一致するかを確認。
– 復活地点のコライダーを子ノードに付ける構成か、本体ノードに付けるかを選べるようにするためのオプション。 - distanceCheckRadius :
number
–useTriggerCollider = falseのときに使用。
– プレイヤーの現在位置と復活地点ノードの距離がこの値以下になったら「触れた」とみなす半径。 - autoSetInitialAnchor :
boolean
–true:start()時に、プレイヤー自身の現在位置を初期復活地点として記録。
–false:最初の復活地点はrespawnPointsに触れるまで設定されない。 - deathYThreshold :
number
– このY座標より下にプレイヤーが落ちたら「死亡」と判定し、自動でリスポーンさせる。
– 例:-1000など。 - autoRespawnOnDeath :
boolean
–true:死亡判定が出た瞬間に自動で復活地点にテレポート。
–false:死亡状態フラグを立てるだけで、実際の復活処理は開発者がrespawnNow()を呼び出して行う(より制御したい場合用)。 - resetVelocityOnRespawn :
boolean
–true:復活時にRigidBody2Dの速度をゼロにリセット。
–false:速度はそのまま(物理挙動を自前で制御したい場合)。 - logDebugInfo :
boolean
–true:復活地点の更新や死亡判定などをconsole.logで出力。
–false:ログ出力を抑制。
また、防御的実装として以下を行います。
- 必要に応じて
Collider2DやRigidBody2DをgetComponentで取得し、存在しなければ警告ログを出す。 - 復活地点が1つも登録されていない場合や、まだ一度も復活地点に触れていない場合には、その旨をログ出力して復活処理をスキップ。
TypeScriptコードの実装
import { _decorator, Component, Node, Vec3, Collider2D, ITriggerEvent, RigidBody2D, v3 } from 'cc';
const { ccclass, property } = _decorator;
/**
* RespawnAnchor
* プレイヤーなどにアタッチして使用する「復活地点管理」コンポーネント。
* - respawnPoints で登録したノードを「復活地点」として扱う
* - 触れた復活地点の位置を記録し、死亡時にそこへ戻す
* - 外部マネージャ不要、これ1本で完結
*/
@ccclass('RespawnAnchor')
export class RespawnAnchor extends Component {
@property({
type: [Node],
tooltip: '復活地点として扱うノード一覧。\nプレイヤーがこれらに触れたとき、その位置が復活地点として記録されます。'
})
public respawnPoints: Node[] = [];
@property({
tooltip: 'true: Collider2D のトリガーイベントで「触れた」を検出します。\nfalse: 距離ベースで毎フレーム判定します。'
})
public useTriggerCollider: boolean = true;
@property({
tooltip: 'true: トリガーに入った相手ノード自体を復活地点候補とします。\nfalse: 相手ノードの parent を復活地点候補とします。'
})
public triggerTargetIsRespawnPoint: boolean = true;
@property({
tooltip: 'useTriggerCollider = false のときに使用。\nプレイヤーと復活地点の距離がこの値以下であれば「触れた」とみなします。'
})
public distanceCheckRadius: number = 50;
@property({
tooltip: 'true: start() 時に自分の現在位置を初期復活地点として記録します。'
})
public autoSetInitialAnchor: boolean = true;
@property({
tooltip: 'このY座標より下に落ちたら死亡とみなし、復活処理を行います。'
})
public deathYThreshold: number = -1000;
@property({
tooltip: 'true: 死亡判定が出た瞬間に自動で復活地点へテレポートします。\nfalse: 死亡フラグのみ立て、respawnNow() を手動で呼び出してください。'
})
public autoRespawnOnDeath: boolean = true;
@property({
tooltip: 'true: 復活時に RigidBody2D の速度をゼロにリセットします。'
})
public resetVelocityOnRespawn: boolean = true;
@property({
tooltip: 'true: 復活地点の更新や死亡判定など、デバッグ情報をコンソールに出力します。'
})
public logDebugInfo: boolean = true;
// 内部状態
private _currentRespawnPos: Vec3 | null = null;
private _isDead: boolean = false;
// 参照キャッシュ
private _collider2D: Collider2D | null = null;
private _rigidBody2D: RigidBody2D | null = null;
onLoad() {
// Collider2D を取得(存在しない場合は警告)
this._collider2D = this.getComponent(Collider2D);
if (!this._collider2D && this.useTriggerCollider) {
console.warn('[RespawnAnchor] Collider2D が見つかりません。トリガー判定を使用するには、プレイヤーノードに Collider2D を追加し、IsTrigger を有効にしてください。');
}
// RigidBody2D を取得(存在しない場合は警告のみ)
this._rigidBody2D = this.getComponent(RigidBody2D);
if (!this._rigidBody2D && this.resetVelocityOnRespawn) {
console.warn('[RespawnAnchor] RigidBody2D が見つかりません。復活時の速度リセットは行われません。');
}
if (this.useTriggerCollider && this._collider2D) {
// トリガーイベント登録
this._collider2D.on('onTriggerEnter', this._onTriggerEnter, this);
}
}
start() {
// 初期復活地点を自分の位置に設定
if (this.autoSetInitialAnchor) {
this._currentRespawnPos = this.node.worldPosition.clone();
if (this.logDebugInfo) {
console.log('[RespawnAnchor] 初期復活地点を現在位置に設定しました:', this._currentRespawnPos);
}
} else if (this.logDebugInfo) {
console.log('[RespawnAnchor] autoSetInitialAnchor = false のため、最初の復活地点は未設定です。');
}
}
update(deltaTime: number) {
// 死亡判定
if (!this._isDead && this.node.worldPosition.y < this.deathYThreshold) {
this._onDeathDetected();
}
// 距離ベースの復活地点更新
if (!this.useTriggerCollider) {
this._checkRespawnPointsByDistance();
}
}
onDestroy() {
// イベント登録解除
if (this.useTriggerCollider && this._collider2D) {
this._collider2D.off('onTriggerEnter', this._onTriggerEnter, this);
}
}
/**
* トリガーに入ったときに呼ばれるコールバック。
*/
private _onTriggerEnter(event: ITriggerEvent) {
const otherNode = event.otherCollider?.node;
if (!otherNode) {
return;
}
// どのノードを復活地点候補とするか決定
const candidate = this.triggerTargetIsRespawnPoint ? otherNode : otherNode.parent;
if (!candidate) {
return;
}
// respawnPoints に登録されているかチェック
const isRespawnPoint = this.respawnPoints.some((n) => n === candidate);
if (!isRespawnPoint) {
return;
}
// 復活地点更新
this._setRespawnPosition(candidate.worldPosition);
}
/**
* 距離ベースで復活地点への接触をチェック。
*/
private _checkRespawnPointsByDistance() {
if (!this.respawnPoints || this.respawnPoints.length === 0) {
return;
}
const currentPos = this.node.worldPosition;
const radiusSq = this.distanceCheckRadius * this.distanceCheckRadius;
for (const point of this.respawnPoints) {
if (!point) continue;
const diff = v3(
point.worldPosition.x - currentPos.x,
point.worldPosition.y - currentPos.y,
point.worldPosition.z - currentPos.z
);
const distSq = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
if (distSq <= radiusSq) {
this._setRespawnPosition(point.worldPosition);
break;
}
}
}
/**
* 復活地点を設定する。
* @param worldPos 世界座標
*/
private _setRespawnPosition(worldPos: Vec3) {
this._currentRespawnPos = worldPos.clone();
if (this.logDebugInfo) {
console.log('[RespawnAnchor] 復活地点を更新しました:', this._currentRespawnPos);
}
}
/**
* 死亡を検出したときの処理。
*/
private _onDeathDetected() {
this._isDead = true;
if (this.logDebugInfo) {
console.log('[RespawnAnchor] 死亡を検出しました。');
}
if (this.autoRespawnOnDeath) {
this.respawnNow();
}
}
/**
* 即座に復活地点へテレポートする。
* 外部からも呼び出せるように public にしてあります。
*/
public respawnNow() {
if (!this._currentRespawnPos) {
console.warn('[RespawnAnchor] 復活地点がまだ設定されていません。respawnPoints に触れてから復活してください。');
// 死亡フラグだけ戻しておく(次の死亡判定を有効にするため)
this._isDead = false;
return;
}
// 位置を復活地点にテレポート
this.node.setWorldPosition(this._currentRespawnPos);
// 速度リセット
if (this.resetVelocityOnRespawn && this._rigidBody2D) {
this._rigidBody2D.linearVelocity = v3(0, 0, 0);
this._rigidBody2D.angularVelocity = 0;
}
if (this.logDebugInfo) {
console.log('[RespawnAnchor] 復活地点へテレポートしました:', this._currentRespawnPos);
}
// 死亡フラグ解除
this._isDead = false;
}
/**
* 現在の復活地点(世界座標)を取得する。
*/
public getCurrentRespawnPosition(): Vec3 | null {
return this._currentRespawnPos ? this._currentRespawnPos.clone() : null;
}
/**
* 外部から任意の位置を復活地点として設定したい場合に使用。
*/
public setCurrentRespawnPosition(worldPos: Vec3) {
this._setRespawnPosition(worldPos);
}
}
コードのポイント解説
- onLoad()
–Collider2DとRigidBody2Dを取得し、存在しない場合は警告ログを出します。
–useTriggerColliderがtrueかつCollider2Dが存在する場合のみ、onTriggerEnterイベントを登録します。 - start()
–autoSetInitialAnchorがtrueの場合、自分自身の現在位置を初期復活地点として記録します。 - update()
– 毎フレーム、Y座標がdeathYThresholdより下に落ちていないかチェックし、死亡を検出します。
–useTriggerCollider = falseの場合は、距離ベースで復活地点への接触をチェックします。 - _onTriggerEnter()
–Collider2Dによるトリガーイベントで呼ばれます。
–triggerTargetIsRespawnPointの設定に応じて、相手ノード自身 or 親ノードを復活地点候補とし、respawnPointsに含まれていれば復活地点を更新します。 - _checkRespawnPointsByDistance()
– 距離ベースモード用。プレイヤーと各復活地点との距離がdistanceCheckRadius以下なら「触れた」とみなして復活地点を更新します。 - _onDeathDetected()
– 死亡フラグを立て、autoRespawnOnDeathがtrueなら即座にrespawnNow()を呼び出します。 - respawnNow()
– 現在の復活地点が未設定なら警告を出して終了。
– 設定されていれば、プレイヤーノードをその位置へテレポートし、必要ならRigidBody2Dの速度をリセットします。
使用手順と動作確認
1. スクリプトファイルの作成
- エディタ上部メニュー、または Assets パネルで作業用フォルダ(例:
assets/scripts)を開きます。 - Assets パネルで右クリック → Create → TypeScript を選択します。
- ファイル名を RespawnAnchor.ts に変更します。
- 作成した
RespawnAnchor.tsをダブルクリックしてエディタで開き、既存コードをすべて削除して、本記事の TypeScript コードを貼り付けて保存します。
2. テスト用シーンの準備
- プレイヤーノードの作成
– Hierarchy パネルで右クリック → Create → 2D Object → Sprite などでプレイヤー用ノードを作成し、名前をPlayerにします(名前は任意)。
– 必要に応じて画像(SpriteFrame)を設定してください。 - プレイヤーに Collider2D と RigidBody2D を追加
–Playerノードを選択し、Inspector の Add Component をクリック。
– Physics2D → BoxCollider2D(または適切な Collider2D)を追加します。
– トリガーモードで使う場合は、Collider2D のプロパティで IsTrigger にチェックを入れます。
– 同様に Physics2D → RigidBody2D を追加します(重力や移動を使わない場合でも、復活時の速度リセットをしたいなら付けておくと便利です)。 - プレイヤーに RespawnAnchor をアタッチ
–Playerノードを選択した状態で、Inspector の Add Component → Custom → RespawnAnchor を選択します。
3. 復活地点ノードの作成
- Hierarchy パネルで右クリック → Create → Empty Node を選択し、名前を
RespawnPoint1にします。 - 同様に
RespawnPoint2,RespawnPoint3など、複数の復活地点を作成しても構いません。 - それぞれのノードをシーン上で好きな位置に配置します(移動ツールで位置を調整)。
- 視認しやすくするために、Sprite を付けたり、Color を変更したりしてもOKです。
- トリガーモードで使う場合:
– 各RespawnPointノードに BoxCollider2D などを追加し、IsTrigger にチェックを入れます。
– プレイヤーがこのコライダーに入ったときにonTriggerEnterが発火します。
4. RespawnAnchor のプロパティ設定
Playerノードを選択し、Inspector で RespawnAnchor コンポーネントを確認します。- respawnPoints
– 配列の右側にある「+」ボタンをクリックして要素数を増やします。
– 各要素に、Hierarchy からRespawnPoint1,RespawnPoint2などをドラッグ&ドロップして登録します。 - useTriggerCollider
– トリガー(Collider2D)で判定したい場合はtrueのままにします。
– Collider2D を使わず、距離ベースで判定したい場合はfalseに変更します。 - triggerTargetIsRespawnPoint
– 復活地点のコライダーを 復活地点ノード自身 に付けた場合:trueのまま。
– コライダーを子ノードに付け、親ノードを復活地点として扱いたい場合:falseにします。 - distanceCheckRadius
–useTriggerCollider = falseのときに有効。
– 例:50(プレイヤーが半径50以内に近づいたら「触れた」とみなす)。 - autoSetInitialAnchor
– ゲーム開始位置を初期復活地点にしたい場合はtrue(デフォルト)。
– 必ず特定の復活地点に触れるまでは復活させたくない場合はfalse。 - deathYThreshold
– 例として-500や-1000など、シーン下方の値を設定します。
– プレイヤーがこのY座標より下に落ちると死亡扱いになります。 - autoRespawnOnDeath
– 自動で復活させたい場合はtrue(デフォルト)。
– 死亡演出を挟んでから復活させたい場合などはfalseにしておき、別スクリプトからrespawnNow()を呼び出してください(ただし、その別スクリプトはこのコンポーネントに依存する形であり、このコンポーネント自体は他に依存しません)。 - resetVelocityOnRespawn
– 復活時にプレイヤーの動きを完全に止めたい場合はtrue(デフォルト)。
– 物理挙動を特別に制御したい場合はfalse。 - logDebugInfo
– 開発中はtrueにしておくと、コンソールに復活地点の更新や死亡判定のログが出てデバッグしやすくなります。
– リリース時はfalseにしても良いでしょう。
5. 実際に動作を確認する
- シーンを保存し、Play(再生)ボタンでゲームを実行します。
- プレイヤーを移動できるようにしている場合は、操作して
RespawnPointに近づくか、トリガーに触れさせます。
– コンソールに[RespawnAnchor] 復活地点を更新しました:のログが出ていれば成功です。 - その後、プレイヤーを
deathYThresholdより下に落下させます。
– 自動復活モードの場合:プレイヤーが最後に触れた復活地点に瞬間移動します。
–autoRespawnOnDeath = falseの場合:
– 死亡フラグだけ立っている状態なので、別スクリプトやデバッグ用にrespawnNow()を呼び出すことで復活します。
まとめ
RespawnAnchor コンポーネントは、
- プレイヤーにアタッチするだけで「チェックポイント制の復活」を実現
- 復活地点はシーン上の任意ノードをドラッグ&ドロップで登録するだけ
- 死亡判定・復活処理・速度リセットまでこの1スクリプトで完結
- Collider2D を使ったトリガーモードと、距離ベースの簡易モードの両方に対応
という、汎用性の高い「復活地点管理」コンポーネントです。
外部の GameManager やシングルトンを一切必要としないため、小さなプロトタイプから本格的なアクションゲームまで、どのプロジェクトにもそのまま組み込みやすい設計になっています。
応用としては、
- チェックポイント通過時にエフェクトやSEを再生する(
_setRespawnPosition()内に演出処理を追加) - 復活時に HP を全回復するなどのゲームロジックを
respawnNow()にフックして追加 - ステージクリア後に次のステージのスタート地点を
setCurrentRespawnPosition()で事前に設定
といった拡張も簡単に行えます。
まずはこの記事のコードをそのまま導入し、プレイヤーにアタッチして「落ちたら最後に触れた地点から復活する」挙動を体感してみてください。




