- Added RequestTransition method to ISceneService for direct scene transition requests without needing Inspector SO references. - Updated DoorTransition and RoomTransition to utilize the new RequestTransition method via ServiceLocator. - Introduced SceneFadeController to manage scene fade effects during transitions, with event channel integration for fade requests. - Created HUDScaffoldWizard to automate HUD Canvas setup, including various UI elements and event channel bindings. - Updated assembly definitions to include necessary dependencies for new UI components. - Added Streaming assets for budget configuration to optimize scene loading and memory management.
109 lines
5.0 KiB
C#
109 lines
5.0 KiB
C#
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,
|
||
ShowLoadingScreen = _transitionType == TransitionType.Scene,
|
||
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);
|
||
}
|
||
}
|
||
}
|