2026-02-13 09:22:11 -05:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using Cielonos.Core.UI;
|
2026-05-10 11:47:55 -04:00
|
|
|
|
using Cielonos.MainGame.Characters;
|
2026-02-13 09:22:11 -05:00
|
|
|
|
using Cielonos.MainGame.Map;
|
|
|
|
|
|
using DG.Tweening;
|
|
|
|
|
|
using SLSUtilities.General;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.SceneManagement;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Cielonos.MainGame
|
|
|
|
|
|
{
|
|
|
|
|
|
public partial class MapManager : Singleton<MapManager>
|
|
|
|
|
|
{
|
|
|
|
|
|
public MapBaseCollection baseCollection;
|
2026-05-10 11:47:55 -04:00
|
|
|
|
|
2026-02-13 09:22:11 -05:00
|
|
|
|
public ZoneData currentZoneData;
|
|
|
|
|
|
public ZoneManager currentZoneManager;
|
|
|
|
|
|
|
2026-05-10 11:47:55 -04:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 加载指定 ZoneData 对应的场景,完成后回调 onComplete。
|
|
|
|
|
|
/// 首次加载时跳过淡出(画面已是黑屏),后续切换时先淡出再卸载旧场景。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="nextZoneData">目标 Zone 数据。</param>
|
|
|
|
|
|
/// <param name="onComplete">场景完全就绪后的回调。</param>
|
|
|
|
|
|
/// <param name="skipBattleSetup">
|
2026-05-23 08:27:50 -04:00
|
|
|
|
/// 为 true 时跳过敌人生成和 CombatRoomSm.StartRoom(),
|
2026-05-10 11:47:55 -04:00
|
|
|
|
/// 用于重入已完成的战斗节点(只需重新加载场景环境,无需重新开始战斗)。
|
|
|
|
|
|
/// </param>
|
|
|
|
|
|
public void LoadZone(ZoneData nextZoneData, Action onComplete = null, bool skipBattleSetup = false)
|
2026-02-13 09:22:11 -05:00
|
|
|
|
{
|
2026-05-10 11:47:55 -04:00
|
|
|
|
StartCoroutine(SwitchRoomRoutine(nextZoneData, onComplete, skipBattleSetup));
|
2026-02-13 09:22:11 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public partial class MapManager
|
|
|
|
|
|
{
|
|
|
|
|
|
public static MapBaseCollection BaseCollection => Instance.baseCollection;
|
|
|
|
|
|
}
|
2026-05-10 11:47:55 -04:00
|
|
|
|
|
2026-02-13 09:22:11 -05:00
|
|
|
|
public partial class MapManager
|
|
|
|
|
|
{
|
2026-05-10 11:47:55 -04:00
|
|
|
|
private IEnumerator SwitchRoomRoutine(ZoneData nextZoneData, Action onComplete, bool skipBattleSetup = false)
|
|
|
|
|
|
{
|
|
|
|
|
|
bool isFirstLoad = currentZoneData == null;
|
|
|
|
|
|
|
|
|
|
|
|
// 0. 禁用玩家输入,防止切换期间误操作
|
|
|
|
|
|
PlayerInputSubcontroller playerInput = MainGameManager.Player.inputSc;
|
|
|
|
|
|
playerInput.inputActions.Player.Disable();
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 淡出画面(首次加载时画面已经是黑屏,无需再 FadeToBlack)
|
|
|
|
|
|
if (!isFirstLoad)
|
|
|
|
|
|
{
|
|
|
|
|
|
bool fadeOutComplete = false;
|
|
|
|
|
|
ScreenFader.Instance.FadeToBlack(onComplete: () => fadeOutComplete = true).Play();
|
|
|
|
|
|
yield return new WaitUntil(() => fadeOutComplete);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-13 09:22:11 -05:00
|
|
|
|
// 2. 异步卸载旧场景
|
2026-05-10 11:47:55 -04:00
|
|
|
|
if (!isFirstLoad)
|
|
|
|
|
|
{
|
2026-02-13 09:22:11 -05:00
|
|
|
|
yield return SceneManager.UnloadSceneAsync(currentZoneData.sceneName);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
currentZoneData = nextZoneData;
|
2026-05-10 11:47:55 -04:00
|
|
|
|
|
|
|
|
|
|
// 3. 异步加载新场景(Additive)
|
2026-02-13 09:22:11 -05:00
|
|
|
|
string nextSceneName = nextZoneData.sceneName;
|
|
|
|
|
|
AsyncOperation op = SceneManager.LoadSceneAsync(nextSceneName, LoadSceneMode.Additive);
|
2026-05-10 11:47:55 -04:00
|
|
|
|
op.allowSceneActivation = false;
|
2026-02-13 09:22:11 -05:00
|
|
|
|
|
2026-05-10 11:47:55 -04:00
|
|
|
|
while (op.progress < 0.9f)
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return null;
|
2026-02-13 09:22:11 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 11:47:55 -04:00
|
|
|
|
op.allowSceneActivation = true;
|
|
|
|
|
|
yield return op;
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 设为活跃场景
|
2026-02-13 09:22:11 -05:00
|
|
|
|
Scene nextScene = SceneManager.GetSceneByName(nextSceneName);
|
|
|
|
|
|
SceneManager.SetActiveScene(nextScene);
|
|
|
|
|
|
|
|
|
|
|
|
yield return new WaitForEndOfFrame();
|
2026-05-10 11:47:55 -04:00
|
|
|
|
|
|
|
|
|
|
// 5. 重置战斗状态、初始化 Zone
|
2026-05-23 08:27:50 -04:00
|
|
|
|
CombatManager.AttackAreaSm.Reset();
|
|
|
|
|
|
CombatManager.CombatRoomSm.Reset();
|
2026-05-10 11:47:55 -04:00
|
|
|
|
|
|
|
|
|
|
// 6. 将玩家放置到 playerSpawns 指定的出生点(无论是否跳过战斗均需执行)
|
|
|
|
|
|
SpawnPlayerAtZone(nextZoneData);
|
|
|
|
|
|
|
|
|
|
|
|
if (skipBattleSetup)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 已完成节点:仅生成交互物体(ExitGate 等),跳过敌人生成和战斗启动
|
|
|
|
|
|
ZoneManager.instance.SetupZoneWithoutEnemies(currentZoneData);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
ZoneManager.instance.SetupZone(currentZoneData);
|
|
|
|
|
|
|
|
|
|
|
|
// 等待一帧,让所有 Instantiate 出的敌人执行 Start(),
|
|
|
|
|
|
// 将自身 Add 进 activeEnemiesList,再启动战斗房间判定。
|
|
|
|
|
|
yield return null;
|
2026-05-23 08:27:50 -04:00
|
|
|
|
CombatManager.CombatRoomSm.StartRoom();
|
2026-05-10 11:47:55 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 7. 淡入画面
|
2026-02-13 09:22:11 -05:00
|
|
|
|
yield return new WaitForSeconds(0.5f);
|
|
|
|
|
|
ScreenFader.Instance.FadeToClear().Play();
|
2026-05-10 11:47:55 -04:00
|
|
|
|
|
|
|
|
|
|
// 8. 恢复玩家输入
|
|
|
|
|
|
playerInput.inputActions.Player.Enable();
|
|
|
|
|
|
|
|
|
|
|
|
// 9. 回调通知调用方(RunManager)
|
|
|
|
|
|
onComplete?.Invoke();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 将玩家传送到 ZoneData.playerSpawns 中随机选择的出生点。
|
|
|
|
|
|
/// 若无配置则回退到原点。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void SpawnPlayerAtZone(ZoneData zoneData)
|
|
|
|
|
|
{
|
|
|
|
|
|
Transform playerTransform = MainGameManager.Player.transform;
|
|
|
|
|
|
|
|
|
|
|
|
if (zoneData.playerSpawns == null || zoneData.playerSpawns.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning("[MapManager] ZoneData 未配置 playerSpawns,玩家将放置在原点。");
|
|
|
|
|
|
playerTransform.position = Vector3.zero;
|
|
|
|
|
|
playerTransform.rotation = Quaternion.identity;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 多个出生点时随机选择一个
|
|
|
|
|
|
ZoneData.SpawnPointKey spawnKey = zoneData.playerSpawns.Count == 1
|
|
|
|
|
|
? zoneData.playerSpawns[0]
|
|
|
|
|
|
: zoneData.playerSpawns[UnityEngine.Random.Range(0, zoneData.playerSpawns.Count)];
|
|
|
|
|
|
|
|
|
|
|
|
if (ZoneManager.instance.spawnPoints.TryGetValue(spawnKey.group, out var points)
|
|
|
|
|
|
&& spawnKey.index < points.Count)
|
|
|
|
|
|
{
|
|
|
|
|
|
SpawnPoint point = points[spawnKey.index];
|
|
|
|
|
|
point.GetTransform(out Vector3 position, out Quaternion rotation);
|
|
|
|
|
|
playerTransform.position = position;
|
|
|
|
|
|
playerTransform.rotation = rotation;
|
|
|
|
|
|
Debug.Log($"[MapManager] 玩家放置在出生点 {spawnKey.group}_{spawnKey.index}。");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning($"[MapManager] 出生点 '{spawnKey.group}_{spawnKey.index}' 不存在,玩家将放置在原点。");
|
|
|
|
|
|
playerTransform.position = Vector3.zero;
|
|
|
|
|
|
playerTransform.rotation = Quaternion.identity;
|
|
|
|
|
|
}
|
2026-02-13 09:22:11 -05:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-05-10 11:47:55 -04:00
|
|
|
|
}
|