diff --git a/Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs b/Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs index 46dada3..6b16e76 100644 --- a/Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs +++ b/Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs @@ -1636,8 +1636,14 @@ namespace BaseGames.Editor AssignLayerMask(marker, "_playerLayers", "Player", report); AssignAsset(marker, "_onCheckpointReached", report, false, "EVT_CheckpointReached"); + // RespawnPoint 子节点:玩家回溯时的出生位置(触发区与出生点解耦) + Transform respawnT = GetOrCreateChild(go.transform, "RespawnPoint"); + respawnT.localPosition = Vector3.zero; + AssignReference(marker, "_respawnPoint", respawnT, report); + report.Add("放置于跳跳乐段落的关键节点处;玩家经过后成为该房间最近检查点。"); report.Add("同一房间可放置多个,以最近经过的为准。"); + report.Add("调整 RespawnPoint 子节点位置 = 玩家回溯出生位置(须落在安全平台上)。"); Selection.activeGameObject = go; MarkDirtyAndLog("Checkpoint Marker", go, report); diff --git a/Assets/_Game/Scripts/World/CheckpointMarker.cs b/Assets/_Game/Scripts/World/CheckpointMarker.cs index 7aeb0a1..663aa34 100644 --- a/Assets/_Game/Scripts/World/CheckpointMarker.cs +++ b/Assets/_Game/Scripts/World/CheckpointMarker.cs @@ -13,6 +13,8 @@ namespace BaseGames.World /// - 激活状态仅存于运行时,不持久化,换房间后重置 /// - 闩锁按接触周期:进入时注册并广播一次,离开触发区后重置, /// 同一次接触内不重复结算 + /// - 触发区与出生位置解耦:注册的是 _respawnPoint 子节点的位置, + /// 触发区可横跨通道,出生点精确落在安全平台上 /// [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()?.RegisterCheckpoint(transform.position); + ServiceLocator.GetOrDefault()?.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)); + } } } }