Files
zeling_v2/Assets/_Game/Scripts/World/RoomTransition.cs
2026-06-07 11:49:55 +08:00

108 lines
4.9 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;
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("Seamless无缝切换流式系统标准选项绝大多数房间门使用此类型。\n" +
"AtmosphericFade短暂淡出 + 区域名提示,适合跨大区域边界。\n" +
"Room极短淡出不走流式系统仅用于非流式独立场景切换。\n" +
"Scene完整淡出 + 加载画面,大区域/地图间传送专用。")]
[SerializeField] private TransitionType _transitionType = TransitionType.Seamless;
[Header("触发方式")]
[SerializeField] private bool _autoTrigger = true; // true = 玩家进入触发器自动触发
[Header("钥匙物品校验")]
[SerializeField] private bool _requiresKeyItem; // 是否需要持有指定钥匙物品
[SerializeField] private string _requiredItemId; // 钥匙物品 ID_requiresKeyItem = true 时生效)
[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;
var request = new SceneLoadRequest
{
SceneName = _targetSceneAddress,
EntryTransitionId = _targetTransitionId,
TransitionType = _transitionType,
IsRespawn = false,
};
var sceneService = ServiceLocator.GetOrDefault<ISceneService>();
if (sceneService != null)
{
sceneService.RequestTransition(request);
return;
}
Debug.LogWarning("[RoomTransition] 无法发送过渡请求ISceneService 未在 ServiceLocator 中注册。", this);
}
/// <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);
}
}
}