2025-09-19 08:26:54 +08:00
|
|
|
|
// Managers/TileManager.cs
|
|
|
|
|
|
|
|
|
|
|
|
using System;
|
2025-08-28 16:20:24 +08:00
|
|
|
|
using System.Collections.Generic;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Threading.Tasks;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
using Data;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
using Map;
|
2025-08-07 16:44:43 +08:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.Tilemaps;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
using Utils;
|
|
|
|
|
|
using Object = UnityEngine.Object; // 明确指定UnityEngine.Object
|
2025-08-07 16:44:43 +08:00
|
|
|
|
|
|
|
|
|
|
namespace Managers
|
|
|
|
|
|
{
|
2025-08-27 19:56:49 +08:00
|
|
|
|
public class TileManager : Singleton<TileManager>, ILaunchManager
|
2025-08-07 16:44:43 +08:00
|
|
|
|
{
|
2025-09-19 08:26:54 +08:00
|
|
|
|
// 缓存所有根据定义生成的RuleTile实例
|
2025-10-10 14:08:23 +08:00
|
|
|
|
private readonly Dictionary<string, RuleTile> _cachedTiles = new();
|
2025-09-19 08:26:54 +08:00
|
|
|
|
|
|
|
|
|
|
// 地图生成器工作类映射,Key: MapGeneratorDef.defName, Value: MapGeneratorWorkClassBase
|
2025-10-10 14:08:23 +08:00
|
|
|
|
private readonly Dictionary<string, MapGeneratorWorkClassBase> _mapGeneratorWorkClassMap = new();
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 指示管理器是否已完成初始化。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool Completed { get; set; } // 新增:实现 ILaunchManager 接口的 Completed 属性
|
2025-08-19 20:22:10 +08:00
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
public string StepDescription => "正在加载瓦片";
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化瓦片管理器:加载所有瓦片定义并创建RuleTile实例,加载地图生成器定义。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>一个表示异步操作完成的 Task。</returns>
|
|
|
|
|
|
public Task Init() // 接口变更:方法签名变为 async Task
|
2025-08-07 16:44:43 +08:00
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
// 使用 Completed 属性作为统一的状态检查,防止重复初始化
|
|
|
|
|
|
if (Completed) return Task.CompletedTask;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
// 遵循不检查单例的原则,假定 DefineManager.Instance 始终可用。
|
2025-08-27 19:56:49 +08:00
|
|
|
|
var tileDefs = DefineManager.Instance.QueryDefinesByType<TileDef>();
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (tileDefs == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Completed = true; // 即使没有定义,也认为初始化流程已完成
|
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
|
}
|
2025-09-19 08:26:54 +08:00
|
|
|
|
|
|
|
|
|
|
foreach (var def in tileDefs)
|
2025-08-07 16:44:43 +08:00
|
|
|
|
{
|
2025-09-19 08:26:54 +08:00
|
|
|
|
if (string.IsNullOrEmpty(def.defName))
|
2025-08-27 19:56:49 +08:00
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
Debug.LogWarning("发现未定义名称或defName的TileDef,已跳过。");
|
2025-09-19 08:26:54 +08:00
|
|
|
|
continue;
|
2025-08-27 19:56:49 +08:00
|
|
|
|
}
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
var tileName = def.defName;
|
|
|
|
|
|
var ruleTile = ScriptableObject.CreateInstance<RuleTile>();
|
|
|
|
|
|
ruleTile.name = tileName; // 设置ScriptableObject的名称
|
|
|
|
|
|
|
|
|
|
|
|
ruleTile.m_DefaultColliderType = def.collider;
|
2025-10-10 14:08:23 +08:00
|
|
|
|
// 遵循不检查单例的原则,假定 PackagesImageManager.Instance 始终可用。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
ruleTile.m_DefaultSprite = PackagesImageManager.Instance.GetSprite(def.texture);
|
|
|
|
|
|
ruleTile.m_TilingRules = GetTileRules(def.rules);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
_cachedTiles[tileName] = ruleTile;
|
2025-08-07 16:44:43 +08:00
|
|
|
|
}
|
2025-08-28 16:20:24 +08:00
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
// 遵循不检查单例的原则,假定 DefineManager.Instance 始终可用。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
var generatorDefs = DefineManager.Instance.QueryDefinesByType<MapGeneratorDef>();
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (generatorDefs != null) // 检查 generatorDefs 是否为 null
|
2025-08-07 16:44:43 +08:00
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
foreach (var mapGeneratorDef in generatorDefs)
|
2025-08-07 16:44:43 +08:00
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
var workClass = StringUtils.CreateMapGeneratorInstance(mapGeneratorDef.workClass);
|
|
|
|
|
|
if (workClass == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning($"无法为地图生成器 '{mapGeneratorDef.defName}' 创建工作类 '{mapGeneratorDef.workClass}',已跳过。");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
workClass.Init(mapGeneratorDef.value);
|
|
|
|
|
|
_mapGeneratorWorkClassMap[mapGeneratorDef.defName] = workClass;
|
|
|
|
|
|
}
|
2025-08-07 16:44:43 +08:00
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Completed = true; // 在所有初始化逻辑完成后设置 Completed 为 true
|
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
|
// 由于 Init 方法内部当前没有真正的异步操作,不需要显式 await Task.CompletedTask;
|
|
|
|
|
|
// 编译器会为同步的 async Task 方法自动生成一个已完成的 Task。
|
2025-08-07 16:44:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 清空所有缓存的瓦片定义和地图生成器工作类。
|
|
|
|
|
|
/// </summary>
|
2025-08-27 19:56:49 +08:00
|
|
|
|
public void Clear()
|
2025-08-07 16:44:43 +08:00
|
|
|
|
{
|
2025-09-19 08:26:54 +08:00
|
|
|
|
foreach (var tile in _cachedTiles.Values)
|
|
|
|
|
|
if (tile != null)
|
2025-10-10 14:08:23 +08:00
|
|
|
|
Object.Destroy(tile); // 销毁动态创建的 ScriptableObject 实例
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
_cachedTiles.Clear();
|
|
|
|
|
|
_mapGeneratorWorkClassMap.Clear(); // 清空地图生成器工作类映射
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
|
|
|
|
|
Completed = false; // 清理后将 Completed 置为 false
|
2025-08-07 16:44:43 +08:00
|
|
|
|
}
|
2025-08-28 16:20:24 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
private static List<RuleTile.TilingRule> GetTileRules(RuleTileRuleDef[] rules)
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
// Null-conditional operator 和 ToList() 确保即使 rules 为 null 也不会抛出异常
|
|
|
|
|
|
return rules?.Select(GetTileRule).ToList() ?? new List<RuleTile.TilingRule>();
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
2025-08-07 16:44:43 +08:00
|
|
|
|
|
2025-08-19 20:22:10 +08:00
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 将自定义的 RuleTileRuleDef 转换为 Unity 的 RuleTile.TilingRule。
|
2025-08-19 20:22:10 +08:00
|
|
|
|
/// </summary>
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <param name="ruleDef">自定义的 RuleTileRuleDef 规则定义。</param>
|
|
|
|
|
|
/// <returns>转换后的 RuleTile.TilingRule 实例。</returns>
|
|
|
|
|
|
private static RuleTile.TilingRule GetTileRule(RuleTileRuleDef ruleDef)
|
2025-08-07 16:44:43 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
if (ruleDef == null)
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
var tilingRule = new RuleTile.TilingRule
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
// 遵循不检查单例的原则,假定 PackagesImageManager.Instance 始终可用。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
m_Sprites = PackagesImageManager.Instance.GetSprites(ruleDef.animationTextures.ToArray()),
|
|
|
|
|
|
m_Output = ruleDef.outputType,
|
|
|
|
|
|
m_ColliderType = ruleDef.outputCollider,
|
|
|
|
|
|
m_PerlinScale = ruleDef.chance,
|
|
|
|
|
|
m_MaxAnimationSpeed = ruleDef.animationSpeed,
|
|
|
|
|
|
m_MinAnimationSpeed = ruleDef.animationSpeed,
|
|
|
|
|
|
m_RuleTransform = ruleDef.transform
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 使用 Dictionary 存储邻居条件,键为位置,值为邻居类型
|
|
|
|
|
|
var neighborConditionsMap = new Dictionary<Vector3Int, int>();
|
|
|
|
|
|
|
|
|
|
|
|
// 预设的8个邻居位置
|
2025-10-10 14:08:23 +08:00
|
|
|
|
var defaultPositions = new[]
|
2025-09-28 15:02:57 +08:00
|
|
|
|
{
|
|
|
|
|
|
new Vector3Int(-1, 1, 0),
|
|
|
|
|
|
new Vector3Int(0, 1, 0),
|
|
|
|
|
|
new Vector3Int(1, 1, 0),
|
|
|
|
|
|
new Vector3Int(-1, 0, 0),
|
|
|
|
|
|
new Vector3Int(1, 0, 0),
|
|
|
|
|
|
new Vector3Int(-1, -1, 0),
|
|
|
|
|
|
new Vector3Int(0, -1, 0),
|
|
|
|
|
|
new Vector3Int(1, -1, 0)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理标准8个邻居条件
|
2025-09-19 08:26:54 +08:00
|
|
|
|
for (var i = 0; i < ruleDef.neighborConditions.Length && i < 8; i++)
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
int neighborType;
|
|
|
|
|
|
switch (ruleDef.neighborConditions[i])
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
|
|
|
|
|
case RuleTileRuleDef.NeighborConditionType.NotThis:
|
2025-09-28 15:02:57 +08:00
|
|
|
|
neighborType = RuleTile.TilingRuleOutput.Neighbor.NotThis;
|
|
|
|
|
|
neighborConditionsMap[defaultPositions[i]] = neighborType; // 添加或更新
|
2025-09-19 08:26:54 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case RuleTileRuleDef.NeighborConditionType.This:
|
2025-09-28 15:02:57 +08:00
|
|
|
|
neighborType = RuleTile.TilingRuleOutput.Neighbor.This;
|
|
|
|
|
|
neighborConditionsMap[defaultPositions[i]] = neighborType; // 添加或更新
|
2025-09-19 08:26:54 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case RuleTileRuleDef.NeighborConditionType.Any:
|
|
|
|
|
|
default:
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 如果是Any或默认,则不添加到map中,表示不关心此位置
|
|
|
|
|
|
break;
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
2025-09-28 15:02:57 +08:00
|
|
|
|
}
|
2025-09-19 08:26:54 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
// 处理扩展邻居条件,如果位置重复,则覆盖标准8个邻居的定义
|
|
|
|
|
|
if (ruleDef.neighborConditionExtend != null)
|
|
|
|
|
|
foreach (var neighborConditionDef in ruleDef.neighborConditionExtend)
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
var pos = StringUtils.StringToVector3Int(neighborConditionDef.position);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
int neighborType;
|
|
|
|
|
|
switch (neighborConditionDef.Type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case RuleTileRuleDef.NeighborConditionType.NotThis:
|
|
|
|
|
|
neighborType = RuleTile.TilingRuleOutput.Neighbor.NotThis;
|
|
|
|
|
|
neighborConditionsMap[pos] = neighborType; // 添加或覆盖
|
|
|
|
|
|
break;
|
|
|
|
|
|
case RuleTileRuleDef.NeighborConditionType.This:
|
|
|
|
|
|
neighborType = RuleTile.TilingRuleOutput.Neighbor.This;
|
|
|
|
|
|
neighborConditionsMap[pos] = neighborType; // 添加或覆盖
|
|
|
|
|
|
break;
|
|
|
|
|
|
case RuleTileRuleDef.NeighborConditionType.Any:
|
|
|
|
|
|
default:
|
|
|
|
|
|
// 如果是Any或默认,则不添加到map中
|
|
|
|
|
|
// 如果我们希望Any清除之前的显式定义,可以在这里neighborConditionsMap.Remove(pos);
|
|
|
|
|
|
// 但通常Any意味着不关心,所以保持不添加即可
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-10 14:08:23 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
tilingRule.m_NeighborPositions = new List<Vector3Int>(neighborConditionsMap.Keys);
|
|
|
|
|
|
tilingRule.m_Neighbors = new List<int>(neighborConditionsMap.Values);
|
|
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
return tilingRule;
|
2025-08-07 16:44:43 +08:00
|
|
|
|
}
|
2025-08-27 19:56:49 +08:00
|
|
|
|
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
2025-08-27 19:56:49 +08:00
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 根据名称获取一个 RuleTile 实例。
|
2025-08-27 19:56:49 +08:00
|
|
|
|
/// </summary>
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <param name="tileName">瓦片的名称 (TileDef.defName)</param>
|
|
|
|
|
|
/// <returns>对应的 RuleTile 实例,如果找不到则返回 null。</returns>
|
|
|
|
|
|
public TileBase GetTile(string tileName)
|
2025-08-27 19:56:49 +08:00
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (_cachedTiles.TryGetValue(tileName, out var tile)) return tile;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
Debug.LogWarning($"瓦片 '{tileName}' 未在TileManager缓存中找到。");
|
|
|
|
|
|
return null;
|
2025-08-27 19:56:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
/// 应用指定的地图生成器,现在是非阻塞的异步操作。
|
2025-08-27 19:56:49 +08:00
|
|
|
|
/// </summary>
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <param name="generatorName">要应用的生成器名称。</param>
|
2025-09-28 15:02:57 +08:00
|
|
|
|
/// <param name="landform">可选:指定要使用的 MapGenerator 实例。如果为 null,将尝试从 Program.Instance.FocusedDimension 获取。</param>
|
2025-09-19 08:26:54 +08:00
|
|
|
|
/// <returns>一个表示异步操作完成的 Task。</returns>
|
2025-10-10 14:08:23 +08:00
|
|
|
|
public async Task ApplyMapGenerator(string generatorName, Landform landform = null)
|
2025-08-27 19:56:49 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
if (landform == null)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 尝试从 Program.Instance.FocusedDimension 获取 mapGenerator
|
|
|
|
|
|
// 假设 Program 和 FocusedDimension 结构存在
|
2025-10-10 14:08:23 +08:00
|
|
|
|
// 遵循不检查单例、不检查给定的API的原则。
|
|
|
|
|
|
landform = Program.Instance.FocusedDimension.landform;
|
2025-09-28 15:02:57 +08:00
|
|
|
|
if (landform == null)
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError(
|
2025-10-10 14:08:23 +08:00
|
|
|
|
$"ApplyMapGenerator: 无法找到地图生成器 '{generatorName}' 对应的 mapGenerator。Program.Instance、FocusedDimension 或其 landform 可能为空。");
|
2025-09-19 08:26:54 +08:00
|
|
|
|
return; // async Task 方法直接 return; 意味着返回 Task.CompletedTask
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
2025-10-10 14:08:23 +08:00
|
|
|
|
if (_mapGeneratorWorkClassMap == null) // 这个检查在 Init 保证了 map 不会为 null 后,理论上在这里是不需要的。
|
2025-09-19 08:26:54 +08:00
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"ApplyMapGenerator: _mapGeneratorWorkClassMap 未初始化,无法找到生成器 '{generatorName}'。");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
if (_mapGeneratorWorkClassMap.TryGetValue(generatorName, out var mapGeneratorWorkClass))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (mapGeneratorWorkClass == null)
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError(
|
|
|
|
|
|
$"ApplyMapGenerator: 为生成器 '{generatorName}' 找到了一个空的 IMapGeneratorWorkClass 实例。这表明 _mapGeneratorWorkClassMap 配置存在问题。");
|
2025-09-19 08:26:54 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
2025-09-19 08:26:54 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
await mapGeneratorWorkClass.Process(landform); // <-- 使用 await 调用异步 Process 方法
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"ApplyMapGenerator: 地图生成器 '{generatorName}' 异步处理过程中发生错误: {ex.Message}");
|
|
|
|
|
|
throw; // 抛出异常以通知调用者,或者根据实际情况选择捕获并完全处理
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-09-28 15:02:57 +08:00
|
|
|
|
Debug.LogError(
|
|
|
|
|
|
$"ApplyMapGenerator: 未找到名为 '{generatorName}' 的 IMapGeneratorWorkClass。请确保该生成器已在 _mapGeneratorWorkClassMap 中注册。");
|
2025-09-19 08:26:54 +08:00
|
|
|
|
}
|
2025-08-27 19:56:49 +08:00
|
|
|
|
}
|
2025-09-28 15:02:57 +08:00
|
|
|
|
|
|
|
|
|
|
public MapGeneratorWorkClassBase GetMapGeneratorWorkClass(string defName)
|
|
|
|
|
|
{
|
2025-10-10 14:08:23 +08:00
|
|
|
|
return _mapGeneratorWorkClassMap?.GetValueOrDefault(defName, null);
|
2025-09-28 15:02:57 +08:00
|
|
|
|
}
|
2025-08-07 16:44:43 +08:00
|
|
|
|
}
|
2025-08-27 19:56:49 +08:00
|
|
|
|
}
|