feat(world): 检查点复活位置由 RespawnPoint 子节点显式配置

CheckpointMarker 新增 _respawnPoint 引用,注册的检查点位置改为
该子节点的位置——触发区与出生点解耦,触发区可横跨通道、出生点
精确落在安全平台上。漏配时 Awake 显式报错且不注册(不以标记
自身位置兜底)。Gizmos 增画复活点(青色)与触发区连线,漏配
画红叉警示。PlaceCheckpointMarker 脚手架自动创建并绑定
RespawnPoint 子节点。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 11:26:02 +08:00
parent bedb0f8ff4
commit 5ccab35948
2 changed files with 35 additions and 1 deletions

View File

@@ -13,6 +13,8 @@ namespace BaseGames.World
/// - 激活状态仅存于运行时,不持久化,换房间后重置
/// - 闩锁按接触周期:进入时注册并广播一次,离开触发区后重置,
/// 同一次接触内不重复结算
/// - 触发区与出生位置解耦:注册的是 _respawnPoint 子节点的位置,
/// 触发区可横跨通道,出生点精确落在安全平台上
/// </summary>
[RequireComponent(typeof(Collider2D))]
public class CheckpointMarker : MonoBehaviour
@@ -21,6 +23,10 @@ namespace BaseGames.World
[Tooltip("勾选 Player 层")]
[SerializeField] private LayerMask _playerLayers;
[Header("复活点")]
[Tooltip("玩家回溯时出现的位置(必配,脚手架自动创建 RespawnPoint 子节点)")]
[SerializeField] private Transform _respawnPoint;
[Header("事件")]
[Tooltip("EVT_CheckpointReached — 激活时广播,供 VFX/SFX 使用")]
[SerializeField] private VoidEventChannelSO _onCheckpointReached;
@@ -38,15 +44,20 @@ namespace BaseGames.World
col.isTrigger = true;
Debug.LogWarning($"[CheckpointMarker] {name}: Collider2D.isTrigger 已自动设为 true。", this);
}
if (_respawnPoint == null)
Debug.LogError($"[CheckpointMarker] {name}: _respawnPoint 未绑定,检查点无法注册。" +
"请用脚手架BaseGames/Scene/Place/Checkpoint Marker创建或手动补 RespawnPoint 子节点并绑定。", this);
}
private void OnTriggerEnter2D(Collider2D other)
{
if (_isActivated) return;
if ((_playerLayers.value & (1 << other.gameObject.layer)) == 0) return;
if (_respawnPoint == null) return; // 漏配已在 Awake 报错,此处不以标记自身位置兜底
_isActivated = true;
ServiceLocator.GetOrDefault<ICheckpointService>()?.RegisterCheckpoint(transform.position);
ServiceLocator.GetOrDefault<ICheckpointService>()?.RegisterCheckpoint(_respawnPoint.position);
_onCheckpointReached?.Raise();
}
@@ -64,6 +75,23 @@ namespace BaseGames.World
Gizmos.DrawWireSphere(transform.position, 0.4f);
Gizmos.DrawLine(transform.position + Vector3.down * 0.4f,
transform.position + Vector3.up * 0.8f);
// 复活点:青色小球 + 落点竖线 + 与触发区的连线;漏配画红叉警示
if (_respawnPoint != null)
{
Gizmos.color = new Color(0f, 0.8f, 1f, 0.9f);
Gizmos.DrawWireSphere(_respawnPoint.position, 0.25f);
Gizmos.DrawLine(_respawnPoint.position + Vector3.down * 0.5f,
_respawnPoint.position + Vector3.up * 0.5f);
Gizmos.color = new Color(0f, 0.8f, 1f, 0.4f);
Gizmos.DrawLine(transform.position, _respawnPoint.position);
}
else
{
Gizmos.color = Color.red;
Gizmos.DrawLine(transform.position + new Vector3(-0.3f, -0.3f), transform.position + new Vector3(0.3f, 0.3f));
Gizmos.DrawLine(transform.position + new Vector3(-0.3f, 0.3f), transform.position + new Vector3(0.3f, -0.3f));
}
}
}
}