Files
zeling_v2/Assets/_Game/Scripts/World/RoomTransition.cs

100 lines
4.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BaseGames.Core.Events;
using UnityEngine;
namespace BaseGames.World
{
/// <summary>
/// 房间/场景过渡触发器。玩家进入触发器或按交互键时,广播 <see cref="SceneLoadRequest"/>。
/// <para>
/// 通过 <see cref="_transitionType"/> 控制过渡演出:
/// <list type="bullet">
/// <item><b>Room</b>:极短淡出,无加载画面,适合相邻房间边界。</item>
/// <item><b>Scene</b>:完整淡出 + 加载画面,适合大区域切换。</item>
/// </list>
/// 如需门动画,请改用 <see cref="DoorTransition"/> 组件,它会在动画完成后内部触发本组件。
/// </para>
/// </summary>
[RequireComponent(typeof(Collider2D))]
public class RoomTransition : MonoBehaviour, IInteractable
{
[Header("本传送门标识")]
[SerializeField] private string _transitionId; // 本出口唯一 ID供 SceneLoader 写入复活点)
[Header("目标")]
[SerializeField] private string _targetSceneAddress; // Addressable key目标场景
[SerializeField] private string _targetTransitionId; // 目标房间出生点 ID
[Header("过渡类型")]
[Tooltip("Room极短淡出无加载画面相邻房间边界专用。\n" +
"Scene完整淡出 + 加载画面,大区域/地图间切换专用。")]
[SerializeField] private TransitionType _transitionType = TransitionType.Room;
[Header("触发方式")]
[SerializeField] private bool _autoTrigger = true; // true = 玩家进入触发器自动触发
[Header("钥匙物品校验")]
[SerializeField] private bool _requiresKeyItem; // 是否需要持有指定钥匙物品
[SerializeField] private string _requiredItemId; // 钥匙物品 ID_requiresKeyItem = true 时生效)
[Header("事件频道")]
[SerializeField] private SceneLoadRequestEventChannelSO _onSceneLoadRequest;
[Header("世界状态")]
[SerializeField] private WorldStateRegistry _worldState;
// ── IInteractable ─────────────────────────────────────────────────────
public bool CanInteract => !_autoTrigger;
public string InteractPrompt => _transitionType == TransitionType.Scene ? "前往下一区域" : "进入";
public void Interact(Transform player) => RequestTransition();
public void OnPlayerEnterRange(Transform player) { }
public void OnPlayerExitRange() { }
// ── Auto Trigger ──────────────────────────────────────────────────────
private void OnTriggerEnter2D(Collider2D other)
{
if (!_autoTrigger) return;
if (!other.CompareTag("Player")) return;
RequestTransition();
}
/// <summary>触发过渡。可由触发器、交互系统或 <see cref="DoorTransition"/> 调用。</summary>
public void RequestTransition()
{
if (_requiresKeyItem && !HasItem(_requiredItemId)) return;
_onSceneLoadRequest?.Raise(new SceneLoadRequest
{
SceneName = _targetSceneAddress,
EntryTransitionId = _targetTransitionId,
TransitionType = _transitionType,
ShowLoadingScreen = _transitionType == TransitionType.Scene,
IsRespawn = false,
});
}
/// <summary>检查玩家是否持有指定物品(通过 WorldStateRegistry.IsCollected 检查)。</summary>
private bool HasItem(string itemId)
{
if (string.IsNullOrEmpty(itemId)) return true;
if (_worldState == null)
{
Debug.LogWarning($"[RoomTransition] WorldStateRegistry 未配置,钥匙 {itemId} 检查跳过");
return false;
}
return _worldState.IsCollected(itemId);
}
private void OnDrawGizmos()
{
var col = GetComponent<Collider2D>();
if (col == null) return;
Gizmos.color = _transitionType == TransitionType.Scene
? new Color(1f, 0.6f, 0f, 0.6f) // 橙色:大区域切换
: new Color(0f, 1f, 0.5f, 0.6f); // 绿色:房间切换
Gizmos.DrawWireCube(transform.position, col.bounds.size);
}
}
}